I18n: Let’s talk about AngularJS and Internationalization
Developping an Enterprise Social Network demands a lot of translated things so we can touch more people. Using AngularJS as our main frontend framework, I’ve had to seek for a good solution to internationalize our ESN.
First we should define some problematics and set up a little glossary. There are 5 main problematics here :
- Internationalization: It is the translation of words or sentences in different languages
- Localization: It is mostly about formats and how we format number or date for instance.
- Genderalization:
- Pluralization: Countries have different plural forms. Some have 2 while others have 3 or more plural forms.
- Globalization: It’s all of the above.
I’ve chosen to restrict the analysis in 2 parts:
- Formatting: It is all about formatting Date, Number and Currency.
- Translation: It is all about text replacement, plural and genderalization.
Now comes the study of existing solutions we could use for the ESN with pros and cons for each solutions.
Format
Date
The native ‘date’ AngularJS filter
{{1288323623006 | date:'medium'}} // Oct 29, 2010 5:40:23 AM
{{1288323623006 | date:'yyyy-MM-dd HH:mm:ss Z'}} // 2010-10-29 05:40:23 +0200
{{1288323623006 | date:'MM/dd/yyyy @ h:mma'}} // 10/29/2010 @ 5:40AM
Filters are very nice in AngularJS as they are very easy to use or to implement. AngularJS has a ‘date’ filter which formats date the way we want. AngularJS also comes with its own i18n system. First we have to add those js files in our web sites then AngularJS automatically internationalize our application.
Pros:
- No additional library needed
- Support Timezones
Cons:
- It does not implement complexe date calculation
Momentjs
var fr = moment().lang('fr');
fr.lang().months(moment([2012, 0])) // janvier
fr.lang('en');
fr.lang().months(moment([2012, 0])) // January
Momentjs is a very well known nodejs library. It comes with several js files used to internationalize an application.
Pros:
- Very mature and well known (17000+ stars on github)
-
Implements complexe date calculation methods
moment().startOf(‘hour’).fromNow(); // 29 minutes ago
moment().subtract(‘days’, 10).calendar(); // 05/10/2014 -
Supports Timezones
- Usage: client-side as well as server-side
Cons:
- Well…
The Date module of globalize.js
Globalize.formatDate( new Date( 2010, 10, 1, 17, 55 ), { datetime: "short" } )
// en: "11/1/10, 5:55 PM" - de: "01.11.10 17:55"
Globalize is a nice solution which comes with several modules. This solution tries to be the all-in-one solution. The ‘Date’ module provides everything needed to format a date, provided that we have provisioned Globalize with internationalization datas.
Pros:
- One solution to rule them all
- Fully uses Unicode CLDR for datas in which we can find the most complete internationalization datas
Cons:
- Still in an alpha version. It cannot be used in production
Number
The native ‘number’ AngularJS filter
{{1234.56789 | number}} // 1,234.568
{{1234.56789 | number:0}} // 1,235
{{-1234.56789 | number:4}} // -1,234.5679
The ‘number’ filter of Angular offers a quick and easy way to localize numbers.
Pros:
- No additional library needed
accounting.js
accounting.formatNumber(5318008); // 5,318,008
accounting.formatNumber(9876543.21, 3, " "); // 9 876 543.210
[Accounting.js}(http://josscrowcroft.github.io/accounting.js/) is a little javascript library for number, money and currency formatting.
Pros:
- No external dependencies are needed
Cons:
- It does not provide any localization files (but it is localizable)
- We need to wrap it into Angular filters
The Number module of globalize.js
Globalize.locale( "en" );
Globalize.formatNumber( 3.141592 ); // "3.142"
Globalize.formatNumber( 3.141592, {}, "es" ); // "3,142"
Globalize.formatNumber( 3.141592, {}, "ar" ); // "3٫142"
The ‘Number’ module of Globalize provides nearly the same features than the native ‘number’ Angularjs filter.
Pros:
- It also does what we want
Cons:
- Still in Alpha
Currency
The native ‘currency’ AngularJS filter
{{1234.56 | currency}} // $1,234.56
{{1234.56 | currency:"USD$"}} // USD$1,234.56
The ‘currency’ filter of Angular localizes currency by replacing the currency symbol to the proper one.
All datas are already provided by those js files.
Pros:
- No additional library needed
Cons:
- Does not automatically convert currency amount. It only replaces the symbol.
accounting.js
accounting.formatMoney(4999.99, "€", 2, ".", ","); // €4.999,99
Pros:
- Easy to use
- No external dependencies are needed
Cons:
- Need to be implemented in Angular with filters and services
- Does not automatically do the convertion of the amount
money.js
fx.convert(12.99, {from: "GBP", to: "HKD"});
money.js is a little library which convert currency using the open exchange rates api. We can use it along with accounting.js or the AngularJS filter to manipulate and localize currencies.
Translation
AngularJS
Text replacement
There is no native mechanism in AngularJS which does the text replacement for us and we must provide one.
Pluralization
Angular implements a ngPluralize directive. The drawback is that there is no genderalization implementation right now.
ng-pluralize count="personCount" offset=2
when="{'0': 'Nobody is viewing.',
'1': '{{person1}} is viewing.',
'2': '{{person1}} and {{person2}} are viewing.',
'one': '{{person1}}, {{person2}} and one other person are viewing.',
'other': '{{person1}}, {{person2}} and {} other people are viewing.'}">
/ng-pluralize>
Angular-translate
Text replacement
<h1>{{'TITLE' | translate}}</h1>
Angular-translate is an AngularJS module which provides a lot of features and full pluralization support through MessageFormat.
Some of those cool features are:
- Seamless integration with AngularJS with directives and filters
- Fallback mechanism
- Lazy and Asynchronous loading
- determinePreferredLanguage method which tries to find the correct language
Pluralization
Angular-translate is the only solution I have found that natively implements a genderalization mechanism.
We provides datas like:
{
"LIKE_TEXT": "{GENDER, select, male{He} female{She} other{They}} liked this."
}
which is then used in our templating like that:
{{ 'LIKE_TEXT' | translate:"{ GENDER: 'male' }" }}
It can become complexe :
{GENDER, select,
male {He}
female {She}
other {They}
} found {NUM_RESULTS, plural,
one {1 result}
other {# results}
} in {NUM_CATEGORIES, plural,
one {1 category}
other {# categories}
}
Angular-gettext
Text replacement
Angular-gettext also provides a seamless Angular integrated module. It uses Gettext and the PO files to translate an application.
<a href="/">Hello {{name}}</a>
The best cons in using angular-gettext and the PO format is that it can easily be used with localization plateform like Pootle or Transiflex due to the PO format.
Pluralization
<span>
There is {{count}} message
</span>
Pluralization here offers the same features than AngularJS pluralization mechanism.
Globalize.js
Text replacement
Globalize.loadMessages( "pt_BR", {
greetings: {
hello: "Olá",
bye: "Tchau"
}
});
Globalize.locale( "pt_BR" );
Globalize.translate( "greetings/bye" ); // "Tchau"
Pluralization
Unfortunately, I did not find anything about pluralization in globalize.js.
Conclusion
First thing to note is that every solutions propose the same API. And most solutions seem viable.
For our needs, in the formatting part we have chosen to stick with AngularJS filters (with a filter for money.js to convert money) and momentjs for everything about dates. In the translation part we will use angular-translate which offers very nice features plus the fact that one of our internal development team was already using it with success.
Apache James with Cassandra How to implement inline validation
on the note of globalize.js… While its technically in Alpha it is in a very production ready state. I’ve had apps that utilize globalize.js that have been built, run-on-production and then retired. It’s most importantly one of the few libraries that I’ve used that actually catches all of the nastier corner formatting corner cases..