A few day ago I came across MessageFormat.js in my twitter stream.
Someone recommended it to someone else as the best client- and
server-side solution to l10n in JavaScript currently available.
I can't find that tweet sadly, but I took some time to dig into
MessageFormat.js and report back with my findings.
The code is at
https://github.com/SlexAxton/messageformat.js and it's
developed by Alex Sexton (
https://twitter.com/SlexAxton,
http://alexsexton.com/). He's involved in Dojo and the author of Jed:
http://slexaxton.github.com/Jed/.
The aim seems to be go beyond plurals with a more-generic 'select'
macro-of-sorts which takes the value passed by the developer and selects
the right form on the (sub)string (essentially behaving like L20n's
index on entities).
Here's what the syntax looks like:
'Your {NUM, plural, one{message} other{messages}} go here.'
NUM is the variable from the developer, 'plural' is the method of
selecting the right value (the other one is 'select,' more on that
below), 'one' and 'other' are the possible keys to select from, while
'message' and 'messages' are — obviously — the forms corresponding to them.
Plural rules are hardcoded:
https://github.com/SlexAxton/messageformat.js/tree/master/locale
The recommended way to use MessageFormat.js is to precompile all strings
on build time. The developer claims it is *much* faster to do it this
way rather than to parse on runtime. I'd like to see the numbers and
compare them to ours.
The compilation produces something like this:
https://github.com/SlexAxton/messageformat.js/blob/master/example/fr/i18n.js
Which you then include in your application:
<script>document.write('<script src="' +
(localStorage.getItem('lang') || 'en') + '/i18n.js"><\/script>')</script>
And use like so:
$('<div>').text( window.i18n[ 'sub/folder/foo' ].bar( { NUM: 1 } )
).appendTo('#content');
The 'select' method is more generic and is supposed to help with
genders, although it could be used with other grammar features, too.
The main drawback, as I see it, is that everything still happens on the
developer's side, which is limiting. Not much of a revolution there,
but it's certainly good to see some evolution as the needs evolve too.
> var mf = new MesssageFormat('en');
> var message = mf.compile('{GENDER, select, male{He} female{She}
other{They}} liked this.');
> message({"GENDER" : "male"});
"He liked this."
> message({"GENDER" : "female"});
"She liked this."
> message({});
"They liked this."
See more examples at:
https://github.com/SlexAxton/messageformat.js/tree/master/example
* * *
One interesting feature of MessageFormat.js is how it tries to reduce
redundancy of text. Notice how in the examples above and on the
website, only the parts of the sentance that actually change are
exploded into multiple forms, while the rest of the sentence is typed
only once.
In L20n, this would be possible with local entities, but it occurs to me
now that one of the design guidelines for L20n should be to prefer
flexibility at the cost of redundancy.
This improves readability and promotes languages where bigger parts of
the sentence need to be adjusted to the subject or object (like,
surprise surprise, Polish)
So for the example above:
'{GENDER, select,
male {He}
female{She}
other{They}} liked this.'
the following L20n equivalent:
<liked[$gender] {
male: "He liked this.",
female: "She liked this."
}>
is better (IMO) than this:
<_pronoun[$gender] {
male: "He",
female: "She"
}>
<liked "{{ _pronoun }} liked this.">
* * *
I was happy to find a new solution to doing i18n/l10n in JavaScript and
wanted to share it. This seems to be a decent implementation of plurals
+ genders which, judging from the tweetverse's reaction, meets many
people's needs.
-stas