2002-02-25  Sven Neumann  <sven@gimp.org>

	* README.i18n: updated

	* app/gui/tips-dialog.c
	* app/gui/tips-parser.[ch]: dropped the locale matching magic since
	it would never work for all cases. Instead introduced a special
	message so translators can specify the exact tips locale.
This commit is contained in:
Sven Neumann 2002-02-25 18:36:03 +00:00 committed by Sven Neumann
parent cdf2a90b03
commit 80aa8233a8
9 changed files with 604 additions and 471 deletions

View File

@ -1,3 +1,12 @@
2002-02-25 Sven Neumann <sven@gimp.org>
* README.i18n: updated
* app/gui/tips-dialog.c
* app/gui/tips-parser.[ch]: dropped the locale matching magic since
it would never work for all cases. Instead introduced a special
message so translators can specify the exact tips locale.
2002-02-25 Michael Natterer <mitch@gimp.org>
* app/core/Makefile.am

View File

@ -1,14 +1,27 @@
This document exists to document the important things to care for
because of locale support.
Actually this one is maintained by me, that is Daniel Egger
(Daniel.Egger@rz.fh-muenchen.de).
This document exists to document the important things to care
for because of locale support. It is aimed at developers and
translators. If you are a translator, you can skip the first
sections, but you definitely want to read sections 5 - 9.
Table of Contents
1. Why localisation?
2. How
3. Deep inside ...
4. Some magic ...
5. Tools and how to use them
6. Gimp is different
7. Adding additional textdomains
8. Tip of the Day messages
9. How to contribute
10. And more ?
1. Why localisation?
Many persons from many countries start to get used to Linux.
Unfortunately not everyone is able to understand English. But
even those people sometimes like to use good and free software
even those people sometimes like to use good and free software
without using a dictionary to get the unknown words.
So why not simply localise the software to make it available to
the mass which isn't wholly English native? Of course this also
@ -19,34 +32,30 @@ Actually this one is maintained by me, that is Daniel Egger
GNU provides a very nice package called gettext. This one offers
the possibility to translate chosen messages from the native language
of the program into that one of the users if a necessary catalog is
provided. Gettext therefore provides some easy tools to create and maintain
such catalogs and a few functions which can be called by the program to
enable automatic translation at runtime. The program gets linked to the
gettext library or glibc2 which already provides that functionality
and everything is fine.
By the way: gettext is a fixed part of glibc2 but will be shipped with
GIMP and so can be automatically compiled on every platform GIMP itself
runs on.
provided. Gettext therefore provides some easy tools to create and
maintain such catalogs and a few functions which can be called by the
program to enable automatic translation at runtime. The program gets
linked to the gettext library or glibc2 which already provides that
functionality and everything is fine.
3. Deep inside...
GIMP provides header files called gimpintl.h and stdplugins-intl.h in the
libgimp directory which check whether gettext is available on the system
which GIMP is compiled on and will deactivate language support if it's not.
You CAN use such a compiled GIMP even without the catalogs or on a system
which doesen't have language support.
GIMP provides header files called gimpintl.h and stdplugins-intl.h in
the libgimp directory which check whether gettext is available on the
system which GIMP is compiled on and will deactivate language support
if it's not.
If the gettext system is there it will declare 3 functions which will be
described below.
3.1 _() [more correctly: char * _( char * )]
This one is a macro for the function gettext(). You can wrap any text with
it that is allowed to be a return value of a function. If you use it then
libintl will try to translate it into the native language of the
user according to his/her environmental settings.
The gettext() function will do a lookup in the hashed catalog which contains
all the translated texts.
This one is a macro for the function gettext(). You can wrap any text
with it that is allowed to be a return value of a function. If you
use it then libintl will try to translate it into the native language
of the user according to his/her environmental settings.
The gettext() function will do a lookup in the hashed catalog which
contains all the translated texts.
- If it is found a pointer to the string will be returned to the caller.
- If not, the caller will receive a pointer to the original string.
@ -59,96 +68,98 @@ Actually this one is maintained by me, that is Daniel Egger
NOTE: I know some of the developer like short functions like _() but
for a better source understanding I suggest to use it consistently only
for text (like _("That's text!")) and not for variables (like _(text) ) BUT
gettext(text) instead.
for text (like _("That's text!")) and not for variables (like _(text)).
Use gettext(text) instead.
3.2 N_() [more correctly: const char * ( const char * ) ]
This one is a macro for the function gettext_noop(). As you can see and
guess it doesn't really do anything in the programm i.e. it is a dummy
macro but nevertheless important. As it isn't possible to call functions
in a structure as seen here:
This one is a macro for the function gettext_noop(). As you can see
and guess it doesn't really do anything in the programm i.e. it is a
dummy macro but nevertheless important. As it isn't possible to call
functions in a structure as seen here:
struct blurb
{
_("This won't work\n");
}
you have to do it in some other way. In GIMP such structures are often used
to create menus or similar things very simply. Here you have to use the
dummy to allow the generation of the template catalog which will be described
below. This one doesn't do anything but it marks the text as important to
the xgettext extractor.
you have to do it in some other way. In GIMP such structures are
often used to create menus or similar things very simply. Here you
have to use the dummy to allow the generation of the template catalog
which will be described below. This one doesn't do anything but it
marks the text as important to the xgettext extractor.
The text has to be translated manually with the next function.
3.3 gettext()
This function is the same as that macro in 3.1. But there is one big
difference: The _()'s and N_()'s are the only expressions which get parsed
by the template generator.
If you have strings that should be translated but are unfortunately in a
structure you have to do that on your own which means that you have to
parse the fields with the messages in a loop and translate the texts with
this gettext() function.
difference: The _()'s and N_()'s are the only expressions which get
parsed by the template generator.
If you have strings that should be translated but are unfortunately
in a structure you have to do that on your own which means that you
have to parse the fields with the messages in a loop and translate
the texts with this gettext() function.
Please note that it may be necessary to free or allocate memory in this
case!
Please note that it may be necessary to free or allocate memory in
this case!
4. Some magic...
As you have seen we only did the programming part until now but this isn't
all by far.
To use catalogs we'll have to create them. Now there are 3 different files
which are importart:
As you have seen we only did the programming part until now but this
isn't all by far. To use catalogs we'll have to create them. Now
there are 3 different files which are importart:
gimp.pot:
This one is the so called template. It contains the messages which are
extracted from the sources and empty fields which have to get filled by the
author. It is used to start a new catalog or to update the an already
available one.
This one is the so called template. It contains the messages which
are extracted from the sources and empty fields which have to get
filled by the author. It is used to start a new catalog or to update
the an already available one.
The Makefile will automatically call the program gettext which will extract
all messages that are wrapped by a _() or a N_() (but NOT gettext()) and
concat them to this template.
The Makefile will automatically call the program gettext which will
extract all messages that are wrapped by a _() or a N_() (but NOT
gettext()) and concat them to this template.
[language].po:
This file has to be an edited gimp.pot and contains the original messages
plus the translated ones. This file will be delivered together with GIMP
and is the base for the final catalog.
This file has to be an edited gimp.pot and contains the original
messages plus the translated ones. This file will be delivered
together with GIMP and is the base for the final catalog.
[language].mo:
This file is a compiled version of [language.po] which will be
automatically compiled by the Makefile system and installed in the locale
directory of the system. It contains everything that the .po file
contains except not translated messages, comments and other overhead.
For maximum speed it is also hashed to allow gettext a faster search.
automatically compiled by the Makefile system and installed in the
locale directory of the system. It contains everything that the .po
file contains except not translated messages, comments and other
overhead. For maximum speed it is also hashed to allow gettext a
faster search.
5. Tools and how to use them...
5. Tools and how to use them
As mentioned the to be translated strings are extracted directly from the
source and written to the template.
I guess many of you will now ask if it is necessary to add new strings
directly to the template or if there's a tool to achieve that.
I think I can calm down those of you who fear lots of had work just to
update the language files. There's a program called msgmerge which will
add all strings that are in the template but not in the uncompiled catalog
to it. Msgmerge does this job very nicely and also tries to use some kind
of fuzzy logic method for already translated strings for possible reduction
of translators work: If an original string seems similar to a new one
and it already has a translation, it will be taken over to the new catalog
together with a remark that this one may not necessarily fit.
As mentioned the to be translated strings are extracted directly from
the source and written to the template.
I guess many of you will now ask if it is necessary to add new
strings directly to the template or if there's a tool to achieve
that. I think I can calm down those of you who fear lots of had work
just to update the language files. There's a program called msgmerge
which will add all strings that are in the template but not in the
uncompiled catalog to it. Msgmerge does this job very nicely and also
tries to use some kind of fuzzy logic method for already translated
strings for possible reduction of translators work: If an original
string seems similar to a new one and it already has a translation,
it will be taken over to the new catalog together with a remark that
this one may not necessarily fit.
6. Gimp is different
Gimp is a complex application which has a bunch of scripts and plug-ins
that all want to be internationalized. Therefore there is not one catalog
but many. For a full translation of the GIMP's UI, you will have to add
translations for the following catalogs:
Gimp is a complex application which has a bunch of scripts and
plug-ins that all want to be internationalized. Therefore there is
not one catalog but many. For a full translation of the GIMP's UI,
you will have to add translations for the following catalogs:
po/gimp.pot -- the core
po-libgimp/gimp-libgimp.pot -- the libgimp library
@ -157,65 +168,71 @@ Actually this one is maintained by me, that is Daniel Egger
po-script-fu/gimp-script-fu.pot -- the script-fu scripts
When translating menu_paths, please do not translate the name of the
item_factory (that is the one in brackets at the front), e.g.
<Image>/Edit/Copy should _not_ be translated to <Bild>/Bearbeiten/Kopieren,
but to <Image>/Bearbeiten/Kopieren. If you get this wrong, Gimp will warn you
at startup about bad translations. So do always test your translations and
watch the console for output.
item_factory (that is the one in brackets at the front), e.g.
<Image>/Edit/Copy should _not_ be translated to <Bild>/Bearbeiten/Kopieren,
but to <Image>/Bearbeiten/Kopieren. If you get this wrong, Gimp will
warn you at startup about bad translations. So do always test your
translations and watch the console for output.
The version of The GIMP you are holding in your hand uses GTK+-2.0. GTK+-2.0
requires that all strings are UTF-8 encoded. Therefore to make
internationalisation work, po files need to be UTF-8 encoded. Unfortunately
most editors don't support UTF-8, so to edit your po file, you need to
convert it to an encoding your editor can handle and convert it back to
UTF-8 before commiting your changes back. The gnome-i18n module in CVS has
some scripts that help with this task, but it can also easily done using
iconv.
The version of The GIMP you are holding in your hand uses
GTK+-2.0. GTK+-2.0 requires that all strings are UTF-8
encoded. Therefore to make internationalisation work, po files need
to be UTF-8 encoded. Unfortunately most editors don't support UTF-8,
so to edit your po file, you need to convert it to an encoding your
editor can handle and convert it back to UTF-8 before commiting your
changes back. The gnome-i18n module in CVS has some scripts that help
with this task, but it can also easily done using iconv.
7. Adding additional textdomains
Third-party plug-ins (plug-ins that are not distributed with The GIMP) can't
have their messages in the gimp-std-plugins textdomain. We have therefore
provided a mechanism that allows plug-ins to install their own message
catalogs and tell The GIMP to bind to that textdomain. This is necessary so
that The GIMP can correctly translate the menupaths the plug-in registers.
Basically the plug-in has to call gimp_plugin_domain_add() or
gimp_domain_plugin_add_with_path() before it registers any functions. Have a
look at the script-fu plug-in to see how it is done in detail.
Third-party plug-ins (plug-ins that are not distributed with The
GIMP) can't have their messages in the gimp-std-plugins
textdomain. We have therefore provided a mechanism that allows
plug-ins to install their own message catalogs and tell The GIMP to
bind to that textdomain. This is necessary so that The GIMP can
correctly translate the menupaths the plug-in registers. Basically
the plug-in has to call gimp_plugin_domain_add() or
gimp_domain_plugin_add_with_path() before it registers any
functions. Have a look at the script-fu plug-in to see how it is done
in detail.
8. Tip of the Day messages
In addition to message catalogs Gimp provides a file with tips that are
displayed in a Tip of The Day window. Tips in English language are located
in tips/gimp_tips.txt. Translated tips should go into
gimp_tips.<lang>.txt. There is one more thing: You need to make sure you
have the right reference set up in po/<lang>.po file something like this:
In addition to message catalogs Gimp provides a file with tips that
are displayed in a Tip of The Day window. This file is in XML format
and can be found in the tips directory. The english tips messages are
extracted from gimp-tips.xml.in so translators can use the usual
tools to create a <lang>.po file that holds the translations. All
translations are then merged into gimp-tips.xml with language
identifiers taken from the po filename.
#: app/tips_dialog.c:72
msgid "gimp_tips.txt"
msgstr "gimp_tips.<lang>.txt"
GIMP needs to know what language it should select from gimp-tips.xml.
Therefore, there's the special message "tips-locale:C" in the main
message catalog that needs to be translated correctly. For a german
translation of the tips this would look like this:
This file needs to be UTF-8 encoded just like the po files (see section 6).
#: app/gui/tips-parser.c:158
msgid "tips-locale:C"
msgstr "tips-locale:de"
9. How to contribute
Any help with translations is appreciated. If you want to help, please get
in contact with the people from the GNOME Translation Project who coordinate
all translation efforts in the GNOME CVS tree. They have a nice web-page at
http://developer.gnome.org/projects/gtp/.
Any help with translations is appreciated. If you want to help,
please get in contact with the people from the GNOME Translation
Project who coordinate all translation efforts in the GNOME CVS
tree. They have a nice web-page at
http://developer.gnome.org/projects/gtp/.
10. And more?
I hope I mentioned everything that is worth it and hope that this document
will clarify some things. If it doesn't please write me a mail and tell me
what you want to know. This text of course contains errors, so if you find one
tell it to me, too....
We hope we mentioned everything that is worth it and hope that this
document will clarify some things. If it doesn't please write us a
mail. This text of course contains errors, so if you find one tell
us...
Happy Gimping. Yours,
Daniel Egger
Happy Gimping.
Daniel Egger
Sven Neumann
Sections (6), (7) and (9) were added by Sven Neumann <sven@gimp.org>.
He is the one to blame for errors in there...

View File

@ -78,9 +78,7 @@ tips_dialog_create (void)
filename = g_build_filename (gimp_data_directory (), "tips",
"gimp-tips.xml", NULL);
tips = gimp_tips_from_file (filename,
setlocale (LC_MESSAGES, NULL),
&error);
tips = gimp_tips_from_file (filename, &error);
g_free (filename);
if (error)

View File

@ -126,11 +126,11 @@ gimp_tip_free (GimpTip *tip)
GList *
gimp_tips_from_file (const gchar *filename,
const gchar *locale,
GError **error)
{
GMarkupParseContext *context;
TipsParser *parser;
const gchar *tips_locale;
FILE *fp;
gsize bytes;
gchar buf[4096];
@ -140,20 +140,32 @@ gimp_tips_from_file (const gchar *filename,
fp = fopen (filename, "r");
if (!fp)
{
g_set_error (error,
0, /* error domain */
0, /* error code */
g_set_error (error, 0, 0,
_("Your GIMP tips file appears to be missing!\n"
"There should be a file called gimp-tips.xml in "
"the tips subfolder of the GIMP data folder.\n"
"Please check your installation."));
"There should be a file called '%s'.\n"
"Please check your installation."), filename);
return NULL;
}
parser = g_new0 (TipsParser, 1);
parser->locale = locale;
parser->value = g_string_new (NULL);
/* This is a special string to specify the language identifier to
look for in the gimp-tips.xml file. Please translate the C in it
according to the name of the po file used for gimp-tips.xml.
E.g. for the german translation, that would be "tips-locale:de".
*/
tips_locale = _("tips-locale:C");
if (strncmp (tips_locale, "tips-locale:", 12) == 0)
{
tips_locale += 12;
if (*tips_locale && *tips_locale != 'C')
parser->locale = tips_locale;
}
else
g_warning ("Wrong translation for 'tips-locale:', fix the translation!");
context = g_markup_parse_context_new (&markup_parser, 0, parser, NULL);
while ((bytes = fread (buf, sizeof (gchar), sizeof (buf), fp)) > 0 &&
@ -175,11 +187,9 @@ gimp_tips_from_file (const gchar *filename,
if (parser->state != TIPS_START)
{
g_set_error (error,
0, /* error domain */
0, /* error code */
_("Your GIMP tips file could not be parsed correctly!\n"
"Please check your installation."));
g_set_error (error, 0, 0,
_("Your GIMP tips file could not be parsed correctly!\n"
"Please check your installation."));
}
tips = g_list_reverse (parser->tips);
@ -370,11 +380,9 @@ tips_parser_parse_locale (TipsParser *parser,
{
if (strcmp (*names, "xml:lang") == 0 && **values)
{
parser->locale_state = ((parser->locale &&
(strcmp (*values, parser->locale) == 0 ||
strncmp (*values, parser->locale, 2) == 0))
? TIPS_LOCALE_MATCH
: TIPS_LOCALE_MISMATCH);
parser->locale_state = (parser->locale &&
strcmp (*values, parser->locale) == 0 ?
TIPS_LOCALE_MATCH : TIPS_LOCALE_MISMATCH);
}
names++;

View File

@ -37,7 +37,6 @@ GimpTip * gimp_tip_new (const gchar *welcome,
void gimp_tip_free (GimpTip *tip);
GList * gimp_tips_from_file (const gchar *filename,
const gchar *locale,
GError **error);
void gimp_tips_free (GList *tips);

View File

@ -78,9 +78,7 @@ tips_dialog_create (void)
filename = g_build_filename (gimp_data_directory (), "tips",
"gimp-tips.xml", NULL);
tips = gimp_tips_from_file (filename,
setlocale (LC_MESSAGES, NULL),
&error);
tips = gimp_tips_from_file (filename, &error);
g_free (filename);
if (error)

View File

@ -126,11 +126,11 @@ gimp_tip_free (GimpTip *tip)
GList *
gimp_tips_from_file (const gchar *filename,
const gchar *locale,
GError **error)
{
GMarkupParseContext *context;
TipsParser *parser;
const gchar *tips_locale;
FILE *fp;
gsize bytes;
gchar buf[4096];
@ -140,20 +140,32 @@ gimp_tips_from_file (const gchar *filename,
fp = fopen (filename, "r");
if (!fp)
{
g_set_error (error,
0, /* error domain */
0, /* error code */
g_set_error (error, 0, 0,
_("Your GIMP tips file appears to be missing!\n"
"There should be a file called gimp-tips.xml in "
"the tips subfolder of the GIMP data folder.\n"
"Please check your installation."));
"There should be a file called '%s'.\n"
"Please check your installation."), filename);
return NULL;
}
parser = g_new0 (TipsParser, 1);
parser->locale = locale;
parser->value = g_string_new (NULL);
/* This is a special string to specify the language identifier to
look for in the gimp-tips.xml file. Please translate the C in it
according to the name of the po file used for gimp-tips.xml.
E.g. for the german translation, that would be "tips-locale:de".
*/
tips_locale = _("tips-locale:C");
if (strncmp (tips_locale, "tips-locale:", 12) == 0)
{
tips_locale += 12;
if (*tips_locale && *tips_locale != 'C')
parser->locale = tips_locale;
}
else
g_warning ("Wrong translation for 'tips-locale:', fix the translation!");
context = g_markup_parse_context_new (&markup_parser, 0, parser, NULL);
while ((bytes = fread (buf, sizeof (gchar), sizeof (buf), fp)) > 0 &&
@ -175,11 +187,9 @@ gimp_tips_from_file (const gchar *filename,
if (parser->state != TIPS_START)
{
g_set_error (error,
0, /* error domain */
0, /* error code */
_("Your GIMP tips file could not be parsed correctly!\n"
"Please check your installation."));
g_set_error (error, 0, 0,
_("Your GIMP tips file could not be parsed correctly!\n"
"Please check your installation."));
}
tips = g_list_reverse (parser->tips);
@ -370,11 +380,9 @@ tips_parser_parse_locale (TipsParser *parser,
{
if (strcmp (*names, "xml:lang") == 0 && **values)
{
parser->locale_state = ((parser->locale &&
(strcmp (*values, parser->locale) == 0 ||
strncmp (*values, parser->locale, 2) == 0))
? TIPS_LOCALE_MATCH
: TIPS_LOCALE_MISMATCH);
parser->locale_state = (parser->locale &&
strcmp (*values, parser->locale) == 0 ?
TIPS_LOCALE_MATCH : TIPS_LOCALE_MISMATCH);
}
names++;

View File

@ -37,7 +37,6 @@ GimpTip * gimp_tip_new (const gchar *welcome,
void gimp_tip_free (GimpTip *tip);
GList * gimp_tips_from_file (const gchar *filename,
const gchar *locale,
GError **error);
void gimp_tips_free (GList *tips);

705
po/de.po

File diff suppressed because it is too large Load Diff