Plugin de localización de idioma
1Presentación
Este plugin permite dos cosas:
- Gestionar URLs con un prefijo de idioma. Por lo tanto, el plugin redirigirá automáticamente al usuario a la página solicitada con /en/ (por ejemplo) al principio de la URL.
- Cargar automáticamente las traducciones correspondientes al idioma usado, para poner las cadenas traducidas a disposición de las plantillas.
2Configuración
En el archivo etc/temma.php, añade el pre-plugin y configúralo:
<?php
return [
// carga del plugin
'plugins' => [
'_pre' => [
'\Temma\Plugins\Language'
]
],
// configuración del plugin
'x-language' => [
// lista de idiomas soportados por el sitio
'supported' => [ 'fr', 'en', 'de' ],
// idioma por defecto, si el navegador no es compatible con
// ninguno de los idiomas indicados anteriormente
'default' => 'fr',
// (opcional) puedes indicar que no se usen
// prefijos de plantilla (ver más abajo)
'templatePrefix' => false,
// (opcional) puedes indicar las URLs para las que
// la gestión de idioma no está activada
'protectedUrls' => [
'/robots.txt',
'/sitemap.xml',
],
// (opcional) pon en false para evitar intentar
// cargar el archivo de traducción
'readTranslationFile' => false,
],
// configuración de la vista Smarty
'x-smarty' => [
'pluginsDir' => '/path/to/project/lib/smarty-plugins'
]
];
-
Líneas 5 a 9: Configuración de los plugins.
- Línea 7: Activación del pre-plugin que permite la gestión de idioma.
-
Líneas 11 a 29: Configuración del plugin.
- Línea 13: Lista de idiomas soportados por el sitio.
- Línea 16: Definición del idioma por defecto (usado si el navegador no es compatible con ninguno de los idiomas indicados).
- Líneas 22 a 25: Definición de la lista de URLs para las que la gestión de idioma está desactivada.
- Línea 28: Desactivación de la carga del archivo de traducción.
-
Líneas 31 a 33: Configuración de la vista Smarty.
- Línea 32: Adición del directorio que contiene los plugins Smarty proporcionados por Temma, para que el intérprete Smarty pueda encontrar la extensión (ver más abajo).
3Funcionamiento
En el ejemplo de configuración anterior, indicamos que el sitio tiene traducciones en francés, inglés y alemán.
Cuando un navegador solicita una página, pueden darse dos casos:
- La URL solicitada no empieza por /fr/, /en/ ni /de/. En este caso, el plugin redirigirá al usuario a la URL solicitada, añadiendo el prefijo de idioma. El idioma elegido será el primero soportado por el navegador que también esté soportado por el sitio (si ninguno es adecuado, se usará el idioma por defecto del sitio).
- La URL solicitada empieza con un prefijo de idioma. En este caso, el plugin comprobará que el idioma solicitado está bien soportado por el sitio (si no es el caso, volvemos al caso anterior). Si el idioma está bien soportado, el plugin extraerá el idioma, y modificará toda la información relativa al controlador, a la acción y a los parámetros, para simular que ese prefijo no existía en la URL. Además, el plugin carga el archivo de traducción correspondiente, y añade un prefijo a la ruta que lleva a los archivos de plantilla.
Por ejemplo, si el usuario solicita la página /page/list/date/5, con un navegador que soporte el francés, el plugin la redirigirá a /fr/page/list/date/5.
Al llegar a /fr/page/list/date/5, el plugin extraerá el idioma (fr), y cargará el archivo de traducción en francés. Después modificará varias cosas:
- El controlador solicitado pasa a ser page (y ya no fr).
- La acción solicitada pasa a ser list (y ya no page).
- La lista de parámetros pasa a ser
['date', '5'](y ya no['list', 'date', '5']).
Las variables de plantilla $CONTROLLER, $ACTION y $URL también se modifican en consecuencia.
4Gestión de los métodos de petición
Si la URL solicitada empieza con información de idioma (y ese idioma está autorizado por la configuración), el procesamiento explicado anteriormente siempre se llevará a cabo.
Por otro lado, si falta la información de idioma, la redirección (a la misma URL a la que se añade el prefijo de idioma) no se lleva a cabo si la petición usó el método POST o PUT. En este caso, el plugin no hace nada y el procesamiento continúa normalmente.
5URLs protegidas
Es posible definir una lista de URLs que no serán gestionadas por el plugin de idioma. Esto es útil si, por ejemplo, tienes controladores que generan automáticamente el contenido de archivos robots.txt o sitemap.xml.
Ten en cuenta que las URLs deben empezar con el carácter '/'.
6Prefijo en la ruta de las plantillas
A menos que la variable de configuración templatePrefix se haya definido como false, el plugin modificará la ruta que lleva a los archivos de plantilla, añadiendo al principio un directorio correspondiente al idioma solicitado.
Así, si la URL es /fr/article/list, la plantilla usada será (por defecto) el archivo templates/fr/article/list.tpl
Si el controlador usa otro archivo, el prefijo se añadirá de todos modos.
Por ejemplo, si el controlador contiene la siguiente línea:
$this->_template('cms/content/article_list.tpl');
Temma usará el archivo templates/fr/cms/content/article_list.tpl
7Archivos de traducción
7.1Formato básico
El plugin carga archivos que contienen las traducciones. Estos archivos deben colocarse en el directorio etc/lang/ del proyecto. Al igual que el archivo de configuración, estos archivos pueden estar en formato PHP, JSON, INI, YAML o NEON.
Se recomienda el formato PHP, ya que se beneficia de la caché de OPCode (el archivo no se vuelve a leer cada vez que se accede a él). Pero puedes elegir un formato diferente, como INI, por simplicidad.
Los nombres de los archivos dependen del idioma de las traducciones que contienen: fr.php, en.ini, es.json, etc.
Aquí tienes un ejemplo de archivo fr.php:
<?php
return [
'default' => [
'Controllers' => 'Contrôleurs',
'Model' => 'Modèle',
'Views' => 'Vues',
],
'header' => [
'title' => 'Temma : framework PHP simple et performant',
'Home' => 'Accueil',
'Download' => 'Télécharger',
'Community' => 'Communauté',
'Examples' => 'Exemples',
],
'footer' => [
'Designed by' => 'Conception par',
],
];
Lo mismo en formato INI (archivo fr.ini):
[default]
Controllers="Contrôleurs"
Model="Modèle"
Views="Vues"
[header]
title="Temma : framework PHP simple et performant"
Home="Accueil"
Download="Télécharger"
Community="Communauté"
Examples="Exemples"
[footer]
Designed by="Conception par"
En formato JSON (archivo fr.json):
{
"default": {
"Controllers": "Contrôleurs",
"Model": "Modèle",
"Views": "Vues"
},
"header": {
"title": "Temma : framework PHP simple et performant",
"Home": "Accueil",
"Download": "Télécharger",
"Community": "Communauté",
"Examples": "Exemples"
},
"footer": {
"Designed by": "Conception par"
}
}
En formato YAML (archivo fr.yaml) o NEON (archivo fr.neon):
default:
Controllers: Contrôleurs
Model: Modèle
Views: Vues
header:
title: "Temma : framework PHP simple et performant"
Home: Accueil
Download: Télécharger
Community: Communauté
Examples: Exemples
footer:
Designed by: Conception par
Como puedes ver, las cadenas traducidas se organizan por secciones (aquí default, header y footer). Estas secciones corresponden a dominios de traducción.
Aquí también, las cadenas base están en inglés, y cada una tiene su traducción al francés.
Importante: si intentas traducir una cadena, pero no se encuentra en el archivo de traducción, se usará tal cual.
En el ejemplo anterior, podemos ver que las cadenas base están en inglés, y que se ha proporcionado una traducción al francés.
Por lo tanto, no será necesario proporcionar un archivo de traducción en inglés.
7.2Gestión de contexto
Es posible crear varias versiones de una cadena de caracteres. Cada una de estas versiones depende de un contexto personalizable. Estos contextos se usan, por ejemplo, para gestionar versiones masculinas/femeninas de un texto.
El contexto por defecto es el que se define primero.
Para definir contextos, basta con asociar un array asociativo a la clave de traducción.
Archivo de ejemplo fr.php:
<?php
return [
'default' => [
'Actor' => [
'male' => 'Acteur',
'female' => 'Actrice',
],
'Waiter' => [
'non-binary' => 'Serveur⋅euse',
'male' => 'Serveur',
'female' => 'Serveuse',
],
],
];
Y el archivo en.php correspondiente:
<?php
return [
'job' => [
'Actor' => [
'male' => 'Actor',
'female' => 'Actress',
],
'Waiter' => [
'non-binary' => 'Waitstaff',
'male' => 'Waiter',
'female' => 'Waitress',
],
],
];
7.3Gestión del recuento (singular/plural)
Los archivos de traducción también pueden incluir diferentes variaciones de la misma cadena de caracteres, según el número de elementos. Esto va más allá del simple singular/plural: se puede usar cuando no hay elementos, o cuando hay un número variable de elementos.
Al igual que con los contextos, debes definir un array asociativo, cuyas claves son el número de elementos correspondiente a la declinación. Es posible tener claves que empiecen por < o <= para definir intervalos.
El valor por defecto se define con la clave *. Si no se proporciona, se usará el primer valor de la lista.
Archivo de traducción de ejemplo fr.php:
<?php
return [
'default' => [
'there are flowers' => [
'0' => "il n'y a pas de fleurs",
'1' => 'il y a une fleur',
'<=3' => 'il y a quelques fleurs',
'<10' => 'il y a des fleurs',
'*' => 'il y a plein de fleurs',
],
],
];
Y su versión en en.php:
<?php
return [
'default' => [
'there are flowers' => [
'0' => 'there are no flowers',
'1' => 'there is one flower',
'<=3' => 'there are a few flowers',
'<10' => 'there are some flowers',
'*' => 'there are lots of flowers',
],
],
];
7.4Contexto + recuento
Los contextos y los recuentos se pueden usar juntos. Para ello, cada contexto debe contener un recuento.
Aquí tienes un ejemplo:
<?php
return [
'default' => [
'there are actors' => [
'male' => [
'0' => "il n'y a pas d'acteurs",
'1' => 'il y a un acteur',
'*' => 'il y a des acteurs',
],
'female' => [
'0' => "il n'y a pas d'actrices",
'1' => 'il y a une actrice',
'*' => 'il y a des actrices',
],
],
],
];
8Uso en las plantillas
En las plantillas Smarty, el plugin crea dos variables adicionales:
- $lang: Contiene el idioma actual (fr, en, etc.).
- $l10n: Contiene la tabla de traducciones. No debe usarse.
Puedes usar la variable $lang directamente en tus plantillas:
{if $lang == 'fr'}
Bonjour tout le monde
{else}
Hello everyone
{/if}
Mostrado en francés, esto se verá así:
Bonjour tout le monde
En inglés:
Hello everyone
También puedes usar el modificador |l10n y la etiqueta de bloque {l10n}...{/l10n}.
9Plantillas: modificador
Para traducir cadenas, puedes usar el modificador l10n. Busca la traducción de la cadena que recibe como entrada, y la devuelve después de escapar los caracteres especiales.
<h1>{"Model"|l10n}</h1>
<h2>{"Views"|l10n}</h2>
{"zkwx<hyq"|l10n}
Mostrado en francés:
<h1>Modèle</h1>
<h2>Vues</h2>
zkwx<hyq
En inglés:
<h1>Model</h1>
<h2>Views</h2>
zkwx<hyq
- Líneas 1 y 2: Las cadenas listadas en la sección default del archivo de traducción se pueden usar directamente.
- Línea 4: Si la cadena no se encuentra en el archivo de traducción, se usa tal cual. El carácter especial < se escapa como <.
9.1Modificador: dominio
Para especificar un dominio, añádelo antes de la cadena de traducción, usando el carácter de almohadilla (#) para separar el dominio de la cadena.
{"header#Home"|l10n}
{"header#Download"|l10n}
Mostrado en francés, esto daría:
Accueil
Télécharger
En inglés:
Home
Download
9.2Modificador: contexto y recuento
El contexto y el recuento se pueden indicar después del dominio, separados por comas.
Si no se indica el contexto, se usa el primero listado en el archivo de traducción. Si no se indica el recuento, se usará el recuento por defecto (*); si este no existe, se usará el primer recuento definido.
Plantilla de ejemplo:
{"default,female,1#there are actors"|l10n}
{",,3#there are actors"|l10n}
{"default,female#there are actors"|l10n}
El resultado en francés:
il y a une actrice
il y a des acteurs
il y a des actrices
- Línea 1: Se usa el dominio por defecto, el contexto female, y el recuento se establece en 1.
- Línea 2: No se especifica el dominio, así que se usa el dominio por defecto. No se especifica el contexto, así que se usa el primero definido. El recuento es 3.
- Línea 3: Se usan el dominio por defecto y el contexto female. No se especifica el recuento, así que se usa el recuento por defecto (*).
9.3Modificador: parámetros
Se pueden proporcionar parámetros al modificador, que se usarán para reemplazar partes del texto. Cada parámetro ocupará el lugar de un marcador del tipo %1%, %2%, %3%, etc.
Si el archivo de traducción contiene las siguientes definiciones:
<?php
return [
'default' => [
'Hello %1%' => 'Bonjour %1%',
'%1% has %2% kids' => "%1% a %2% enfants"
]
];
Tu plantilla puede contener:
{"Hello %1%"|l10n:'James'}
{"%1% has %2% kids"|l10n:'Alice':3}
Mostrado en francés:
Bonjour James
Alice a 3 enfants
Por supuesto, los parámetros se pueden usar al mismo tiempo que el dominio, el contexto y el recuento.
El dominio está disponible con el marcador %domain%.
El contexto está disponible con el marcador %ctx%.
El recuento está disponible con el marcador %count%.
Por ejemplo, con el siguiente archivo de traducción:
<?php
return [
'default' => [
'%1% has %count% kids' => [
'any' => [
'0' => "%1% n'a pas d'enfant",
'1' => "%1% a un enfant",
'*' => "%1% a %count% enfants"
],
'girls' => [
'0' => "%1% n'a pas de filles",
'1' => "%1% a une fille",
'*' => "%1% a %count% filles"
],
'boys' => [
'0' => "%1% n'a pas de garçons",
'1' => "%1% a un garçon",
'*' => "%1% a %count% garçons"
]
]
]
];
Si tu plantilla contiene esto:
{",,3#%1% has %count% kids"|l10n:'Alice'}
{"default,boys,0#%1% has %count% kids"|l10n:'Bob'}
{",girls,1#%1% has %count% kids"|l10n:'Camille'}
El resultado será:
Alice a 3 enfants
Bob n'a pas de garçons
Camille a une fille
- Línea 1: No se especifica el dominio, así que se usará el dominio por defecto. No se especifica el contexto, así que se usará el primero definido (any). Y tomamos el valor 3 para el recuento.
- Línea 2: Se especifica el dominio default. Se especifica el contexto boys. El recuento se establece en 0.
- Línea 3: Dominio no especificado. Se especifica el contexto girls. El recuento es 1.
10Plantillas: etiqueta de bloque
También puedes usar la etiqueta de bloque Smarty {l10n}.
{l10n}Model{/l10n}
Mostrado en francés:
Modèle
A diferencia de los modificadores, los bloques de traducción no escapan los caracteres especiales.
10.1Etiqueta de bloque: dominio
El dominio por defecto siempre es default. Se puede especificar otro dominio usando el atributo _ (el carácter guion bajo) o el atributo domain en la etiqueta de apertura.
{l10n _='header'}
Home
{/l10n}
{l10n domain='header'}
Download
{/l10n}
Mostrado en francés:
Accueil
Télécharger
10.2Etiqueta de bloque: contexto y recuento
Es posible especificar el contexto y el recuento de dos formas diferentes.
La primera es añadir los atributos ctx y count
a la etiqueta de apertura.
La segunda es usar el atributo _ (carácter guion bajo),
añadiendo el contexto y el recuento después del dominio, separados por comas.
Si no se indica el contexto, se usará el primero listado en el archivo de traducción. Si no se indica el recuento, se usará el recuento por defecto (*); si este no existe, se usará el primer recuento definido.
Ejemplo de plantilla:
{l10n _='default,female,1'}
there are actors
{/l10n}
{l10n _=',,3'}
there are actors
{/l10n}
{l10n _='default,female'}
there are actors
{/l10n}
Mostrado en francés:
il y a une actrice
il y a des acteurs
il y a des actrices
- Línea 1: Se usan el dominio por defecto, el contexto female, y el recuento establecido en 1.
- Línea 2: No se especifica el dominio, así que se usa el dominio por defecto. No se especifica el contexto, así que se usa el primero definido. El recuento es 3.
- Línea 3: Se usan el dominio por defecto y el contexto female. No se especifica el recuento, así que se usa el recuento por defecto (*).
El atributo count puede ser un número o un array. Si es un array, se usará su número de elementos como recuento.
Ejemplo de plantilla:
{$actors = ['Alice', 'Bernadette', 'Camille']}
{l10n ctx='female' count=$actors}
there are actors
{/l10n}
Mostrado en francés:
il y a des actrices
10.3Etiqueta de bloque: parámetros
Al igual que los modificadores, los bloques de traducción pueden recibir parámetros. Estos parámetros se pasan como atributos en la etiqueta de apertura {l10n}, y se usan en las cadenas con la forma %name_parameter%.
Así, es posible usar parámetros como name="Luke" en la etiqueta (con el marcador %name% en la plantilla). Pero para ser compatible con los parámetros usados con el modificador (ver más arriba), se recomienda nombrar los parámetros usando números a partir de 1. Por ejemplo, el parámetro 1="Luke" en la etiqueta, y el marcador %1% en la plantilla.
Si el archivo de traducción contiene las siguientes definiciones:
<?php
return [
'default' => [
'Hello %1%' => "Bonjour %1%",
'%1% has %2% kids' => "%1% a %2% enfants"
]
];
Tu plantilla puede contener:
{l10n 1='Marie'}
Hello %1%
{/l10n}
{l10n 1='Alice' 2='3'}
%1% has %2% kids
{/l10n}
Mostrado en francés:
Bonjour Marie
Alice a 3 enfants
Por supuesto, los parámetros se pueden usar al mismo tiempo que el dominio, el contexto y el recuento.
El dominio está disponible con el marcador %domain%.
El contexto está disponible con el marcador %ctx%.
El recuento está disponible con el marcador %count%.
Por ejemplo, con el siguiente archivo de traducción:
<?php
return [
'default' => [
'%1% has %count% kids' => [
'any' => [
'0' => "%1% n'a pas d'enfant",
'1' => "%1% a un enfant",
'*' => "%1% a %count% enfants"
],
'girls' => [
'0' => "%1% n'a pas de filles",
'1' => "%1% a une fille",
'*' => "%1% a %count% filles"
],
'boys' => [
'0' => "%1% n'a pas de garçons",
'1' => "%1% a un garçon",
'*' => "%1% a %count% garçons"
]
]
]
];
Si tu plantilla contiene:
{l10n _=',,1' 1='Alice'}
%1% has %count% kids
{/l10n}
{l10n _='default,girls,0' 1='Bob'}
%1% has %count% kids
{/l10n}
{l10n _=',boys,3' 1='Camille'}
%1% has %count% kids
{/l10n}
Sería exactamente lo mismo que esto:
{l10n count=1 1='Alice'}
%1% has %count% kids
{/l10n}
{l10n domain='default' ctx='girls' count=0 1='Bob'}
%1% has %count% kids
{/l10n}
{l10n ctx='boys' count=['Huey', 'Dewey', 'Louie'] 1='Camille'}
%1% has %count% kids
{/l10n}
El resultado será:
Alice a un enfant
Bob n'a pas de filles
Camille a 3 garçons
- Líneas 1 a 3: No se especifica el dominio, así que se usa el dominio por defecto. No se especifica el contexto, así que se usará el primero definido (any). Y tomamos el valor 1 para el recuento.
- Líneas 4 a 6: Se especifica el dominio default. Se especifica el contexto girls. El recuento se establece en 0.
- Líneas 7 a 9: No se especifica el dominio. Se especifica el contexto boys. Se proporciona un array para el recuento, que contiene 3 elementos.
11Prefijo en los archivos de error
Cuando se usa este plugin, es necesario traducir los archivos de error definidos en la sección errorPages del archivo etc/temma.php (ver la documentación).
Las rutas definidas en la configuración reciben entonces un prefijo formado por un directorio error-pages, seguido de un directorio correspondiente al idioma usado.
Por ejemplo, para el siguiente archivo de configuración:
[
'errorPages' => [
'404' => 'error404.html'
]
]
Si solicitamos una página que no existe en francés (por ejemplo, la URL /fr/sdsjnzeoizoueh), Temma buscará el archivo
www/error-pages/fr/error404.html
Si solicitamos la misma página en inglés (por ejemplo, la URL /en/sdsjnzeoizoueh), Temma buscará el archivo
www/error-pages/en/error404.html