Está en la página 1de 7

Traduccin de proyectos con GNU gettext en 15 minutos

Jos Toms Tocino Garca Hackathon UCA - Diciembre 2010


Este documento tiene licencia Reconocimiento-CompartirIgual 3.0 Espaa de Creative Commons http://creativecommons.org/licenses/by-sa/3.0/es

ndice
1. Introduccin 1.1. Internacionalizacin vs localizacin . . . . . . . . . . . . . . . . . . . . . . . . . 1.2. El paquete de herramientas de GNU gettext . . . . . . . . . . . . . . . . . . . . 2. Pasos en el proceso de traduccin 2.1. Adaptacin del cdigo fuente . . . . . . . . . 2.2. Generando los cheros de traduccin . . . . 2.2.1. Creando la plantilla .pot . . . . . . . . 2.2.2. Creando los cheros de traduccin .po 2.2.3. Creando los binarios .mo . . . . . . . . 2.3. Compilacin y ejecucin . . . . . . . . . . . . 2.4. Mantenimiento . . . . . . . . . . . . . . . . . 1 2 2 2 2 3 4 5 5 6 6 7 7 7

. . . . . . .

. . . . . . .

. . . . . . .

. . . . . . .

. . . . . . .

. . . . . . .

. . . . . . .

. . . . . . .

. . . . . . .

. . . . . . .

. . . . . . .

. . . . . . .

. . . . . . .

. . . . . . .

. . . . . . .

. . . . . . .

. . . . . . .

. . . . . . .

. . . . . . .

. . . . . . .

3. Goodies nales 3.1. PO-mode en Emacs . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 3.2. Referencia . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .

1.

Introduccin

GNU gettext es un conjunto de herramientas libres de internacionalizacin que permite traducir nuestros proyectos de una manera sencilla. Es el sistema de i18n 1 ms utilizado, y lo podis encontrar en una gran cantidad de proyectos. Las ventajas de usar un sistema como gettext en lugar del tpico men de eleccin de idiomas dentro de la aplicacin son muchas. Por ejemplo, con gettext el ajuste del idioma es transparente al usuario. Adems, ofrece todas las ventajas de usar un sistema establecido y prcticamente estndar.
i18n es una alternativa a escribir internacionalizacin, el 18 simboliza los 18 caracteres entre la i inicial y la n nal
1

1.1.

Internacionalizacin vs localizacin

La internacionalizacin de un proyecto consiste en prepararlo de forma que sea capaz de trabajar y presentarse en una multitud de idiomas. Por otro lado, la localizacin trata de coger un programa internacionalizado y darle la suciente informacin para que se adapte al idioma y conguracin del usuario actual.

1.2.

El paquete de herramientas de GNU gettext

GNU gettext est compuesto de un conjunto de elementos que forman un framework de trabajo comn. En particular, esto incluye: Una serie de directivas y convenciones a la hora de escribir un programa. Un esquema estndar de organizacin de cheros y directorios para guardar los cheros relacionados con la traduccin (Os suena LC_MESSAGES?) Una biblioteca que provee funciones relacionadas con las cadenas traducidas. Algunas utilidades para la creacin y edicin de los cheros con las cadenas de traduccin. Un modo para Emacs :)

2.

Pasos en el proceso de traduccin

A la hora de adaptar un proyecto para internacionalizarlo hay que seguir una serie de pasos bastante mecnicos que se repiten cada vez que aadamos o modiquemos las cadenas de nuestro proyecto.

2.1.

Adaptacin del cdigo fuente

Primero, necesitamos adaptar el cdigo de nuestro programa, marcando de alguna forma las cadenas que queremos que queden traducidas. Podra pensarse que este paso podra ser automtico, pero hay cadenas que a buen seguro no queremos que sean traducidas, como por ejemplo parmetros de funciones o cosas as. Para ello, aadiremos las siguientes lneas al inicio de nuestro chero fuente:
1 2 3

#include <libintl.h> #include <locale.h> #define _(x) gettext(x)

La biblioteca libintl ser la encargada de la internacionalizacin de nuestro proyecto, siendo de especial inters su funcin char * gettext (const char *), a la que le pasaremos las cadenas originales y nos devolver la cadena traducida dependiendo del locale del sistema. Para hacer menos evidente su uso, utilizamos la macro denida arriba.

Nota: Para ahorrarnos trabajo y problemas, el idioma por defecto ser el ingls, ya que los cheros de traduccin iniciales se generan en ingls y no he encontrado ninguna forma de cambiarlo.

Lo siguiente ser, lgicamente, cambiar todas las cadenas que queramos traducir en nuestro proyecto, de forma que en realidad sean siempre llamadas a la funcin gettext, o preferiblemente a su macro _().
1

string mensaje = "Hello world";

Pasar a ser:
1

string mensaje = _("Hello world");

Algo a tener en cuenta es que es necesario elegir un nombre para el dominio de la internacionalizacin, que por regla general coincidir con el proyecto. En nuestro ejemplo, este nombre ser jakatoner (del ingls hackathon y el sujo ibrico -er ). En las primeras lneas de nuestro proyecto aadiremos las siguientes instrucciones de inicializacin:
1 2 3 4

bind_textdomain_codeset ("jakatoner", "UTF-8"); setlocale(LC_ALL, ""); bindtextdomain("jakatoner", "lang" ); textdomain("jakatoner");

Eso le indicar a la biblioteca de i18n cul es el dominio de la traduccin, as como el directorio de las traducciones (lang), y pondr el locale por defecto. As pues, un posible chero main.cpp de ejemplo podra ser:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18

#include <iostream> #include <libintl.h> #include <locale.h> #define _(x) gettext(x) using namespace std; int main(int argc, char *argv[]) { bind_textdomain_codeset ("jakatoner", "UTF-8"); setlocale(LC_ALL, ""); bindtextdomain("jakatoner", "lang" ); textdomain("jakatoner"); cout << _("Hello world") << endl; return 0; }

2.2.

Generando los cheros de traduccin

Una vez que tengamos todas las cadenas a traducir apropiadamente adaptadas como se ha comentado antes, pasaremos a crear los cheros con los que realizaremos las traducciones. Hay varios tipos de estos cheros:

.POT (Portable Object Template) Es el primer chero que se genera, y contiene todas las cadenas extradas del cdigo fuente, que servir luego como plantilla para los cheros .po. .PO (Portable Object) Son los cheros principales de traduccin, los que se editan con las cadenas traducidas. Hay uno por cada locale que queramos incluir. .MO (Machine Object) Son la versin binaria de los cheros .po, los que nuestra aplicacin usar para leer las cadenas traducidas. La forma de organizar los diferentes cheros est bastante estandarizada, de forma que lo ms recomendado es seguirla de no hacerlo podemos tener problemas a la hora de que el programa encuentre los cheros de traduccin. En la raz de nuestro proyecto tendremos una carpeta po que albergar el chero de plantilla .pot, en nuestro caso jakatoner.pot, as como los cheros .po de cada locale : en.po, es.po, etc. Adems, tambin en la raz tendremos otra carpeta llamada lang. Dentro de ella habr una carpeta por cada chero .po en la carpeta antes mencionada, y dentro de cada una de ellas, una carpeta LC_MESSAGES, que albergar el chero .mo correspondiente, todos con el nombre del dominio, en nuestro caso jakatoner.mo La estructura de directorios que obtendremos ser algo as: lang |-- en | -- LC_MESSAGES | -- jakatoner.mo -- es -- LC_MESSAGES -- jakatoner.mo po |-- en.po |-- es.po -- jakatoner.pot

2.2.1.

Creando la plantilla .pot

As pues, el primer paso ser generar el chero .pot. Para ello utilizaremos la utilidad xgettext, que tiene una pech de opciones. As pues, creamos los directorios antes comentados y usamos la siguiente expresin:
1 2 3 4

xgettext --package-name jakatoner --package-version 0.1 \ --default-domain jakatoner --output po/jakatoner.pot --from-code=utf-8 \ --copyright-holder="Tu nombre" --msgid-bugs-address="tu@mail.com" \ -s -k_ -C main.cpp

La mayora de las opciones son autoexplicativas, pero es interesante conocer el signicado de las que no lo son:

-s Salida ordenada, ordena las cadenas en el chero de plantilla, til cuando tenemos muchos cheros fuente y queremos tener las cadenas organizadas. -k_ Indica que tambin busque cadenas marcadas con _(cadena) adems de gettext(cadena). -C Indica que el lenguaje es C++. Con esto tendremos el chero en po/jakatoner.pot. Es necesario editarlo y cambiar el valor de CHARSET (en la lnea Content-Type: ...) por UTF-8, xgettext an no ofrece ninguna opcin para autorrellenar este campo. 2.2.2. Creando los cheros de traduccin .po

El siguiente paso ser el de crear un chero .po para cada uno de los idiomas a los que queramos traducir nuestro proyecto. Para ello utilizaremos la utilidad msginit de la siguiente manera, suponiendo los idiomas ingls y espaol:
1 2

msginit -l es -o po/es.po -i po/jakatoner.pot msginit -l en -o po/en.po -i po/jakatoner.pot

Al ejecutar los comandos nos pedirn nuestro email en un mensaje bastante utpico en el que describe un mundo en el que el feedback del usuario realmente existe ms all del Tu programa es una mierda!! Si le echamos un vistazo al chero po/es.po, aparte de toda la morralla inicial, nos encontraremos con las cadenas de nuestro programa de la siguiente manera:
1 2 3

#: main.cpp:15 msgid "Hello world" msgstr ""

El formato es muy sencillo: la primera lnea indica la situacin de la cadena en el cdigo fuente, la segunda es la cadena original, y la tercera es la cadena traducida. Para el chero en espaol, quedara:
1 2 3

#: main.cpp:15 msgid "Hello world" msgstr "Hola mundo"

Cabe notar que como el lenguaje original es el ingls, podemos dejar el chero en.po intacto, ya que por defecto utilizar las cadenas originales. 2.2.3. Creando los binarios .mo

Una vez terminado el apartado anterior, nos queda el ltimo paso, que es generar los cheros binarios con las traducciones. Para ello, utilizaremos la utilidad msgfmt, que convertir los .po en .mo, de la siguiente manera:
1 2 3

mkdir lang/{es,en}/LC_MESSAGES msgfmt -c -v -o lang/es/LC_MESSAGES/jakatoner.mo po/es.po msgfmt -c -v -o lang/en/LC_MESSAGES/jakatoner.mo po/en.po

La opcin -c indica que se hagan chequeos ante errores, y la opcin -v muestra una salida extendida (verbose ). Con esto, ya tendremos todos los cheros necesarios. 5

2.3.

Compilacin y ejecucin

Para compilar nuestro proyecto, si utlizamos GCC no ser necesario enlazar a ninguna librera especial, puesto que libintl ya viene en la biblioteca estndar. As pues, good old gcc, here we go :
1

g++ -o jakatoner main.cpp

Tras esto, podremos probar nuestro programa:


1 2 3 4

jose@jose-desktop:~$ ./jakatoner Hola mundo jose@jose-desktop:~$ LANG=en_UK ./jakatoner Hello world

2.4.

Mantenimiento

Supongamos ahora que aadimos una lnea ms a nuestro cdigo, en la que se utiliza una cadena nueva. Si seguimos el proceso anterior perderemos todas las traducciones que ya tenamos, ya que los cheros se crearan de cero. Para evitar esto, GNU gettext ofrece una utilidad llamada msgmerge que nos permitir actualizar los cheros .po con las nuevas cadenas manteniendo las traducciones ya realizadas. As pues, supongamos que aadimos esta lnea al chero:
1

cout << _("Bye bye, dear user") << endl;

Generamos el chero de plantilla .pot igual que lo hicimos antes, pero a la hora de generar los cheros .po utilizaremos lo siguiente:
1 2 3 4 5 6 7

xgettext --package-name jakatoner --package-version 0.1 \ --default-domain jakatoner --output po/jakatoner.pot --from-code=utf-8 \ --copyright-holder="Tu nombre" --msgid-bugs-address="tu@mail.com" \ -s -k_ -C main.cpp msgmerge -s -U po/es.po po/jakatoner.pot msgmerge -s -U po/en.po po/jakatoner.pot

La opcin -s genera una salida ordenada, y -U indica que la operacin es de actualizacin (update ). Con esto, ya tendremos el chero .po con las nuevas cadenas aadidas y las cadenas antiguas sin cambios, podremos proceder a aadir las traducciones y generar los cheros .mo tal y como se ha explicado previamente.
1 2 3 4 5 6 7 8 9 10

msgfmt -c -v -o lang/es/LC_MESSAGES/jakatoner.mo po/es.po msgfmt -c -v -o lang/en/LC_MESSAGES/jakatoner.mo po/en.po ./jakatoner Hola mundo Nos vemos, querido usuario LANG=en_UK ./jakatoner Hello world Bye bye, dear user

3.
3.1.

Goodies nales
PO-mode en Emacs

Como coment al principio, existe un modo de Emacs para la edicin eciente de archivos .po. Puede instalarse manualmente de la manera habitual o en sistemas basados en paquetera deb con el siguiente comando:
1

sudo apt-get install gettext-el

Una vez hecho esto, al abrir un chero .po entraremos en el modo PO (podemos forzarlo con M-x po-mode). Hay gran cantidad de comandos para editar los cheros PO, pero los ms tiles son los siguientes: Con n y p iremos al siguiente o anterior mensaje de traduccin. Para saltar entre los mensajes traducidos usaremos t y T. Para los no traducidos, u y U. Para editar la traduccin, pulsamos Intro, que abrir un marco con el mensaje a editar. Tras modicarlo, podemos conrmar los cambios con C-c C-c o cancelarlos con C-c C-k Podemos acceder a la ayuda en cualquier momento pulsando h. Una vez acostumbrados, la edicin de estos cheros se har mucho ms liviana y rpida. Existen, de cualquier modo, editores ntegramente dedicados a la edicin de cheros .po.

3.2.
2

Referencia

Para ampliar conocimientos sobre GNU gettext, lo mejor es dirigirse a la referencia ocial que, aunque bastante extensa, resulta muy interesante y amena de leer, explicando toda clase de casos especiales de traduccin, como aquellos en los que aparecen cadenas de formato relacionadas con sentencias al estilo de printf y otros casos particulares.

http://www.gnu.org/software/gettext/manual/gettext.html