22 Sep 2013

X-ation on JavaScript

During my work on a new brand project based on Backbone.JS in scope of my current employee company, I faced with comprehensive task - get the best Internationalization solution to meet project goals. At first glance, it seems to be simple task - like resource bundle (file where I may store strings which are repetitively used or should bee able to re-configure with no coding). But it turns out as more complex task. And here is list of goals:
  1. Easy integration with Backbone application. Not so strict, but would be great.
  2. Store localization strings in *.js or *.json or even in *.properties (if such way exists).
    • Caching. Performance. Development and Production mode.
    • And maybe store cached files in localStorage
  3. Languages support:
    • Ability to setup resource bundle for many languages.
    • Ability to catch browser language and being able to enable/disable it.
  4. Namespaces support (aka nested items/strings aka Resources.company1.person1.name).
  5. Interpolation aka replace by variable: ${var1} or __var2__ data into final string.
  6. Widely usage: in js code, in templates and as AMD module.
  7. Ability to use t("string") or l("string") or any other function to translate string on the fly.
  8. Multi-line property using "\" as it done in Java.
  9. Having one main resource bundle file translate into many languages in automatic manner.
  10. Author support. In case of some issues need to be sure that I may have some help/assistance in troubleshooting and bugs fixing.
All above items are about (refer to) this:
And I'm eager to get all stuff on Internet about it, to find the best solution.

To be honest, I don't like i18n-like projects. I do really prefer only one language on The Earth planet - English. But world is cruel - there are many languages, and from client point of view it may be important stuff.

So back to my task.
Below I tried to list all libraries I researched, and how they meet my goals.


According page info I need to override Backbone.Collection.parse() to meet that goal that I have text file with properties. Here is more detailed info how I may do override, but it's not the best way i think.
It may work if algorithm of overriding is the same on all project. I know, that my REST service may response with different JSON objects so this way is not for me.
Here is another example but with suggestion to override Backbone.Marionette.Renderer.render().

Looks good approach because related to require.js but this way doesn't allow work with templates by default. Here is a few thoughts about using plugin for Localizing templates using require.js, backbone and underscore Namespace is supported.


From last link as an answer for main topic, we may find another i18n solution:
It's kinda better way, which works on top Underscore template() and works with AMD modules. It's really minimalistic. Underi works with resources.json by only one key level (Namespaces are not supported). No Interpolation.
Using ajax call, via json, it's tricky, because need to be careful with valid json data. But data will not be chached.

Kinda Backbone native implementation - using require.js i18n plugin, with more complex underscore override. Similar as above, but this is more like properties editor on the fly. And in fact do the same job as Require.js i18n plugin. The same issue with namespaces.
In templates "<%"= and "<%"- works as usual, but to separate localization's and model's data you need to require resources object in all templates. Here is the point where we need to think about performance.


Comparing Underi18n and Require.JS i18n plugin, here is what I have (Gist snippet):


As short summary:
- Underi18n works with underscore template via <%_ but doesn't support namespaces.
- Require.JS i18n lang package should be included in every template, but supports Namespaces.
Both variants NOT TESTED with interpolation. Because template passed to Backbone as string.

So what next? Need more libraries to compare.

I do believe that using such approach, we may develop some good stuff. Need to try.
Here is example of using helpers and override template() function from Underscore.
Nice post about underscore helpers and Implementation on pure Backbone and Marionette Now I know how to extend what I want.

All locales in one file. Not sure if we can separate them.

Jquery i18n
Another jquery implementation of i18n project. Loading in json. Has Plurality support. data-i18n attr needed. There is no namespace support by default. I tried to add "three": {"hi":"Hello"} but parser threw parse error.

I like idea, how interpolation is implemented. You have the key, pass the data and returns parsed/compiled string. Multi-line supported. But properties are globally accessed. This may cause conflicts with other javascript/DOM code.

Jan Mühlemann aka @jamuhl was inspired by https://github.com/jpjoyal/jsperanto and wrote his own module and module for node.js.  Obj.obj.obj namespace supported, but need to write data-i18n attribute for being used. HUGE API. All features are highly configurable. Pluralitation support. But looks like all language data are going in one file. Assuming u have dozen of strings, such file will be very big.
BTW, I have installed by NPM, built with GRUNT, but in generated file were some errors with undefined symbols/chars in code.
Here is Backbone realization of i18next usage. Author tend to use jesperanto but looks like he stopped on i18next.
There is an issue with loading i18next with require.js, so to fix it there is AMD-like version.

Uncaught SyntaxError: Unexpected token ( i18next-latest.js:816). Almost the same 944 line
Issue persists with files downloaded from site (including AMD version as well) and via npm after grunt build. Reproduced on Chrome and Firefox on CentOS.
With minified file everything works fine :)
Fixed in 1.7.1 version.


John Resig (JQuery creator) aka @jresig was inspired by i18n-node and wrote his own plugin/module 
i18n-node-2 :) It's cool, but, isn't odd to re-invent some wheel? I would never rewrite someone's module to meet my goals and publish it. It's harmful and disoriented for programmers who 's searching for  better way. Ok, let it be. Maybe, when I use my future project based on Express.JS I will use one of above modules. But not now. In case u are interested in, here is details from John

Another simple library to get 3rd-party translation bundles into javascript.


Backbone with Polyglot.js
It's kinda good solution, cause I have snippet how to integrate with Backbone. But according Polyglot API and blogpost author comment, Polyglot doesn't support Namespaces.


Alex Sexton (author of yepnope.js) created 2 libraries:
Messageformat.JS
It's really huge work by developers in scope of Pluralitation support.

Jed (rebranding to gettext2.js coming soon)
On top of messageformat.js and numberformat.js Alex release another Pluraity rich approach: Jed.
Here is his thought and video about how language is important from UX point of view.

Not sure I need so comprehensive logic. This all looks like intelligent internationalization way. Alex is eager to develop/handle huge toolkit for Tool for i18n stuff: http://jedtoolkit.org/ Coming soon. Details here.


So what?
I made some kinda comparison table, and I'm stuck :)

So what to choose?
I'm between Underi18n, Requirejs-i18n, i18ntext, JQuery-i18n and JQuery Properites.
After some long research and decision making, I stopped on i18next. It's really huge work, and usful library.
Currently implemented in my project.



PS.
Here is list of resources to read and to understand how widely important languages are for client and how developers can implement it. 

Overall summary of what is mean by Globalization, Internationalization and Localization:
  • Translation is one part of Localization
  • Internationalization is a pre-requisite of Localization
  • Internationalization and Localization are parts of Globalization
  • Globalization includes many business-related activities outside of the product itself.

2 comments:

  1. Here is some tweets from i18next Creator: Jan Mühlemann @jamuhl


    @landike 1) the article about backbone and i18next vs. jsperanto is misleading i think…tried to clear that (comments) but still wrong



    @landike the syntax error - that's a typo - ||A '' -> should be || ''. fixed in repo. will release a fixed version today.



    @landike while you could have namespace like obj.obj.obj…there also namespace to split files fileA:obj.obj.obj http://i18next.com/pages/doc_init.html



    @landike as i myself only used handlebars (mustache) there is a sample to integrate templates



    @landike basically you should be able to build a solution with underscore helpers with ease



    @landike http://localhost:8000/pages/doc_features.html multiline json -> with postprocessing you could create what ever needed



    @landike v1.7.1 will fix the issue...

    ReplyDelete
  2. First of all, I would like to thank Jan for support, it's very useful.

    I asked Jan in twitter about:
    1) Is there any chance to not use data-i18n attr? I'm not quite sure I can do this according API reading.

    And here is some my github reserach:
    https://github.com/jamuhl/i18next/commit/f36a1b8db3ae12f3111a5879d6185b9bba3a2aef#commitcomment-4158567

    But looking forward verification from jan.

    ReplyDelete