pfritz

April 26, 2009

Setting up autofoo for gettext

Filed under: Uncategorized — pfritz @ 23:44
Tags:

Using gettext in your application or library is very easy and straight forward. The hard part is to setup autoconfig and automake to use gettext. Not because itis very difficult, but because there is not a good tutorial, at least I haven’t found one. The only resource is the gettext manual which is over 100 pages large and covers too many legacy cases to be simple. And the other resource is to look into existing project and take their setup as a base, either easy and you’ll find out that there are many ways of doing it, most of them are dated.

Since I added gettext support to EWL, I thought I can tell you the single steps, making your life easier, one you want to add i18n support to your application or library. I assume that you already have a autoconfig setup for your software.


First step: Setup the c code

Libraries need a different treatment here, because they cannot rely on global settings, else they would overwrite the catalog of the application that is using the library. Nevertheless the steps are very similar. I start here with the steps for the application.

Create a header file called intl.h or – if you prefer – mynamespace_intl.h it’s containing this code:

#ifndef INTL_H
#define INTL_H

#include <string.h>

#ifdef ENABLE_NLS
# include <libintl.h>
# include <locale.h>
#else
# define gettext(str) ((char*) (str))
#endif

#define _(str) gettext(str)
#define gettext_noop(str) str
#define N_(str) gettext_noop(str)
#define S_(str) sgettext(str)

static inline char *
sgettext(const char *msgid)
{
        char *msgval = gettext(msgid);
        if (msgval == msgid)
                msgval = strrchr(msgid, '|') + 1;
        return msgval;
}

#endif

This defines some useful macros, namely (), N() and S_(). Take a look into the gettext handbook to see how they work.

For libraries use this header:

#ifndef INTL_H
#define INTL_H

#include <string.h>

#ifdef ENABLE_NLS
# include <libintl.h>
# include <locale.h>
#else
# define dgettext(domain, str) ((char*) (str))
#endif

#define D_(str) dgettext(PACKAGE, str)
#define gettext_noop(str) str
#define N_(str) gettext_noop(str)
#define SD_(str) sdgettext(PACKAGE, str)

static inline char *
sdgettext(const char *domain, const char *msgid)
{
        char *msgval = dgettext(domain, msgid);
        if (msgval == msgid)
                msgval = strrchr(msgid, '|') + 1;
        return msgval;
}

#endif

Add this new header file to the (not installed) list of source files in your Makefile.am. You also need to add the following option to the AM_CPPFLAGS

-DPACKAGE_LOCALE_DIR=\"$(localedir)\"

We need this definition later.

To initialize the correct language and loading the language catalog we need to add some code, for apps add this code near the beginning of your main() function:

    /* Initialize NLS */
#ifdef ENABLE_NLS
    setlocale(LC_MESSAGES, "");
    bindtextdomain(PACKAGE, PACKAGE_LOCALE_DIR);
    bind_textdomain_codeset(PACKAGE, "UTF-8"); /* add this only if you want to
                                                  deal with UTF-8 strings
                                                  exclusivly. If you are using
                                                  evas, you most probably
                                                  want. */
    textdomain(PACKAGE);
#endif

For libraries add this:

    /* Initialize NLS */
#ifdef ENABLE_NLS
    bindtextdomain(PACKAGE, PACKAGE_LOCALE_DIR);
    bind_textdomain_codeset(PACKAGE, "UTF-8"); /* add this only if you want to
                                                  deal with UTF-8 strings
                                                  exclusivly. If you are using
                                                  evas, you most probably
                                                  want. */
#endif

As you can see it is up to the library user to set the locale. Don’t forget to add the intl.h header file.

The only missing thing for the c-files is to mark translatable strings, with the defined macros. I will not explain here how to use them.


Second step: Setup autoconfig and automake

First add the following line in your autogen.sh or bootstrap.sh file, if you are using autoreconf you can jump to the next topic.

echo "Running autopoint..." ; autopoint -f || :

Before the line where aclocal is called.

Now execute autopoint -f in your package base dir. It will create the po/-directory and copy some files you will need later.

Add the following lines some where in your configure.ac file:

AM_GNU_GETTEXT([external])
AM_GNU_GETTEXT_VERSION([0.15])

And add po/Makefile.in (don’t forget the .in, this is not a typo!) into the AC_OUTPUT list. And add the po dir at the end of the subbdir list in the Makefile.am.

Now create the po/Makevars file, you will find there already a template for it. Simply copy it and adjust it for your needs. You may want to add the S_ or the D_ and SD_ macros to the xgettext options.

Create a new file called POTFILES.in. There you put every source file that contains a translatable string. The path should be relative to your base directory.

Well, if you are an English-speaker you are done know. Your project should now be translatable. If your not an English-speaker you can test your work and start a translation for your mother tongue.


Step three: The first translation

Run now ./autogen.sh, ./bootstrap.sh or autoreconf and the ./configure and make. After that you will find a pot file in the po/ directory. Use it to create a translation for your project and save the po file in the po/ dir.

Therefor that your translation will be converted into a binary form and later be installed add this file to a newly created LINGUAS file. There are all available translations listed. For example:

# Set of available languages.
de it cz

Call now make maintainer-clean and the next time you are going to build your project, your translation will be installed and used.

Advertisements

2 Comments »

  1. Hi,

    Thanks for this good gettext tutorial.! Very useful.

    Greets.

    Comment by futility — August 30, 2009 @ 18:58 | Reply

    • Nice to hear that the tutorial was useful to some one 🙂

      Comment by pfritz — August 30, 2009 @ 20:10 | Reply


RSS feed for comments on this post. TrackBack URI

Leave a Reply

Fill in your details below or click an icon to log in:

WordPress.com Logo

You are commenting using your WordPress.com account. Log Out / Change )

Twitter picture

You are commenting using your Twitter account. Log Out / Change )

Facebook photo

You are commenting using your Facebook account. Log Out / Change )

Google+ photo

You are commenting using your Google+ account. Log Out / Change )

Connecting to %s

Blog at WordPress.com.

%d bloggers like this: