Traducción de Zend Validate con gettext y poedit

Zend Framework cuenta con una lógica de Formularios bastante «chori».

Consta de una clase Zend_Form, algunas cuantas Zend_Form_Element_* y algunos Zend_Form_Decorator_*.

Lo «chori» es como funciona. Integra en un solo objeto la lógica de los datos de un formulario, la vista html, el procesamiento de las entradas por cada campo (elemento) y la validación de los valores ingresados.

Así nos ahorramos la lata de escribir varios scripts por separado. Antes era necesario coordinar los nombres de los elementos con las claves que llegaban por $_GET o $_POST. Al hacer cualquier cambio al formulario html, podía provocarle hipo al script validador.

Ahora solo es necesario declarar el formulario, agregarle los validadores a cada elemento (que sea necesario), los decoradores del formulario y/o de los elementos y ya esta todo cocinado. Se pasa el objeto $form al script de vista y automáticamente es dibujado como HTML, y nuestro script Controller puede perfectamente procesar los mismos inputs declarados en el Form.

Tutoriales y documentación para trabajar con Zend Form abundan, así que no voy a profundizar en ello.

El Problema

Los validadores arrojan mensajes de error cuando el valor recibido no coincide con su criterio de validación. Pero estos mensajes estan en idioma inglés, definidos en constantes de clase en cada clase Zend_Validate_*.

La solución

Zend_Translate permite introducir texto traducible en nuestro código.

Escoger un adaptador de traducción

Entre sus adaptadores, mi favorito por el momento es el basado en Gettext. Las ventajas de gettext son múltiples:

  • Las traducciones están en un formato binario y no texto plano, lo que facilita evitar problemas como la codificación de caracteres en distintos sistemas operativos. De hecho, la codificación es un parámetro que se guarda en el mismo binario, ahorrando el «parseo» para detectarlo.
  • PHP es compatible con gettext, por lo tanto, la integración es directa. Cuanta con funciones nativas para cargar las traducciones y además soporta la macro _(‘texto’) para convertir cualquier string en su traducción.
  • El rendimiento de carga uso es altísimo comparado con cualquier otro adaptador basado en texto.

Por su puesto que, dada las circunstancias, se puede escoger cualquier otro adaptador. Solo que gettext es mi favorito 😀 .

Acá hay más detalles sobre Zend_Translate y sus adaptadores.

Zend_Form permite usar automáticamente los mensajes que ya estén traducidos cuando ocupamos validadores con él. ¿Pero como se hace la magia?

Directorios de traducción

Debemos escoger tambien donde y como guardar las traducciones.

En mi caso hice esta estructura de directorios:

/language/*/LC_MESSAGES

Donde * es el código del idioma (es, en, fr, …, es_CL). Es la forma corriente para las traducciones usando gettext. Para el ejemplo, usese «es».

Iniciar Zend_Translate

Es cosa de poner el siguiente código en algún lugar previo a la carga de los controladores de acción:

Zend_Loader::loadClass('Zend_Translate');

$translate = new Zend_Translate(
        'gettext',
        APP_ROOT.'/language/',
        null,
        array('scan' => Zend_Translate::LOCALE_DIRECTORY)
    );

$translate->setLocale('es');

Zend_Registry::set('Zend_Translate', $translate);

En mi caso, lo hice en un Controller Plugin, pero también es posible dejarlo en el Bootstrap. Es importante usar el Zend_Registry para guardar nuestro objeto de traducción. También es importante guardarlo con la clave‘Zend_Translate’, pues Zend_Form busca ese nombre automáticamente en el registry para traducir los mensajes de error que retornan los validadores. Si no le ponemos ‘Zend_Translate’, la documentación del api de Zend_Form tiene unos métodos para establecer el objeto de traducción.

¿Cómo hacer el texto «traducible»?

Primero, debe haber texto traducible. De acá en adelante se asume que estamos trabajando con el patrón MVC.

Podemos hacer 3 cosas, separadas o mezcladas:

1) Helper de Vista

Usar el método helper de vista translate para traducir en los scripts de vista (si tenemos todo automático, debería funcionar de inmediato).

Ejemplo:


 

 

2) Usar la macro _()

La macro _() puede usarse para mandar el texto traducible a las vistas desde los controladores. Vease esta mácro como si fuera una función cualquiera, que realiza lo siguiente: Si existe texto traducido para la cadena de entrada, entonces retorna una cadena con el texto traducido, sino retorna la misma cadena de entrada. Ejemplo: MyController.php

3) Usar directamente el objeto Zend_Translate

Esta es la forma que «debería usarse» siempre, mientras no sea el script de vista donde podemos usar el helper. Variando un poco el ejemplo anterior, quedaría así: MyController.php

Hasta ahora, solo se ha preparado el terreno. Al probar el controlador y al vista, debería

¿Cómo Traducir?

Acá está la gracia. Entra en juego la herramienta Poedit. Instalarla en windows es cosa de bajar el instalador y click, click, … Instalarla en linux, es cosa de buscar en los repositorios, en debian/ubuntu sería así:


sudo apt-get install poedit

Luego, es necesario hacerle un pequeño arreglín.

Una característica de trabajar con poedit, es que puede encontrar el texto traducible en la aplicación, examinando los archivos fuente. Automáticamente, cualquier cadena de texto encerrada en la macro _() será considerada «una cadena traducible». Nos interesa que tambien tome las cadenas que aparecen dentro del método translate().

Otra cosa importante. No se puede agregar otras cadenas manualmente en poedit. Aparentemente eso es malo en felixibilidad, pues no se puede agregar cualquier texto que uno quiera a la traducción. Sin embargo, esto es bueno por eficiencia, así no habrán cadenas basura en el binario de traducción, solo estarán presentes aquellas que realmente estén en el código fuente de la aplicación.

El arreglín consiste en:

  • Ir al menú Archivo -> Preferencias …
  • Pestaña «Procesadores», escoger PHP y presionar Editar
  • En la lista de extensiones, dejar la caja así: *.php;*.phtml
  • En la caja «Linea de comandos para procesar» agregar al final: -L php

Luego, al crear un catálogo (así se llama el archivo *.mo que contendrá la traducción), debemos configurarlo con lo siguiente:

  • Ir al menú Catálogo -> Opciones …
  • Pestaña «Palabras clave», agregar una nueva y poner: translate
  • En la pestaña «Carpetas», se debe poner la ruta al código fuente que se va a traducir. Recomiendo poner una ruta relativa. Relativa a la posición donde guardarémos el catálogo (*.po y *.mo)

Listo. Esto hará que el procesador de gettext lea los archivos .php y .phtml dentro de la carpeta de interés. Además tomará traducciones desde el método translate().

¿Cómo traduje los mensajes de los validadores de Zend Framework?

Una opción abría sido pasar poedit por la carpeta Zend/Validate del framework, pero lamentablemente, los mensajes de error no están en una forma que se pueda escanear con gettext. Cada mensaje de error es un código (string) guardado en una constante de clase, además de un array donde la clave es la constante de clase correspondiente, y su valor contiene un string con el mensaje en sí.

Así que opte por hacer algo un poco más sucio, pero válido.

Cree un archivo template.php, el cual contiene un array, pero de la siguiente forma:

<?php
$translate[_('isEmpty')] = 'Value is empty, but a non-empty value is required';
$translate[_('stringEmpty')] = "'%value%' is an empty string";

//... Y así con todos los mensajes de error que aparecen en Zend/Validate/*

Si se fijan, cada clave de array está encerrada por la macro de traducción _().

¿Cual es la magia?, configurar el catálogo en Poedit, para que pase por este archivo, actualizar el catalogo desde el código fuente, y listo.

El archivo finalmente quedó así.

Ahora, la otra alternativa, es actualizar el catálogo desde una plantilla *.pot. En el fondo, es igual a un .po, que podemos editar afuera y Poedit no va a alegar, pero si lo hará si volvemos a actualizar desde el código fuente.

El .po quedó así finalmente.

Así que si alguien necesita traducir los mensajes de los validadores de Zend Framework, acá hay 2 formas ya listas para bajar y «compilar».

3 comentarios sobre “Traducción de Zend Validate con gettext y poedit”

  1. Excelente tutorial, la duda que tengo respecto a este componente del framework y que he intentado buscar, aunque no en mucho detalle, es si realmente usar el componente de formularios para webs que no sean en ingles ni multilingues aporta realmente beneficio directo. Seguramente tener que integrar Zend_Translator no es tan complicado, pero en terminos de eficiencia y del codigo. No se si hacer uso de ficheros .po y el elemento de traduccion en una web que solo ira en un idioma es la mejor solucion desde el punto de vista de la organizacion del codigo.

  2. Otra pregunta sería, como usar Zend Translate cuando tienes textos en base de datos, en mi caso tengo los menús de navegación.

    Saludos y muy buen tuto.

Deja una respuesta

Tu dirección de correo electrónico no será publicada. Los campos obligatorios están marcados con *

Este sitio usa Akismet para reducir el spam. Aprende cómo se procesan los datos de tus comentarios.