In this tutorial we walk through the steps needed in order to add localizations to an existing project that uses GNU Autotools as build system.
We start by taking a a slightly modified version of the Hello World example that comes with Automake sources. You can keep track of the changes to the source throughout this tutorial by following the commits to amhello-gettext on GitHub. We start with the following files:
$ ls -RF
.:
configure.ac Makefile.am README src/
./src:
main.c Makefile.am
Running gettextize
The first step is copying some necessary gettext
infrastructure to your project. This is done running gettexize
in the root directory of your project. The command will create a bunch of new files and modify some existing files. Most of these files are auto-generated, so there is no need to add them to your version control. You should only add those files you create or modify manually.
You will need to add the following line to your configure.ac
.
AM_GNU_GETTEXT([external])
AM_GNU_GETTEXT_VERSION(0.18)
The version specified is the minimum required version of gettext your package can compile against.
Copy po/Makevars.template
to po/Makevars
and modify it as needed.
The next step is to copy over gettext.h
to your sources.
$ cp /usr/share/gettext/gettext.h src/
libintl.h
, which is the header that provides the different translation functions. gettext.h
is a convenience wrapper around it which allows disabling gettext
if the --disable-nls
is passed the ./configure
script. It is recommended to use gettext.h
in favor of libintl.h
.
Triggering gettext
in main()
In order for gettext
to work, you need to trigger it in your main()
. This is done by adding the following lines to the main()
function:
setlocale (LC_ALL, "");
bindtextdomain (PACKAGE, LOCALEDIR);
textdomain (PACKAGE);
You should also add #include "gettext.h
to the list of includes.
PACKAGE
should be the name of your program, and is usually defined in config.h
file generated by either autoconf
or autoheader
. To define LOCALEDIR
we need to add the following line to src/Makefile.am
:
AM_CPPFLAGS = -DLOCALEDIR='"$(localedir)"'
If AM_CPPFLAGS
is already defined, just append to it the -DLOCALEDIR='"$(localedir)"'
part.
Marking strings for translation
At this point, your program should compile with gettext
. But since we did not translate anything yet it will not do anything useful. Before translating we need to mark the translatable strings in the sources. Wrap each translatable string in _(...)
, and add the following lines to each file that contains translatable strings:
#include "gettext.h"
#define _(String) gettext (String)
Extracting string for translation
Before extracting the strings, we need to tell gettext
where to look. This is done by listing each source file with translatable strings in po/POTFILES.in
. So in our example po/POTFILES.in
should look like:
# List of source files which contain translatable strings.
src/main.c
Afterwards the following command can be used to actually extract the strings to po/amhello.pot
(which should go in the version control):
make -C po/ update-po
If you haven’t ran ./configure
yet you need to run autoreconf --install && ./configure
before running the above make command
.
Translating strings
To begin translating, you need to a *.po
file for your language. This is done using msginit
:
cd po/ && msginit --locale he_IL.utf8
The locale should be specified as two-letter language code followed by two-letter country code. In my example, I’ve used Hebrew, hence it will create a po/he.po
file. To translate the program you edit the .po
file, using either a text editor or a dedicated program (see list of editors here).
After you updated the .po
file for your language, list the language in po/LINGUAS
(you need to create it). For example, in my case:
# Set of available languages
he
Now you should be ready to compile and test the translation. Unfortunately, gettext
requires installing the program in order to properly load the message catalogs, so we need to call make install
.
./configure --prefix /tmp/amhello
make
make install
Now to check the translation simply run /tmp/amhello/bin/hello
(you might need to change LC_ALL
or LANGUAGES
depending on your locale to see the translation).
$ LANGUAGE=he /tmp/amhello/bin/hello
שלום עולם!
Final note about bootstrapping. When people checkout your code from the version control, many autogenerated files will be missing. The simplest way to bootstrap the code into a state which you can simple call ./configure && make
is by using autoreconf
:
autoreconf --install
Will add any missing files and run all the autotools friends (aclocal
, autoconf
, automake
, autoheader`, etc.) in the right order. Additionally it will call
autopointwhich copies the necessary
gettextfiles that were generated when you called
gettextize` earlier in the tutorial. If your project is using ./autogen.sh
script that call the autotools utilities manually, you should add a call to autopoind --force
before the call to aclocal
.
Finally, those are the files that end up version controlled in our example:
$ ls -RF
.:
configure.ac Makefile.am po/ README src/
./po:
amhello.pot he.po LINGUAS Makevars POTFILES.in
./src:
gettext.h main.c Makefile.am
Refrences
- The
gettext
manual - The
gettext
FAQ
Thanks. Really helpful and concise.
I tried a lot of things, but “make -C po/ update-po” only results in “No rule to make target ‘/config.status’, needed by ‘Makefile’. Stop.” What do I need to do?
Useful thanks!