The First and Only Magazine for Macromedia MX™
   
 
Notes from the Flash, Flex and ColdFusion trenches

Category List

Quick Poll

Where are you located?
North America
South America
Europe
Asia
Africa
Australia

My RSS Feeds








Hit Counter

Total: 1,305,972
since: 20 Jan 2005

Search Box

 

Search The Web

Google

MAX 2008

Fun Stuff

Mailing List

Got A Question?

Got A Question?

Leave a comment by the appropriate Entry, or email me

Tag Cloud

                                                                                                                       

Internationalizing Flex 2 Apps Pt 2

posted Friday, 13 October 2006

As the 2nd part of my 3 part series on internationalizing Flex Applications, this article will explore the use of multiple instances of the ResourceBundle class to allow for run time switching of locales.  As you may recall from the first article on this subject, the native use of the ResourceBundle class requires separate compiled swfs for each language.  This is not always desirable, and there are times when you may want to allow for switching of languages at run time.  One strategy I've used successfully for this is to trick the flex compiler and have several different properties in the same locale folder, and to create separate instances of the ResourceBundle class for each of them.  This way, its a fairly simple process to determine what the current locale is, and to pull the labels from that ResourceBundle.  To start, I took 3 properties files and placed them in a single directory. 


Here is a simple example of how to get it working:


<?xml version="1.0" encoding="utf-8"?>
<mx:Application xmlns:mx="http://www.adobe.com/2006/mxml"
 layout="vertical" creationComplete="doLangChange()">
 <mx:Script>
  <![CDATA[
   import mx.formatters.DateFormatter;
  
   import mx.resources.ResourceBundle;
   [ResourceBundle("helloWorld_us")]
   private var rb_us:ResourceBundle;
   [ResourceBundle("helloWorld_uk")]
   private var rb_uk:ResourceBundle;
   [ResourceBundle("helloWorld_fr")]
   private var rb_fr:ResourceBundle;
   [Bindable]
   private var today:Date = new Date();
   [Bindable(event="langChange")]
   private function geti18nText(key:String):String{
    return this["rb_"+lang.selectedItem.lang].getString(key);
   }
   [Bindable(event="langChange")]
   private function geti18nDate(dt:Date):String{
    var formatter:DateFormatter = new DateFormatter();
    formatter.formatString = geti18nText("dtformat");
    return formatter.format(dt);
   }
   private function doLangChange():void{
    var e:Event = new Event("langChange");
    this.dispatchEvent(e);
   }
  ]]>
 </mx:Script>
 <mx:DateFormatter id="smeNme" formatString="MM/DD/YYYY"/>
 <mx:ApplicationControlBar dock="true">
  <mx:ComboBox id="lang" change="doLangChange()">
   <mx:dataProvider>
    <mx:Object label="US English" lang="us"/>
    <mx:Object label="UK English" lang="uk"/>
    <mx:Object label="French" lang="fr"/>
   </mx:dataProvider>
  </mx:ComboBox>
 </mx:ApplicationControlBar>
 <mx:Label fontSize="50" text="{geti18nText('hello')}"/>
 <mx:Label fontSize="50" text="{geti18nText('welcome')}"/>
 <mx:Label fontSize="50" text="{geti18nDate(today)}"/>
</mx:Application>

I named each file based on the language it was there to support (helloWorld_fr.properties, helloWorld_uk.properties, helloWorld_us.properties).  Notice that there is ResourceBundle instance for each of the three files.  I've also added some simple functions to get the data from these files (geti18nText, geti18nDate).  Bare in mind, this is a simplistic example.  In real world apps, I tend to have a singleton responsible for embedding and retrieving the data from the files.  But, even in this simple case, you can see the power of it, as simply switching the selected language in the combo box instantly translates the labels and dates to the appropriate format.


Remember to add a compiler argument to specify the proper directory for the locale files.  In my case, all three files where in a locales/multi directory, so i added the argument:  -sp ../locales/multi


 

tags:            

links: digg this    del.icio.us    technorati    reddit




1. deep left...
Tuesday, 12 December 2006 1:55 am

I tried but it picks up only one resource (us only) what could be the problem. When clicked to French, it displays blank entries


2. Laurent left...
Thursday, 8 February 2007 11:43 am

Nice but selecting french will still display month names in english (January instead of Janvier).


3. Carlos Corredor left...
Thursday, 8 February 2007 2:02 pm

deep/Laurent, I have had similar problems and almost gone crazy with the Flex documentation, but have managed to work a lot of them out.

The Flex SDK 2 installation gives you only one locale, “en_US”.

For French, for example, try the following:

Make a copy of the ‘C:\Program Files\Adobe\Flex Builder 2\Flex SDK 2\frameworks\locale\en_US’ (or whatever your path is) folder and name it fr_FR. Now you have two locales in your locale folder.

In that new folder, edit ‘SharedResources.properties’ and ‘formatters.properties’ – translate the month names to French. Now it should work.

In these files, you may also want to modify other items, such as currency, phone number and date formats – and, after you get this working, you may want to modify other files; just inspect them all and what you want to translate/modify will be obvious.

BTW, for you and anyone else who works with resource bundles, here is a great Resource Bundle Manager: http://www-306.ibm.com/software/globalization/icu/rbmanager.jsp; it’s a Java application called “RB Manager” that comes with its own tutorial and it’s FREE! I have found it very useful.

I am no expert at any of this, but will be glad to help, if I can. Just post here or contact me directly.

Carlos Corredor carlos@timos.com


4. Jeff Tapper left...
Thursday, 8 February 2007 2:24 pm :: http://jeff.mxdj.com

Carlos -

thanks for pointing that out.

Laurent - the internal names used by the Flex Framework are not part of the structure I set up, but are based on more resource bundles, which are included. The suggestion from Carlos should solve your problems here.


5. Carlos Corredor left...
Thursday, 8 February 2007 3:07 pm

Hello, Jeff:

I tried your example on locale switching at runtime and it works fine. I have an project coming up that will use some Custom Components, but I’m having a hell of a time getting ‘geti18n Text(key:String)’ to work anywhere except in the main MXML Application.

I think that you might be able to tell right away what I am missing. You can see exactly what my problem is here: http://www.adobe.com/cfusion/webfo rums/forum/messageview.cfm?forumid=60&catid=582&threadid=1238407&enterthrea d=y (this is in the Adobe Flex Forums, so far no results). In my little test project, I have modified the function like so:

public function getKeyText(key:String):String { return this.getString(key); }

If you have time, I would really appreciate your taking a look and giving me some kind of hint.

BTW, I learned recently from your blog about the availability of Flex TFS and am actively studying it now. Beautiful, thank you very much!

Carlos


6. Carlos Corredor left...
Saturday, 17 February 2007 1:03 pm

Jeff (or anyone who can help, pleeease say something):

Referring to my above February 8 comment, I still have not been able to make a function defined in the main app to also work in Custom Components. I was hoping to get the answer by thoroughly studying the chapter on Creating Components with MXML in the TFS book, but no luck.

In Jeff’s code, the function is called ‘geti18nText’; in my code, it’s ‘getKeyText’. It works fine when used in the main MXMl app, but not when used in a Custom Component. I have tried the following:

In the component: text="{outerDocument.getKeyText('theKey')}" text="{parentApplication.getKeyText('theKey')}" text="{parentDocument.getKeyText('theKey')}" text="{Application.application.getKeyText(' theKey ')}" In all above, no compiler error or warning, but the text does not show up on the Custom Component – it does appear in the main app.

In the main MXML app, within the customXmlns:cutomComponent tag: rb_en_US = "{rb_en_US}" rb_es_CO = "{rb_es_CO}" I get a compiler warning: ‘Data binding Hill not be able to detect assignments to “rb_es_CO”’ (and “rb_en_US”). The text still does not display.

What else to do?

Carlos


7. Carlos Corredor left...
Monday, 19 February 2007 3:06 pm

Jeff, just so you have a little more info on this, here is what I have just posted in the Adobe Flex General Discussion forum:

OK, peterent – et al:

I was away from this for a few days, but now I am back trying to make it work. I tried the ‘trace’ statement, as you suggested on 2/5 and the result was what I expected: the keys on the main app show up, but not the ones in the component (not even the literal part of the trace).

The present state of the relevant code is like this:

In the main app (this works as expected):

import mx.resources.ResourceBundle;

public var rb_en_US:ResourceBundle; public var rb_es_CO:ResourceBundle;

public function getKeyText(key:String):String { var theKeyText:String = this.getString(key); trace("This key = "+theKeyText); return theKeyText;

  • }

public function doLangChange():void{ var e:Event = new Event("langChange"); this.dispatchEvent(e);

(‘lang’ is the ID of the ComboBox where you select the language)

Function call example: <mx:Text htmlText="{getKeyText('p1')}" />

In the component (nothing displays):

Function call example: <mx:Text text="{parentApplication.getKeyText('p1')}"/> NO compiler error.

So, pleeease, what next? Thanks,

Carlos


8. Carlos Corredor left...
Thursday, 22 February 2007 1:14 pm

Hello, Jeff

This is again about the code not working in a Custom Component (see my above posts).

Upon my first reading of Lesson 8 in TFS, I found your note about accessing properties of the top-level application (page 213).

So now, instead of “text="{Application.application.getKeyText('p1')}”, I tried

“text="{mx.core.Application.application.getKeyText('p1')}”.

It still does not work in the Custom Component.

Do you think this has something to do with the fact that, as you say in your code you “trick the Flex compiler”?

Any light on this subject would be greatly appreciated.

Carlos


9. last blade left...
Tuesday, 22 May 2007 1:20 am

A great example. A little question, where I can get the property file? Thanks


10. Carlos Corredor left...
Tuesday, 22 May 2007 8:25 am :: http://www.timos.com/blog

last blade, look at comment #3 above


11. Moes left...
Wednesday, 13 June 2007 7:23 am

Carlos have you tryied to use an event listener in your custom component to broadcast (and listen) any change in language ??? Perhaps, have you already find an answer to your question ?


12. Carlos Corredor left...
Wednesday, 13 June 2007 11:55 am :: http://www.timos.com/blog/

Thank hyou, maudinet:

Recently, I figured out that the event listener is the way to go, What I have not figured out is how to implement it – I have to take the language change out of the ‘function geti18ntext(key)’ – maybe create a new function? - because I cannot have that ComboBox in the main application AND also in the custom component(s).

Please remember I am new at this, I am just learning ActionScript. If you have any suggestions on how to implement the above, I am all ears.

Carlos


13. Moes left...
Thursday, 14 June 2007 2:28 am

Hi Carlos,

I'm working right now on such problem and I guess I've found something.

The main idea is to create a new static object (I create myself a singleton) which will access data in the resource bundles. This object will listen to events brodcasted by components and return String variables (or array of Strings) which contain translations

So, I create myself a class called staticlanguage defined as a singleton (see here http://www.tricedesigns.com/tricedesigns_home/blog/2006/09/single ton-in-as3.html) then defined a getter/setter to know which language is needed. And finally use the geti18nDate function to set translation.

Hope it will help

Moes aka maudinet


14. Carlos Corredor left...
Thursday, 14 June 2007 10:50 am :: http://www.timos.com/blog/

maudinet, thank you for replying. You are probably on the right track: Jeff Tapper mentions that, in real-world apps, he uses a singleton to handle the data. The problem with me is I am so green at this, that ‘singleton’ might was well be a Chinese character; I am barely beginning to understand what getter/setters are, and I imagine I’ll get to the singleton part in due time.

But if you come up with something that works and don’t mind sharing it, I will certainly study it.

For now, I am going to check out Flex 3. I heard some time ago that they planned to support runtime language switching.

Thanks again,

Carlos


15. Moes left...
Monday, 18 June 2007 2:56 am

Ok no problem, I will let you know as soon as I've got something that works. See you then.


16. yoann left...
Wednesday, 11 July 2007 10:23 am :: http://flexme.wordpress.com/

based on this solution, I made a tutorial on how to get this to work with singleton etc ... :

http://flexme.wordpress.com/2007/07/11/internationalization-in-flex/


17. Dave left...
Wednesday, 12 September 2007 12:51 pm :: http://www.mifdesign.com

Thanks for this example. It is very helpful