PHPProgramación

Sitio Web Multi-Lenguaje con PHP

Traducir un sitio web es una necesidad que muchos clientes y empresas tienen hoy en día y para ello es esta breve explicación funcional de cómo convertir un sitio web PHP en un sitio web multi-lenguaje.

Lo primero que debemos hacer es crear nuestra estructura de archivos y folders en nuestro hosting o servidor, se recomienda seguir la siguiente estructura:

/ (raíz o public_html) 
-locale 
-- es_MX 
---- LC_MESSAGES 
------ file.mo
------ file.po  
-- en_US 
---- LC_MESSAGES 
------ file.mo
------ file.po    

La carpeta locale hace énfasis a que será donde se almacenen y enseguida deben estar las carpetas del lenguaje a utilizar, por ejemplo, la carpeta es_MX para el lenguaje de español para México y en_US para inglés de Estados Unidos. Inmediatamente de la carpeta del lenguaje deberás crear una carpeta llamada LC_MESSAGES en la cual deberás almacenar los archivos .PO y .MO con el nombre de la aplicación en cuestión, para el caso de eShop by Anubbe deben ser llamados eshop.po y eshop.mo.

El lenguaje PHP cuenta con una función llamada gettext() la cual se encargará de obtener el texto de acuerdo al lenguaje deseado, esta función es muy sencilla de utilizar, ya sea por la forma completa:

<?php echo gettext("mensaje deseado");

O utilizando la función en su forma corta utilizando un guión bajo:

<?php echo _("mensaje deseado");

Adicional, también podemos usar la función ngettext() para hacer traducciones de plurales o singulares dependiendo algún resultado que tengamos, por ejemplo, si tenemos buscador y queremos mostrar el mensaje “Un resultado encontrado” para cuando solo exista un solo resultado y para cuando exista más de un resultado mostrar “Varios resultados encontrados” necesitaremos hacer uso de esta función de la siguiente forma:

<?
// Variable donde almacenaremos el número de resultados
$results = 1;

// Llamado e impresión del mensaje que ngettext nos regrese
// funcion ngettext requiere de 3 parámetros string:
// - Primer parámetro: ID de mensaje en singular, para este ejemplo "Un resultado encontrado"
// - Segundo parámetro: ID de mensaje en plural, para este ejemplo "Varios resultados encontrados"
// - Tercer parámetro: Número a evaluar para decidir si regresar el mensaje en singular o en plurar, para este ejemplo usamos la variable $results
echo ngettext("Un resultado encontrado", "Varios resultados encontrados", $results);

Ahora, podemos hacer más personalizado el mensaje a mostrar utilizando la función sprintf() la cual nos permitirá dar formato a un string con variables. Ejemplo: si en lugar de mostrar el mensaje “Varios resultados encontrados” queremos mostrar el mensaje con el número de resultados (ej. “5 resultados encontrados”), entonces haremos lo siguiente:

<?
$results = 5;
echo sprintf(ngettext("Un resultado encontrado", "%d resultados encontrados", $results), $results);

// Esto hará la impresión de "5 resultados encontrados"

Lo mismo podemos hacer para mensajes simples (aquellos que no requieran de un selector de singular o plural), sprintf() nos brindará ese apoyo para poder concatenar mensajes y variables de forma adecuada y sin perder su formato, simplemente deberemos usar especificadores de tipo de dato, aquí un ejemplo:

<?
// Mostrar el mensaje "Bienvenido NOMBRE, hoy es tu visita número #, ¡disfruta tu día!"
$nombre = "Fernando";
$numeroDeVisita = 5;
echo sprintf(_("Bienvenido %s, hoy es tu visita número %d, ¡disfruta tu día!"), $nombre, $numeroDeVisita);

// Resultado: Bienvenido Fernando, hoy es tu visita número 5, ¡disfruta tu día!

Si tienes curiosidad de cómo escoger el especificador de sitio correcto o cómo funcionan visita la documentación oficial de PHP para sprintf().

Todo eso que acabamos de ver es lo primero que hay que hacer antes de comenzar a traducir el sitio, no olvides reemplazar todos tus textos a formato gettext, es decir, utilizando siempre la función en su forma normal o corta.

Una vez que ya hayas terminado el sitio web en un idioma, ahora hay que generar un archivo .POT para poder generar las traducciones a los diferentes lenguales, para ello utilizaremos el siguiente comando para generarlo, este código trabaja de forma recursiva buscando en cada archivo de todos ficheros que se encuentren donde lo corras todos los mensajes que se muestren con la función gettext() sin importar su forma de uso.

Comando para generar archivo .POT de forma recursiva:

find . -iname "*.php" | xargs xgettext --output locale/eshop.pot --from-code UTF-8

Si necesitas actualizar el las traducciones del sitio web, no es necesario volver a traducir todo el sitio nuevamente, utiliza este comando para generar un archivo actualizado del lenguaje deseado y solo traduce los nuevos mensajes:

msgmerge --update locale/en_US/LC_MESSAGES/eshop.po eshop.pot

Ya casi terminamos, ahora solo necesitas agregar un poco de código PHP para que el sitio web muestre los mensajes traducidos de acuerdo al lenguaje deseado y lo haremos con el siguiente fragmento de código:

<?php
$lang = "en_US"; // Lenguaje seleccionado (debe coincidir con alguno de los lenguajes de tus carpetas)
putenv("LC_ALL=$lang");
setlocale(LC_ALL, $lang);
bindtextdomain("eshop", __DIR__ . "/locale");
textdomain("eshop");

Si trabajas con un producto eShop by Anubbe que no cuente con las traducciones de forma automática, en el archivo app.php agrega los siguiente métodos:

<?php
    /* Language */
    public function loadLocale() {
        // Detect language
        $lang = $this->lang;
        $browserLang = substr($_SERVER['HTTP_ACCEPT_LANGUAGE'], 0, 2);
        if (isset($_COOKIE['eshopLang'])) {
            $lang = $_COOKIE['eshopLang'];
        } else {
            if ($lang != $browserLang)
                $lang = $browserLang;
        }
        
        if (isset($_GET['lang'])) {
            $lang = $this->getLocale($_GET['lang']);
            $this->setLocale($lang, true);
        }
        
        putenv("LC_ALL=$lang");
        setlocale(LC_ALL, $lang);
        bindtextdomain("eshop", __DIR__ . "/../locale");
        textdomain("eshop");
    }
    
    public function getLocale($lang) {
        $locales = array(
            "en" => "en_US",
            "en_us" => "en_US",
            "es" => "es_MX",
            "es_mx" => "es_MX",
            "es_ar" => "es_AR",
        );
        return $locales[strtolower($lang)];
    }
    
    public function setLocale($locale, $force = false) {
        if (!isset($_COOKIE['eshopLang']) or $force) 
            setcookie("eshopLang", $locale, strtotime("+1 year"), "/");
    }
    /* Language */

No olvides agregar también la siguiente línea de código en el método seteShop() del mismo archivo para mandar a llamar las funciones de traducción:

<?php // Recomendamos agregarlo enseguida de la línea en la cual se define el menú del sitio
   // Set language
   $this->loadLocale();

Si tienes problemas o dudas, acércate a alguno de tus compañeros Anubbers y estarán dispuestos a apoyarte, solo no olvides antes intentar usar tu creatividad y resolverlo.

Publicaciones relacionadas
NativeScriptProgramación

NativeScript: Usando Localize para internacionalizar nuestra aplicación

NativeScriptProgramación

NativeScript: Comprendiendo los eventos de página

NativeScriptProgramación

NativeScript: Obtener elementos de la vista por el nombre de la clase