How does internationalization work in JavaScript?

Localization support in legacy browsers is poor. Originally, this was due to phrases in the ECMAScript language spec that look like this:

Number.prototype.toLocaleString()
Produces a string value that represents the value of the Number formatted according to the conventions of the host environment’s current locale. This function is implementation-dependent, and it is permissible, but not encouraged, for it to return the same thing as toString.

Every localization method defined in the spec is defined as "implementation-dependent", which results in a lot of inconsistencies. In this instance, Chrome Opera and Safari would return the same thing as .toString(). Firefox and IE will return locale formatted strings, and IE even includes a thousand separator (perfect for currency strings). Chrome was recently updated to return a thousands-separated string, though with no fixed decimal.

For modern environments, the ECMAScript Internationalization API spec, a new standard that complements the ECMAScript Language spec, provides much better support for string comparison, number formatting, and the date and time formatting; it also fixes the corresponding functions in the Language Spec. An introduction can be found here. Implementations are available in:

  • Chrome 24
  • Firefox 29
  • Internet Explorer 11
  • Opera 15

There is also a compatibility implementation, Intl.js, which will provide the API in environments where it doesn't already exist.

Determining the user's preferred language remains a problem since there's no specification for obtaining the current language. Each browser implements a method to obtain a language string, but this could be based on the user's operating system language or just the language of the browser:

// navigator.userLanguage for IE, navigator.language for others
var lang = navigator.language || navigator.userLanguage;

A good workaround for this is to dump the Accept-Language header from the server to the client. If formatted as a JavaScript, it can be passed to the Internationalization API constructors, which will automatically pick the best (or first-supported) locale.

In short, you have to put in a lot of the work yourself, or use a framework/library, because you cannot rely on the browser to do it for you.

Various libraries and plugins for localization:

  • Mantained by an open community (no order):
  • Polyglot.js - AirBnb's internationalization library
  • Intl.js - a compatibility implementation of the Internationalisation API
  • i18next (home) for i18n (incl. jquery plugin, translation ui,...)
  • moment.js (home) for dates
  • numbro.js (home) (was numeral.js (home)) for numbers and currency
  • l10n.js (home)
  • L10ns (home) tool for i18n workflow and complex string formatting
  • jQuery Localisation (plugin) (home)
  • YUI Internationalization support
  • jquery.i18Now for dates
  • browser-i18n with support to pluralization
  • counterpart is inspired by Ruby's famous I18n gem
  • jQuery Globalize jQuery's own i18n library
  • js-lingui - MessageFormat implementation for JS (ES2016) and React
  • Others:
  • jQuery Globalization (plugin)
  • requirejs-i18n Define an I18N Bundle with RequireJS.

Feel free to add/edit.


Mozilla recently released the awesome L20n or localization 2.0. In their own words L20n is

an open source, localization-specific scripting language used to process gender, plurals, conjugations, and most of the other quirky elements of natural language.

Their js implementation is on the github L20n repository.