How Does Internationalization Work in JavaScript

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.

Best practice javascript and multilanguage

When I've built multi-lingual sites before (not very large ones, so this might not scale too well), I keep a series of "language" files:

  • lang.en.js
  • lang.it.js
  • lang.fr.js

Each of the files declares an object which is basically just a map from key word to language phrase:

// lang.en.js
lang = {
greeting : "Hello"
};

// lang.fr.js
lang = {
greeting : "Bonjour"
};

Dynamically load one of those files and then all you need to do is reference the key from your map:

document.onload = function() {
alert(lang.greeting);
};

There are, of course, many other ways to do this, and many ways to do this style but better: encapsulating it all into a function so that a missing phrase from your "dictionary" can be handled gracefully, or even do the whole thing using OOP, and let it manage the dynamic including of the files, it could perhaps even draw language selectors for you, etc.

var l = new Language('en');
l.get('greeting');

Best practice for localization and globalization of strings and labels

As far as I know, there's a good library called localeplanet for Localization and Internationalization in JavaScript. Furthermore, I think it's native and has no dependencies to other libraries (e.g. jQuery)

Here's the website of library: http://www.localeplanet.com/

Also look at this article by Mozilla, you can find very good method and algorithms for client-side translation: http://blog.mozilla.org/webdev/2011/10/06/i18njs-internationalize-your-javascript-with-a-little-help-from-json-and-the-server/

The common part of all those articles/libraries is that they use a i18n class and a get method (in some ways also defining an smaller function name like _) for retrieving/converting the key to the value. In my explaining the key means that string you want to translate and the value means translated string.

Then, you just need a JSON document to store key's and value's.

For example:

var _ = document.webL10n.get;
alert(_('test'));

And here the JSON:

{ test: "blah blah" }

I believe using current popular libraries solutions is a good approach.

Internationalization inside JavaScript

You can probably do this server side with Java using java.text.NumberFormat, but Dojo has code to do this client side. See dojo.number and dijit.form.NumberTextBox which uses dojo.number.

Web Application Internationalization, do it server-side or client-side?

The first rule of I18n: follow the standard way. Do not re-invent the wheel. In case of Asp.Net that means server-side Internationalization.

Well, sort of. If you happen to have tons of dynamically created controls, you still need some Localization mechanism for client-side scripts. You can centralize it, i.e. create one global array of translated strings and the model+controller, so you can i.e. populate it via AJAX call (although X would be best replaced by J for JSON...).

Anyway, your model should simply retrieve appropriate strings from resource files and controller should feed the JSON to the client side (good idea is to actually request smaller chunks, i.e. just the translation for given view/screen instead of translations for the whole application).

As you can see, the best would be some mixed approach. For many reasons, one would be it is better to use one Localization model for the whole application, i.e. use only *.resx files.

Besides, there is much more to Internationalization than just plain string externalization...

Internationalization and localization of existing JavaScript applications

The short answer:

There is no way to add i18n support to an application without changing it source.

Let me elaborate on that. What you need to do with i18n is:

  1. Externalize strings.
  2. Format dates, times, numbers, etc. according to a valid locale.
  3. Accept user input (i.e. date, time, number) according to a specific locale.
  4. Handle cultural bias correctly (i.e. modify colors, images, sounds...).

None of these things could be done without modifying source code. Sorry.

Ad1. Externalizing strings seems easy, right? Just walk through DOM and replace any instances with translated text.

No, it is not like that. Firstly, you probably also have non-accessible text like JavaScript-driven error or information messages (i.e. via alert() function). This is not DOM-accessible. Secondly, there always be compound messages, i.e. you put some numbers ("12 records matches your query"). When translating, it is common need to reorder the sentence (i.e. number comes last). You would need to analyze each sentence for numbers or dates and treat it specially. And what if you put a variable string? How you would overcome this situation (especially if this string could be change over time)?

Ad2. & Ad3. Formatting and parsing is easy, right? Well, yes if you know the locale. Unfortunately, the only sensible way to detect locale is to do that on the server side (from Accept-Language header). Client-side support for it is virtually non-existent (in case of many browsers) or severely broken (in case of others). So you don't even know which locale to use. And how will you accept i.e. local date, when you cannot modify underlying JavaScript?

Ad4. Support for different colors is achievable, however the only way to do that is to set it manually for each DOM element. Good luck with that.
Adding additional images or sounds theoretically requires placing them in right directory and modify DOM so that appropriate ones would be used. Again, good luck with that.

Basically, you want to reduce amount of effort, right? Turns out that by implementing non-standard solution (this is actually not what industry standards suggests) you will end-up doing more work, or your i18n support would be (to let me use this euphemism) poor.



Related Topics



Leave a reply



Submit