Intro

Gestionar una aplicación web con php que tiene que aparecer en dos idiomas puede ser un dolor de muelas. No digamos si el número de idiomas aumenta. En nuestro caso lo que solía variar eran los títulos y las etiquetas de los formularios. El sistema que empleamos desde que nos surgió el problema consistía en emplear arrays en un script externo.

El sistema no está mal, pero no termina de convencerme. Afortunadamente php permite el empleo de la herramienta gettext, que hace las cosas mucho más fáciles.

Configurando el sistema

En nuestro caso el sistema donde corre el servidor web es linux debian. Numero los pasos seguidos:

  • Instalar gettext
  • Instalar php-gettext
  • Activar la extensión gettext en php
  • Instalar los locales

Instalar gettext y php-gettext

Se hace mediante apt-get install gettext php-gettext

Activar la extensión gettext en php

Para activarla se generaría el archivo /etc/php5/apache2/conf.d/gettext.ini con el siguiente contenido:

extension=gettext.so

Luego reiniciamos apache.

El problema vino cuando tratamos de probar el sistema. No había forma de que funcionase, así que googleamos un poco (bastante, la verdad) hasta descubrir que nuestro problema era que no teníamos instalados los locales.

Instalar los locales

Cuando comprobábamos los locales instalados con locale -a nos aparecían solamente C y POSIX, así que cuando le decíamos al script de php que pusiese el local en el idioma correspondiente con la línea setlocale(LC_ALL, $locale);, al no existir los archivos de locale para ese idioma, el script no funcionaba.

Para instalar los locales deseados (inglés de GB y de US) ejecutamos:

# dpkg-reconfigure locales

Nos aparece una lista de los locales disponibles y seleccionamos los que nos interesen.

Utilizando gettext en los scripts de php

Creando el archivo .pot

Para comenzar a trabajar necesitamos un archivo .pot

Puesto que gettext puede leer los scripts de php y generar un archivo de traducción (.pot) solamente con aquellos mensajes necesarios, primero habría que empezar empleando el sistema gettext en los scripts de php.

Una vez tenemos ya scripts que tienen mensages de gettext generamos el archivo .pot con la siguiente instrucción (es necesario tener el gettext instalado en el servidor previamente) dentro del directorio donde están nuestros scripts:

# xgettext --from-code=UTF-8 -o messages.pot *.php

Una vez generado habría que editarlo con nano para cumplimentar la parte de la cabecera donde vienen los datos.

Previendo futuras colaboraciones con grupos de otras partes del mundo he decidido emplear el inglés como idioma por defecto, por lo que tendremos que generar las traducciones a castellano.

Para generar las traducciones empleamos el programa Poedit (para Mac).

Código en los scripts

Para que el sistema de gettext funcione es necesario incluir las siguientes líneas de código en los scripts:

if (isset($_GET["locale"])) {
    $locale = $_GET["locale"];
}
else if (isset($_SESSION["locale"])) {
    $locale  = $_SESSION["locale"];
}
else {
    $locale = "en_GB";
}

putenv("LANG=".$locale);
setlocale(LC_ALL, $locale);
$domain = "messages";
bindtextdomain($domain, "/var/www/secure/cect/locale");
bind_textdomain_codeset($domain, 'UTF-8');
textdomain($domain);

En las primeras líneas aceptamos una variable GET para incluir el locale. Si no le pasamos la variable, el sistema coge ‘en_GB’ por defecto.

El valor de la variable $domain es el nombre que deben tener los archivos .mo con la traducción.

Para evitar tener que andar incluyendo el código en todos los scripts, lo guardamos en un archivo (ej. gettext.php) y lo incluimos en cada script con include_once('gettext.php');

Donde pongo los archivos .mo generados?

El programa Poedit genera los archivos .po y .mo y los refresca cada vez que le damos a guardar. Donde hemos de poner esos archivos en nuestro servidor para que funcionen las traducciones?

Habría que generar un arbol de directorios en la ruta que aparece como segundo parámetro en el comando bindtextdomain. A partir de este directorio tendríamos que crear una carpeta para cada uno de los idiomas a emplear (en nuestro caso solamente el castellano). El nombre de esta carpeta o directorio debe ser el código del idioma de acuerdo a las especificaciones ISO 639-1 e ISO 3166-1 alpha-2

Dentro de esos directorios tiene que existir otro llamado LC_MESSAGES

En el directorio LC_MESSAGES hemos de incluir el archivo nombrado como indica la variable $domain y con la extensión .mo

En nuestro caso sería el archivo messages.mo

Añadiendo términos al archivo .pot inicial

A medida que vayamos añadiendo scripts o modificando los existentes irán apareciendo necesariamente cadenas gettext que necesitan traducción. Cuando esto ocurra habrá que añadirlas al archivo .pot inicial. Ésto se hace empleando el comando msgmerge.

El procedimiento es el siguiente:

Crear un archivo .pot con la situación actual. Una opción para generar el nombre de este archivo es emplear el nombre indicado en $domain y añadir la fecha entre el final del nombre del archivo y la extensión. Ejemplo:

# xgettext --from-code=UTF-8 -o messages.20160614.pot *.php

Una vez creado el nuevo .pot habría que mezclarlo con el messages.po original para que añada los nuevos términos:

# msgmerge --update messages.po messages.20160614.pot


De este modo actualiza messages.po

Enlaces

Un buen tutorial de LingoHub donde además explican los plurales: PHP internationalization with gettext tutorial

Un tutorial entrado en programas en C donde aparece la opción de merge: A Quick Gettext Tutorial