Freeciv
Advertisement

Here you can find information about the internationalization (i18n) of Freeciv.

Freeciv uses the gettext system for internationalization and localization support. See the info file about gettext for further information.

For a quick overview of gettext, see Freeciv's gettext guide and gettext notes.

See Freeciv Localization for available translations.

How to Contribute

You may find information of general interest to all contributors here, including how to submit changes.

See the info file about gettext for definitive information on its use.

How to prepare a C source file for i18n

In every C source file that contains strings which need to be translated, you need to ensure that the file includes config.h and fcintl.h:

If the following lines are not near the top of the file, add them:

#ifdef HAVE_CONFIG_H
#include "config.h"
#endif

(typically added immediately after the large "header" comment block)

Make sure the following is also included:

#include "fcintl.h"

(included from Freeciv's ./common directory)

Also, each of these C source files must be processed by xgettext at build-time. The list of files that xgettext processes at build-time is maintained in ./po/POTFILES.in, one file per line including the path relative to the top-level Freeciv directory:

...
common/support.c
common/unit.c
common/version.c
server/barbarian.c
server/cityhand.c
server/citytools.c
...

To add a new file to the ./po/POTFILES.in list, simply add a new line in alphabetical order within the subdirectory section. E.g., adding thing.c to the ./common directory would alter the above to look like:

...
common/support.c
common/thing.c
common/unit.c
common/version.c
server/barbarian.c
server/cityhand.c
server/citytools.c
...

How to mark new strings for translation

There are two parts to arranging for a string to be translated:

  1. The string must be marked, so that xgettext will copy it to the freeciv.pot file (the master file used by the translators (people) when they localize Freeciv).
  2. The string must be run trough the gettext() function, which looks up and returns the translation of the string.


If the string is used somewhere a function can be called, then both of the above parts are accomplished with one, simple mechanism: the _() macro. When xgettext is run on a C source file, it copies all strings surrounded by _( and ) to the freeciv.pot file. Thus, _() accomplishes marking. Also, the _() macro is implemented as: #define _(String) gettext(String), which accomplishes calling gettext() on the string.

E.g.:

void myfunction(void)
{
  char *foo = _("new string");

(foo now points to the string, appropriately translated.)

If the string is used somewhere a function can not be called, then the two parts must be handled separately. First, we mark the string using the N_() macro. Like with the _() macro, when xgettext is run on a C source file, it copies all strings surrounded by N_( and ) to the freeciv.pot file.

E.g.:

#include "fcintl.h"
static char *bar = N_("new string");

This doesn't, however, call gettext() on the string. So, this must be accomplished at some later point, when the string is used in a context where a function may be called. At this later point, simply wrap the reference to the string in _( and ) (which, as we saw above, is implemented as a call to gettext()).

E.g.:

void myfunction(void)
{
  printf ("%s", _(bar));

(This prints the translation of "new string".)

See the info file about gettext for further information.

Qualified translatable strings

Some strings are too ambiguous to be easily translated. The canonical example is the English word "game", which is used in Freeciv in two roles:

  1. The game we play: Freeciv; the name of the first menu item.
  2. The terrain special of game animals -- animals hunted for food.


These are two very different concepts, and must frequently be translated into different words. However, they often occur in the code as the sole content of a string. E.g.:

menu.name = "Game"; 
special.name = "Game"; 

If we were to internationalize these in the normal gettext way, we would simply wrap each string in _( and ), e.g.:

menu.name = _("Game"); 
special.name = _("Game"); 

But, this would result in a single entry in the freeciv.pot file:

#: menu.c:123 terrain.c:321 
msgid "Game" 
msgstr "" 

And, hence, could not be translated into the two distinct words it needs be.

Freeciv solves this problem by introducing the concept of qualified translatable strings. Strings are "qualified" by prefixing them with a descriptive tag, surrounded by "?" and ":".

Using our game example, the qualified strings might be:

"?play:Game" 
"animals:Game" 

However, we don't want the qualifiers to appear to the user. To correctly strip the qualifiers, we use a new gettext-like macro: Q_(). So, our example code becomes:

menu.name = Q_("?play:Game"); 
special.name = Q_("?animals:Game"); 

Also, the Q_() macro acts as a marker for translatable strings. And, since the strings are now different as far as xgettext is concerned, they show up as two distinct entries in the freeciv.pot file:

#: menu.c:123 
msgid "?play:Game" 
msgstr "" 
     
#: terrain.c:321 
msgid "?animals:Game" 
msgstr "" 

Note that the Q_() macro is similar to the _() macro, in that it must only be used in a context where a function may be called.

Internationalization Mini-FAQ

These address a few problems and questions about Internationalization.

Should I ever call gettext() directly?

No. When NLS (Native Language Support) is disabled at configuration time, the definitions of the _() and Q_() macros are changed to not call gettext().

Should I try to internationalize "Freeciv"?

No, just leave it "Freeciv" wherever you find it. (Also, note that the "c" in "Freeciv" is not capitalized.)

Advertisement