Sie sind auf Seite 1von 24

A Step-By-Step

Guide To JavaScript Localization

phraseapp.com | sales@phraseapp.com | +49-40-357-187-76 | twitter.com/phraseapp | facebook.com/phraseapp | linkedin.com/company/phraseapp

A Step-by-Step Guide To JavaScript Localization

Table of Content
Preparations For JavaScript Localization

JQuery.I18n

In Practice

Polyglot.Js

13

In Practice

15

Globalize
In Practice

18
18

PhraseApp Saves The Day Once Again

22

Conclusion

23

phraseapp.com | sales@phraseapp.com | +49-40-357-187-76 | twitter.com/phraseapp | facebook.com/phraseapp | linkedin.com/company/phraseapp

A Step-by-Step Guide To JavaScript Localization

Internationalization (dubbed as I18n) and localization (dubbed as L10n) are very important
(though often hard) steps for any application that is going to be used worldwide. In one of the
previous articles weve seen how to implement I18n at the back-end powered by Ruby on Rails,
but today its time to talk about front-end. In this article we will discuss how JavaScript
Localization for applications works using the following solutions:
jQuery.I18n by Wikimedia
Polyglot by Airbnb
Globalize by jQuery team
All of these solutions are quite different and have their own specifics so well see them all in
action.
The source code is available at GitHub.

Preparations For JavaScript Localization


Before proceeding to the main part lets quickly prepare a basic structure for our simple
JavaScript Localization demo project. Create a separate folder with the i ndex.html file inside.
Well make copies of this file to test various solutions. Then create a nested folder called
common and inside place the jquery.js file that can be downloaded from the jquery.com
website. You may pick either version of jQuery (1, 2 or 3) depending on what browsers you wish
to support it does not really matter for this demo.
Now populate index.html with some markup:
index.html
1
2
3

<script src="common/jquery.js"></script>

This is enough for us to get started!

phraseapp.com | sales@phraseapp.com | +49-40-357-187-76 | twitter.com/phraseapp | facebook.com/phraseapp | linkedin.com/company/phraseapp

A Step-by-Step Guide To JavaScript Localization

JQuery.I18n
Lets start with a jQuery-based internationalization library developed and maintained by
Wikimedia. Wikimedia is a global movement which takes care of such well-known projects as
Wikipedia, Wikinews, Wikibooks and others. j Query.I18n, in turn, uses a JSON-based
localization file format and supports gender, grammar forms, dynamic change of language,
fallback chains and more.
Translations for jQuery.I18n can be separated in multiple files (en.json, d
e.json etc) or stored all
together in one file. Here is an example of e n.json:
1

"@metadata": {

"authors": [

"Me"

],

"last-updated": "2016-09-21",

"locale": "en",

"message-documentation": "qqq"

},

10

"appname-title": "Example Application",

11

"appname-sub-title": "An example application with jquery.i18n"

12

13

So, 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 apps name to make it unique, but thats not
mandatory.

phraseapp.com | sales@phraseapp.com | +49-40-357-187-76 | twitter.com/phraseapp | facebook.com/phraseapp | linkedin.com/company/phraseapp

A Step-by-Step Guide To JavaScript Localization

For smaller apps you may provide all translations in a single file. In this case languages name is
specified as a parent key:
1

"@metadata": { ... }

"en": {

"appname-title": "Example Application"

},

"ru": {

"appname-title": " "

8
9

}
}

10

Whats more, you can even provide path to the translations file:
1

"@metadata": { ... }

"en": {

"appname-title": "Example Application"

},

"ru": "ru.yml"

phraseapp.com | sales@phraseapp.com | +49-40-357-187-76 | twitter.com/phraseapp | facebook.com/phraseapp | linkedin.com/company/phraseapp

A Step-by-Step Guide To JavaScript Localization

Now, of course, you are 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 l oad function:
1

$.i18n().load({

'en': {

'appname-title': 'Example Application'

},

'ru' : {

'appname-title': ' '

});

I cant say that this is a recommended practice but for really small projects it is fine.

Another solution is to load messages from an external URL


1

$.i18n().load({

2
3

en: 'i18n/en.json'
})

When using this approach the load will return, so you can place further actions inside the d one
function:
1
2
3

$.i18n().load({
en: 'i18n/en.json'
}).done( function() { console.log('done!') } )

phraseapp.com | sales@phraseapp.com | +49-40-357-187-76 | twitter.com/phraseapp | facebook.com/phraseapp | linkedin.com/company/phraseapp

A Step-by-Step Guide To JavaScript Localization

You can set the locale upon librarys initialization using either l ocale option
1

$.i18n( {

locale: 'en'

} );

or by providing it inside the lang attribute for the h tml tag:


1
2
3

Of course, locale can be switched later by redefining the locale option:


1
2

$.i18n({
locale: 'de'

});

// or

$.i18n().locale = 'de';

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


1

$.i18n('message-key1');

phraseapp.com | sales@phraseapp.com | +49-40-357-187-76 | twitter.com/phraseapp | facebook.com/phraseapp | linkedin.com/company/phraseapp

A Step-by-Step Guide To JavaScript Localization

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 cannot be found:
1
2
3

Fallback text

Note that messages support interpolation by taking parameters. These are written as $1, $2 etc:
1

var message = "Good day, $1";

$.i18n(message, 'Joe');

Plurals and genders are handled with the following syntax:


1

var message = "Found $1 {{PLURAL:$1|result|results}}";

$.i18n(message, 1);

3
4

var message = "$1 changed {{GENDER:$2|his|her}} profile picture";

$.i18n(message, 'Emma', 'female');

phraseapp.com | sales@phraseapp.com | +49-40-357-187-76 | twitter.com/phraseapp | facebook.com/phraseapp | linkedin.com/company/phraseapp

A Step-by-Step Guide To JavaScript Localization

In Practice
To start off, copy our base index.html file as the jquery_i18n.html. Create a new j query_i18n
directory and place the main-jquery_i18n.js file inside. Next clone jQuery.I18n somewhere on
your PC along with sub-modules:
1

$ git clone https://github.com/wikimedia/jquery.i18n.git

$ cd jquery.i18n

$ git submodule update --init

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
1

[...]<script src="jquery_i18n/CLDRPluralRuleParser.js"></script><script
src="jquery_i18n/jquery.i18n.js"></script><script
src="jquery_i18n/jquery.i18n.messagestore.js"></script><script
src="jquery_i18n/jquery.i18n.fallbacks.js"></script><script
src="jquery_i18n/jquery.i18n.language.js"></script><script
src="jquery_i18n/jquery.i18n.parser.js"></script><script
src="jquery_i18n/jquery.i18n.emitter.js"></script><script
src="jquery_i18n/jquery.i18n.emitter.bidi.js"></script><script
src="jquery_i18n/main-jquery_i18n.js"></script>[...]

Lets also provide the initial locale via the lang attribute:
jquery_i18n.html
1

[...]

[...]

Lastly, add links to switch the language and a couple of empty tags that are going to host our
translated content. Ill work with English and Russian but of course you may choose any other
languages it does not really matter, but for real-world apps make sure your texts are p
roperly
translated, preferably by a human.

phraseapp.com | sales@phraseapp.com | +49-40-357-187-76 | twitter.com/phraseapp | facebook.com/phraseapp | linkedin.com/company/phraseapp

A Step-by-Step Guide To JavaScript Localization

jquery_i18n.html
1

[...]

<a class="lang-switch" href="#" data-locale="en">English</a> |

<a class="lang-switch" href="#" data-locale="ru"></a>

4
5

1
2
3

1
2

[...]

Now proceed to the script. Well need to load translations as soon as the document is ready. For
simplicity lets store all our messages in the script:
main-jquery_i18n.js
1

[...]

jQuery(document).ready(function() {

$.i18n().load({

'en': {

'welcome': 'Welcome!',

'ru': {

'welcome': ' !',

phraseapp.com | sales@phraseapp.com | +49-40-357-187-76 | twitter.com/phraseapp | facebook.com/phraseapp | linkedin.com/company/phraseapp

A Step-by-Step Guide To JavaScript Localization

10

});

11

});

12

[...]

13

Note the welcome key the same name is used in the d ata-i18n attribute for the h 1 tag. This way a
proper translation will be used automatically all we have to do is run this process by calling
the i 18n() function. Ill extract it inside theupdate_texts:
main-jquery_i18n.js
1

[...]

jQuery(document).ready(function() {

var update_texts = function() {

$('body').i18n();

};

6
7

$.i18n().load({...});

8
9

update_texts();

10

});

11

[...]

12

Now lets take care of language switching. This is simple just listen to the c lickevent, extract
value of the data-localeattribute and then set locale accordingly:
main-jquery_i18n.js
1
2

[...]
$('.lang-switch').click(function(e) {

e.preventDefault();

$.i18n().locale = $(this).data('locale');

update_texts();

phraseapp.com | sales@phraseapp.com | +49-40-357-187-76 | twitter.com/phraseapp | facebook.com/phraseapp | linkedin.com/company/phraseapp

A Step-by-Step Guide To JavaScript Localization

6
7

});
[...]

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
1
2
3

[...]
$.i18n().load({
'en': {

4
5
6
7
8

'welcome': 'Welcome!',
'message_from': '$1 has send you $2 {{plural:$2|message|messages}}. {{gender:$3|He|She}}
is waiting for your response!'
},
'ru': {
'welcome': ' !',

9
1
0
1
1
1
2

'message_from': '$1 {{gender:$3||}} $2


{{plural:$2|||}}. {{gender:$3||}}
!'
}
});
[...]

1
3

Here pluralization and gender info are used at the same time. For Russian language I had to add
more options because pluralization rules are more complex.

phraseapp.com | sales@phraseapp.com | +49-40-357-187-76 | twitter.com/phraseapp | facebook.com/phraseapp | linkedin.com/company/phraseapp

A Step-by-Step Guide To JavaScript Localization

In order for this to work tweak the update_texts() function:


main-jquery_i18n.js
1
2

[...]
var update_texts = function() {

$('body').i18n();

$('#messages').text($.i18n('message_from', 'Ann', 2, 'female'));

};

[...]

Now open the page and try to switch between languages everything should be working just
great!

Polyglot.Js
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.
To start working with Polyglot, i nstantiate it:
1

var polyglot = new Polyglot();

Its a class-based, therefore you may work with a different sets of locales at the same time.
Next provide a list of phrases:
1
2

polyglot.extend({
"hello": "Hello"

});

// or

var polyglot = new Polyglot({phrases: {"hello": "Hello"}});

phraseapp.com | sales@phraseapp.com | +49-40-357-187-76 | twitter.com/phraseapp | facebook.com/phraseapp | linkedin.com/company/phraseapp

A Step-by-Step Guide To JavaScript Localization

As a common pattern, documentation suggests to prepare a hash of phrases on the back-end


and then output them in thescript tag. Note that Polyglot wont do translation its your job to
give proper phrases based on users locale.
Phrases can be replaced or removed completely (for example, to free up memory) by using
replace or clear methods respectively.
Note that nesting is supported as well:
1
2

polyglot.extend({
"nav": {

"sidebar": {

"welcome": "Welcome"

});

If youve come from the Rails world, interpolation should look familiar to you:
1
2
3

polyglot.extend({
"hello_name": "Hello, %{name}."
});

To perform the actual translation, utilize the t method:


1

polyglot.t("hello_name", {name: "John"});

If your key is nested, then use dot . as a delimiter:


1

polyglot.t("nav.sidebar.welcome");

Note that languages name is not provided anywhere currently it is used only when working
with pluralization.

phraseapp.com | sales@phraseapp.com | +49-40-357-187-76 | twitter.com/phraseapp | facebook.com/phraseapp | linkedin.com/company/phraseapp

A Step-by-Step Guide To JavaScript Localization

To set it, employ the locale function


1

polyglot.locale("de")

or set it upon instantiating a new object by passing a locale option.


Messages with pluralization should be delimited with four pipes (||||):
1
2
3

polyglot.extend({
"num_cars": "%{smart_count} car |||| %{smart_count} cars",
});

The correct message will be picked based on the smart_count parameter.

In Practice
Now lets quickly see this solution in action. Copy i ndex.html file and name it p
olyglot.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
1

[...]<script src="polyglot/polyglot.js"></script><script
src="polyglot/main-polyglot.js"></script>[...]

For this demo we will utilize Underscore.js template engine that will be used to render content
(though you may stick withHandlebars or some other solution). If you havent 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.
Place the production version of Underscore into the c ommon folder and require it:
polyglot.html
1

[...]<script src="common/jquery.js"></script><script
src="common/underscore.js"></script>[...]

phraseapp.com | sales@phraseapp.com | +49-40-357-187-76 | twitter.com/phraseapp | facebook.com/phraseapp | linkedin.com/company/phraseapp

A Step-by-Step Guide To JavaScript Localization

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
1

<script id="main-content" type="text/template">// <![CDATA[

2
3

<%= hello %>

4
5
6

<small><%= unread %></small>


// ]]></script>

Now inside the script lets wait until the document is ready and then instantiate the Polyglot
class while providing two messages:
main-polyglot.js
1
2

jQuery(document).ready(function() {
var polyglot = new Polyglot({

phrases: {

4
5
6

"hello": "Hello, %{name}!",


"unread": "You have %{smart_count} unread message |||| You have %{smart_count}
unread messages"
}

7
8
9

});
});

Here we utilized interpolation and pluralization (note the parameters name s mart_count when
using another name the pluralization seems to stop working). Now lets grab the template
1

var main_content_temp = _.template($('#main-content').html());

phraseapp.com | sales@phraseapp.com | +49-40-357-187-76 | twitter.com/phraseapp | facebook.com/phraseapp | linkedin.com/company/phraseapp

A Step-by-Step Guide To JavaScript Localization

and then provide values to the parameters inside it


1

$('body').prepend(main_content_temp({

hello: polyglot.t('hello', {name: 'John'}),

unread: polyglot.t('unread', {smart_count: 2})

}));

Here is the resulting code:


main-polyglot.js
1
2

jQuery(document).ready(function() {
var polyglot = new Polyglot({

phrases: {

4
5
6

"hello": "Hello, %{name}!",


"unread": "You have %{smart_count} unread message |||| You have %{smart_count}
unread messages"
}

7
8

});

9
10
11

var main_content_temp = _.template($('#main-content').html());


$('body').prepend(main_content_temp({
hello: polyglot.t('hello', {name: 'John'}),

12

unread: polyglot.t('unread', {smart_count: 2})

13
14
15

}));
});

Load the HTML document and test it out!

phraseapp.com | sales@phraseapp.com | +49-40-357-187-76 | twitter.com/phraseapp | facebook.com/phraseapp | linkedin.com/company/phraseapp

A Step-by-Step Guide To JavaScript Localization

Globalize
Globalize is a pretty big library for internationalization developed by the members of jQuery
core team. It works in 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 worlds languages, with the largest and most
extensive standard repository of locale data available. Whats more, Globalize is modular and
does not contain any I18n data you are free to load it yourself.
There are three main API functions:
that 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

Globalize.load()

Also there are variety of different functions for each module that you can find h
ere.

In Practice
Lets see Globalize in action right away. Copy index.html and name it g
lobalize.html. Also create
the globalize folder with theglobalize-main.js file inside. As long as Globalize is modular,
dependencies has to be loaded in the proper order (there is even an online tool available
helping you to find out which dependencies are needed).
Therefore, youll need to download the latest version of Globalize as well as C
LDR. Here is the
list of Globalizes 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

phraseapp.com | sales@phraseapp.com | +49-40-357-187-76 | twitter.com/phraseapp | facebook.com/phraseapp | linkedin.com/company/phraseapp

A Step-by-Step Guide To JavaScript Localization

Unfortunately, thats not all. Here are the required CLDR files that has 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 h
ere and
place under the cldr/cldr_data.jsname. Finally, hook all those files in the proper order:
globalize.html
1

[...]<script src="common/jquery.js"></script><script src="cldr/cldr.js"></script><script


src="cldr/event.js"></script><script src="cldr/supplemental.js"></script><script
src="globalize/globalize.js"></script><script src="globalize/message.js"></script><script
src="globalize/number.js"></script><script src="globalize/plural.js"></script><script
src="globalize/currency.js"></script><script src="globalize/date.js"></script><script
src="cldr/cldr_data.js"></script><script src="globalize/globalize-main.js"></script>[...]

Also add a couple of placeholders for our content:


globalize.html
1

[...]

2
3

1
2
3

1
2

[...]

phraseapp.com | sales@phraseapp.com | +49-40-357-187-76 | twitter.com/phraseapp | facebook.com/phraseapp | linkedin.com/company/phraseapp

A Step-by-Step Guide To JavaScript Localization

Now lets load a welcome message:


globalize-main.js
1
2

jQuery(document).ready(function() {
Globalize.loadMessages({

"en": {

'welcome': 'Welcome, {name}!'

6
7

});
});

Here we are using the message-formatter module. Next instantiate the Globalize class
1

var globalize = new Globalize("en");

and populate the #welcome section:


1

$('#welcome').text( globalize.messageFormatter('welcome')({name: 'John'}) );

Note that messageFormatter returns a function that we then call and pass the object containing a
name. This can be re-written as
1

var welcome_message = globalize.messageFormatter('welcome');

$('#welcome').text( welcome_message({name: 'John'}) );

Actually, messages parameters do not need to be named you may say 0, 1, 2 etc instead:
1

'welcome': 'Welcome, {0}!'

In this case pass an array to the formatter:


1

$('#welcome').text(globalize.messageFormatter('welcome')(['John']));

phraseapp.com | sales@phraseapp.com | +49-40-357-187-76 | twitter.com/phraseapp | facebook.com/phraseapp | linkedin.com/company/phraseapp

A Step-by-Step Guide To JavaScript Localization

Next provide another message containing the todays day and total earnings:
1

"en": {

'welcome': 'Welcome, {0}!',

'earned': 'Today is {date} and you\'ve earned {amount}!'

In this example well use date and c urrency formatters:


1

$('#earnings').text(

globalize.messageFormatter('earned')({

amount: globalize.formatCurrency(500.5, 'USD'),

date: globalize.formatDate( new Date(), {

datetime: "medium"

})

7
8

})
)

When formatting the currency, we pass U SD 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:
1

"currencies": {

"USD": {

"symbol": "$"

4
5

}
}

phraseapp.com | sales@phraseapp.com | +49-40-357-187-76 | twitter.com/phraseapp | facebook.com/phraseapp | linkedin.com/company/phraseapp

A Step-by-Step Guide To JavaScript Localization

medium
1

is the name of the datetime format it was also defined inside the c lrd_data.js file as
"dateTimeFormats": {

2
3

"medium": "{1}, {0}"


}

Here 1 is the date and 0 is time. Date and time, in turn, are formatted using the following masks:
1

"dateFormats": {

"medium": "MMM d, y"

},

"timeFormats": {

5
6

"medium": "h:mm:ss a"


}

Now that everything is ready you can observe the result!

PhraseApp Saves The Day Once Again


Managing translations for multiple languages can be tedious indeed. With PhraseApp, however,
the whole process becomes much simpler.
Grab your free trial if you have not signed up already and create a new project. PhraseApp
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.
Whats 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 PhraseApp a try!

phraseapp.com | sales@phraseapp.com | +49-40-357-187-76 | twitter.com/phraseapp | facebook.com/phraseapp | linkedin.com/company/phraseapp

A Step-by-Step Guide To JavaScript Localization

Conclusion
So in this article about JavaScript Localization weve taken a look at various solutions helping
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
its up to you which one pick!
Hopefully, you found this article useful and interesting. Thanks for staying with me and happy
coding!

phraseapp.com | sales@phraseapp.com | +49-40-357-187-76 | twitter.com/phraseapp | facebook.com/phraseapp | linkedin.com/company/phraseapp

A Step-by-Step Guide To JavaScript Localization

phraseapp.com
sales@phraseapp.com
+49-40-357-187-76

Groe Theaterstrae 39
Hamburg, Germany

phraseapp.com | sales@phraseapp.com | +49-40-357-187-76 | twitter.com/phraseapp | facebook.com/phraseapp | linkedin.com/company/phraseapp

Das könnte Ihnen auch gefallen