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()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
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.
.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
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.
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
// 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:
- Externalize strings.
- Format dates, times, numbers, etc. according to a valid locale.
- Accept user input (i.e. date, time, number) according to a specific locale.
- Handle cultural bias correctly (i.e. modify colors, images, sounds...).
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
What Is the Point of Void Operator in JavaScript
Event.Path Is Undefined Running in Firefox
Difference Between Obtrusive and Unobtrusive JavaScript
Options for Testing Service Workers via Http
Accessing JSON Object Keys Having Spaces
How Do Cors and Access-Control-Allow-Headers Work
Understanding Xmlhttprequest Over Cors (Responsetext)
Javascript: Dynamically Creating Variables for Loops
JavaScript Date Timezone Issue
When Do I Need to Specify the JavaScript Protocol
Intercept Paste Event in JavaScript
How to Change the Pop-Up Position of the Jquery Datepicker Control
Why Can't I Assign a New Value to "This" in a Prototype Function
Angularjs - UI Router - Programmatically Add States
Insert Text at Cursor in a Content Editable Div
How to Load All Files in a Directory Using Webpack Without Require Statements