vendredi 6 février 2009

Internationalisation (i18n) en Javascript


Difficile de gérer le multilinguisme (i18n) en Javascript ! Et pourtant, on est souvent tenté de rapidement écrire dans son code des messages destinés à l'utilisateur. La gestion a posteriori de plusieurs langues devient alors un casse tête. Mieux vaut anticipé et externaliser ses libellés.
var labels_fr =  {
'hello' : 'Bonjour {0}, tu as {1} ans',
'quit' : 'Quitter ?'
}
var labels_en =  {
'hello' : 'Hello {0}, you are {1}',
'quit' : 'Quit ?'
}

La classe ci-dessous permet d'obtenir simplement le libellé souhaité en fonction de la langue :
var i18n = new I18n();
i18n.load(labels_fr);
i18n.translate('hello','JC', '33');

Plus propre, non ?
La classe en question (UPDATE 18/10/2010 : prise en compte de plusieurs patterns) :
/**
* I18n est une classe permettant d'obtenir un libellé
* caractérisé par une clé dans une map contenant un
* ensemble de libellés traduits dans la langue choisie
* @constructor
*/
var I18n = function(){}

/**
* Charge la map de clés/libellés
* @param {Object}  translations Les clés/libellés traduits
* @constructor
*/
I18n.prototype.load = function(translations) {
this._translations = translations;
}

/**
* Remplace les nombres entre accolades ({0}) par les
* chaînes de caractères passées en paramètre
* exemple  : _format('Hello {0} ! ', 'guy') => Hello guy !
* @param {String}  format La chaîne de caractère à formater
*/
I18n.prototype._format = function(format) {
var args = arguments[1];
return format.replace(/\{(\d+)\}/g, function(m, i){
return args[i];
});
}

/**
*  Retrouve le libellé correspondant à la clé passée en paramètre
* et le formate en fonction des paramètres supplémentaires
* exemple  : translate('hello', 'guy') => Hello guy !
* @param {String}  key La clé à traduire
*/
I18n.prototype.translate = function(key) {
if (typeof(this._translations)!='undefined' && this._translations[key]) {
return this._format(this._translations[key],Array.prototype.slice.call(arguments,1));
}
return key;
}

2 commentaires:

Anonyme a dit…

Salut,

ne fonctionne pas avec par exemple :
"vous êtes {0} et vous avez {1} ans"

jclagache a dit…

Merci metropical pour cette remarque. En effet, le fait d'avoir plusieurs patterns dans un même clé posait pb.
La fonction _format est uniquement appelée depuis la fonction translate où le 2ième argument envoyé en paramètre de _format est déjà transformé en Array.
Une seconde transformation dans _format est donc inutile et source d'erreur.