PDA

View Full Version : Different languages/Translations



hotdp
22 Feb 2012, 1:12 PM
Hi,
The application I am developing for my work should be in 12 different languages.
So every button, tabbutton..... Has its own "text" depending on the language selected on the first view.


How do I solve this in the designer?

Phil.Strong
23 Feb 2012, 10:31 AM
We plan to add multi lang support further in the road map. We don't support it directly as of yet

hotdp
23 Feb 2012, 10:38 AM
We plan to add multi lang support further in the road map. We don't support it directly as of yet

Sounds good. But we have a lot of customers with the need for languages. So I need temp solution.

Any good advise? I did it in ST1 by having a object for every language, like danish.hello world give "hej".

But I don't see how I could set a text property to something else then a String in the Designer?

Phil.Strong
24 Feb 2012, 9:09 AM
Would have to be done after the fact outside of designer. You could use Designer to do it in one language and then use favorite text editor and find/replace tactics to replace the strings with objects

hotdp
24 Feb 2012, 11:04 AM
Would have to be done after the fact outside of designer. You could use Designer to do it in one language and then use favorite text editor and find/replace tactics to replace the strings with objects

I have to change the language inside the application. So the first view is a language selector and the language in the whole application should be the selected one.

My deadline is soon so I have to figure this out. If no one has any sugestions I might post my solution here. Language selection will be essential for many of our apps.

ssamayoa
24 Feb 2012, 6:27 PM
I have to change the language inside the application. So the first view is a language selector and the language in the whole application should be the selected one.

My deadline is soon so I have to figure this out. If no one has any sugestions I might post my solution here. Language selection will be essential for many of our apps.

Mmmmm...

I been thinking on such issue and the only solution you have is to write some sort of interceptor on constructor and/or initComponent() which read language resource, traverse the DOM tree and replace properties (label, title, etc.) of already instantiated views.

Regards.

pdm
28 Feb 2012, 9:26 AM
We need to be able to offer users customisable literals for everything.

So what we've done so far is to define a function in launch() like window.myapp.t() which takes a string argument and returns the corresponding string from an associative array defined in a localisation js file included earlier. So every time you need a literal (eg a label) you put myapp.t('thisform.thislabel')

I'd be interested to hear better suggestions and look forward to Sencha fully supporting translations.

hotdp
28 Feb 2012, 9:56 AM
We need to be able to offer users customisable literals for everything.

So what we've done so far is to define a function in launch() like window.myapp.t() which takes a string argument and returns the corresponding string from an associative array defined in a localisation js file included earlier. So every time you need a literal (eg a label) you put myapp.t('thisform.thislabel')

I'd be interested to hear better suggestions and look forward to Sencha fully supporting translations.

Can you do this in the Designer? I can only set text as Strings and not a function/object.

Phil.Strong
28 Feb 2012, 7:58 PM
No you can't do this in Designer.

you could do something clever like set all the components you need localized to a special cls like localizeMe and a 2nd cls to $localizeIndex.

then you could have a script that traverses the dom on application launch looking for all components that have .localizeMe and you could use the $whatever to lookup the correct text depending on localization. Include a different resource file depending on language.

...?

hotdp
2 Mar 2012, 3:02 AM
Hi,
Its going great with this feature. I just have one problem, Navigation View Title.
I would like to change the title on the toolbar title. But if i change config.title = foo; It will not be visible.
There is not set and get. What can i do?

hotdp
5 Mar 2012, 4:44 AM
Just to answer my one question:
You have to get the Navigation View, on that use
.getNavigationBar().titleComponent.getTitle() /setTitle('')

I can now translate my whole application with one button press: buttons, lists, placeholders, ect.

aconran
5 Mar 2012, 5:44 AM
I can now translate my whole application with one button press: buttons, lists, placeholders, ect.

Awesome!

editor
21 Mar 2012, 5:33 AM
that's great, but can you provide maybe simple more detailed example (newbie level) for this all together ...

ssamayoa
3 May 2012, 8:27 AM
I can now translate my whole application with one button press: buttons, lists, placeholders, ect.

Would you please elaborate a little bit?

Where you put your localization code?

At creation time?

Before render?

After render?

At which level?

Top views or each component is responsible of its own localization?

I'm starting a new application and I want at least two languages support (english and spanish) so any help you can give me will be appreciated.

Regards.

hotdp
4 May 2012, 6:18 AM
Would you please elaborate a little bit?

Where you put your localization code?

At creation time?

Before render?

After render?

At which level?

Top views or each component is responsible of its own localization?

I'm starting a new application and I want at least two languages support (english and spanish) so any help you can give me will be appreciated.

Regards.

Every component has a translation "key", typical the text. I will take this key look in my translation store (jsonp loaded at the start) if the store has the key I will replace the translation "key" with the value/text from the store for the given language code.
If it is a dynamic translation I will look it op when I create the component etc. none loaded buttons or titles.
getTranslation(key).
So I will do this for every component in the application. Its fast and works perfectly.
I hope this helps, let me know if I need to explain some things a little more.

ssamayoa
4 May 2012, 7:32 AM
getTranslation(key).


I was thinking on traverse the config object or the dom looking for fieldLabel, column items and any localizable property and look for the localizable value in a (key, value) object and if found set the value.

What I still dont know at which moment do this: beforeRender, afterRender, override initComponent, etc.

In which event/method you do the localization?

Thanks.

ssamayoa
4 May 2012, 2:55 PM
Never mind.

I been experimenting today and crafting a singleton class "Localizer" which receives an instantiated container (window for example) and looks for localizable properties on each children and if appropiate text found is replaced "a la gettext".

What I still dont decided is the way I should get and store the translatation text and if I should design my application in english or spanish since english text are normally shorter than any other language.

Regards.

hotdp
5 May 2012, 6:10 AM
I use "activate".
But I could use another but I have to be sure that some of the components are rendered.

ssamayoa
6 May 2012, 1:05 PM
I'm attaching a project which is my current test bed for Localizer class.

Is work in progress but I'm attaching so any interested can test it and make suggestions.

The concept is simple: to localize a component you just call Localizer.localize(component, locale). The class looks for localized strings in "locales" property and if is not loaded tries to load it synchronously from ./app/locale/<code>.json. Then for each component in the container looks for localizable properties and for each one looks for the equivalent.

I used gettext port for Delphi a few years ago so to easy the localization of messages inside code, Localizer class creates a global function called _().

I start to figure out how to get localizable values from project's metadata files then generate a file or database table to be used for translation.

Regards.



PD: Tried to upload XDA file but allways loader says "invalid file".

Phil.Strong
6 May 2012, 3:12 PM
sorry we know for now you have to zip up xda files. Going to put in a request to get these on the white list.

jturle
8 May 2012, 5:46 PM
I can't seem to get it working with the output from Sencha Architect... Has anyone had any luck? I'm using 2.0.0-beta3.

Cheers.

JT

ssamayoa
8 May 2012, 6:00 PM
What you mean?

Sencha Architect 2.0.0-beta3?

Sencha Architect is already released and current version is 2.0.o build 412.

m@rcello
9 May 2012, 1:16 AM
We plan to add multi lang support further in the road map. We don't support it directly as of yet

Hi Phil,
do you have a planned date for this feature?
Thanks,
Marcello

Phil.Strong
10 May 2012, 6:22 AM
There are no dates set for this feature. Others on the forum have come up with some pretty promising solutions however.

apsq
15 May 2012, 1:43 AM
Sencha obviously didn't develop the frameworks with I18N/translation in mind. Strings in component definitions are treated as strings (rather than, say, getters) and need to be set before the component is initialized and rendered; the text won't update automatically.

There are two ways to go about this really:

1. Static translation. You write a script which runs over the generated JS files and does a string replace (e.g. by using translation keys with a common prefix). You need to do this every time you export from ExtDesigner/Architect.

2. Dynamic translation. The strings are translated automatically as the components are initialized.

We have been going with approach #1 in a previous project. As Architect 2 now seems to generate the files on every save, however, we have been looking into a way to approach #2. We wanted to wait for Architect 2 because we were told translation would be addressed "soon", but apparently that's a stretch.

Here's what we did:

Every JS file generated by Architect applies the properties by calling Ext.applyIf. You can hook into that (assign Ext.applyIf to a private variable and assign a new function to Ext.applyIf that does some magic before calling the original) and iterate over the passed config object recursively, doing a pattern match on any strings you find. You will hit a recursion limit if you do this the obvious way (i.e. use recursion), so you need to work around that.

I think there may be cases where the configuration will be in what's passed to Ext.define or Ext.create itself, so you may need to override those, too.

I'm not entirely sure where to place this code as JS resource files added in Architect seem to be loaded *after* the application (i.e. when all the Ext.applyIf/etc calls have already been made), but I'm sure there's a way to sort this out.

All this wouldn't be necessary if Architect allowed inserting arbitrary code instead of strings because we could then simply put a function call instead of a string, but as Architect uses JSON literals to define components, I'm not sure this would be possible without breaking compatibility with the current XDS format.

In any case, keep in mind that the changes likely won't show up in Architect itself as you're applying these changes at runtime.

EDIT: Note that there are examples for I18N with ExtJS 4. They completely rely on implementing the translation on the server side or otherwise manipulating the application state before runtime. There is no way to change the locale at runtime without regenerating the entire DOM and possibly redefining various components. This behaviour is due to the way ExtJS was designed.

ssamayoa
15 May 2012, 10:07 AM
2. Dynamic translation


I would prefer dynamic translation "a la" gettext on already instantiated components.
This is more easy than post-processings generated JS files and allows you to change language at run time and (not confirmed yet) without the need of redefining components.

Look for a project I posted few weeks ago.

Regards.

apsq
15 May 2012, 11:32 AM
Here's my implementation for a function to apply a function to each and every property to an object recursively without running into recursion depth errors:



function convert(object, func) {
var
result = [],
visited = [],
input = [object],
temp;

while (input.length) {
// poor man's unrolled recursion
temp = input;
input = [];
Ext.Array.each(temp, function(object) {
if (!Ext.isArray(object) && !Ext.isObject(object)) {
// we don't want to touch any properties of things
// that aren't trivial data structures.
return;
}
Ext.Array.each(Ext.Object.getKeys(object), function(key) {
var value = object[key];
if (visited.indexOf(value) === -1 && !func(value, key, object)) {
value = object[key];
visited.push(value);
input.push(value);
}
});
});
}
}


You can supply a function(value, key, object) like such:



function func(value, key, object) {
var matches;
if (typeof value === 'string') {
matches = /i18n:(.+)/.exec(value);
if (matches) {
object[key] = _(matches[1]);
}
return true;
}
return false;
}


(I'm assuming your gettext equivalent is called '_' and you use a prefix of "i18n:" to mark strings that should be translated as Architect won't allow you to enter anything but strings where it expects strings.)

To apply it whenever applyIf is called, you can override the function:


var applyIf = Ext.applyIf;
Ext.applyIf = function(object, config) {
convert(config, func);
return applyIf(object, config);
};


Note that this will be executed only when applyIf is called. You could probably do the same to define and create for a more bulletproof solution. It's definitely not perfect, but I'm certain if the project is important enough, you know better than to copy code off the internet.

Anyhow, a real runtime translation is sadly impossible because ExtJS and Sencha Touch do a lot of magic to make things fast. Unless Sencha decides to rewrite both libraries for the benefit of internationalization over speed, it's unlikely we'll get "real" dynamic translations.

(EDIT: Above code is dual-licensed under WTFPL (http://sam.zoy.org/wtfpl/) or Unlicense (http://unlicense.org/), depending on which one you prefer. In other words: I waive all copyright where possible and grant unrestricted usage where not.)

devtig
19 May 2012, 11:36 PM
There are no dates set for this feature.

This doesn't sound promising to say the least. First requests for this feature date back to april 2010:
http://www.sencha.com/forum/showthread.php?97366-Localization
(http://www.sencha.com/forum/showthread.php?97366-Localization)http://www.sencha.com/forum/showthread.php?114644-xds-and-multilanguage-app

Responses from the Sencha development team made it sound like it was coming. At the time the Designer maybe wasn't ready, but now the Architect is totally ready for having multi language support.

charlez
21 May 2012, 9:07 AM
Replies: 27 (http://www.sencha.com/forum/misc.php?do=whoposted&t=182631)
Views: 1,545

Well this seems like about the most viewed and commented thread in the forum - and oddly enough I'm working on a multi-language app as well (who isn't these days?)

Would be great if this feature got priority :-D

aconran
21 May 2012, 10:19 AM
We're aware of the need and it's on our radar.

mcbl
22 May 2012, 1:53 AM
Oh yeah! We need i18n and l10n as quick as possible!

// For newbies:
var i18n = "internationalization",
l10n = "localization";

Svinja
24 May 2012, 4:15 AM
agree, we need this is as soon as possible, no rush though :D

Svinja
24 May 2012, 6:09 AM
I'm attaching a project which is my current test bed for Localizer class.

Is work in progress but I'm attaching so any interested can test it and make suggestions.

The concept is simple: to localize a component you just call Localizer.localize(component, locale). The class looks for localized strings in "locales" property and if is not loaded tries to load it synchronously from ./app/locale/<code>.json. Then for each component in the container looks for localizable properties and for each one looks for the equivalent.

I used gettext port for Delphi a few years ago so to easy the localization of messages inside code, Localizer class creates a global function called _().

I start to figure out how to get localizable values from project's metadata files then generate a file or database table to be used for translation.

Regards.



PD: Tried to upload XDA file but allways loader says "invalid file".

Thx for the code, this works great,it can localize whole app by calling:


Localizer.localize(this.up('viewport'));


Maybe it would be good idea to put this on git, in my opinion it is the best solution so far. I have found this also:
https://github.com/mitchellsimoens/Ux.locale.Manager
but i like Localizer better since it is simpler.

ssamayoa
24 May 2012, 6:36 AM
Thx for the code, this works great,it can localize whole app by calling:
Localizer.localize(this.up('viewport'));


Glad to heard that!



Maybe it would be good idea to put this on git


I been very busy with another project lately.
When I get some spare time I will do that.

Regards.

devtig
24 May 2012, 7:06 AM
I like Localizer better too, because the translation files are simpler compared to Ux.locale.Manager. I think translation files for Ux.locale.Manager are complicated beyond necessity.

Yeah, I have already made some improvements to Localizer. For example translating multiple times and translating to a baseLocale which resets the translation by getting data from initialConfig. And some more minor fixes. But those changes I only made local...

I would join the Localizer project on Github as a developer....

ssamayoa
24 May 2012, 7:30 AM
I would join the Localizer project on Github as a developer....


If you have enough time, please create the project and be the principal maintainer.

Just keep in the js file a reference to me as original contributor.

As soon as I can I will join the project.

Regards.

mcbl
31 May 2012, 5:36 AM
Please tell us here if you do so. Thanks!

devtig
4 Jun 2012, 12:29 AM
I have started the GitHub project for Localizer: https://github.com/devotis/Ext.ux.Localizer

It's contains now just a copy of what ssamayoa posted in this thread earlier (test1.zip). I have all my improvements integrated in a project. I need to isolate those improvements and also learn Git. I am used to working with Subversion. Give me some days and I hope to have my improvements on GitHub

Everybody happy with the name Ext.ux.Localizer?

thesilentman
4 Jun 2012, 3:07 AM
Great! Thanks for your effort!! (@ssamayoa & @devtig) :)

ssamayoa
4 Jun 2012, 6:52 AM
I have started the GitHub project for Localizer:

Excellent!

Regards.

devtig
11 Jun 2012, 3:39 AM
I'm done. My improvements:

Allow for language change after language change after language change etc.
Go back to original language using initialConfig
Localizable grid values through column renderers!
When components need tooltips, I usually add them as a tip property to the same component. That tooltip can be translated as well.
Prevention against word wraps after translation that I have seen occuring.
upgrade to latest build of SA (442)
Use ExtJS from cdn.sencha.io
renamed locale file to js, because IIS for example can't read .json files by default. (just to make it easy to test run this)
Most of my comments and changes are described in the commits and code. Code is mostly equal to what ssamayoa has posted (http://www.sencha.com/forum/showthread.php?182631-Different-languages-Translations&p=797073&viewfull=1#post797073).

This is work in progress and needs further optimization. Specially in the area of configurability.

Check it out, improve it and update it on Git . I will too. Thanks.

https://github.com/devotis/Ext.ux.Localizer

thesilentman
11 Jun 2012, 3:43 AM
Awesome!! As soon as I find a minute I'll check it out. Thanks!!

ssamayoa
11 Jun 2012, 4:28 AM
Excellent!

Regards.

Zeigon
15 Dec 2012, 8:46 AM
Hi, it's already been a little while since the last reply to this post but I'd like to share what I did in this regard (Localization) with my project.

I started referring to all the localizable strings by a variable name:


var header = Ext.create( 'Ext.TitleBar',
{
id: 'header', docked: 'top', title: titleName, cls: '', html: htmlHeaderContent
});

And then I created a file for every language in the application with the translations:



//file eng_us.js
var titleName="English title";
var htmlHeaderContent="Html content in English";

//file spa_es.js
var titleName="Título español";
var htmlHeaderContent="Contenido en español";


Then in the html file I can either check the language of the browser, or create a language selection screen, and decide which file to load.

I find this way pretty easy to use and maintain.

Dumas
15 Dec 2012, 11:28 AM
Hello,

the basic concept is quite good, but you are poluting the namespace by defining lots of global variables, this is not good. So I would recommend you the above posted solution using the Localizer.

Best regards,
Roland

devtig
15 Dec 2012, 12:10 PM
The namespace pollution alone is not a valid argument to use Localizer. He might as well use Ext.translations.titleName="Título español";

ssamayoa
15 Dec 2012, 12:14 PM
The namespace pollution alone is not a valid argument to use Localizer. He might as well use Ext.translations.titleName="Título español";

Yep.

But Localizer is meant to be use with existing applications and with applications crafted with Sencha Architect.

Regards.

devtig
15 Dec 2012, 12:26 PM
Yes, I agree. I still use Localizer with projects I create with Sencha Architect today.

Dumas
15 Dec 2012, 1:38 PM
Yeah, this is true. I keept my explanation a little short. I didn't wanted to specifically recommend Ext.ux.Localizer, I wanted to recommend the concept of a localizer.

I believe it's a more elegant way to have a text file which maps english strings to localized strings instead of using variables. This is a common an very successful pattern. You might want to look at gettext (http://en.wikipedia.org/wiki/Gettext). There are many implementation of this in other languages, e.g. CakePHP has its implementation, and also JavaScript has multiple implementation, e.g. Jed (http://slexaxton.github.com/Jed/).

Since I'm using CakePHP as a backend I have my own implementation in Bancha. I have a shell task which collects all translatable strings and writes them all in a pot file (A catalog of all translatable strings, supported by a lot of fancy translation tools). When I then open my WebApp the localizer pulls the correct language translations, afterwards each call of Banacha.t('Hello %s, good to see you', name) will be translated and returns the localized version.

Besides the advantage of having very readable code and having good tools to update and manage translations over time, I'm able to outsource specific translations.

Best regards,
Roland

Phil.Strong
17 Dec 2012, 6:04 AM
Sencha Architect 2.2 (coming soon) will include a new feature called process config.

This allows you to integrate ideas like Localizer much more easily. More details to come from the author of this feature.

The One
18 Dec 2012, 1:02 AM
Sencha Architect 2.2 (coming soon) will include a new feature called process config.

This allows you to integrate ideas like Localizer much more easily. More details to come from the author of this feature.

Wonderful. Worth the two year wait I guess. Can't wait to hear more.

Zeigon
20 Dec 2012, 10:39 AM
In my opinion, using a localization system with the English (or any other language) translation as the key of the translations file is wrong. I'm all for string keys with generic names that make life easier and (among other things) don't bloat the files with unnecessary text . Like in Android and, as far as I know, unlike in iOS, which also uses translations as keys.

Looking at the code of the Localizer class, the format of the locale files could be changed to something like <ComponentID>.<PropertyName>, i.e.:

//en.js
{key: "buttonBrowse.text", value: "Browse..."},
{key: "buttonBrowse.tooltip", value: "Browse for a file."},

//es.js
{key: "buttonBrowse.text", value: "Explorar..."},
{key: "buttonBrowse.tooltip", value: "Elige un archivo."},


So you could continue iterating through the localizable properties but instead of checking for the English string you would do it exactly for the element and property that you want. You could even implement a fallback method where in the case that you couldn't find a translation in a certain locale (replace==null) you could still use the English text as a last resort. This might require to load the English strings no matter what the current locale were or implement some kind of on-the-fly string loading, although I don't think this would be necessary.

ssamayoa
20 Dec 2012, 10:58 AM
In my opinion, using a localization system with the English (or any other language) translation as the key of the translations file is wrong.

Could be but Localizer is, as I said, for all those exiting applications which must be translate without too much coding or for those generated with *CURRENT* version of Architect.

Regards.

Zeigon
20 Dec 2012, 11:17 AM
Well, I was just saying because now that someone took the time to create this class, github project, etc. to share the Localizer with everyone, maybe we could all contribute with some ideas that might improve it. Besides, now that the big effort is already made I don't think it'd require too much extra coding.

ssamayoa
11 Apr 2013, 12:38 PM
FWIW, after almost a year I wrote the original code, I will start to use Localizer.

Regards.

franklt69
29 May 2013, 11:20 AM
Hi I was playing with this component https://github.com/devotis/Ext.ux.Localizer and work ok, but I added a container, in the html properties set "hello"

en.js
{key: "hello", value: "hello container"}

es.js

{key: "hello", value: "hola contenedor"}

and in Ex.ux.Localizer.js I added



localizableProps : {
....
image: ["src"],
container: ["html"]
},

but not work, am I missing something to added a new xtype to localizable list?

regards
Frank