Lately, while working on Butterflive, I was faced with the challenge of internationalising a pure Javascript module. Using the usual server-side techniques to provide translation was not an option.
Basically, I wanted to easily provide a chat window with messages that would be translated automatically depending on the browser's locale.
After a quick Google search, I realized there was no real out-of-the-box solution that suited my needs. The module that came closer to my needs was the jQuery localisation plugin, but I realised that if the locale was not supported, it would perform a 404 HTTP call to a non-existing resource before falling back to the default translation file. I wanted to avoid 404 calls, so I decided to write my own module, which turned-out to be really easy.
The whole strategy is to write a special Javascript file that contains the translated messages. For Butterflive, this file looks like this:
messages.js (default file in English)
ApiMessages={ "visitor": "Visitor", "me": "Me", "chattingwith": "You are now chatting with ", "joinedtheroom": " joined the room", "disconnectedmsg": "You have been disconnected. Trying to reconnect.", "chatsessionclosed": "Chat session closed.", "hasbeendisconnected": " has been disconnected.", "connecting": "Connecting", "waitingforuser": "Waiting for user", "mainwindowtitle": "Chat window" }
The translated version of this file in French:
messages-fr.js
ApiMessages={ "visitor": "Visiteur", "me": "Moi", "chattingwith": "Vous êtes maintenant en chat avec ", "joinedtheroom": " a rejoint le chat", "disconnectedmsg": "Vous avez été déconnecté. Tentative de reconnection.", "chatsessionclosed": "Session de chat terminée.", "hasbeendisconnected": " a été déconnecté.", "connecting": "Connection en cours", "waitingforuser": "En attente de l'utilisateur", "mainwindowtitle": "Fenêtre de chat" }
Now, I need to be able to load the correct file. I decided to write a localize function. This function takes in parameter either the name of the language to be loaded (as a 2 characters string), or an array of available languages.
For instance, localize("fr") will force the loading of the messages-fr.js file. Alternatively, localize(["en","fr","de"]) will load one of those 3 language files depending on the browser's locale, or will default to messages.js otherwise.
function localize(language) { // If a string is passed in parameter, let's load the file associated. if (typeof(language)=="string") { loadScript("i18n/messages-"+language+".js"); return; } // Let's get the browser's language var l_lang; if (navigator.userLanguage) // Explorer l_lang = navigator.userLanguage; else if (navigator.language) // FF l_lang = navigator.language; else l_lang = ""; // If the parameter passed is not a string or an array, // or if no browser's language can be found, let's use default file. if (typeof(language)!="object" || l_lang == "") { loadScript("i18n/messages.js"); return; } var browserLang = l_lang.substr(0,2); // If the browser's language is available in the translation files // let's use that! for (var i=0; i<language.length; i++) { if (language[i] == browserLang) { loadScript("i18n/messages-"+browserLang+".js"); return; } } // If no language found, let's load the default language file: loadScript("i18n/messages.js"); }; // A simple function to dynamically load a script. // Please note it uses jQuery (but you can adapt it easily)! function loadScript(url) { var script=document.createElement('script'); script.type='text/javascript'; script.src=url; $("head").append(script); return; };
That's it! Pretty easy isn't it?