A Step-by-Step Guide to JavaScript Localization

It's time to talk about front-end. This guide will walk you through the localization of JavaScript apps using jQuery.I18n by Wikimedia, Polyglot by Airbnb, and Globalize by jQuery.

Internationalization (dubbed as i18n) and localization (l10n) are very important (though often hard) steps for any application that is going to be used worldwide. In one of our previous articles, we saw how to implement I18n at the backend powered by Ruby on Rails, but today it’s time to talk about frontend. This guide will walk you through JavaScript Localization from A to Z, using the following solutions:

  • jQuery.I18n by Wikimedia
  • Polyglot by Airbnb
  • Globalize by the jQuery team

All of these solutions are quite different and have their own specifics, so we’ll see them all in action. The source code is available at GitHub.

How to Get Started with JavaScript Localization?

Before proceeding to the main part, let’s quickly prepare a basic structure for our simple JavaScript localization demo project. Create a separate folder with the index.html file inside. We’ll make copies of this file to test various solutions. Then, create a nested folder called common and place the jquery.js file inside. You may download this file from the official JQuery website. Pick either version of jQuery (1, 2 or 3), depending on what browsers you wish to support. Now, populate index.html with some markup: index.html https://gist.github.com/bodrovis/58757249d74c5f04f97a8ca33001dc8f This is enough for us to get started!


Let’s start with a jQuery-based internationalization library developed and maintained by Wikimedia. Wikimedia is a global movement which takes care of well-known projects such as Wikipedia, Wikinews, Wikibooks, and others. jQuery.I18n, in turn, uses a JSON-based localization file format and supports gender, grammar forms, dynamic change of language, fallback chains and more.

Translation Files

Translations for jQuery.I18n can be separated into multiple files (en.json, de.json, etc.) or stored all together in one file. Here is an example of en.json: https://gist.github.com/bodrovis/8534de2c717f57289408da25485897b2 As you can see, these files support metadata where you specify authors, date of the latest update, locale, and other information. Next, you provide the actual translations in a key-value format. It is best practice to prefix keys with the app’s name to make it unique, but that’s not mandatory. For apps of a smaller scope, you may provide all translations in a single file. In this case language’s name is specified as a parent key: https://gist.github.com/bodrovis/a8b3ff0477bda43b32de4e84f8f7a699 What’s more, you can even provide a path to the translations file: https://gist.github.com/bodrovis/ff6470da5146a515b3ded2385b78fcac

Loading Translation Files

Now, of course, you may be wondering how to load these translations into your app. There are a couple of ways, and the first is probably the easiest one. Instead of creating a separate JSON file, you can place all translations directly into the script by passing them to the load function: https://gist.github.com/bodrovis/8195db98f0caf625e083c42d587e4dc5 I can’t say this is a practice to recommend but it is just fine for (really) small projects. Another solution is to load messages from an external URL (relative or absolute): https://gist.github.com/bodrovis/aac39c3c8c06e5d48a22567f9f32251f When using this approach, the load will return a promise, so you can place further actions inside the done function: https://gist.github.com/bodrovis/4fb32568658d052aa5ed1377b8a30b5f

Setting Locale

You can set the locale upon the library’s initialization using either locale option … https://gist.github.com/bodrovis/cd430339db46f90b3af81995f09b10e5 … or by providing it inside the lang attribute for the html tag: https://gist.github.com/bodrovis/b2c1015dca57807f0a470bb347afcd0b Of course, the locale can be switched later by redefining the locale option: https://gist.github.com/bodrovis/09464a7fd08f06fae390c0dd967c4353

Performing Translations

To translate a message, you would provide a key to the $.i18n function

or just employ a data- attribute (no additional JavaScript is needed). The initial content is a fallback text to display in case something goes wrong and the translation is absent: https://gist.github.com/bodrovis/002dea5e5187a33305bea21138f15620 Note that messages support interpolation by taking parameters. These are written as $1, $2 etc: https://gist.github.com/bodrovis/7c3211f614c15b23606aba6037fe074a Plurals and genders are handled with the following syntax: https://gist.github.com/bodrovis/0408b40c5962333f9c13b507f7f4b37b

In Practice

To start off, copy our base index.html file as the jquery_i18n.html. Create a new jquery_i18n directory and place the main-jquery_i18n.js file inside.

Loading Dependencies

Next clone jQuery.I18n somewhere on your PC along with sub-modules: https://gist.github.com/bodrovis/1aea5ed4f6cbb5c14a276cd4cccb7d03 We will require all files from the src directory (without the languages folder) and also CLDRPluralRuleParser.js from thelibs\CLDRPluralRuleParser\src. Copy all of these into the jquery_i18n folder and then include them in the proper order: jquery_i18n.html https://gist.github.com/bodrovis/24dfb755df25eef690688d6ce0214965

Preferred Language and Switchers

Let’s also provide the initial locale via the lang attribute: jquery_i18n.html https://gist.github.com/bodrovis/5a7ca03abea986162b17b8f8e403655e Lastly, add links to switch the language and a couple of empty tags that are going to host our translated content. I’ll work with English and Russian, but of course, you may choose any other languages – it does not really matter. For real-world apps, make sure your texts are properly translated, preferably by a human. jquery_i18n.html https://gist.github.com/bodrovis/5bca2e85604df5930429d2f62f2c4359

Loading Translations

Now proceed to the script. We’ll need to load translations as soon as the document is ready. For simplicity, let’s store all our messages in the script: main-jquery_i18n.js https://gist.github.com/bodrovis/9bcc102173722606130ec50c614fadd8 Note the welcome key – the same name lives in the data-i18n attribute for the h1 tag. This way, a proper translation will be used automatically – all we have to do is run this process by calling the i18n() function. I’ll extract it inside the update_texts: main-jquery_i18n.js https://gist.github.com/bodrovis/6ee914ed6f93c7eab07a60fe3056319e

Switching the Language

Next, let’s take care of language switching. This is simple – just listen to the click event, extract the value of the data-locale attribute and then set the locale accordingly: main-jquery_i18n.js https://gist.github.com/bodrovis/88b0c01eaf518917db80925b8db8cafb Lastly, we are going to add a translation for the #messages section. This is going a be a bit more complex: main-jquery_i18n.js https://gist.github.com/bodrovis/eb39352c52dad1df2ccfc23ced180636 Here, pluralization and gender info are used at the same time. For Russian, I had to add more options because pluralization rules are more complex. In order for this to work, tweak the update_texts() function: main-jquery_i18n.js https://gist.github.com/bodrovis/accdc286db4f2416dd96641c36fa1be1 Now open the page and try to switch between languages – everything should be working just great!


Polyglot.js is a small solution created by Airbnb (an engineering company) that works in browser and in Common.js environments. It supports interpolation and pluralization while having zero dependencies. Grab production version here.

Getting Started with Polyglot

So, to start working with Polyglot, instantiate it: https://gist.github.com/bodrovis/890ab771d2532c6cb81ed48ab4b6d42d It’s class-based, therefore you may work with different sets of locales at the same time. Next, provide a list of phrases: https://gist.github.com/bodrovis/e87673be95f6d99031df112c20162019 As a common pattern, the documentation suggests to prepare a hash of phrases on the backend and then output them in the script tag. Note that Polyglot won’t do translation – it’s your job to give proper phrases based on a users’ locale. You can replace or completely remove phrases (for example, to free up memory) by using replace or clear methods, respectively. Note that Polyglot also supports nesting: https://gist.github.com/bodrovis/7de8959447e49658de626c3ae4eb695e If you’ve come from the Rails world, interpolation should look familiar to you: https://gist.github.com/bodrovis/d2a78732c7a094a31d3d84e07a2964d0

Performing Translations

To perform the actual translation, apply the t method: https://gist.github.com/bodrovis/4b0a0a917f76cb12d3cda3be2d55e896 If your key is nested, use dot . as a delimiter: https://gist.github.com/bodrovis/5b48d85ee9e8f9b1c57bed9ade8e0acd


Note that a language’s name is not provided anywhere – currently, it is used only when working with pluralization. To set it, employ the locale function … https://gist.github.com/bodrovis/6b052c950c7f4b89f5ebbf1ec7038a97 … or set it upon instantiating a new object by passing a locale option. Messages with pluralization should be delimited with four pipes (||||): https://gist.github.com/bodrovis/1a76d3230da704cf8f808f39f4484bef The correct message will be picked based on the smart_count parameter.

In Practice

Now, let’s quickly see this solution in action. Copy the index.html file and name it polyglot.html. Then create a polyglot folder and place the production version of the script inside. Also, create the main-polyglot.js file there and hook everything up: polyglot.html https://gist.github.com/bodrovis/a6170bc5544d2f21b4f151f94a94ca3f


For this demo, we will utilize Underscore.js’ template engine to render content (though you may stick with Handlebars or some other solution). If you haven’t worked with such templates before, the idea is pretty simple: you have a markup with some parameters. This template is then being “compiled” (meaning that the parameters receive their values) and rendered on the page like any other HTML. So, place the production version of Underscore into the common folder and load it: polyglot.html https://gist.github.com/bodrovis/7b2d37d3c4f4217e2bcbde41be0651c9 I am going to place our template directly onto the page, at the very bottom. Note that it has to be wrapped with a script tag with a special type (to prevent browsers from trying to process it as a JavaScript code): polyglot.html https://gist.github.com/bodrovis/d5f4635b68eab5e299bce4d39353b0c2

Loading Polyglot

Next, inside the script, let’s wait until the document is ready and then instantiate the Polyglot class while providing two messages: main-polyglot.js https://gist.github.com/bodrovis/f7c5247ed8dd5b74d139e76fd4662b51 Here, we used interpolation and pluralization (note the parameter’s name smart_count – when using another name the pluralization seems to stop working). Now, let’s grab the template … https://gist.github.com/bodrovis/b3ca57bb710bfcb8e208f089a96455e2 … and then provide values to the parameters inside it: https://gist.github.com/bodrovis/32c3fad5cb1285d642d2584c233ed500 Here is the resulting code: main-polyglot.js https://gist.github.com/bodrovis/b1fc1495b604694107467fc3603dda7d Load the HTML document and test it out!


Globalize is a pretty big internationalization library developed by the members of the jQuery core team. It works in the browser (supporting all modern browsers and IE starting from version 9) and with Node.js, providing many useful features including number, date and time parsing, pluralization, interpolation, unit support and much more. It uses Unicode CLDR that provides key building blocks for software to support the world’s languages, with the largest and most extensive standard repository of locale data available. What’s more, Globalize is modular and does not contain any I18n data – you are free to load it yourself. There are three main API functions:

  • Globalize.load() – loads CLDR locale data in JSON format (such as date and time formats, names of the month etc)
  • Globalize.locale() – getter and setter for the locale
  • [new] Globalize – instantiates a new Globalize object

Also, there are a variety of different functions for each module that you can find here.

Globalize in Practice

Let’s see Globalize in action right away. Copy the index.html file and name it globalize.html. Also, create the globalize folder with the globalize-main.js file inside.

Loading Dependencies

As long as Globalize is modular, you need to load dependencies in the proper order. There is even an online tool available helping you to identify the necessary dependencies. Therefore, you’ll need to download the latest version of Globalize as well as CLDR. Here is the list of Globalize’s files to grab (place them inside the globalize folder of your project):

  • dist/globalize.js
  • dist/globalize/date.js
  • dist/globalize/number.js
  • dist/globalize/currency.js
  • dist/globalize/message.js
  • dist/globalize/plural.js

Unfortunately, that’s not all. Here are the required CLDR files that have to be placed inside cldr folder (create it now):

  • dist/cldr.js
  • dist/cldr/event.js
  • dist/cldr/supplemental.js

Phew. The last part is providing some common locale data for CLDR – download it here and place it under the cldr/cldr_data.jsname. Finally, hook all those files in the proper order: globalize.html https://gist.github.com/bodrovis/003cd9f6a68fae0c7af1c5d1e224d7e0

Adding Translations

Also, add a couple of placeholders for our content: globalize.html https://gist.github.com/bodrovis/fb21f009fff2bc9dc03cdb38e24ad78f Now, let’s load a welcome message: globalize-main.js https://gist.github.com/bodrovis/03a0ae2700143ed1dfcd2e8c0d7bfb88 Here we are using the message-formatter module.

Loading Globalize

Next, instantiate the Globalize class and populate the #welcome section: https://gist.github.com/bodrovis/87f212292a0a0f6e90bb9200ddd0cbad Note that messageFormatter returns a function that we then call and pass the object containing a name. You can re-write it as: https://gist.github.com/bodrovis/0ae8fe510d3c2a24d54a150ddc58e697 Actually, message’s parameters do not need to be named – you may say 0, 1, 2 etc instead: https://gist.github.com/bodrovis/e824dace7d60069ce3c4dadbfef45e50 In this case, pass an array to the formatter: https://gist.github.com/bodrovis/2a1356a5d14a566deacbfdb11b92f6ab

Working with Currency

Next, provide another message containing today’s date and total earnings: https://gist.github.com/bodrovis/71ef6eea57c8da2c182ee2e4d53079f3 In this example, we’ll use date and currency formatters: https://gist.github.com/bodrovis/cc64150068bc9be36d23e118a7bfbd41 When formatting the currency, we pass USD as the second argument. This argument is used to display a proper symbol when rendering the result. The symbol itself was defined inside the clrd_data.js file: https://gist.github.com/bodrovis/bebcf8dff107e5a36a0e5bff01bc3f08 medium is the name of the date-time format – it was also defined inside the clrd_data.js file as: https://gist.github.com/bodrovis/5ce87c4323436974c4e0d883f8d6a1e7 Here, 1 is the date and 0 is time. Date and time, in turn, are formatted using the following masks: https://gist.github.com/bodrovis/bc3eba0d5921eacea61644c8536bebda Now that everything is ready, you can observe the result!

Phrase Saves the Day Once Again

Managing translations for multiple languages can be tedious indeed. With Phrase, however, the whole process becomes much simpler. Grab your free trial if you have not signed up already and create a new project. Phrase supports a great range of various formats from simple to nested JSON (and specific formats for AngularJS or React). Next just add as many locales as you need and upload existing JSON files with translations if you have any. Having done that you will be able to quickly understand which translations are missing, manage your keys and messages as well as download updated translations with one click. What’s even cooler, you can easily request support from professional translators (which is probably better as localization is not only about translation). Therefore, I really encourage you to give Phrase a try!


In this article about JavaScript localization, we took a look at various solutions that can help you to localize your app: jQuery.I18n, Globalize and Polyglot. Polyglot appeared to be the smallest and simplest library, whereas Globalize and jQuery.I18n are quite big and complex – it’s up to you which one pick! Hopefully, you found this article useful and interesting. Thanks for staying with me and happy coding!

4.7 (94%) 50 votes