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.
  1. var labels_fr =  {  
  2. 'hello' : 'Bonjour {0}, tu as {1} ans',  
  3. 'quit' : 'Quitter ?'  
  4. }  
  5. var labels_en =  {  
  6. 'hello' : 'Hello {0}, you are {1}',  
  7. 'quit' : 'Quit ?'  
  8. }  

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

Plus propre, non ?
La classe en question (UPDATE 18/10/2010 : prise en compte de plusieurs patterns) :
  1. /** 
  2. * I18n est une classe permettant d'obtenir un libellé 
  3. * caractérisé par une clé dans une map contenant un 
  4. * ensemble de libellés traduits dans la langue choisie 
  5. * @constructor 
  6. */  
  7. var I18n = function(){}  
  8.   
  9. /** 
  10. * Charge la map de clés/libellés 
  11. * @param {Object}  translations Les clés/libellés traduits 
  12. * @constructor 
  13. */  
  14. I18n.prototype.load = function(translations) {  
  15. this._translations = translations;  
  16. }  
  17.   
  18. /** 
  19. * Remplace les nombres entre accolades ({0}) par les 
  20. * chaînes de caractères passées en paramètre 
  21. * exemple  : _format('Hello {0} ! ', 'guy') => Hello guy ! 
  22. * @param {String}  format La chaîne de caractère à formater 
  23. */  
  24. I18n.prototype._format = function(format) {  
  25. var args = arguments[1];  
  26. return format.replace(/\{(\d+)\}/g, function(m, i){  
  27. return args[i];  
  28. });  
  29. }  
  30.   
  31. /** 
  32. *  Retrouve le libellé correspondant à la clé passée en paramètre 
  33. * et le formate en fonction des paramètres supplémentaires 
  34. * exemple  : translate('hello', 'guy') => Hello guy ! 
  35. * @param {String}  key La clé à traduire 
  36. */  
  37. I18n.prototype.translate = function(key) {  
  38. if (typeof(this._translations)!='undefined' && this._translations[key]) {  
  39. return this._format(this._translations[key],Array.prototype.slice.call(arguments,1));  
  40. }  
  41. return key;  
  42. }