[PATCH] improving on i18n in gnome-libs



As you probably already know there are lots of problems with current i18n
tools. Every genuine inscription can have only one equivalent in particular
language when using gettext. In some cases it's impossible to correctly
translate application to many languages.
The authors of Freeciv worked out an easy method of the partial solving this
problem. My patch is based on their idea.
Every string marked for translation can be preceded with a prefix in the
form "!prefix!". Thanks to this prefix, two appearances of the same
string can have different meanings. The prefix can be omited in
translated string, but leaving it will not influence displayed text because
it will be always stripped (it is helpful for translators who don't know
this solution). You should just use Q_() macro instead of _() in your code
to use this feature.

The advantage of my version is that if you replace _() with Q_() and add some
prefix to the string in your code, current translations will still work
(Freeciv _requires_ modified translations in this case).

Please take a look at the first attached patch and tell me if you like it.
The second patch (for gnumeric) is a simple example of how to use this
feature in the GNOME app.

If you accept this patch, we should also decide, what characters should
sorround a prefix (Q_PREFIX_START and Q_PREFIX_END in
libgnome/gnome-i18n.c), I've used '!' for both in my patch.


Zbigniew
diff -ru /home/cyba/gcvs/gnome-libs/libgnome/gnome-i18n.h gnome-libs/libgnome/gnome-i18n.h
--- /home/cyba/gcvs/gnome-libs/libgnome/gnome-i18n.h	Wed Oct 25 21:49:23 2000
+++ gnome-libs/libgnome/gnome-i18n.h	Tue Dec  5 23:41:37 2000
@@ -12,13 +12,19 @@
 
 BEGIN_GNOME_DECLS
 
+gchar *gnome_i18n_qualifier_prefix_gettext (const gchar *s);
+gchar *gnome_i18n_qualifier_prefix_dgettext (const gchar *domain, const gchar *s);
+gchar *gnome_i18n_qualifier_prefix_noop (const gchar *s);
+
 #ifdef ENABLE_NLS
 #    include <libintl.h>
 #    ifdef GNOME_EXPLICIT_TRANSLATION_DOMAIN
 #        undef _
 #        define _(String) dgettext (GNOME_EXPLICIT_TRANSLATION_DOMAIN, String)
+#        define Q_(String) gnome_i18n_qualifier_prefix_dgettext (GNOME_EXPLICIT_TRANSLATION_DOMAIN, String)
 #    else 
 #        define _(String) gettext (String)
+#        define Q_(String) gnome_i18n_qualifier_prefix_gettext (String)
 #    endif
 #    ifdef gettext_noop
 #        define N_(String) gettext_noop (String)
@@ -33,6 +39,7 @@
 #    define dcgettext(Domain,Message,Type) (Message)
 #    define bindtextdomain(Domain,Directory) (Domain)
 #    define _(String) (String)
+#    define Q_(String) gnome_i18n_qualifier_prefix_noop (String)
 #    define N_(String) (String)
 #endif
 
diff -ru /home/cyba/gcvs/gnome-libs/libgnome/gnome-i18nP.h gnome-libs/libgnome/gnome-i18nP.h
--- /home/cyba/gcvs/gnome-libs/libgnome/gnome-i18nP.h	Wed Oct 25 21:49:23 2000
+++ gnome-libs/libgnome/gnome-i18nP.h	Tue Dec  5 23:48:05 2000
@@ -13,10 +13,15 @@
 
 BEGIN_GNOME_DECLS
 
+gchar *gnome_i18n_qualifier_prefix_gettext (const gchar *s);
+gchar *gnome_i18n_qualifier_prefix_dgettext (const gchar *domain, const gchar *s);
+gchar *gnome_i18n_qualifier_prefix_noop (const gchar *s);
+
 #ifdef ENABLE_NLS
 #    include <libintl.h>
 #    undef _
 #    define _(String) dgettext (PACKAGE, String)
+#    define Q_(String) gnome_i18n_qualifier_prefix_dgettext (PACKAGE, String)
 #    ifdef gettext_noop
 #        define N_(String) gettext_noop (String)
 #    else
@@ -30,6 +35,7 @@
 #    define dcgettext(Domain,Message,Type) (Message)
 #    define bindtextdomain(Domain,Directory) (Domain)
 #    define _(String) (String)
+#    define Q_(String) gnome_i18n_qualifier_prefix_noop (String)
 #    define N_(String) (String)
 #endif
 
diff -ru /home/cyba/gcvs/gnome-libs/libgnome/gnome-i18n.c gnome-libs/libgnome/gnome-i18n.c
--- /home/cyba/gcvs/gnome-libs/libgnome/gnome-i18n.c	Wed Oct 25 21:49:23 2000
+++ gnome-libs/libgnome/gnome-i18n.c	Tue Dec  5 23:39:33 2000
@@ -6,6 +6,9 @@
 /* Name of config key we use when looking up preferred language. */
 #define LANGKEY "/Gnome/i18n/LANG"
 
+#define Q_PREFIX_START '!'
+#define Q_PREFIX_END   '!'
+
 static GHashTable *alias_table = NULL;
 
 /*read an alias file for the locales*/
@@ -361,4 +364,114 @@
 gnome_i18n_get_preferred_language (void)
 {
   return gnome_config_get_string (LANGKEY);
+}
+
+/***
+ * gnome_i18n_qualifier_prefix_gettext
+ *
+ **/
+gchar *
+gnome_i18n_qualifier_prefix_gettext (const gchar *string)
+{
+	g_assert (string != NULL);
+
+	if (*string != Q_PREFIX_START) {
+		return gettext (string);
+	} else {
+		gchar *translation;
+
+		translation = gettext (string);
+		if (translation != string) {
+			if (*translation != Q_PREFIX_START) {
+				return translation;
+			} else {
+				gchar *real_translation;
+
+				real_translation = strchr (translation + 1, Q_PREFIX_END);
+				if (real_translation != NULL) {
+					return real_translation + 1;
+				} else {
+					g_warning ("Ivalid Q_() translation: \"%s\"", translation);
+					return translation;
+				}
+			}
+		} else {
+			gchar *real_string;
+
+			real_string = strchr (string + 1, Q_PREFIX_END);
+			if (real_string != NULL) {
+				return gettext (real_string + 1);
+			} else {
+				g_warning ("Ivalid Q_() string: \"%s\"", string);
+				return (gchar *) string;
+			}
+		}
+	}
+}
+
+/***
+ * gnome_i18n_qualifier_prefix_dgettext
+ *
+ **/
+gchar *
+gnome_i18n_qualifier_prefix_dgettext (const gchar *domain, const gchar *string)
+{
+	g_assert (string != NULL);
+
+	if (*string != Q_PREFIX_START) {
+		return dgettext (domain, string);
+	} else {
+		gchar *translation;
+
+		translation = dgettext (domain, string);
+		if (translation != string) {
+			if (*translation != Q_PREFIX_START) {
+				return translation;
+			} else {
+				gchar *real_translation;
+
+				real_translation = strchr (translation + 1, Q_PREFIX_END);
+				if (real_translation != NULL) {
+					return real_translation + 1;
+				} else {
+					g_warning ("Ivalid Q_() translation: \"%s\"", translation);
+					return translation;
+				}
+			}
+		} else {
+			gchar *real_string;
+
+			real_string = strchr (string + 1, Q_PREFIX_END);
+			if (real_string != NULL) {
+				return dgettext (domain, real_string + 1);
+			} else {
+				g_warning ("Ivalid Q_() string: \"%s\"", string);
+				return (gchar *) string;
+			}
+		}
+	}
+}
+
+/***
+ * gnome_i18n_qualifier_prefix_noop
+ *
+ **/
+gchar *
+gnome_i18n_qualifier_prefix_noop (const gchar *string)
+{
+	g_assert (string != NULL);
+
+	if (*string != Q_PREFIX_START) {
+		return (gchar *) string;
+	} else {
+		gchar *real_string;
+
+		real_string = strchr (string + 1, Q_PREFIX_END);
+		if (real_string != NULL) {
+			return real_string + 1;
+		} else {
+			g_warning ("Ivalid Q_() string: \"%s\"", string);
+			return (gchar *) string;
+		}
+	}
 }
diff -ru /home/cyba/gcvs/gnumeric/po/update.pl gnumeric/po/update.pl
--- /home/cyba/gcvs/gnumeric/po/update.pl	Mon Nov 13 07:23:49 2000
+++ gnumeric/po/update.pl	Wed Dec  6 01:22:24 2000
@@ -293,7 +293,7 @@
     close INFILE;
 
     $GETTEXT ="xgettext --default-domain\=$PACKAGE --directory\=\.\."
-             ." --add-comments --keyword\=\_ --keyword\=N\_"
+             ." --add-comments --keyword\=\_ --keyword\=N\_ --keyword\=Q\_"
              ." --files-from\=\.\/POTFILES\.in ";  
     $GTEST   ="test \! -f $PACKAGE\.po \|\| \( rm -f \.\/$PACKAGE\.pot "
              ."&& mv $PACKAGE\.po \.\/$PACKAGE\.pot \)";
diff -ru /home/cyba/gcvs/gnumeric/src/commands.c gnumeric/src/commands.c
--- /home/cyba/gcvs/gnumeric/src/commands.c	Sun Dec  3 12:17:31 2000
+++ gnumeric/src/commands.c	Wed Dec  6 01:13:12 2000
@@ -1110,7 +1110,7 @@
 	me->parent.size = 1;  /* FIXME?  */
 
 	/* TODO : Something more descriptive ? maybe the range name */
-	me->parent.cmd_descriptor = g_strdup (_("Clear"));
+	me->parent.cmd_descriptor = g_strdup (Q_("!command!Clear"));
 
 	/* Register the command object */
 	return command_push_undo (wbc, obj);


[Date Prev][Date Next]   [Thread Prev][Thread Next]   [Thread Index] [Date Index] [Author Index]