-
19 Jul 2010 4:37 AM #1
More general approach to i18n in Ext
More general approach to i18n in Ext
Intro: Background
Our products are localized to 7 languages (with tendency to grow).
We use various independent APIs on the backend side, two or more in one application.
Because of that, we find that it will be easier to localize our products on the frontend side with english language as reference.
What we got in Ext?
Ext is localized in various places.
A little bit in Date and Ext.util.Format objects, then of course we have got ext-lang-xx.js files... just to mention a few places.
Some parts are good, some not... as in real world
Date
Date is vary general object - it is its strength as well as weakness (sometimes).
There is no natural/common way to localize date formats.
November 16, 2003 may be localized as '11/16/2003' (US format 'm/d/Y') as well as '2003-11-16' ('Y-m-d').
The date format is parameter here.
Ext.util.Format
Ext.util.Format behave like there is US and TheRestOfTheWorld, or US and nothing more.
The 1st approach I used to call 'I can live with it... for a while at least', the 2nd one IMHO is just inappropriate for such a professional framework.- Ext.util.Format.number()
- quite good as far as You can live only with 'comas' and 'dots' as a separators. Unfortunately sometimes there is a need to have other separators like 'space' for grouping. - Ext.util.Format.plural()
- It may be hard to imagine, but there are other languages with more than one plural form, and it's not so easy as to add 's' or another magic character to singular form. - Ext.util.Format.usMoney()
- yes, we have a little bit more than one currency... unfortunately. Should we add euMoney(), ukMoney(), jpMoney()? Maybe a more general function will work for all of us?
ext-lang-xx.js
For me, the problem with ext-lang-xx.js files is redundancy, but frankly speaking, I got no good solution for this...
After all it works, so 'do not touch' may be the right way
In general... Yes, we can override functions, or extend objects just to have what we need, but sometimes it just don't work or it's wrong if we need portable and universal code.
Our solution
We got separate i18n class so we got all in one place.
It's not a singleton, so we can have as many instances as we need.
It may be helpful when more than one language is needed at the same time.
i18n got few config params so we don't need to override functions to have different results.
Numbers
StringsCode:var EN = new Our.i18n({ group: ',', dec = '.' }); var PL = new Our.i18n({ group: ' ', dec = ',' }); EN.number(1234567890.987, '0.00'); // => '1,234,567,890.99' PL.number(1234567890.987, '0.00'); // => '1 234 567 890,99'
The key approach is to translate the strings 'on the fly', so we can translate texts in JavaScript files as well as from AJAX requests.
Each instance of i18n has got its dictionary, few params and translation functions that works according to dictionary and params.
Translation engine is based on GNU gettext - i18n has _() and _n() functions that allows to translate text with optional context.
DatesCode:Ext.ns('App'); App.i18n = new Our.i18n({ lang: 'en', pluralForms: 2, plural: function (n) { return (n == 1 ? 0 : 1); }, dict: { __default__: { single: { 'new': 'New' }, plural: { 'car': ['1 car', '{0} cars', 'no car'] } }, 'super': { single: { 'new': 'Super New' }, plural: { 'car': ['1 super car', '{0} super cars', '{0} super cars'] } } } }); App.i18n._('new'); // -> 'New' App.i18n._('new', 'super'); // -> 'Super New' App.i18n._n('car', 2); // -> '{0} cars' App.i18n._n('car', 2, 'super'); // -> '{0} super cars' App.i18n._n('car', 0); // -> 'no car' App.i18n._n('car', 0, 'super'); // -> '{0} super cars'
In each i18n instance we have defined few date/time format params, so we can use uniform syntax and got variable response. The main problem here is naming convention, as usually
Code:var EN = new Our.i18n({ date_YMD: 'm/d/Y' }); var PL = new Our.i18n({ date_YMD: 'Y-m-d' }); var now = new Date(); var lang = PL; now.format(lang.date_YMD); ... //then we can switch the language lang = EN; now.format(lang.date_YMD);
Outro
After over 18 months of development We've got few ideas about i18n of Ext and apps based on it. (If it will help, we can share the code.)
It's not a perfect solution, but maybe it will led to more general and universal approach to localization in Ext?
Do we know the plans for i18ning the ExtJS 4.0 ?...
- Ext.util.Format.number()
-
19 Jul 2010 11:21 PM #2
I just use override files that load localization and translation. The order is (1) load code, (2) load i18n overrides, (3) initialize code based on overrides. The override files are dynamically generated from PHP based on current translation files and database settings. The size of the files is kept reasonable through on-demand loading mechanisms (each piece of on-demand loaded code also loads its translation overrides file). The only downside is that locale changes require a complete refresh of the app's UI.
-
20 Jul 2010 12:37 PM #3
We also use override files. Right now it is the only effective way to localize Ext framework - and it works quite well.
After loading Ext we use only our i18n object - it works very well
Of course our solution might not suits to everyone needs, but...
Thanks to our i18n functions to translate texts we have more natural interface from linguistic point of view - no matter which language was chosen by user.
It's easy as switching between two dictionaries.
Let us asume that we have Ext.i18n (singleton as Ext.Ajax).
Then everything related to localization would be in one place.
With a little effort we can have very universal tool not only for US part of the community.
After all, even if it's bad idea (is it?), existence or behavior of functions like Ext.util.Format.number(), Ext.util.Format.plural() or Ext.util.Format.usMoney() is questionable.
-
29 Jul 2010 5:01 AM #4
I managed to localize my app extending the existing classes and adding in the properties labels to be localized, also modifying the ext-lang-xx.js file.
But in this way I'm forced to extend every single object I added to my app.
Is there a way to obtain a more clear and elegant result?
Would be possible for you to exploit plugin development in this case?
-
29 Jul 2010 12:00 PM #5
I use something similar to the dictionary approach, based on resource files as they work in .NET
MyApp.Local = new MyCompany.ResourceBag({
SomeWord: { en: 'SomeWordInEnglish', fr: 'SomeWordInFrench', cn: 'SomeWordInChinese' }
})
Then a little bit of magic in ResourceBag so that:
MyApp.Local.SomeWord gives me the appropriate version.
Thus i never use a displayed string anywhere in my code, always using MyApp.Local.Something...
Now obviously this wouldn't scale to 100 languages, but in my case i sometimes need multiple languages on one page, or switching between 2 languages in the middle of a workflow. If you don't need that, the ResourceBag could be replaced simply by an object of key/values, generated from the server. Problem solved.
The critical part is to centralize your strings in a file that can be swapped (or contain multiple languages, depending on requirement). Everything else is just case by case gravy.
-
30 Jul 2010 5:27 AM #6
First of all thanks for your advice.
So, if I'm not wrong, it should be enough to build somethign like this:
and having put this definition in each locale file (I need only a few locales) it is possible to substitute labels with a call toCode:var localeStrings = Ext.extend(Object, { attenzione: 'Attention', carica: 'Load', constructor : function() { Ext.ux.uirnet.localeStrings.superclass.constructor.call(this); } });
I have a limited number of custom labels (other than ExtJS built-in ones) so I think this wouldn't suffer any performance issue...Code:localeString.prototype.carica
-
30 Jul 2010 5:30 AM #7
localeStrings.carica would be sufficient. Why call the prototype? No need to extend object or anything either.
localStrings = {
foo: 'bar',
foo2: 'bar2',
}
Basically all you need to do is make a bag of constants and only load one such bag form the server.
My version was slightly more complex since i needed all the languages at the same time as well as ways to dynamically select them based on various factors
-
30 Jul 2010 9:01 AM #8
Could you make your I18n code available it would help to look it everything together.
Similar Threads
-
i18n with Ext.js: Resource Bundles!
By elmasse in forum Community DiscussionReplies: 29Last Post: 25 Jan 2013, 2:21 PM -
[UNKNOWN][3.0.0] Ext.form.DateField is not fully i18n
By 4him in forum Ext 3.x: BugsReplies: 0Last Post: 25 Nov 2009, 4:27 AM -
General approach for forms with variable fields
By BitPoet in forum Ext 2.x: Help & DiscussionReplies: 2Last Post: 8 Mar 2009, 11:07 PM -
Using TinyMCE as a field in an Ext Form - best approach?
By pianoroy in forum Ext 1.x: Help & DiscussionReplies: 4Last Post: 27 Sep 2007, 1:52 PM


Reply With Quote