Archive for the ‘PHP’ Category

Internacionalización en Javascript usando Poedit

Posted on Mayo 31st, 2010 in Desarrollo Web, Javascript, PHP | No Comments »

Gettext es uno de los sistemas mas utilizados para internacionalizar aplicaciones. Básicamente, un programa (xgettext) analiza el codigo fuente de los archivos de la aplicación, extrae las cadenas  y genera un catálogo que permite al usuario realizar la traducción usando una aplicación, como por ejemplo Poedit. Luego el catálogo (archivo .po) se compila y se crea un archivo binario con extensión .mo, el cual posee todas las traducciones en un formato optimizado.
Lamentablemente, el comando xgettext carece de soporte para Javascript. El intérprete de Python es lo mas cercano posible, pero a mi no me ha funcionado correctamente porque no analiza bien las expresiones regulares y algunas cadenas.

Hasta ahora la forma mas común de internacionalizar una aplicación en Javascript era identificar cada una de las frases con una clave o variable, pero el problema de esta técnica es que hay que agregar las frases manualmente.

He decidido desarrollar un pequeño script en PHP que se utiliza en conjunto con Poedit y facilita esta tarea. Éste funciona como intérprete Javascript y analiza el codigo fuente para extraer las cadenas y generar un catálogo,  luego se utiliza otro script para convertirlo a formato JSON, el cual se incluye en nuestra página como un archivo externo. De esta manera tenemos disponible las frases traducidas en una variable global.

El intérprete es lo suficientemente inteligente para detectar cadenas con o sin comillas escapadas y excluir las expresiones regulares y comentarios.

Para utilizarlo, primero debemos instalar Poedit. Abrimos la aplicación, vamos a Archivo -> Nuevo catálogo y completamos los datos:

Cambiamos a la solapa Rutas y agregamos la ruta de la carpeta que contiene nuestros archivos Javascript:

Cambiamos a la última solapa y agregamos los nombres de las funciones que usaremos para invocar una traducción. En este caso usamos el guión bajo y como alias “jsgettext”:

La magia ocurre cuando agregamos el nuevo intérprete. Vamos a Editar -> Preferencias, seleccionamos la solapa de intérpretes y hacemos click en “Agregar”:

Luego simplemente debemos actualizar el catálogo haciendo click en el botón “Actualizar catálogo” y nos aparecerán las frases extraídas de los archivos JS. Nos tomamos el trabajo de traducirlas y guardamos el catálogo.
Descartamos el archivo .mo que nos genera el programa ya que a continuación vamos a transformar el archivo .po en un .js usando la utilidad po2json.php:

php /ruta/a/jsgettext/po2json.php -i catalog.po -o l10n.js -k l10n

Eso nos genera un archivo con la variable global “l10n”, cuyo valor es un objeto que contiene las frases traducidas.
Podemos acceder a una traducción usando la función “_”:

function _(s) {
return typeof l10n[s] != 'undefined' ? l10n[s] : s;
}
alert(_("Hello world"))

El código esta alojado en Google Code: http://code.google.com/p/jsgettext/
Pueden reportar bugs o enviar alguna sugerencia o mejora :)

  • Share/Bookmark

Como acceder a múltiples servicios web en paralelo con PHP

Posted on Octubre 11th, 2009 in AJAX, Desarrollo Web, Javascript, PHP | 3 Comments »

Veamos el caso de una aplicación Web donde se realizan búsquedas en base a cierta información ingresada por el usuario, y para generar los resultados, el sistema debe consultar varios servicios web, los cuales tardan varios segundos en responder. Habría que buscar una forma de minimizar el tiempo de búsqueda para que al cliente le lleguen los resultados antes que la muerte.
La solución que propongo fue aplicada en un sistema de búsqueda y reserva de vuelos y hoteles.

Se pueden utilizar varias técnicas, yo tuve en cuenta las siguientes:

  • Acceder a los web services en forma concurrente utilizando CURL: Se podría buscar y generar la página de resultados directamente, o hacerlo mediante AJAX, lo cual nos permitiría hacer un polling e ir obteniendo resultados parciales.
    Sería la solución mas elegante, pero hay que tener en cuenta que desgraciadamente no todos los web services son de tipo REST y algunos usan SOAP, por lo tanto se hace dificil implementarlo usando esta librería porque habría que generar el XML e interpretar la respuesta manualmente. Mucho trabajo a mi parecer.
  • Implementar threads: Quizás piensen en el suicidio antes de tener en cuenta esta opción.
  • Buscar la solución en el lado del cliente y enviar una petición AJAX por cada web service: Aún así tenemos el problema de los límites de conección por host que imponen algunos navegadores como IE 6 y 7.

En principio opté por la última opción, pero me vi forzado a descartar el uso de AJAX debido a que algunos browsers imponen un límite de 2 conecciones concurrentes por host y yo necesito consultar 6 servicios web. Para evitar este límite tenemos que engañar al navegador creando al menos 3 subdominios, los cuales nos permitiría realizar 6 peticiones en paralelo, 2 por cada uno.
Quizás la solución no es muy elegante pero es muy usada para agilizar la descarga de los distintos componentes de la página. Tal es el caso de Google Maps, que utiliza subdominios mt0.google.com, mt1.google.com, mt2.google.com, etc.
Si bien no podemos enviar una petición a otro subdominio usando AJAX (hasta el momento), podemos inyectar un script en el documento y cumpliría la misma función, siempre y cuando la respuesta sea en formato JSON. Aca va un ejemplo usando jQuery:

$(function() {
    var webServices = [1,2,3,4,5,6]; // id's de los webservices
    var count = 1, host;
    for (var i = 0; i < webServices.length; i++) {
        // generamos un host
        host = 'http://ws' + count + '.' + location.host + '/search?ws=' + i;
        if ((i+1)%2 == 0) count++;
        // enviamos el request, jQuery inyecta el script en el documento al detectar otro dominio
        $.getJSON(host, function(json) {
            // actualizamos los resultados...
            $('#results').html(json.results);
        });
    }
});

Aunque en el título menciono a PHP, mas bien nos limita en vez de darnos una solución práctica.

  • Share/Bookmark