Dans ce billet, nous allons voir une solution pour gérer la traduction des IHM web côté client avec i18next. i18next est une bibliothèque Javascript compatible avec les toolkits tels que jQuery ou mootools. La documentation de cette bibliothèque n’étant pas très intuitive, je vous propose de vous en expliquer le principe avec un exemple concret. Histoire de pouvoir démarrer rapidement.
Introduction
Disons d’emblée que je ne suis pas trop fan de l’approche. Je préfère gérer la traduction côté serveur pour plusieurs raisons :
- Il y a plus d’outils (par exemple poedit) et de pratiques (comprendre plus d’exemples et de retour d’expérience) avec l’approche côté serveur.
- Comme nous allons le voir plus loin, la libraire a besoin d’un serveur HTTP, elle ne peut pas être utilisée dans un projet 100% statique (par exemple un projet de type CD-ROM).
- L’approche avec gettext est plus ou moins devenue standard. Mais pour l’instant HTML5 ne propose pas de solution de traduction standard du code HTML statique.
Pourquoi diantre utiliser une telle bibliothèque (N’hésitez pas à commenter ce billet avec vos propres idées) ?
- Votre hébergeur vous fait payer le temps d’exécution, mais pas le trafic, ni le temps http statique (les GET de ressources statiques sont gratuites).
- Vous souhaitez une implémentation 100% AJAX sans code côté serveur.
- Pour une raison ou pour une autre de logique, la traduction n’est pas évidente à réaliser côté serveur et doit se faire côté client.
Exemple d’intégration
Organisation des fichiers
Par défaut, la bibliothèque – après avoir déterminé la langue de l’utilisateur – enverra une requête HTTP pour récupérer un fichier de ressource de traduction en JSON. Votre projet doit contenir un répertoire « locales », puis un répertoire par langue. Dans ce répertoire il faut déposer un fichier « translation.json » contenant les traductions. Vous pouvez créer un répertoire « dev » dans le répertoire « locales ». Ce répertoire contiendrait le(s) fichier(s) de traduction par défaut (si la langue de l’utilisateur n’est pas traduite). Personnellement, je préfère utiliser le paramètre fallbackLng afin de préciser explicitement une langue par défaut.
Bien sûr, la bibliothèque contient de nombreuses options vous permettant de modifier l’emplacement de ces fichiers. On peut aussi séparer les traductions dans des fichiers JSON différents. I18next permet, en effet, de raisonner en namespaces. Ce qui permet de regrouper les objets (boutons, labels…) dans un même fichier ou de découper les écrans de l’application en domaines. Tout dépend de la nature et du contexte de votre projet.
Exemple de fichier de traduction
On peut organiser le fichier de ressource de traduction en classant les clés de traduction sous la forme d’une arborescence. Ça tombe bien, JSON le permet et la finalité est quand même de traduire des éléments innerText situé quelque part dans le DOM d’une page web.
Bien entendu l’arborescence de la clé de traduction (dans le fichier JSON) doit se retrouver dans la valeur de l’attribut data-i18n. Par exemple, la valeur de l’attribut data-i18n (voir plus bas, l’exemple de codeHTML/ Javascript) « nav.home » renvoie à la clé de traduction « nav » : { « home » : « … »}.
Code Javascript minimal
I18next n’a pas besoin de jQuery, mais si jQuery est chargée avant, I18next est augmenté des fonctionnalités de jQuery. Ce qui est quand même plus sympa pour sélectionner des éléments du DOM.
On comprend que la bibliothèque va écraser le contenu innerText avec le contenu du fichier JSON à chaque fois qu’elle trouve une correspondance. Donc et pas soucis de clarté, le fichier HTMl peut être chargé avec des labels par défaut qui seront ensuite traduits par i18next.
Principe de fonctionnement
Processus de détermination de la langue
La bibliothèque tente de déterminer la langue de l’utilisateur dans l’ordre suivant :
- La langue est explicitement passée en paramètre de l’initialisation de la bibliothèque
- La page en cours contient le code langage/pays dans le paramètre (?setLng=fr-FR).
- Il y a un cookie (i18next) contenant le code langage/pays.
- Langue définie dans les préférences utilisateur du navigateur.
Ensuite et en ce qui concerne le chargement des ressources, l’ordre suivant est respecté :
- i18next essaye de charger un fichier JSON contenu dans un répertoire nommé avec le code langage/pays (par exemple, « fr_FR » pour le français parlé en France).
- Essayer de charger un fichier JSON contenu dans un répertoire nommé avec le code langage seulement (par exemple, « fr » pour le français).
- Si aucun fichier n’est trouvé, essayer de charger le fichier dans le répertoire nommé selon la variable fallbackLng ou qui s’appelle « dev ».
Chargement des ressources de traduction
Le chargement est asynchrone, donc la bibliothèque ne peut pas être utilisée en local pour un contenu statique. Il faut un serveur web. Il n’est cependant pas nécessaire d’avoir du code côté serveur (en PHP, par exemple). La librairie se contenant de faire un HTTP GET (chargement Ajax, via requête HTTP).
L’aspect asynchrone de la bibliothèque fait que l’on ne peut appeler les fonctions de traduction qu’une fois les ressources chargées (après l’appel Ajax). Il faut passer par une fonction de callback comme dans cet exemple :
i18n.init(function(t) {
alert(i18n.t("app.name"));
});
On peut coupler l’utilisation de la librairie à jQuery pour la fonctionnalité de sélecteur (c.-à-d. sélectionner d’un coup tous les éléments d’une classe donnée ou d’un type donné…). Comme avec cet extrait de code où l’on demande la traduction de tous les éléments de classe « nav » :
$(".nav").i18n();
Autres informations
- La bibliothèque gère les formes plurielles.
- On peut brancher une fonction de post processing pour une traduction.
- On peut utiliser des formateurs de texte (sprintf, un peu en lien avec le point précédent).
- Il est possible de faire de la substitution de variable (par exemple : « il y a __nbePommes__ pommes ») sans utiliser sprintf.
- On peut stocker une valeur sur plusieurs lignes dans le fichier de ressource en JSON.
- RTFM pour le reste des fonctions.
Alternatives
- Jed qui se réclame proche de Gettext : http://slexaxton.github.com/Jed/
- Le toolkit Dojo contient un module i18n : http://dojotoolkit.org/reference-guide/1.8/dojo/i18n.html
- Jsperanto : https://github.com/jpjoyal/jsperanto
Liens utiles
- Récupérer mon projet exemple en cliquant ici.
- Téléchargement et documentation (en anglais) : http://jamuhl.github.com/i18next/index.html
- Intégration avec Express et Jade (en anglais) : http://rbeere.tumblr.com/post/41212250036/internationalization-with-express-jade-and
- Intégration avec Backbone.js (en anglais) : http://pedromadias.wordpress.com/2013/01/27/backbone-js-and-i18n/