- ^ Composants de jelix
- jTpl : le moteur de templates
- jZone : découper vos pages en zones
- jDao : mapping objet relationnel
- Formulaires classiques
- jForms : des formulaires automatiques
- jDb : accéder à une base de données SQL
- jKvDb : accéder à une base de type key/value
- jUrl : des URLs automatiques
- jAuth : système d'authentification
- jAcl2 : système de droits
- jLocale: internationaliser votre application
- jEvents : communication inter-module
Chapitre: jLocale: internationaliser votre application
« jAcl2 : système de droits | ^ Composants de jelix | jEvents : communication inter-module » |
− Table des matières
Jelix possède son propre mécanisme de localisation/internationalisation. Les
fonctions setlocale
et gettext
de PHP ne sont pas utilisées car
trop contraignantes à mettre en place, et leur configuration est aléatoire
sur les serveurs.
Principes ¶
Chaque texte ou chaîne que vous voulez traduire est associée à une clé, un code. Ces associations sont stockées dans des fichiers "properties". Chaque fichier properties étant attribué à une langue et un encodage de caractère.
L'exemple suivant permet de récupérer le code courant du language, dans une variable lang :
$lang = jApp::config()->locale;
Mais vous n'aurez pas à utiliser ce paramètre, sauf utilisation particulière.
En effet, pour récupérer une chaîne dans la langue courante, il suffit d'appeler
jLocale::get('la.cle.de.la.chaine')
, ou dans les templates d'utiliser la
syntaxe dédiée aux chaînes localisées (voir la page sur les templates).
Configuration ¶
Dans le fichier de configuration de l'application (mainconfig.ini.php
),
vous avez plusieurs paramètres pour configurer le langage et l'encodage, utilisés
dans votre application :
locale
: indique le code du language par défaut. Il peut être changé à la volée si nécessaire. La valeur a une syntaxe particulière, semblable aux tags IETF : un tag primaire + "_" + un sous-tag. Le tag primaire est le code langue, le sous-tag est le code pays. Par défautl, la locale vauten_US
.charset
: indique l'encodage utilisé. Par défaut il vautUTF-8
.availableLocales
: indique la liste des locales pris en charge par l'application.fallbackLocale
: indique la locale à utiliser si jLocale ne trouve pas la clé dans la locale courante ou similaire.- Il y a aussi une section
[langToLocale]
. Voyez la fin du chapitre.
Fichiers properties ¶
Ce sont des fichiers contenant des traductions. Ils sont situés dans le répertoire
locales/
des modules. Ce répertoire a une organisation spécifique. Il
contient des sous répertoires pour chaque langue. Exemple : locales/fr_FR/
pour le français, locales/en_US/
pour l'anglais américain etc. Et dans chacun
de ces sous-répertoires, il y a les fichiers properties correspondant à la langue.
Il peut y en avoir plusieurs, en particuliers, ils peuvent définir les mêmes
chaînes mais pour des encodage différents.
Les fichiers d'une même langue peuvent aussi être regroupé dans un même répertoire,
en dehors des modules, afin de faciliter la traduction par des tiers. Le
répertoire <yourapp>/app/locales/
doit contenir un répertoire par langue,
et dans chacun de ces répertoires, un répertoire par module, c'est à dire
<yourapp>/app/locales/<lang>/<modules>/locales/<fichier.properties>
. Par exemple :
myapp/app/locales/fr_FR/mon_module/locales/exemple.properties
.
On peut ainsi copier facilement un répertoire <yourapp>/app/locales/<lang>/
d'une application à une autre, ou pour une autre langue.
Il y a aussi la possibilité de redéfinir les fichiers properties en mettant une
copie dans le répertoire <yourapp>/app/overloads/
. Voir
[/application/surcharge-de-fichiers|le chapitre correspondant].
Noms des fichiers ¶
Le nom des fichiers properties est structuré comme suit : NAME.CHARSET.properties
.
NAME
est un nom que l'on utilisera dans les sélecteurs, et CHARSET
correspond à
un encodage de caractères. Exemple : foo.ISO-8859-1.properties
,
foo.UTF-8.properties
etc.
Avec la configuration par défaut, jLocale ira chercher les chaînes dans les fichiers
locales/en_US/*.UTF-8.properties
.
Contenu des fichiers ¶
La structure des fichiers est simple : il s'agit d'une suite de lignes
cle=chaine traduite
, avec toutefois des éléments syntaxiques particuliers comme
nous le verrons dans la suite. Tout d'abord, vous ne pouvez pas utiliser des
simples ou doubles quotes pour délimiter les chaînes.
Pour les clés, vous pouvez utiliser les caractères "a" à "z" (minuscule/majuscule), ainsi que les signes "_", "-", ".".
Exemple, pour un fichier fr_FR/foo.UTF-8.properties
:
title.offlineElements = éléments à traiter
title.onlineElements = éléments en ligne
buttons.save = Enregistrer
buttons.ok=Valider
buttons.cancel=Annuler
buttons.search=Rechercher
Et dans son équivalent anglais en_US/foo.UTF-8.properties
:
title.offlineElements = elements to check
title.onlineElements = online elements
buttons.save = Save
buttons.ok=Ok
buttons.cancel=Cancel
buttons.search=Search
Passage à la ligne ¶
Si un texte est long et que vous voulez l'écrire sur plusieurs lignes, vous devez mettre un anti-slash (\) à la fin de chaque retour à la ligne (sauf sur la dernière du texte) :
intro=ceci est un trés tres\
long texte qui fait\
plusieurs lignes
foo=bar
Cependant, cela n'insère pas un saut de ligne (\n) dans la chaine, mais un espace. Pour insérer un vrai saut de ligne, il faut utiliser \n et/ou \r suivant la plateforme (\n est recommandé) :
intro=ceci est un très très\
long texte qui fait\nplusieurs lignes\nfoo=bar
Commentaires ¶
Vous pouvez aussi mettre des commentaires. Ils doivent commencer par un #, le reste de la ligne étant alors ignoré. Vous pouvez mettre un commentaire en début de ligne ou à la suite d'une chaîne traduite. De ce fait, si vous voulez utiliser un # dans votre chaîne, il faut précéder ce caractère par un "\".
Espaces ¶
Il y a un "trim" qui est fait sur la chaîne traduite, c'est à dire que les espaces avant et après sont supprimés. Si vous voulez que la chaîne soit un espace, vous utiliserez alors \w
nospace= #this is using a regular space
space= \w#this is using a \w space
La valeur de space
sera ' ', et la valeur de nospace
, une chaîne vide.
Entités HTML ¶
Les chaînes localisées ne devraient pas contenir du code HTML. D'une part parce qu'une chaîne localisée n'est pas forcément destinée à être incluse dans du HTML, mais aussi parce que les réponses HTML échappent (htmlspecialchars) à plusieurs endroits le contenu que vous lui donnez.
De ce fait, les entités et autres signes HTML seront échappés si vous donnez par
exemple une chaîne pour en faire le titre d'une page. Les entités ne seront donc
pas interprétées comme telles par le navigateur. Par exemple, ©
deviendra
&copy;
.
Si vous avez besoin d'utiliser des caractères spécifiques, choisissez l'encodage adéquat plutôt que de recourir aux entités HTML. C'est pour cette raison qu'il est fortement encouragé d'utiliser l'encodage UTF-8, qui contient pratiquement tous les caractères utilisés dans toutes les langues, en plus de caractères spéciaux, les emoji etc.
Malgré tout si vous souhaitez absolument mettre du html dans une chaîne localisée qui doit être utilisée dans un template, la possibilité est de mettre ".html" au bout de la chaîne comme suit :
mon.beau.titre.de.paragraphe.html = <strong>Mon Titre de paragraphe</strong>
Dans le template, il faut récupérer cette chaine localisée uniquement avec
{jlocale}
, qui n'échappera donc pas le contenu si le nom de la locale se
termine par ".html".
Récupération d'une chaîne localisée ¶
Pour récupérer une chaîne, il faut utiliser la méthode statique get
de
jLocale. Cette méthode accepte en premier argument un sélecteur de locale, qui a
cette structure : <module>~<name>.<key>
. la partie "<module>~" est facultative s'il
s'agit d'un fichier se trouvant dans le module courant.
Pour récupérer par exemple la valeur de "buttons.save" dans foo.UTF-8.properties
situé dans le module "bar" :
$chaine = jLocale::get("bar~foo.buttons.save");
Dans un template cela donnerait par exemple :
<input type="button" value="{@bar~foo.buttons.save@}" />
Note : pour l'utilisation dans les templates, voir les possibilités dans la page sur les templates
Chaîne localisée avec paramètres ¶
Il peut être utile d'avoir des chaînes localisées dans lesquelles on veut insérer des valeurs dynamiquement. Par exemple, imaginons que voulez écrire :
Vous allez sur le site http://foo.com et vous cliquez sur la rubrique voiture
Vous voulez pouvoir changer l'url du site et le nom de la rubrique. Vous pouvez alors passer les données en paramètres à jLocale :
$chaine = jLocale::get("bar~foo.phrase", array('http://foo.com', 'voiture'));
Dans le fichier properties, vous mettez un %s
partout où vous voulez insérer
des valeurs dynamiques :
phrase = Vous allez sur le site %s et vous cliquez sur la rubrique %s
Et il faut donner les paramètres dans l'ordre d'apparition des %s
. En fait,
la chaîne est traitée par la fonction sprintf
de php, donc vous avez toutes
les possibilités syntaxiques de sprintf.
En particulier, il se peut que l'ordre d'insertion des paramètres change d'une
langue à une autre. Plutôt donc que de modifier l'ordre des paramètres quand vous
appelez jLocale, vous indiquez quel paramètre va à quel endroit dans la chaîne
localisée, au moyen de la syntaxe %x$s
où x est un nombre d'ordre.
phrase = Vous allez sur le site %1$s et vous cliquez sur la rubrique %2$s
En anglais (même si ce n'est pas la véritable traduction, c'est juste pour l'exemple) ça pourrait donner ça :
phrase = Clic on the %2$s section, when you go on the %1$s web site.
Ainsi le premier paramètre ira à l'emplacement de %1$s
, le deuxième à la place
de %2$s
etc...
Par contre, dans un template, vous ne pouvez pas utiliser la notion foo
quand il faut des paramètres. Vous devez alors utiliser le plugin jlocale :
<p>{jlocale "bar~foo.phrase", array('http://foo.com', 'voiture')}</p>
Changer la langue à la volée ¶
Jelix fourni un plugin pour le coordinateur qui permet de changer la langue
dynamiquement. C'est le plugin autolocale, qui est situé dans lib/jelix/plugins/coord/
(voir la section sur les plugins de coordinateur).
Pour cela, le plugin regarde si un paramètre est présent dans l'url, indiquant
la nouvelle langue à prendre en compte, et utilisera cette langue durant le
reste de la visite. En fait le nouveau code langue est stocké dans une variable
de session, et le plugin modifie l'option de configuration locale
une fois
la configuration lue (le fichier de configuration n'est donc pas modifié).
Aussi c'est totalement transparent pour vous. Pour connaître la langue à tout moment, il suffit de faire comme d'habitude :
$lang = jApp::config()->locale;
Pour utiliser le plugin, ajouter cette section dans app/system/mainconfig.ini.php
ou le fichier de configuration de l'un des points d'entrée :
[coordplugin_autolocale]
enableUrlDetection = on
urlParamNameLanguage = lang
enableUrlDetection
permet d'activer la détection de la langue dans l'url.
Le paramètre urlParamNameLanguage
contient le nom du paramètre de l'url qui
contiendra le code du language à utiliser. Aussi, vous pouvez mettre des liens
sur votre site qui permettent à l'utilisateur de changer la langue. Exemple :
<a href="index.php?lang=fr_FR">français</a>
<a href="index.php?lang=en_US">english</a>
Vous pouvez aussi utiliser les codes langues sans le code pays :
<a href="index.php?lang=fr">français</a>
<a href="index.php?lang=en">english</a>
Bien sûr, il est possible de définir des urls spécifiques pour
chaque langue, et même d'indiquer les paramètres de langues, qui seront
renseignés automatiquement ou détectés automatiquement, sans avoir à l'indiquer
à jUrl::get()
entre autre (voir [[/composants/urls/mapping|la documentation
correspondante]]). Vous n'avez alors probablement pas besoin du plugin
autolocale.
Notez aussi que si le code de language donné n'est pas listé dans le paramètre
availableLocales
de la configuration principale, jLocale essaiera d'abord
d'utiliser la locale la plus approchante (même langue mais d'un autre pays),
et si il ne trouve pas, il utilisera la langue par défaut de l'application,
celle indiquée dans locale
, et en dernier recours, celle indiquée dans fallbackLocale
.
Enfin, il faut activer le plugin. Pour cela, dans la configuration de jelix,
mettez dans la section [coordplugins]
:
[coordplugins]
autolocale = 1
Détection automatique de la langue ¶
Le plugin autolocale permet aussi de détecter automatiquement la langue en fonction du navigateur, c'est à dire en analysant les en-tête HTTP envoyés par le navigateur.
Pour cela, il suffit de mettre le paramètre useDefaultLanguageBrowser
à
on
dans la configuration du plugin. Et quand l'internaute arrive pour la
première fois sur le site, le plugin détecte la langue utilisée dans son
navigateur et donc active la bonne langue dans jelix (si bien sûr, ce code
langue est l'un de ceux que vous aurez indiqué dans availableLocales
).
Template localisé ¶
Dans certains cas, pour éviter d'avoir trop de chaînes locales, il peut s'avérer intéressant de traduire un template complet.
Pour cela il suffit de placer le template qui nécessite l'internationalisation
dans un sous-répertoire du répertoire templates. Comme pour les
fichiers de locales un sous-répertoire est
nécessaire pour chaque langue (Exemple : templates/en_US/
, templates/fr_FR/
).
Prise en charge des codes de language inconnues ou alternatifs ¶
À partir d'un code de langue simple (comme "en", "fr"..), Jelix peut donner le
code language associé défini par défaut : "en_US" pour "en", "fr_FR" pour "fr" etc.
Cependant, ce n'est pas forcément le code que vous voulez obtenir. Vous voudriez
par exemple "en_GB" pour "en" et "fr_CA" pour "fr". Ou peut-être encore vous
voudriez prendre en charge une langue non reconnue (la liste par défaut se
trouve dans le fichier lib/jelix/core/lang_to_locale.ini.php
).
Pour modifier ces associations, vous devez remplir la section [langToLocale]
dans la configuration principale. La clé du paramètre est le code langue simple,
et la valeur le code du language complet.
[langToLocale]
en = en_GB
; ou pour garder une compatibilité avec d'anciens modules :
en = en_EN
En cas de clé inexistante ¶
Quand jLocale ne trouve pas la clé dans un fichier properties correspondant à la langue, il va essayer de la trouver dans une locale similaire, en se basant sur le fichier de correspondance entre le code langue, et la qui y est associé par défaut (voir paragraphe précédent).
Si il échoue à nouveau, il va essayer de chercher avec la locale indiquée
dans fallbackLocale
.
Si il échoue encore, jLocale::get()
génère une exception. C'est pour
cela qu'il est préférable d'avoir au moins une langue dans laquelle toutes
les clés existent, et d'indiquer cette langue dans fallbackLocale
.
Installer des paquets de traductions ¶
Jelix et certains modules ont été traduits dans diverses langues, via le site Transifex. Certaines traductions ne sont pas complètes, et peut-être n'y-a-t-il pas de traduction dans votre langue préférée. Nous vous encourageons alors à contribuer sur Transifex.
Les fichiers properties résultants de ces traductions sont disponibles en téléchargement sur https://download.jelix.org/jelix/langpacks/.
Il suffit de dézipper les fichiers de langues que vous souhaitez dans le répertoire
<yourapp>/app/locales/
(répertoire que vous devez créer). Videz le repertoire
temp, configurer l'application pour pouvoir utiliser les nouvelles langues
(voir plus haut), et vous pouvez profiter des traductions.