Blog.

Localization of Ext Applications

The Legend

Tower of BabelOur problem, the problem of translating and rendering our applications in different languages is not new, contrarily, it started about 4-5 thousand years ago. People then spoke just one language so anybody understood anybody from all corners of world and all walks of life. But, people wanted to equate with God and started to build the Tower of Babel that would top in the Heaven. God, seeing that, came down and confused their languages. Not understanding each other, they stopped building and scattered all over the world.

And now we need to translate our applications.

Background

From the user viewpoint, the localization is very easy: He just selects his preferred language at the operating system install time or changes it in settings afterward. However, it was not always so. Computers were invented and their production started in United States so they spoke and understood only English. In 80-ties, if you didn’t understand English you were entirely lost in the world of computers. Computers’ origin and spread over the whole world may be the reason of popularity of English language mainly among the youngsters.

The problem was that Americans did not need translations because you can travel 3,000 miles in US and still speak one language. If you travel 300 miles in Europe you may need 5 languages to speak to locals. Not needing localization, the first computers and software did not include any infrastructure for implementing translations.

The situation improved over time, we cannot imagine that our iPhone or OS would not speak our native language, yet we cannot call it ideal especially when talking about ExtJS. It is not that localization of Ext applications is impossible, there are even locale files packed with the library. It is that the current official localization system of Ext is awkward, lengthy and lacking features.

The Ext official way

Imagine you have an application that defines a panel with a title:

Ext.define('MyApp.view.MyPanel', {
    extend:'Ext.panel.Panel
   ,title:'Hello World!'
});

How could we translate the title into a different language?

Now imagine you have a locale file with translations:

Ext.define('MyApp.locale.view.MyPanel', {
    override:'MyApp.view.Panel'
   ,title:'Hallo Welt!' // German translation
});

What happens? When locale file is processed Ext sees that we are overriding a base class so ‘MyApp.view.Panel’ is loaded first (if it has not yet been loaded) and then its title is overridden with German translation. Subsequently

Ext.create('MyApp.view.MyPanel');

renders the panel with the German title.

We only need a thin layers of locale overrides between the application definition files and the actual run of the app that creates instances of the language-overridden classes. Nice, isn’t it? Well, not so much or not at all. Why?

Problems with locale overrides

1. Locale files are incorporated into production build

At the time of Ext 3.x and older we had to manually include Ext and the application classes in index.html. It was usually a three steps sequence:

  1. include Ext
  2. include concatenated application classes
  3. include app.js that started the app in onReady

Therefore, it was really easy to add one extra include between 2. and 3.: concatenated localization overrides. I had one Ext 2.x application (it is still working) that used server-side gettext system to generate the locale file on the fly and injected it just before the application start. It works more than satisfactory.

However now, Sencha Cmd packs everything into one file leaving the developer with no option to dynamically include anything before the app start. If you want a translation then you must make a different build. This is also true for themes so if you want 3 themes and 5 languages you need 15 different builds of the same app.

Yes, it can be automated, you can configure app.json or build.xml to do it for you and in some cases it may be everything what is needed. Nevertheless, it is not up to par with the elegance of the old override-to-localize way.

2. Changing the locale (or theme) means app restart

With this build-per-language system, there is no other way but to restart the application, reload the page, with a different locale sent to the server for different app.js build to be included in index.html.

Well, in many cases users just set their preferred language once and never change it so this might not be a great issue.

3. Translations can hardly be done by laymen

When I was developing the application I mention above, I gave gettext source files to (semi)professional translators that knew nothing about programming, javascript or Ext and you can bet what happened. I had to go through the files they turned in and I had to fix all nonmatching quotes. They just saw the quotes as the spoken language element, not as a text-enclosing marks for a programming language.

Now imagine what would happen if you gave them files full of Ext overrides. They may translate even “extend”, “override” and “title” property names.

4. There is no way of per-component translation

It is not possible to have the application in English, for example, but one window or panel in it in German. It is questionable if this behavior is necessary, but it might be needed sometimes. With one build including only one language, it is just not possible. (You could load the locale from the server on demand for that window, but it a different story.)

5. Translations are dependent on application names

What happens if you change ‘MyApp.view.MyPanel’ to ‘MyApp.view.YourPanel’? You need to walk through all locales to change the name in them too, otherwise the build would fail or, even worse, the build would succeed but a language wouldn’t work.

Advantage of override based localization

Enough problems! There is one advantage, and it is an important one: This localization system can be implemented on the top of existing application without changes in it. Of course, the application must have been written with a (future) localization in mind because overrides cannot go any further than class properties.

This is not translatable by overriding:

Ext.define('MyApp.view.MyPanel',{
    displayDialog:function() {
        alert('Hello World!');
    }
});

This is:

Ext.define('MyApp.view.MyPanel',{
     message:'Hello World!'
    ,displayDialog:function() {
        alert(this.message);
    }
});

How to use build multiple locales

I do not use this official way myself, nevertheless, I know of a perfect localization howto on Sencha forums by Michal Charvát.

Other localization systems

One other class of localization systems would be variable or function system. To illustrate, consider the following chunks:

MyApp.currentLocale = 'de';
Ext.define('MyApp.Locales', {
   statics:{
       title:{
            en:'Hello World!'
           ,de:'Hallo Welt!'
       }
   }
});

Ext.define('MyApp.view.MyPanel', {
     extend:'Ext.panel.Panel'
    ,title:MyApp.Locales.title[MyApp.currentLocale]
});

THis very simple example shows how variable localization could work. The title of MyPanel is not a text but a variable that points to global “repository” of translations, the static class Locales. I’m not going to speculate on how clumsy it is to type “MyApp.Locales.title[MyApp.currentLocale]” instead of “Hello World”, or about how Locales gets populated, how translations are made and how it is maintained. I leave these speculations to you if you want to use this system. (I wouldn’t.)

Another way is to define a global translation function

MyApp.currentLocale = 'de';
Ext.define('MyApp.store.Locales',{
     extend:'Ext.data.Store'
    ,storeId:'locales'
});

_ = function(textId) {
    var  store = Ext.getStore('locales')
        ,rec = store.findRecord('textId', textId)
    ;
    return rec ? rec.get(MyApp.currentLocale) : text;
};

Ext.define('MyApp.view.MyPanel',{
     extend:'Ext.panel.Panel'
    ,title:_('title')
});

I have opted for function name “_” (underscore) that is consistent with GNU gettext, however, you must be careful in real life and make sure that this function is not already defined by a library other than Ext. The example illustrates how the function could look if we kept the translations in a store.

Both methods have their advantages and disadvantages, however, the main drawback is that they need to write the application a specific way. It may be fine when starting from the scratch but image you need to replace each string in your 1,000 files application with _(“that string”). Then, you have to maintain text ids – this can be alleviated by considering English text as a text id.

You may now think “There must be something better” and you are right. Let me explain how would an ideal localization system look.

An Ideal Localization System

Here I summarize features of a hypothetical localization system so that it could be called ideal.

  1. No changes of the original application code are necessary. Really none: title:'Hello World!' stays as it is, in English.
  2. Texts are completely separate from the code. Translators are not fed with the language spoiled by programmatic constructs, not even quotes. Ideally, translators can work over internet in an editable grid immediately seeing translated texts in the application.
  3. No application restarts are necessary on locale change, no separate builds are required and the locale change is immediate.
  4. Localization system is completely separate and independent of the application, it can be added or removed at any time and changes in the application have no impact on the system. (New or changed texts must be (re)translated, of course.)
  5. There is a possibility to use many languages in the application at the same time.
  6. It must be easy to implement. Setting aside translations themselves that could take time depending on the size of the application, implementation of the system itself must fast and easy.

Now I could conclude with a call to Sencha developers: “Please invent and implement such system!” but I won’t. I’ve already coded it, however, it is not yet in the production quality. I would rather call it a concept proof. Let me know if you want to see it, test it and improve it. Then may come a day when it will be incorporated in the core library.

saki
Follow me:
Latest posts by saki (see all)

18 Responses

  1. Hi Saki,

    I liked your article and it helped. Further we have a requirement to localize our entire website content wherein we have many similar below code for which I need your help. Here we need to display the value of displayField i.e. “I have an account” in French\English\Spanish etc. Can you please suggest a generic solution for the same asap ? Thanks in advance

    Ext.define(“TestPortal.view.CustomerLogInForm”, {
    extend: ‘Ext.panel.Panel’,
    alias: ‘widget.customerlogin’,
    id: ‘loginform’,

    layout: {
    type: ‘fit’
    },
    initComponent: function(){
    var me = this;
    me.border = false;
    me.baseCls = ‘bodyColor’;
    me.items = [{
    xtype: ‘form’,
    baseCls: ‘bodyColor’,
    controller: null,
    id: ‘customerLogInForm’,
    items: [{
    xtype: ‘displayfield’,
    margin: ‘5 0 -2 15’,
    width: ‘100%’,
    value: ‘I Have an Account’
    }, {

  2. Hi Saki,
    I’m interested to see and test the localization system. There is one constraint – we are working with Sencha Architect. Can I still use your code?
    Thanks & regards Karina

    1. Karina, I do not use Sencha Architect because there is a too much cost to pay, in the form of limitations like your _() function, for the convenient “visual” design.

      I would start to use SA, and I will, the moment it will be able not only to generate code but also to read the source files written in an IDE.

      Therefore, I haven’t tried to run the example code in architect. Nevertheless, I am slightly optimistic that it could work if Architect supports overrides.

      Good luck!
      Saki

  3. I know this is an old thread, but it gave me useful information, so here are my thoughts:
    Binding to the viewmodel sounded great at first, but then I realized that might need localization in places where VM binding might not be available, and then it would be harder to use it that way.
    I decided that I am OK with reloading the app in order to switch language so I tried to go with Sakis underscore method, but it does have a problem:
    If you want to use translation when defining your classes (like in the example), then it just won’t work. That is simply because the Locale store is nonexistent when Sencha is parsing all of Ext.defines. Or at least this is the case when using Sencha Cmd.
    And finally, this is what I am going with, at the moment:

    var xhttp = new XMLHttpRequest();
    xhttp.open(‘GET’, ‘/LocaleData/Translations’, false);
    xhttp.send();

    var l = JSON.parse(xhttp.responseText);

    This is what it looks like in my class definitions:

    items: [{
    padding: ’20 20 0 20′,
    html: l.login.window.title,
    width: 200
    }

    I am pretty satisfied with this at the moment, but later on I will need to add a feature to be able to use placeholders in the translations.

    1. I used to work with a function system _() and it worked fine. But now we switched to Sencha Architect and I’m no longer able to use the function expression as a value for the names, labels etc. Only strings are allowed. Any idea how to solve this?

  4. Hi Ahmed,

    if you’re writing a new application from scratch your approach works fine. For existing applications, you would need to scan all the code for texts and bind them to the data in the main view model.

    Also, I think – but it is only my opinion – that binding is too heavy for that. MVVM involves many listeners, scheduler – too much infrastructure for such simple thing as localization so I’m a little bit afraid of performance

    Anyway, it should work and it should be reasonably simple to code. Share please your experiences with your way of localization.

    Best,
    Saki

  5. Hi Saki,
    Thanks a lot for this nice post. I used your 6 points as requirements for localization system.

    My implementation for translation was rather simple.
    I just have MainViewModel that all other views inherit, and I update all locale strings in this view model and use Sencha’s own binding system to update my locales.

    I personally find that my approach satisfy all the 6 points.

    Do you have any disadvantages in mind concerning my approach (Central ViewModel + bindings)?

  6. Pat,

    thank you very much for your detailed description of your localization system and I hope it helps readers to understand the possibilities we have in this area.

    Thanks a lot again,
    Saki

  7. I introduced localization of our ExtJS apps about a year ago in our company.

    I did a multitude of things, but to summarize

    1) I deemed the override approach by Sencha to be really unusable and avoided as best as possible.

    2) I implemented a class “i18n” that is ExtJS agnostic and is loaded with all translations before ExtJS. The i18n class is somewhat similar to the i18next, but slightly simpler, but it e.g. also supports placeholder replacements.

    3) The “i18n” class has a config which tells it, which localization should be used. If the user is logged in, the localization can be set from the user profile, if not it’s dependent from the user client settings / http request headers. Furthermore there’s a default language for fallback purposes (usually English or German) in case the preferred language does not exist.

    4) The i18n class loads all localizations that exist in a hierarchical JSON object. This is used to group them logically; e.g. to get the localization for the field “name” for the entity “customer” I would call i18n.t(“entity.customer.field.name”); [A]
    This can be easily used in the default way ExtJS classes are loaded, e.g. just use Ext.define(“App.view.Order.Panel”,{title: i18n.t(“ui.orders.panel.title”); });

    5) Lastly there’s an “extension for ExtJS” of this i18n class which is loaded when ExtJS gets ready. E.g. it loads the corresponding overrides for the hardcoded strings in existing framework widgets, also those not covered by the Sencha localization files (to see that e.g. try out EJLOD on all the localization files http://www.sencha.com/forum/showthread.php?299466 )

    Notes:
    [A] This implementation doesn’t fulfill property (1) of your “hypothetical ideal localization” system, but that’s not bad per se. IMO to keep the code free of display strings helps to avoid wording inconsistencies which are bad for UX.
    [B] If the language is changed during runtime, the app currently has to restart. This is because one would have to hop through all created ExtJS objects and replace all the strings.
    [C] If anyone is interested, our company may publish & open-source this class, but I would have to speak to my colleagues first about it 😉

  8. Hi Saki,
    I am working on a multi app (3 to be exact) suite for the health-care industry in the USA. Localization was one of the selling points for us in choosing ExtJS, but the implementation, as you pointed out, is less than stellar.

    We aren’t quite ready to put localization into our apps, but as the lead developer, I would love to test this as I too was thinking about an “locale overlay” type of logic that would just hit objects with a text property. It sounds like you and I might have similar concepts but yours is already in the works. So, instead of re-creating the wheel, I’d very much like to participate in testing your framework when we are ready to implement it.

    Thanks for your consideration.
    -JL

  9. Please don’t tease us, spit it out 😉
    Me too. Based my existing stuff on Mitchell’s github project.
    In time I discovered all the downsides you mentioned.

    To your ideal specs I would add a “translator controller” that can be loaded by an app on the fly, presenting a mechanism for users to translate in situ.

    For me, the more generic problem is how to work around the giant blob that Cmd creates. Localization is just one instance of chunks that want to be loaded independently…

    “English as the text id” is essential to produce code on time, yet still imperfect as a key. It seems to me a shame that Cmd’s much-touted code awareness does not encompass locale strings ;(

    Thanks for posting. Yes, you nailed the problem description. I am all ears for a solution…

  10. Hello Saki,
    thanks for this great article! I did make my own localization system, but it’s far from perfect… In my ExtJS 3 application I am using 6 languages and more than 20 themes. In ExtJS 4/5 this is big problem. So I am also very interested to see and test your localization system.

    Thanks.
    M. Dostal

  11. Hello Saki,

    I’m interested to see and test!
    I’m also working on such Localization system… I built a system based on the same principale as Ux.locale.Manager (https://github.com/mitchellsimoens/Ux.locale.Manager) but supporting ExtJs 5.
    However… my system require a lot of component overrides, is not fully transparent for the existing application and is still unstable yet…

    Thanks in advance,
    PsychoKrameur

Leave a Reply

This site uses Akismet to reduce spam. Learn how your comment data is processed.

Enter your username and password to log into your account. Don't have an account? Sign up.

Want to collaborate on an upcoming project?