Guidelines for Software Development

Using Gettext For Native Language Support

The GNU gettext C library provides basic NLS, allowing a program's text messages to be translated. GNU gettext is licensed with the GPL, not the LGPL, so any programs using it must also be GPL'ed if they are distributed.


Modifying autoconf/automake For gettext

gettext is intended to be used in conjunction with the autoconf/automake OS portability tools, and will not easily work without them. The programmer should modify the autoconf configuration files in the top-level package directory as follows:

  • In "configure.in," add the following lines:

    ALL_LINGUAS=""
    AM_GNU_GETTEXT
    
    AC_OUTPUT([
    intl/Makefile
    po/Makefile.in
    ])
    
    Your AC_OUTPUT section will list other files as well, but the above is what is needed for gettext support. When support for a new language is added to your package, add the language code to the ALL_LINGUAS macro. For example, if your package has translations for German and French, the line will read ALL_LINGUAS="de fr".

  • In "acconfig.h," add the following lines:

    #undef PACKAGE
    #undef VERSION
    #undef HAVE_LIBSM
    #undef HAVE_CATGETS
    #undef HAVE_GETTEXT
    #undef HAVE_LC_MESSAGES
    #undef HAVE_STPCPY
    #undef ENABLE_NLS
    

  • In the top-level "Makefile.am", add "intl" and "po" to SUBDIRS.


Setting Up gettext

Once you've set up autoconf and automake to work with gettext, create the gettext support files:

  • From the top-level package directory, run "gettextize" once. This creates the necessary support files for gettext, including copying the gettext library into an "intl/" subdirectory, and setting up a "po/" subdirectory to hold translation files. This way, gettext is distributed with your package so users don't need to install it separately. (The intl/ subdirectory will contain links, so if you use tar to archive your distribution, give it the -h option. autoconf does this automatically for "make dist".)

  • In the "intl/" subdirectory, run "make all-yes" once.

  • Create a file "po/POTFILES.in" listing all the source code files that have translatable strings, and keep this file up-to-date. For example:

    # Source files containing translatable strings:
    lib/hello_msg.c
    lib/hello_help.c
    src/hello.c
    
    Running make in the po/ directory will run xgettext to rebuild the ".pot" file containing all translatable strings. This will normally be done automatically from a make in the top-level directory, but can also be done independently if desired.


Programming With gettext

To use gettext, the programmer should:

  • Edit each source code directory's Makefile.am to make sure LIBS and INCLUDES include the following:

    LIBS=-L../../intl -lintl
    INCLUDES=-DLOCALEDIR=\"$(datadir)/locale\" -I../../intl
    
    Replace "../../intl" with the location of your intl directory.

  • Add the following near the top of each source code file, or in a common header file:

    #include <libintl.h>
    #define _(s) gettext(s)
    #define gettext_noop(s) (s)
    #define N_(s) gettext_noop (s)
    
    The defines aren't absolutely necessary but they make the source code cleaner. If you #include <gnome.h>, do not do the above, as gnome.h will do it for you.

  • Include the following code early in each program's main() function:

    setlocale (LC_ALL, "");
    bindtextdomain (PACKAGE, LOCALEDIR);
    textdomain (PACKAGE);
    
    PACKAGE is the package name and LOCALEDIR is the package's locale directory, as specified in config.h and the make file respectively. In certain cases the LC_ALL flag might not be correct. See the gettext documentation and the locale(7) man page for details.

  • To ease translation, use whole, standalone strings when creating messages, as opposed to building them from pieces. For example:

    	/* the wrong way */
    printf("You have %d guess%s left.\n", nguesses, (nguesses == 1)? "" : "es");
    
    	/* the right way */
    if (nguesses == 1)
    	printf("You have one guess left.\n");
    else
    	printf("You have %d guesses left.\n", nguesses);
    

  • Wrap all translatable strings in each program with _(), including output and error messages, user interface components like menu names, and so forth. For example:

    	printf( _("You have %d guesses left.\n"), nguesses);
    

    The only exception is for places where the output of a function isn't acceptable, such as in static initializations; these should be marked with N_() instead, and _() when they are actually used. For example:

    	static char **messages = {
    		N_("potato"),
    		N_("carrot"),
    		N_("onion")
    	};
    	...
    	printf( _("You guessed %s.\n"), _(messages[i]) );
    

See the gettext documentation for details on providing translation files for other languages.


Security


Tools

  • gettext

Guidelines for Software Development