Flex Localization

I wanted to continue to play with a little fun project which I localized for three languages but my compiler showed me the error:

unable to open ‘/Applications/Adobe Flex Builder 3 Plug-in/sdks/3.0.2.2113/frameworks/locale/de_DE’

Hmm, this formerly worked so what changed? I changed the SDK to 3.0.2.2113 to upgrade to AIR 1.1 and all framework resources except default en_US are not part of the SDK and have to be created.

So here a little step by step tutorial how to enable localization from scratch with a new SDK. My reference for Flex localization is the article on Adobe Labs written by Gordon Smith which covers all necessary informations and is written in a funny style which I like a lot.

Create Framework Resources

  • Open a console/terminal and change to the Flex SDK directory. In my case /Applications/Adobe Flex Builder 3 Plug-in/skds/3.0.2.2113
  • Execute this command ./bin/copylocale en_US de_DE where you can replace de_DE with the locale you want to have in your app. After executing the command you see a lot of output on the console which gives you an overview what happens behind the scenes. Repeat this step for each locale you want to add.
  • When you look into SKD_DIR/locale/de_DE you should now see the three new files airframework_rb.swc, framework_rb.swc and rpc_rb.swc where “rb” is short for resource bundle.

Setup Flex Project

  • Open Flex Builder and create a new Flex project
  • Create the directory locale as a project subdirectory
  • Create the directories en_US and de_DE
  • Create the file myResources.properties in locale/en_US and locale/de_DE
  • Add this line to the english property file: Hello=Hello
  • Add this line to the german (de_DE) property file: Hello=Hallo (Note in german it is different with “a”)
  • Change the project compiler settings (right-click Project->Properties->Flex Compiler) and change the additional compiler settings to -locale en_US de_DE -source-path+=../locale/{locale}

Code with resource bundles in MXML or ActionScript Class

  • Open the main MXML src/YourProjectName.mxml

Now you have got two ways to include the localized string:

  1. <mx:Label text="@Resource(bundle='myResources', key='Hello')" />
  2. <mx:Label text="{resourceManager.getString('myResources', 'Hello')}" />

The first option uses the compiler directive @Resource and runs out of the box. The second option does not give a compiler error but when you test the application you see no text appearing. This is because data binding is used which only evaluates at runtime. To tell the compiler upfront that we need the resource bundle myResources we have to add a Metadata tag and declare the resource bundle:

<mx:Metadata>
[ResourceBundle("myResources")]
</mx:Metadata>

You can also declare this in an ActionScript class like this:

[ResourceBundle("myResources")
public class YourClass{...}

You can also use the resource metadata brackets in ActionScript classes:

[Resource(bundle="myResources", key="Hello")]

or use the ResourceManager singleton:

ResourceManager.getInstance().getString("myResources", "Hello");

Using Placeholders in Strings

Often you have to locate strings where parts have to be replaced by variables. Placeholder can be defined like this:

Welcome=Hello {0}!

As you want to replace the {0} with a variable this only works at runtime so you have to use data binding:

<mx:Label text="{resourceManager.getString('myResources', 'Welcome', [userObject.username])}" />

The third argument of getString is an Array of parameters where each index corresponds to the placeholder index so you could have a string like Foo=Hello {0}! The time is {1} and you have {2} new emails.

Multiline Strings and Comments

You can define multiline strings with “\” (backslash on OS X is alt+shift+7). Comments in a property file start with a #:

# this is a comment
MyText=Here is a text written
in two lines

HTML

There is also nothing to say against using HTML:

MyHTMLText=Here is <b>bold text</b>.
<mx:Label htmlText="{resourceManager.getString('myResources', 'MyHTMLText')}" />

Switch Locale and Fallback

Switching the locale depends on whether you have use the compiler directive @Resource or data binding. The easier thing is data binding because you can switch with one line of code:

 resourceManager.localeChain = ["de_DE"];

As you see localeChain is an Array so you can define it like this:

 resourceManager.localeChain = ["de_DE", "en_US"];

In this case first de_DE is looked up and when the key is not found the fallback is english so you show at least something up.

When it comes to the static implementation with @Resource the switch is a bit more difficult and also explained in the wiki article. There you have to compile the resource bundles via console to SWF and load them at runtime.

Use Resource Bundles for Code/Content Separation

I recommend to use resource bundles also if you do not localize your application. The separation of code and content will at least be beneficial when for instance someone has to review all text and you simply have to hand over property files instead of several MXML classes …

Links

So far! These are the most basics for localization I hope. For more detailed information check the first link to Adobe Labs which covers all in detail. But there is much more possible which I did not cover like not using strings but to localize images or even classes but enough for now.

20 comments to Flex Localization

  • […] would have been a dead-end for me but for the useful blog I found surfing the […]

  • Joe

    I keep loosing this post, and then always find it for each locale… for me the thing I forget to add do is : ./bin/copylocale en_US xx_XX

  • loco

    Hi, I setup everything according to your tutorial, and it still doesn’t work. It stays on whichever locale was the first one when the application runs. Even if I try to explicitly call the separate locales like so:

    resourceManager.getString(‘myResources’, ‘GREETING’, null, “de_DE”)
    resourceManager.getString(‘myResources’, ‘GREETING’, null, “en_US”)

    the result is always the English version. Do you have any idea about what could fix this?

    Thanks you very much.

  • vijay

    Hi, Hope u did not set the additional compiler settings
    -locale en_US de_DE -source-path+=../locale/{locale}

  • johans

    Just came across your FlairLoc AIR application – nice work!

  • fred

    Hi, nice tutorial but i think you did a mistake here:
    “The first option uses the compiler directive @Resource and runs out of the box. The second option does not give a compiler error but when you test the application you see no text appearing.”
    Actually, I think it is the opposite.
    I cannot get the @Resource working. But the other one works on my tests from Flexbuilder.

  • Sonke,

    I created an l10nInjection Localization framework that is open sourced on GitHub. This framework provides an amazingly easy solution to “adding multi-language support to Flex RIAs” and works within any Flex (2, 3, and 4) application to inject [at runtime] localized resources into any view, data model, or controller. Best of all, it does this transparently WITHOUT any changes to the original source. Not only text but skins, bitmaps, data – localized for the locales of choice – can be injected. Viewstate changes, deferred creation policies, Flex 4 skinnable containers, and more are all supported.

    This framework works transparently and in parallel with application frameworks such as Swiz, RobotLegs, Cairngorm, and Mate. Below are some links that may be of interest to you:

    * “Framework Source Code at GitHub
    * l10nInjection Samples and Source
    * Blog Articles and Tutorials

    Your FlairLoc is very interesting in that it parses source code to build properties files. But it modifies the source code to use the ResourceManager. As my blogs illustrate that solution is not ideal nor maintainable. The l10nInjection would be a perfect extension to FlairLoc. Instead of modifying the view source code, you could create a LocalizationMap… 1 new class file to do all the work of runtime changes to the GUI, models, and controllers.

    – Thanks,
    ThomasBurleson

  • Anthony

    Hi

    Thats a nice article. I am having some issues with an Adobe Air application which implements localization.

    There is a combo box through which, the user selects the language. On selecting the language, the appropriate property files are loaded and the application updates itself to display the text in the selected language. However, one label which alternates between two values , simply does not update itself instantaneously. It requires an application restart.

    Has anyone of you come across a similar problem? Any help would be appreciated.

  • There could be lots of reasons. How does the code for that label look like?
    If it does not use data binding with resourceManager or does not listen for the locale change that is the issue.

  • Anthony

    The code looks as below, basically conditional data binding using the resourceManager I believe.

    if (condition A){
    Lbl.text = resourceManager.getString(‘resource’,’value1′);

    } else{
    Lbl.text = resourceManager.getString(‘resource’,’value2′);
    }

  • I guess the code is not executed when the locale changes so you should add an event listener to do so.

  • Elena

    The code looks as below, basically conditional data binding using the resourceManager I believe.

    if (condition A){
    Lbl.text = resourceManager.getString(‘resource’,’value1′);

    } else{
    Lbl.text = resourceManager.getString(‘resource’,’value2′);
    }

    Sönke

    I guess the code is not executed when the locale changes so you should add an event listener to do so.

    Hi Sönke, Anthony,

    I am having the exact same problem, I am trying to create an eventListener on the component that causes the condition, but no luck. Any hints will be much appreciated :)

  • Neo

    Nice article! Thanks for mentioning placeholders or how to pass parameters to resource string. I couldn’t find it elsewhere.

  • Wimmerke

    hello,

    I’ve set everything up and it works fine.

    But when I create a PHP webservice and try to run the application, I get the following error:
    “Unable to open ‘c:\Program Files(x86)\Adobe\Adobe Flash Builder 4.5\eclipse\plugins\com.adboe.flexbuilder.project.nl1_4.5.1.313231\nl\en_US nl_BE fr_BE de_DE\dcradSwcs\4.5\locale'”

    When I retrieve the compiler addition: no errors (without customized localization, non standard out of the box supported).
    When I retrieve the service created: no errors.

    Can anyone please help me on this one? Really stuck for 2weeks now….

  • All locales you are using have to be created when they are not in SDK/frameworks/locale already.
    You can see how it works on the very top where I talk about bin/copylocale.

  • namG

    I did all above mentioned steps for localization for en_US using RegistrationForm as property file but getting error like –
    Unable to resolve resource bundle “RegistrationForm” for locale “en_US”
    any one suggest solution?

  • Did you add locale/{locale} to your source path?
    And did you force compilation of the locales with the ResourceBundle metadata?

  • namG

    thanx a lot sonke.

  • amine

    i have a problem in displaying arabic text in Alert.show method of flex 3 so kindly tell me the procedure of displaying arabic text in flex 3