jueves, 3 de diciembre de 2015

La solución multilenguaje en MyFamilyServer (Parte 3, Ejecución de la aplicación)

Esta publicación es la continuación a
La solución multilenguaje en MyFamilyServer (Parte 2, generación de plantillas)

En la parte uno y dos ya hemos visto:
  • Como proceder en el momento del desarrollo.
  • Que ocurre en el momento de generar la traducción.
Ahora solo nos falta:
  • Que ocurre en ejecución.


Si has llegado hasta este punto, ya dispones de.
  • Un conjunto de plantillas html que hacen la función de 'máster'.
  • Un diccionario por cada idioma que necesitas.
  • Un conjunto de plantillas, copia del 'máster' traducidas a cada idioma y
  • Un árbol de directorios que te permite tener las plantillas ordenadas por idiomas.
(Recuerda que, cualquier cambio que necesites realizar, debes hacerlo en el 'máster' y el proceso de traducción lo propagará a todos los idiomas)

En este post, vamos a ver, paso a paso, como seleccionar y utilizar las plantillas del idioma adecuado (vamos a ver como esta realizado en MyFamilyServer).
En MyFamilyServer hay pantallas que están realizadas en partes (una parte es la cabecera, otra el menú izquierdo, otra el contenido, y otra el pie) y pantallas que están realizadas con una sola plantilla. En este ejemplo vamos a ver como funciona para ambos casos, que son muy parecidos.

MyFamilyServes es una aplicación privada (no para uso publico) que requiere de un usuario y contraseña para utilizarse, en este caso, sabemos que usuario esta utilizando la aplicación, ya que la misma requiere login..... Que bueno, según haces login en la aplicación (validas tu usuario y contraseña), recuperamos del registro de usuarios cual es el idioma en el quieres trabajar... fácil.
El idioma (como algún otro dato) lo dejamos en sesión y de este modo esta disponible en cualquier momento que necesitemos.

Supongo que en tu aplicación puedes saber que idioma quiere utilizar el usuario. Una vez dispones del idioma a utilizar, el proceso es el siguiente:

Las plantillas se encuentran todas en los mismos arboles de directorio, cada conjunto dentro del su arbol de idioma pero dentro del idioma todos los sub-arboles son iguales (de esto estamos seguros por que el árbol lo copia el proceso de traducción).
La selección del conjunto de plantillas la realizo con estas porciones de código:

El idioma lo recupero de sesión con esa función (tu puedes utilizar esta o cualquier otra)

function recuperar_de_sesion($parametro) {
    $valor = $_SESSION[$parametro];
    return $valor;
}


La selección del directorio la realizo con esta función (el directorio de las plantillas html en MyFamilyServer esta compuesto por el idioma, el modelo y la funcionalidad):

function seleccionar_directorio($modelo, $funcionalidad, $idioma) {
    $directorio = $idioma.'/'.$modelo.'/'.$modelo.$funcionalidad.'/';
    return $directorio;
}
 

Con estas dos funciones ya puedo recuperar la plantilla adecuada, primero obtengo el valor del idioma:

$idioma = recuperar_de_sesion('idioma');

luego identifico el directorio de la plantilla:

$directorio = seleccionar_directorio($modelo, $funcionalidad, $idioma);

y finalmente recupero la plantilla:

$htmlCuerpoObjeto = file_get_contents('html/'.$directorio. $plantilla . '.html');

Cuando una pantalla esta compuesta por varias plantillas las concateno despues de haberlas recuperado todas:

  $html = $htmlCabeceraGral .
            $htmlCabeceraObjeto .
            $htmlMenuObjeto .
            $htmlMenuGral .
            $htmlCuerpoObjeto .
            $htmlPieObjeto .
            $htmlPieGral;

 

y finalmente lo presento:

    print $html;


Ya esta, esta es la explicación completa de la solución multi idioma en MyFamilyServer.
No hace falta explicar que las plantillas pasan, antes de concatenarlas,  por otra transformación, para sustituir las etiquetas de datos por valores en el momento de ejecución, pero eso NO forma parte de la explicación de la solución multi idioma.

Estoy preparando documentación completa de la arquitectura del software y del código en MyFamilyServer, en cuanto este disponible publicare un post explicando como y donde descargarla. 

miércoles, 2 de diciembre de 2015

La solución multilenguaje en MyFamilyServer (Parte 2, generación de plantillas)

Esta publicación es la continuación a
La solución multi lenguaje en MyFamilyServer (Parte 1, el desarrollo)

Decíamos :
El proceso consta de tres pasos:
  • Como proceder en el momento del desarrollo.
  • Que ocurre en el momento de generar la traducción.
  • Que ocurre en ejecución.
En el paso anterior (mo desarrollar) hemos ido muy despacio hasta tener un  fichero .ini para la traducción, una (o mas plantillas .html) y un proceso .php que es capaz de leer el fichero de traducción y traducir las plantillas.
Ahora vamos a pensar como hacer esto antes de la ejecución, en un proceso previo de traducción.

La idea general en un desarrollo MVC, es tener bien estructurados (y separados) los componentes, en el caso de la Vista, esta dividida en varias partes, una la lógica de la vista, otra los diccionarios, otra las plantillas...  De hecho, lo normal es que todas las plantillas para generar las futuras pantallas este en una carpeta 'html'. 
En el caso de MyFamilyServerV2, efectivamente todas las plantillas están en su carpeta html (y dentro en otras carpetas por funcionalidad). 
El primer nivel en la carpeta html es el idioma. 
Para el ejemplo que queremos realizar ahora, debes crear una carpeta (llamada Master por ejemplo) donde creas las plantillas. En esa carpeta, a partir de ahora, siempre creas y modificas las plantillas .El proceso de traducción realizará una copia entera de la carpeta Master en el idioma a traducir y realizará la traducción.

En la carpeta Master (html/Master/) dejas el .html del ejemplo anterior y uno nuevo. (por ejemplo este: y le pones de nombre bye.html)

<html>
    <head>
        <title>¬Bye multi idioma¬</title>
    </head>
    <body>
        ¬Otro ejemplo multi idioma utilizado de MyFamilyServer¬
    </body>
</html> 


(Ahora en la carpeta html/Master/ tienes dos plantillas .html -helloworld.html y bye.html)

En el diccionario (fichero .ini) incorporas las traducciones para esta otra plantilla:

[html/Master/helloworld.html]
Hello World multi idioma = Multi language Hello World
Ejemplo de multi idioma utilizado en MyFamilyServer = MyFamilyServer multilanguage example


[html/Master/bye.html]
Bye multi idioma = Bye Multi language
Otro ejemplo multi idioma utilizado de MyFamilyServer = Another example of Multi language in MyFamilyServer

 

Y le cambias el nombre al fichero. Llamale 'hellowold_En.ini' ya que este va ser el fichero para traducir a Ingles.
Fijate que, en el fichero de traducción, he cambiado la ruta de los archivos .html , ahora el nombre de cada plantilla incorpora su ruta.

El proceso a realizar consiste en copiar toda la carpeta Master a una nueva de cada uno de los idiomas que quieres realizar y a continuación la traducción.
Para copiar el árbol he utilizado esta función: (que debes incorporar a tu fichero helloworld.php)

 function copiarArbol($origen, $destino) {
    # creo el destino
    mkdir($destino, 0777);
    chmod($destino, 0777);

    $directorio = opendir($origen);
    while ($fichero = readdir($directorio)) {
        if ($fichero == '.' || $fichero == '..')
            continue;
        if (is_dir($origen . '/' . $fichero)) {
            if (!is_dir($destino . '/' . $fichero)) {
                mkdir($destino . '/' . $fichero, 0777);
                chmod($destino . '/' . $fichero, 0777);
            }
            copiarArbol($origen . '/' . $fichero, $destino . '/' . $fichero);
        } else {
            if (strrchr($fichero, '.') != '.db') {
                copy($origen . '/' . $fichero, $destino . '/' . $fichero);
                chmod($destino . '/' . $fichero, 0777);
            }
        }
    }
    closedir($directorio);
    return 1;
}


En el hellowold.php se incorpora la llamada a copiarArbol y las variables necesarias para poder hacer multiples idiomas:
Así queda ahora helloworld.php:

<?php

function copiarArbol($origen, $destino) {
    # creo el destino
    mkdir($destino, 0777);
    chmod($destino, 0777);

    $directorio = opendir($origen);
    while ($fichero = readdir($directorio)) {
        if ($fichero == '.' || $fichero == '..')
            continue;
        if (is_dir($origen . '/' . $fichero)) {
            if (!is_dir($destino . '/' . $fichero)) {
                mkdir($destino . '/' . $fichero, 0777);
                chmod($destino . '/' . $fichero, 0777);
            }
            copiarArbol($origen . '/' . $fichero, $destino . '/' . $fichero);
        } else {
            if (strrchr($fichero, '.') != '.db') {
                copy($origen . '/' . $fichero, $destino . '/' . $fichero);
                chmod($destino . '/' . $fichero, 0777);
            }
        }
    }
    closedir($directorio);
    return 1;
}

# inicio del programa
$idioma = 'En';
$origen = 'html/Master/';
$destino = 'html/' . $idioma . '/';

if (copiarArbol($origen, $destino)) {
    # la copia de arbol ha ido bien
    $fichero_traduccion = "helloworld_" . $idioma . ".ini";

    $traductor = parse_ini_file($fichero_traduccion, true);
    foreach ($traductor as $fichero => $campos) {
        # recuperamos la plantilla a traducir
        $html = file_get_contents($fichero);
        # El diccionario es la relacion identificador -> dato
        foreach ($campos as $campo => $valor) {
            # sustituimos los textos entre ¬ ¬ por los textos traducidos
            $html = str_replace('¬' . $campo . '¬', $valor, $html);
        }
        $ficheroSalida = str_replace('Master', $idioma, $fichero);
        file_put_contents($ficheroSalida, $html);
    }
    Print "Se han generado las plantillas en idioma -".$idioma."- correctamente";
} else {
    # Ha fallado la copia de arbol (revisa permisos o como has definido las rutas)
    Print " Ha fallado la copia de arbol (revisa permisos o como has definido las rutas)";
}
?>

 

Genial!! ya tienes tu traductor y tus plantillas preparadas. Vamos a preparar otro idioma veras que fácil es:

Vamos a traducir a Español.

Primero: Generar el diccionario para Español.  Copia helloworld_En.ini a hellowold_Es.ini.
A continuación: Traduce los textos al español: (en hellowold_Es.ini).

[html/Master/helloworld.html]
Hello World multi idioma = Hola Mundo Multi Idioma
Ejemplo de multi idioma utilizado en MyFamilyServer = Ejemplo de Multi Idioma de MyFamilyServer

[html/Master/bye.html]
Bye multi idioma = Adios Multi Idioma
Otro ejemplo multi idioma utilizado de MyFamilyServer = Otro ejemplo Multi Idioma de MyFamilyServer


Y finalmente ejecuta tu programa de traducción (helloworld.php) con la variable $idioma="Es"
Veras que por cada idioma se ha generado una nueva carpeta dentro de la carpeta html/, con el código del idioma y las plantillas traducidas dentro.

¡¡¡ Fantastico !!!

Resumiendo.
El programa esta compuesto de un fichero.php para la ejecución del proceso y tantos ficheros .ini como necesites para traducción.

En la raíz de tu proyecto dejas el helloworld.php y los ficheros helloworld_Es.ini, helloworld_En.ini y tantos otros como idiomas necesites.
En el directorio html/Master generas las plantillas .html que necesites para la traducción. En estas plantillas los textos deben estar rodeados por el símbolo ¬ .
Al ejecutarse el programa se creara un directorio en html/ con el valor de la variable $idioma y se copiarán y traducirán las plantillas según los textos preparados en el fichero .ini con ese código de idioma en el nombre.

Todos los cambios que quieras hacer los realizaras solo en los ficheros .html 'master' y estos se propagaran a todos los idiomas con la ejecución del proceso de traducción.

Muy bien, en el siguiente post te explico como se selecciona el idioma en MyFamilyServer y como se selecciona el conjunto de plantillas de cada idioma.

martes, 1 de diciembre de 2015

La solución multilenguaje en MyFamilyServer (Parte 1, el desarrollo)

Esta publicación es la continuación a
La solución multilenguaje en MyFamilyServer (Introducción)

Decíamos :
El proceso consta de tres pasos:
  • Como proceder en el momento del desarrollo.
  • Que ocurre en el momento de generar la traducción.
  • Que ocurre en ejecución.
Paso primero: Como desarrollar.
Vamos a ir muy muy muy despacio.

Estamos de acuerdo en este ejemplo de hello world: (llámalo helloworld.html)
 
 <html>
    <head>
        <title>Hello World multi idioma</title>
    </head>
    <body>
        Ejemplo de multi idioma utilizado en MyFamilyServer
    </body>
</html>


Este ejemplo es un HTML que presenta en la pantalla la frase 'Ejemplo de multi idioma utilizado en MyFamilyServer'

Ahora vamos a construir el siguiente PHP (llamale helloworld.php)

<?php
    $html = '';
    $html = file_get_contents('helloworld.html');
    print $html;
?>


Si ejecutas el PHP tienes el mismo resultado que si ejecutas el HTML. 
El resultado es el mismo, pero ahora puedes tratar el HTML.
Vamos a modificar el helloworld.php:

<?php
    $html = '';
    $html = file_get_contents('helloworld.html');
    $html = str_replace('Ejemplo de multi idioma utilizado en MyFamilyServer',
            'MyFamilyServer multilanguage example', $html);
    print $html;
?>

 
 

En esta ocasión he remplazado un texto por otro. He mantenido el mismo HTML pero he remplazado un texto. Vamos a dar un pasito mas y reemplazar también el titulo:


<?php
    $html = '';
    $html = file_get_contents('helloworld.html');
    $html = str_replace('Hello World multi idioma',
            'Multi language Hello World', $html);
    $html = str_replace('Ejemplo de multi idioma utilizado en MyFamilyServer',
            'MyFamilyServer multilanguage example', $html);
    print $html;
?>


Esta es la idea, ahora vamos a ponerla en su sitio.

Para evitar posibles problemas, los textos en el HTML (que ahora se esta convirtiendo en una plantilla) se rodean por algún carácter para estar seguros que estamos sustituyendo realmente un texto, y no otra parte del HTML que coincide con una traducción. por ejemplo podéis utilizar ¬ (por ejemplo). En ese caso el HTML debe escribirse con un ¬ delante y detrás¬ de cada texto a ser sustituido. El HTML helloworld.html seria:

<html>
    <head>
        <title>¬Hello World multi idioma¬</title>
    </head>
    <body>
        ¬Ejemplo de multi idioma utilizado en MyFamilyServer¬
    </body>
</html>

 

y hay que tenerlo en cuenta en el PHP. El helloworld.php quedará:

<?php
    $html = '';
    $html = file_get_contents('helloworld.html');
    $html = str_replace('¬Hello World multi idioma¬',
            'Multi language Hello World', $html);
    $html = str_replace('¬Ejemplo de multi idioma utilizado en MyFamilyServer¬',
            'MyFamilyServer multilanguage example', $html);
    print $html;
?>


Hasta ahora bien, tenemos una plantilla HTML y sabemos como 'traducirla' a otro idioma, pero... el php se esta complicando, vamos a utilizar un diccionario sencillo, por ejemplo un fichero formato .ini (podría ser una base de datos, un json, un xml... pero en .ini es muy fácil de usar y va bien para el ejemplo) y vamos a mantener las traducciones en un fichero aparte.

Ejemplo de fichero de traducción, llamalo helloworld.ini

[helloworld.html]
Hello World multi idioma = Multi language Hello World
Ejemplo de multi idioma utilizado en MyFamilyServer = MyFamilyServer multilanguage example


y he cambiado el helloworld.php para leer ficheros .ini

<?php
$fichero_traduccion = "helloworld.ini";
$traductor = parse_ini_file($fichero_traduccion, true);
foreach ($traductor as $fichero => $campos) {
    # recuperamos la plantilla a traducir
    $html = file_get_contents($fichero);
    # El diccionario es la relacion identificador -> dato
    foreach ($campos as $campo => $valor) {
        # sustituimos los textos entre ¬ ¬ por los textos traducidos
        $html = str_replace('¬' . $campo . '¬', $valor, $html);
    }
    print $html;
}
?>


El comando parse_ini_file genera una array que mantiene: primero el nombre de la plantilla que  se ha definido entre [] en el fichero ini, y para cada plantilla un identificador con el texto a traducir y un valor con la traducción.

Después de generar el array lo recorremos (con el foreach), para cada plantilla a traducir se realiza otro bucle que va reemplazando cada identificador por cada valor.

Este ejemplo esta completo, en el caso en MyFamilyServer, no se presenta en este momento (no se ejecuta un print), se almacena, (con el comando file_put_contents), de este modo las plantillas originales (master, con los simbolos ¬) generan nuevas plantillas en cada idioma antes (si antes) de la ejecución por parte del usuario.

Completo las explicaciones de grabación de plantillas en la siguiente entrada del blog.

(Usar ficheros .ini es muy sencillo, como veis, pero los ficheros .ini tienen algunas restricciones de uso de caracteres (como los paréntesis ()) y palabras que puedan tener significado (como true) en su interpretación, es bueno para el ejemplo, pero con cuidado)

La solución multilenguaje en MyFamilyServer (introducción)

Siguiendo el Roadmap de MyFamilyServer (Roadmap que cambie ya que tenia previstas algunas cosillas pero teniendo gran parte de visitas de lengua 'En' es buena idea adaptarse al mercado) bueno  ... Siguiendo el Roadmap de MyFamilyServer, el paso siguiente ha sido multilenguaje.

La solución multi lenguaje ha quedado muy chula, no la he puesto en producción todavía (no esta disponible para descargar) pero voy a explicar bien la solución para que, el que le interese hacer un desarrollo web PHP HTML multi-idioma pueda utilizar la solución utilizada en MyFamilyServer.

En el caso de MyFamilyServer (MyFamilyServerV2) la arquitectura utilizada es MVC (Modelo Vista Controlador -sin framework-) esto quiere decir que el código esta segmentado en tres grandes partes, una con la funcionalidad (modelo) otra con el flujo que debe seguir la aplicación (controlador) y finalmente otra parte con toda la presentación (vista). Todos los trabajos multi lenguaje se realizan en esta ultima parte, la capa de presentación. 
(¿Es posible realizar una web multi idioma en una arquitectura no MVC?, si, es posible, pero tener mezclado desarrollo de parte servidora con desarrollo de presentación y de acceso a datos es una pesadilla para el presente y el futuro, entonces, ¿puedes crear una web multilenguaje en una arquitectura no MVC?: SI puedes .. pero te va a costar un poco mas)

En la parte de presentación, en el caso de MyFamilyServer, se ha utilizado HTML, CSS y Javascript y las pantallas se desarrollan utilizando plantillas HTML.
(Plantillas HTML me refiero a código HTML que contiene etiquetas que son sustituidas por otros datos antes de presentarse al usuario, el el caso del idioma las etiquetas se sustituyen por los textos en el idioma que corresponda)(en esas mismas plantillas hay también otras etiquetas que serán sustituidas por los datos en el momento de ejecución).

Los componentes que intervienen en la presentación multi lenguaje son:
  • Las plantillas HTML.
  • El código Javascript (en ocasiones, en javascript se realizan validaciones en las que se dice al usuario 'el formato de el campo debe ser xxx' y este comentario debe ser multi idioma también).
  • Un diccionario donde se almacena la traducción. 
El proceso consta de tres pasos:
  • Como proceder en el momento del desarrollo.
  • Que ocurre en el momento de generar la traducción.
  • Que ocurre en ejecución.

MyFamilyServerV2, no esta todavía disponible para descargar, comencé con multi idioma y he realizado muchos cambios mas y próximamente dejare una versión nueva, totalmente nueva, del proyecto disponible en la web. 
Esta entrada el el blog (Solución multilenguaje en MyFamilyServer) esta dividida en varias partes para que sea un poco mas fácil de tratar.