Internacionalización y localización: usando gettext()
La función
gettext()
es la forma semi-oficial de manejar una localización y está muy bien integrado
en los entornos del tipo Unix, lo cual es bueno y malo. Un grave problema es
que depende del soporte de idioma que esté instalado en el servidor, lo cual
puede hacer que una aplicación que funciona perfectamente en un servidor, no
funcione en otro. Por otra parte, para su inicialización requiere una serie de
llamadas a funciones que parecen un tanto caprichosas y que están pensadas más
desde el punto de vista organizativo del servidor Unix que de la aplicación.
Otros entornos, como Windows, esto puede representar un problema, por ejemplo,
si se desarrolla en un ordenador Windows para usar en un servidor con Linux.
El
ejemplo
muestra cómo usar las funciones necesarias para
gettext(). El fuente de la página muestra llamadas a las funciones
setlocale(),
bindtextdomain()
y
textdomain()
las cuales deben estar al inicio de cualquier script, antes de la primer
llamada a
gettext()
que, por otra parte, no verán en el fuente, dado que
gettext()
tiene predefinido como alias la función
_(), que siendo mucho más breve, es más cómoda.
La explicación del manual sobre el uso de estas funciones es insuficiente y sin recorrer los comentarios de los usuarios, más abajo (que, además, no están traducidos) no es posible poner la cosa a funcionar.
La función
setlocale()
es la que establece el idioma que se utilizará, aunque en realidad hace mucho
más que eso. Permite definir, por ejemplo, cómo se les dará formato a los
números (el uso de comas y puntos para miles y decimales), moneda (símbolo
monetario, cantidad de decimales, etc), fechas (orden de las partes) y varias
otras cosas que se detallan en su
documentación.
En el
ejemplo
usamos la constante LC_ALL para localizar todos los aspectos
posibles. Aquí es donde reside el primer problema, el éxito de la función
setlocale()
depende de que la localización pedida exista en el servidor. Por ejemplo, un
servidor puede tener instalado
fr_FR (francés de Francia) pero no fr_BE (francés de
Bélgica) o fr_CG (francés del Congo), puede tener
ca_ES (catalán de España) pero no ca_FR (catalán de
Francia). Uno podría querer obviar estos problemas simplemente indicando el
código de idioma y no el de país, por ejemplo fr,
es o ca, y dependiendo del servidor, estos pueden
estar disponibles o no.
Por otra parte, el sitio en cuestión puede ser un sitio para un grupo de
filólogos que estudian idiomas inusuales, tales como klingon, que tiene su
código ISO-639 (tlh) o esperanto (epo). En el
ejemplo se ha agregado una casilla donde ingresar un código de localización y
ver el resultado donde dice `locale actual´. Si se muestra un resultado, el
código indicado existe, sino, queda en blanco. La función
setlocale()
llama a la función equivalente del sistema operativo y retorna lo que esta le
indica. Esto es importante pues es posible que la función devuelva algo, pero
distinto de lo indicado. Por ejemplo, el sistema operativo es libre de indicar
que no tiene `en_UK´ pero que si tiene `en´. Eso hace que uno no tenga más
remedio que ponerse a explorar en el servidor para ver qué idiomas tiene y,
según eso, ver qué ofrecer y, por encima de todo, cómo estructurar la
aplicación, pues lo que todavía no hemos visto es dónde ubicar el archivo de
traducciones.
Los argumentos de este trío de funciones son los que determinan la ubicación de los archivos de traducción, concretamente en el caso del ejemplo:
$locale = setlocale(LC_ALL, `en_US´);
bindtextdomain(`ejemplo´, `./locale´);
textdomain(`ejemplo´);
el archivo de traducciones se encontrará en:
./locale/en_US/LC_MESSAGES/ejemplo.mo
Dejo como ejercicio para el lector dilucidar de dónde sale cada segmento,
aunque aclaro que LC_MESSAGES es fijo e inalterable como lo es la
extensión .mo para el archivo. Esto hace evidente un problema,
uno debe tener tantas carpetas con códigos de localización como vaya a
ofrecer, aunque el contenido de es_AR sea idéntico al de
es_UY, como en el caso del ejemplo donde usé
en_US arbitrariamente en lugar de, por ejemplo,
en_UK. La diferencia puede no ser importante en las traducciones,
pero si en otros aspectos de la localización como el signo monetario $ ó �, o
el orden de los elementos de la fecha.
Todo esto hace que esta solución no sea muy portable, y es de suponer que si uno está internacionalizando una aplicación en muchos casos es porque pretende hacerla portable. La dependencia de todo el paquete de gettext() de la configuración del servidor en que reside, hace que pueda ser un problema para quien debe instalar y mantener el paquete.
Finalmente, un `bug´ que seguramente se solucionará, eventualmente … La mayoría de las aplicaciones `internacionales´ se escriben en inglés por lo que los textos originales están en ese idioma. El ejemplo que acompaña este artículo está en castellano. Noten que si seleccionan como idioma el inglés, los textos donde el original contuviera acentos, eñe o cualquier otra letra o símbolo que no sea ASCII nativo, gettext() no encontrará la traducción, cosa que sí hará con cualquier texto donde el original sea puro ASCII, aunque el texto traducido sí contenga caracteres no-ASCII.
Por todo esto, en conclusión, no recomiendo usar las funciones de
gettext()
de PHP aunque, como alternativa, existe un paquete de PHP escrito en PHP
mismo, que es mucho más simple de usar y más fácil de mantener. De hecho, es
el que usa la aplicación WordPress con que funciona este mismo blog y que
veremos en el siguiente artículo.
Viene de: Internacionalización y localización: usando arrays
Continúa en:Internacionalización y localización: usando PHP-gettext