From f46eb0af74f48cd0e501415d865bf655ae793856 Mon Sep 17 00:00:00 2001 From: Pierre Pronchery Date: Mon, 3 Feb 2020 06:07:08 +0100 Subject: [PATCH] Translate the Calendar --- po/POTFILES | 3 + po/es.po | 55 +++++++++++++ po/fr.po | 55 +++++++++++++ po/gettext.sh | 214 ++++++++++++++++++++++++++++++++++++++++++++++++ po/project.conf | 20 +++++ project.conf | 4 +- src/calendar.c | 22 ++--- src/main.c | 26 ++++++ src/window.c | 4 +- 9 files changed, 390 insertions(+), 13 deletions(-) create mode 100644 po/POTFILES create mode 100644 po/es.po create mode 100644 po/fr.po create mode 100755 po/gettext.sh create mode 100644 po/project.conf diff --git a/po/POTFILES b/po/POTFILES new file mode 100644 index 0000000..f6309bb --- /dev/null +++ b/po/POTFILES @@ -0,0 +1,3 @@ +../src/calendar.c +../src/main.c +../src/window.c diff --git a/po/es.po b/po/es.po new file mode 100644 index 0000000..64a8cfe --- /dev/null +++ b/po/es.po @@ -0,0 +1,55 @@ +# Spanish translations for DeforaOS Calendar. +# Copyright (c) 2020 Pierre Pronchery +# This file is distributed under the same license as DeforaOS Calendar. +# Pierre Pronchery , 2020. +# +msgid "" +msgstr "" +"Project-Id-Version: Calendar 0.0.0\n" +"Report-Msgid-Bugs-To: \n" +"POT-Creation-Date: 2020-02-03 06:04+0100\n" +"PO-Revision-Date: 2020-02-03 05:45+0100\n" +"Last-Translator: Pierre Pronchery \n" +"Language-Team: Spanish\n" +"Language: es\n" +"MIME-Version: 1.0\n" +"Content-Type: text/plain; charset=UTF-8\n" +"Content-Transfer-Encoding: 8bit\n" +"Plural-Forms: nplurals=2; plural=(n != 1);\n" + +#: ../src/calendar.c:117 +msgid "Today" +msgstr "Hoy" + +#: ../src/calendar.c:130 +msgid "Details" +msgstr "" + +#: ../src/calendar.c:178 +msgid "Open file..." +msgstr "Abrir archivo..." + +#: ../src/calendar.c:271 +msgid "Edit detail" +msgstr "" + +#: ../src/calendar.c:283 +msgid "Edit detail for " +msgstr "" + +#: ../src/calendar.c:401 ../src/calendar.c:406 +msgid "Error" +msgstr "Error" + +#: ../src/calendar.c:456 +msgid "Not a valid calendar" +msgstr "" + +#: ../src/main.c:121 +#, c-format +msgid "Usage: %s -x\n" +msgstr "Usage: %s -x\n" + +#: ../src/window.c:65 +msgid "Calendar" +msgstr "" diff --git a/po/fr.po b/po/fr.po new file mode 100644 index 0000000..f342f6f --- /dev/null +++ b/po/fr.po @@ -0,0 +1,55 @@ +# French translations for DeforaOS Calendar. +# Copyright (c) 2020 Pierre Pronchery +# This file is distributed under the same license as DeforaOS Calendar. +# Pierre Pronchery , 2020. +# +msgid "" +msgstr "" +"Project-Id-Version: Calendar 0.0.0\n" +"Report-Msgid-Bugs-To: \n" +"POT-Creation-Date: 2020-02-03 06:04+0100\n" +"PO-Revision-Date: 2020-02-03 05:45+0100\n" +"Last-Translator: Pierre Pronchery \n" +"Language-Team: French\n" +"Language: fr\n" +"MIME-Version: 1.0\n" +"Content-Type: text/plain; charset=UTF-8\n" +"Content-Transfer-Encoding: 8bit\n" +"Plural-Forms: nplurals=2; plural=(n > 1);\n" + +#: ../src/calendar.c:117 +msgid "Today" +msgstr "Aujourd'hui" + +#: ../src/calendar.c:130 +msgid "Details" +msgstr "Détails" + +#: ../src/calendar.c:178 +msgid "Open file..." +msgstr "Ouvrir fichier..." + +#: ../src/calendar.c:271 +msgid "Edit detail" +msgstr "Modifier le détail" + +#: ../src/calendar.c:283 +msgid "Edit detail for " +msgstr "Modifier le détail pour " + +#: ../src/calendar.c:401 ../src/calendar.c:406 +msgid "Error" +msgstr "Erreur" + +#: ../src/calendar.c:456 +msgid "Not a valid calendar" +msgstr "Pas un calendrier valide" + +#: ../src/main.c:121 +#, c-format +msgid "Usage: %s -x\n" +msgstr "Usage: %s -x\n" + +#: ../src/window.c:65 +msgid "Calendar" +msgstr "Calendrier" diff --git a/po/gettext.sh b/po/gettext.sh new file mode 100755 index 0000000..5f07dc2 --- /dev/null +++ b/po/gettext.sh @@ -0,0 +1,214 @@ +#!/bin/sh +#$Id$ +#Copyright (c) 2010-2017 Pierre Pronchery +# +#Redistribution and use in source and binary forms, with or without +#modification, are permitted provided that the following conditions are met: +# +# * Redistributions of source code must retain the above copyright notice, this +# list of conditions and the following disclaimer. +# * Redistributions in binary form must reproduce the above copyright notice, +# this list of conditions and the following disclaimer in the documentation +# and/or other materials provided with the distribution. +# +#THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" +#AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE +#IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE +#DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE +#FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL +#DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR +#SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER +#CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, +#OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +#OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + + + +#variables +PREFIX="/usr/local" +[ -f "../config.sh" ] && . "../config.sh" +LOCALEDIR="$PREFIX/share/locale" +POTFILES="POTFILES" +PROGNAME="gettext.sh" +#executables +DEBUG="_debug" +INSTALL="install -m 0644" +MKDIR="mkdir -p" +MSGFMT="msgfmt" +MSGINIT="msginit" +MSGMERGE="msgmerge" +RM="rm -f" +XGETTEXT="xgettext --force-po" + + +#functions +#debug +_debug() +{ + echo "$@" 1>&3 + "$@" +} + + +#error +_error() +{ + echo "$PROGNAME: $@" 1>&2 + return 2 +} + + +#usage +_usage() +{ + echo "Usage: $PROGNAME [-c|-i|-u][-P prefix] target..." 1>&2 + return 1 +} + + +#gettext_mo +_gettext_mo() +{ + package="$1" + lang="$2" + potfile="$3" + pofile="$4" + mofile="$5" + + _gettext_po "$package" "$lang" "$potfile" "$pofile" || return 1 + $DEBUG $MSGFMT -c -v -o "$mofile" "$pofile" || return 1 +} + + +#gettext_po +_gettext_po() +{ + package="$1" + lang="$2" + potfile="$3" + pofile="$4" + + if [ -f "$pofile" ]; then + $DEBUG $MSGMERGE -U "$pofile" "$potfile" || return 1 + else + $DEBUG $MSGINIT -l "$lang" -o "$pofile" -i "$potfile" \ + || return 1 + fi +} + + +#gettext_pot +_gettext_pot() +{ + package="$1" + potfile="$2" + + $DEBUG $XGETTEXT -d "$package" -o "$potfile" --keyword="_" \ + --keyword="N_" -f "$POTFILES" || return 1 +} + + +#main +clean=0 +install=0 +uninstall=0 +while getopts "ciO:uP:" name; do + case "$name" in + c) + clean=1 + ;; + i) + uninstall=0 + install=1 + ;; + O) + export "${OPTARG%%=*}"="${OPTARG#*=}" + ;; + u) + install=0 + uninstall=1 + ;; + P) + PREFIX="$OPTARG" + ;; + ?) + _usage + exit $? + ;; + esac +done +shift $(($OPTIND - 1)) +if [ $# -lt 1 ]; then + _usage + exit $? +fi + +#check the variables +if [ -z "$PACKAGE" ]; then + _error "The PACKAGE variable needs to be set" + exit $? +fi + +LOCALEDIR="$PREFIX/share/locale" +exec 3>&1 +while [ $# -gt 0 ]; do + target="$1" + source="${target#$OBJDIR}" + lang="${source%%.mo}" + lang="${lang%%.po}" + shift + + #clean + [ "$clean" -ne 0 ] && continue + + #uninstall + if [ "$uninstall" -eq 1 ]; then + $DEBUG $RM "$LOCALEDIR/$lang/LC_MESSAGES/$PACKAGE.mo" \ + || exit 2 + continue + fi + + #install + if [ "$install" -eq 1 ]; then + $DEBUG $MKDIR "$LOCALEDIR/$lang/LC_MESSAGES" || exit 2 + $DEBUG $INSTALL "$target" \ + "$LOCALEDIR/$lang/LC_MESSAGES/$PACKAGE.mo" \ + || exit 2 + continue + fi + + #create + case "$target" in + *.mo) + #XXX may not match + if [ -n "$OBJDIR" ]; then + potfile="$OBJDIR/$PACKAGE.pot" + else + potfile="$PACKAGE.pot" + fi + mofile="$target" + pofile="${source%%.mo}.po" + _gettext_mo "$PACKAGE" "$lang" "$potfile" "$pofile" \ + "$mofile" || exit 2 + ;; + *.po) + #XXX may not match + if [ -n "$OBJDIR" ]; then + potfile="$OBJDIR/$PACKAGE.pot" + else + potfile="$PACKAGE.pot" + fi + pofile="$target" + _gettext_po "$PACKAGE" "$lang" "$potfile" "$pofile" \ + || exit 2 + ;; + *.pot) + package="${source%%.pot}" + potfile="$target" + _gettext_pot "$package" "$potfile" || exit 2 + ;; + *) + exit 2 + ;; + esac +done diff --git a/po/project.conf b/po/project.conf new file mode 100644 index 0000000..5cc9745 --- /dev/null +++ b/po/project.conf @@ -0,0 +1,20 @@ +targets=Calendar.pot,es.mo,fr.mo +dist=Makefile,gettext.sh,POTFILES,es.po,fr.po + +#targets +[Calendar.pot] +type=script +script=./gettext.sh +depends=POTFILES,gettext.sh + +[es.mo] +type=script +script=./gettext.sh +install= +depends=$(OBJDIR)Calendar.pot,es.po,gettext.sh + +[fr.mo] +type=script +script=./gettext.sh +install= +depends=$(OBJDIR)Calendar.pot,fr.po,gettext.sh diff --git a/project.conf b/project.conf index 893d95e..d4286f8 100644 --- a/project.conf +++ b/project.conf @@ -1,9 +1,9 @@ vendor=Desktop package=Calendar version=0.0.0 -config=h +config=h,sh -subdirs=data,src,tools +subdirs=data,po,src,tools dist=Makefile,COPYING,config.h #dist diff --git a/src/calendar.c b/src/calendar.c index a2c1ad0..29e1310 100644 --- a/src/calendar.c +++ b/src/calendar.c @@ -23,11 +23,13 @@ #include #include #include +#include #include #include #include "event.h" #include "calendar.h" #include "../config.h" +#define _(string) gettext(string) /* constants */ #ifndef PROGNAME_CALENDAR @@ -112,7 +114,7 @@ Calendar * calendar_new(void) calendar->widget = vbox; /* toolbar */ widget = gtk_toolbar_new(); - toolitem = gtk_tool_button_new(NULL, "Today"); + toolitem = gtk_tool_button_new(NULL, _("Today")); gtk_tool_button_set_icon_name(GTK_TOOL_BUTTON(toolitem), "go-jump"); g_signal_connect_swapped(toolitem, "clicked", G_CALLBACK( _calendar_on_today), calendar); @@ -125,7 +127,7 @@ Calendar * calendar_new(void) _calendar_on_open), calendar); gtk_toolbar_insert(GTK_TOOLBAR(widget), toolitem, -1); toolitem = gtk_toggle_tool_button_new(); - gtk_tool_button_set_label(GTK_TOOL_BUTTON(toolitem), "Details"); + gtk_tool_button_set_label(GTK_TOOL_BUTTON(toolitem), _("Details")); g_signal_connect(toolitem, "toggled", G_CALLBACK(_calendar_on_details), calendar); gtk_toolbar_insert(GTK_TOOLBAR(widget), toolitem, -1); @@ -173,7 +175,7 @@ static void _calendar_on_open(gpointer data) GtkWidget * dialog; gchar * filename = NULL; - dialog = gtk_file_chooser_dialog_new("Open file...", + dialog = gtk_file_chooser_dialog_new(_("Open file..."), GTK_WINDOW(gtk_widget_get_toplevel(calendar->widget)), GTK_FILE_CHOOSER_ACTION_OPEN, GTK_STOCK_CANCEL, GTK_RESPONSE_CANCEL, @@ -259,14 +261,14 @@ static void _calendar_on_edit(gpointer data) guint year; guint month; guint day; - char buf[32]; + char buf[64]; char const * p; GtkWidget * dialog; GtkWidget * vbox; GtkWidget * entry; int res; - dialog = gtk_dialog_new_with_buttons("Edit detail", + dialog = gtk_dialog_new_with_buttons(_("Edit detail"), GTK_WINDOW(gtk_widget_get_toplevel(calendar->widget)), GTK_DIALOG_MODAL | GTK_DIALOG_DESTROY_WITH_PARENT, GTK_STOCK_CANCEL, GTK_RESPONSE_CANCEL, @@ -278,8 +280,8 @@ static void _calendar_on_edit(gpointer data) #endif gtk_calendar_get_date(GTK_CALENDAR(calendar->calendar), &year, &month, &day); - snprintf(buf, sizeof(buf), "%s%02u/%02u/%u:", "Edit detail for ", day, - ++month, year); + snprintf(buf, sizeof(buf), "%s%02u/%02u/%u:", _("Edit detail for "), + day, ++month, year); gtk_box_pack_start(GTK_BOX(vbox), gtk_label_new(buf), FALSE, TRUE, 0); entry = gtk_entry_new(); if((p = calendar_get_detail(calendar, year, month, day)) != NULL) @@ -396,12 +398,12 @@ static int _calendar_error(Calendar * calendar, char const * message, int ret) GTK_DIALOG_DESTROY_WITH_PARENT, GTK_MESSAGE_ERROR, GTK_BUTTONS_CLOSE, #if GTK_CHECK_VERSION(2, 6, 0) - "%s", "Error"); + "%s", _("Error")); gtk_message_dialog_format_secondary_text(GTK_MESSAGE_DIALOG(dialog), #endif "%s%s%s", message ? message : "", message ? ": " : "", error); - gtk_window_set_title(GTK_WINDOW(dialog), "Error"); + gtk_window_set_title(GTK_WINDOW(dialog), _("Error")); gtk_dialog_run(GTK_DIALOG(dialog)); gtk_widget_destroy(dialog); return ret; @@ -451,7 +453,7 @@ static int _open_parse(Calendar * calendar, char const * filename, FILE * fp) return -_calendar_error(calendar, filename, 1); /* FIXME report error */ fprintf(stderr, "%s: %s: %s\n", PROGNAME_CALENDAR, filename, - "Not a valid calendar"); + _("Not a valid calendar")); return -1; } ret = _open_parse_headers(calendar, filename, fp, buf, sizeof(buf)); diff --git a/src/main.c b/src/main.c index dfe281c..d741697 100644 --- a/src/main.c +++ b/src/main.c @@ -17,6 +17,8 @@ #include #include +#include +#include #include #if GTK_CHECK_VERSION(3, 0, 0) # include @@ -25,11 +27,21 @@ #include "calendar.h" #include "window.h" #include "../config.h" +#define _(string) gettext(string) /* constants */ #ifndef PROGNAME_CALENDAR # define PROGNAME_CALENDAR "calendar" #endif +#ifndef PREFIX +# define PREFIX "/usr/local" +#endif +#ifndef DATADIR +# define DATADIR PREFIX "/share" +#endif +#ifndef LOCALEDIR +# define LOCALEDIR DATADIR "/locale" +#endif /* calendar */ @@ -37,6 +49,7 @@ /* prototypes */ static int _calendar(int embedded); +static int _error(char const * message, int ret); static int _usage(void); @@ -93,6 +106,15 @@ static void _embedded_on_embedded(gpointer data) } +/* error */ +static int _error(char const * message, int ret) +{ + fputs(PROGNAME_CALENDAR ": ", stderr); + perror(message); + return ret; +} + + /* usage */ static int _usage(void) { @@ -109,6 +131,10 @@ int main(int argc, char * argv[]) int o; int embedded = 0; + if(setlocale(LC_ALL, "") == NULL) + _error("setlocale", 1); + bindtextdomain(PACKAGE, LOCALEDIR); + textdomain(PACKAGE); gtk_init(&argc, &argv); while((o = getopt(argc, argv, "x")) != -1) switch(o) diff --git a/src/window.c b/src/window.c index e819537..ac1771f 100644 --- a/src/window.c +++ b/src/window.c @@ -16,9 +16,11 @@ #include +#include #include #include "calendar.h" #include "window.h" +#define _(string) gettext(string) /* CalendarWindow */ @@ -60,7 +62,7 @@ CalendarWindow * calendarwindow_new(void) gtk_window_set_icon_name(GTK_WINDOW(calendar->window), "stock_calendar"); #endif - gtk_window_set_title(GTK_WINDOW(calendar->window), "Calendar"); + gtk_window_set_title(GTK_WINDOW(calendar->window), _("Calendar")); g_signal_connect_swapped(calendar->window, "delete-event", G_CALLBACK( _calendarwindow_on_closex), calendar); widget = calendar_get_widget(calendar->calendar);