Internationalizing Flex 2 Apps Pt 2
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
