Rich Rodecker’s blog on flash, flex, actionscript, javascript, and php, with a dash of randomness
Flex localization with Resource Bundles
Working with resource bundles in Flex is (surprise, surprise) relatively easy and pretty cool. They're a great way to separate content from code and localize your flex apps. You have the choice to either compile the different locales statically into the app, or load them dynamically using the ResourceManager.
Adding support for different locales
First thing you need to know is that, Flex techinically doesn't support most locales right "out of the box". In order to support more, it needs to create a bunch of framework resource SWCs for each locale you want to use. This is really easy though. There is a command-line utillity called copylocale that will handle creating those for you...all you need to do is tell it which locale you want to create. Pop open a terminal and navigate to your flex SDK directory, and run this command, substituting "fr_FR" for the locale you wish to create:
./bin/copylocale en_US fr_FR
This will generate all the asset files the framework needs. You're done with this part.
Adding resource bundles
To add resource bundles, there are a few steps you need to follow. Each step will be discussed further below:
- Create a source directory in your project for each locale you wish to use. Normally, it would go something allong the lines of src/locale/en_US, src/locale/en_GB, etc.
- Create a properties file that will contain the resources to be localized. This property file is a simple text file containing key/value pairs. Mostly it's going to contain strings to be localized, but can also contain ClassReferences and Embedded assets, just like a style swf.
- If you want to compile all the locales into the app, update the compiler settings to include the locales and source paths into the app.
- If you would like to load the additional locales on demand, create a resource swf to be loaded in by calling ResourceMananger.loadResourceModule().
Creating the properties file
The properties file is what the compiler uses to make the resource bundle. In fact, the compiler parses that file and creates a subclass of ResourceBundle for use in the app. It is made up of simple key/value pairs:
mytitle=Title
myothervalue=This is some other text we want to localize
You don't enclose the strings in quotes, and any whitespace before the value is trimmed (which is great for keeping your properties file nice and neat). Whatever you name the file will be the name of the resource bundle: a file named "strings.properties" becomes the "strings" resource bundle in the app. One important note, the text file must be encoded in UTF-8.
Telling the flex compiler which bundles to include in the app
In order for flex to know which resource bundles you plan on using in the app, you need to explicitly tell it using metadata tags. In mxml it looks like:
-
<mx:Metadata>
-
[ResourceBundle("strings")]
-
</mx:Metadata>
and in actionscript it looks like this:
-
[ResourceBundle("myResources")]
Specifying which locales to compile into the app
If you are going to statically compile all the locales you want to use in the app, you simple add a couple of compiler options:
-locale=en_US,fr_FR -source-path=locale/{locale}
if you get a warning about the source path overlapping after changing those options, you can also add the compiler option -allow-source-path-overlap=true.
Now when you compile your app, flex will create resource bundles for each of the locales.
Creating resource modules to dynamically load in
If you would like to load different locale bundles on the fly, you need to comile swfs for each locale. Unfortunately, you cannot do this within Flex Builder, you must use the command line. Luckily, this is also easy, though it is a two step process.
First, we need to find out exactly which bundles to include into the module swf. The way we do this is by compiling our app with no locale specified, and including the compiler option -resource-bundle-list:
mxmlc -locale= -resource-bundle-list=myresources.txt MyApp.mxml
Note that the above example using the command line, but you can do this part in Flex Builder by adding additional compiler options under the project preferences (Flex Compiler > additional compiler arguments). Now when you compile the app, a text file will be output that contains a list of bundles to include in the module:
bundles = strings collections containers controls core effects skins styles
Note the "strings" bundle. Flex knew to include this because we specified it in the metadata.
What do we do with that list? That's the second step. We go back to the command line, and use that list as part of a the -include-resource-bundles compiler argument when we compile the module swf. Open a terminal window, navigate to your projects directory, and use the following command:
mxmlc -locale=en_US -source-path=locale/{locale} -include-resource-bundles=strings,collections,containers,controls,core,effects,skins,styles -output en_US_resources.swf
You can customize the -output file name to your liking, and be sure the -source-path arguments points to the directory which contains the properties file. Repeat this step for each locale you want to compile, changing the -locale and -output options accordingly.
Using the resource bundles
Using the resource bundles is pretty easy. Wherever you want a string localized, you can do two things:
If you plan on only localizing once when the app starts, you can use the @Resource() compiler directive wherever you want to use the text. You simply pass the name of the resource bundle, and the key which you wish to use:
-
<mx:Label text="@Resource(bundle='strings', key='mytitle')" />
If you plan on dynamically updating the content during the life of the app (for example, allowing the suer to set the locale), you can use bindings and the ResourceManager singleton to specify the strings:
-
<mx:Label text="{resourceManager.getString('strings', 'mytitle')}" />
When using bindings, the value of the string will be updated once you set the ResourceManager.localeChain property, which is an array containing the locales to use, in cascading order. For example, if you specify ['fr_FR', 'en_US'], the ResourceManager will first look for the key in the fr_FR bundle. If that key is not found, it will use the key from the en_US bundle instead. You can use just a single locale in the array if you wish.
Loading additional resource bundles
Again, pretty simple. you can use ResourceManager.loadResourceBundles() to load the resource module swf containing the new locale. One that locale is loaded, you can set the ResourceManager.localeChain property to use the new locale.
For some additional info, the Runtime Localization article on Labs is a great resource. Also see:
http://www.herrodius.com/blog/123
http://soenkerohde.com/2008/07/flex-localization/
http://hillelcoren.com/2008/09/12/resource-bundles-in-flex-wo-lots-of-extra-code/ ( for a nice ResourceManager utility class)
| Print article | This entry was posted by rich on July 3, 2009 at 12:52 pm, and is filed under Flex. Follow any responses to this post through RSS 2.0. You can leave a response or trackback from your own site. |
about 3 years ago
Hi,
Nice post
I just wanted to let you know that I released an AIR app, Lupo Manager, which basically takes care of the whole i18n process :
http://www.dehats.com/drupal/?q=node/81
about 3 years ago
sweet, I was thinking about doing something similar. I'll check it out
about 3 years ago
Hi,
I want to load a property file dynamically and create a resource bundle. is there any way for this..??
I know we can use resourceManager.loadResourceBundle(), but it's to load swf file... similarly is there any approach for .property or .xml file...?
I'l b thankful for any kind of help
about 3 years ago
I am pretty sure I remember seeing that you could do that, but I don't remember where. I'd check the docs.
about 3 years ago
yeah, here: http://livedocs.adobe.com/flex/3/html/help.html?content=l10n_6.html
about 3 years ago
Thanks for reply,
This i have already seen, here data is there in the application or u get through urlloader or something froma file and then create your own resource bundle.
but what i want is that flex itself load my property file and create resource bundle like it does for .swf files.
about 1 year ago
nice post on flex localization