22 November 2010
Intermediate
Localization is the process of preparing your Flex application—or any application—for international use. Because of this, it is an obvious keystone feature for any application with a global audience. Flex has a very powerful localization framework, which enables you to implement localization easily and efficiently through the use of simple text-based properties files. These properties files must be loaded into your application before they can be used, which is commonly done in one of two ways:
This article covers the first (and simpler) option by stepping through the localization process for a basic Flex application. I'll cover the second method in Part 2 of this series.
Localization is a very important feature for any application intended for a global audience. It can seem like a daunting task, but with the help of the localization features in Flex, you will see how easy it can be. To illustrate the process, this article will step through the localization of a very simple Flex application. For the sake of brevity, I've included a starter project that you can use (localization-part-i-start) as your base. It is a simple Flex contact form with a handful of localizable fields, such as "Name", "Street Address", and so on. It also includes a drop-down menu that can be used to change the language (although at the start of this exercise, it doesn't work yet). Starting with this seed project, you can follow the steps in this article to localize it, even enabling language changes at run time! But, before you dive into the example, it will help to understand the process as a whole.
There are essentially four tasks that must be completed before your application can be localized:
The first two steps involve setting up the application so that your properties files are accessible and ready to be used. The third and fourth steps ensure that your application will get compiled properly by including the newly created properties files and using the appropriate compiler flags and localization framework files. Once this is done, your properties files are compiled into resource bundles. Resource bundles are available for use by your application via the Flex ResourceManager class. After that, all that's left is step 5.
Begin by importing the starter project in Flash Builder. You'll notice that this looks very similar to a brand new project except for a few minor changes:
Run the project and familiarize yourself with the code. You should see something like this:
Inside the locale folder, there are four subfolders, one for each of the application's four locales. The convention for naming a locale is:
{language}_{country code}For example, en_US represents English as spoken in the United States. The locale en_CA represents, as you can guess, English as spoken in Canada. The sample application will support four common languages: English, French, German, and Japanese (see Figure 1).

Note: The directory structure described here is not a standard, although it is an accepted convention. You can name and organize your localization files any way you like, but you should take care to reflect those changes in your compiler arguments. See Specify compiler options for more details on setting the compiler arguments.
A properties file is essentially a text file that defines the localization targets and their corresponding values. You place each properties file in its corresponding locale subfolder. Collectively, the properties files completely define all localization targets in your application that will be localized. Follow these steps to create your first properties file for the locale en_US as an example.
## resources.properties file for locale en_US ##
# contact-form labels and assets
contact.title=Contact Form
contact.flagImg=assets/us.gif
contact.submit=Submit
# contact-form fields
contact.field.name=Name
contact.field.streetAddress=Street Address
contact.field.city=City
contact.field.state=State
contact.field.zipCode=ZIP Code
contact.field.country=Country
Note: You can name the file anything you like; resources.properties is a commonly used name, but it is not required. Feel free to name it according to any convention that makes sense for your application. Also, you can have as many properties files as you wish. So, for instance, if you're separating image and asset sources for localization as well as text labels, you may want to use one file, assets.properties, for your assets, and another file, dictionary.properties, for your text labels.
As you can see, the properties file is a simple text file with a basic key/value pair structure describing the localization targets and values. In this example, the key is separated from the value with an equal sign ( =) . You can also use a colon ( : ), or just whitespace. For example:
Comment lines within a properties file start with a # or ! ; for example:
! This is a comment
# This is also a comment
Note: For additional rules for properties file syntax and usage, see Properties File Syntax.
Now that you've seen what the properties file for en_US looks like in the sample application, you can create the rest of the files and place them in their appropriate locale folders.
## resources.properties file for locale fr_FR ##
# contact-form labels and assets
contact.title=Nom
contact.flagImg=assets/fr.gif
contact.submit=Soumettre
# contact-form fields
contact.field.name=Nom
contact.field.streetAddress=Adresse
contact.field.city=City
contact.field.state=État
contact.field.zipCode=Code Postal
contact.field.country=Pays
## resources.properties file for locale de_DE ##
# contact-form labels and assets
contact.title=Kontaktformular
contact.flagImg=assets/de.gif
contact.submit=Senden
# contact-form fields
contact.field.name=Name
contact.field.streetAddress=Strasse und Hausnummer
contact.field.city=City
contact.field.state=Staat
contact.field.zipCode=Postleitzahl
contact.field.country=Land
## resources.properties file for locale ja_JP ##
# contact-form labels and assets
contact.title=お問い合わせフォーム
contact.flagImg=assets/jp.gif
contact.submit=送信
# contact-form fields
contact.field.name=名contact.field.streetAddress=ストリートアドレス
contact.field.city=市
contact.field.state=状態contact.field.zipCode=郵便番号
contact.field.country=国
For every locale that you support in your application, you must ensure that the framework resources for that locale are present. Essentially for each of your application's locales, a specific set of SWCs must be in place for your application to compile and work properly. You can see what these files look like in the following folder:
FLEX_HOME/sdks/x.x.x/frameworks/locale/en_US/
So, for instance, if you want to support Italian (it_IT) in your application, you'll want to make sure that the necessary localization files are also present in a folder it_IT within the frameworks/locale folder alongside en_US. Conveniently, the Flex SDK provides a utility, named copylocale, that simplifies this process. You can find it at the following location:
FLEX_HOME/sdks/x.x.x/bin/ copylocale
Simply open up a terminal and invoke the command using the following syntax:
copylocale original_locale new_localeThis utility creates a new folder in the frameworks directory for the new locale and then copies the necessary framework files into it. You need a locale in the frameworks folder for each locale that your application will support.
Note: Flash Builder and the Flex 4 SDK come with support for 16 of the most common locales already, meaning that these folders will already be present and populated with the necessary files. Before creating any of your own, check in the locale folder to see which locales are already supported. If all of the locales that you wish to support are already there, then you don't have to do anything here. Only run the utility for locales that you don't already see.
For this tutorial example, you need the folders en_US, de_DE, fr_FR, and ja_JP. The en_US folder is present by default (and you may have all of the others as well). Use the copylocale utility to add support for any of the other three locales that don't already exist. From the command line, run the following command if you don't see the fr_FR folder:
copylocale en_US de_DE
copylocale en_US ja_JP
Note: If you don't see folders being created as you run the utility, you may need admin privileges. On Windows, make sure to run the terminal as Administrator. On Max OS X, make sure to use sudo.
You should now have (at least) the following four folders in your frameworks/locale folder:
With the directory structure created, the properties files in place, and the necessary framework files copied, you just need to tell the compiler that you're enabling localization. You do this by specifying two compiler options:
There are various ways to set these option but the two simplest are via the command line and via Flash Builder.
To set the additional locales and source paths via the command line, simply add the –locale flag and –source-path flag when calling mxmlc; for example:
mxmlc –locale=en_US,fr_FR,de_DE,ja_JP –source-path=./locale/{locale}To set the additional locales in Flash Builder, you can simply add them to the compiler arguments:
-locale en_US de_DE fr_FR ja_JP –source-path ./locale/{locale}Note: When modifying the compiler arguments this way, there is no equal sign (=) and the locales are not comma-separated.
The {locale} at the end of the source-path value for each of these methods is used to dynamically specify the locales for the application. The {locale} is replaced by each of the locale values that you specify using the - locale option. So, if you modify the names of your locale folders, make sure those changes are reflected in the compiler arguments as well. As an alternative, you could also add each source path manually (for example: src/locale/en_US , src/locale/de_DE , and so on).
Note: You may get a compiler warning, “Source path entry, ‘PROJECT_HOME/localization-part-i-end\src\locale\en_US', is a subdirectory of source path entry, 'PROJECT_HOME\localization-part-i-end\src’”. This is normal, and won’t stop your application from functioning as expected. However, if you want to remove this warning, add the additional compiler argument “-allow-source-path-overlap=true”.
At this point, you've set up your project to compile the properties files into resource bundles and make them available for use in your application. Once you have all of this in place, all of the hard work is done! To reference the values in the properties files, you use the ResourceManager class. The ResourceManager class is actually a Singleton and is in charge of handling all of the resource bundles that you want to use in your application. First, you must declare the resources that you want to use. In the steps above, you named the properties files resources.properties, so the resource bundles are called resources .
</fx:Script> tag in Main.mxml:<fx:Metadata>
[ResourceBundle("resources")]
</fx:Metadata>
Alternatively, you can make the declaration in ActionScript using the following code:
[ResourceBundle("resources")]
public class MyComponent extends UIComponent {
...
}
<fx:Script> tag :// within the Script tag
private function comboChangeHandler():void
{
resourceManager.localeChain = [localeComboBox.selectedItem.locale];
}
<mx:ComboBox id="localeComboBox" dataProvider="{locales}" change="comboChangeHandler()"/>
<mx:FormItem label="Name"> And change it to:
<mx:FormItem label="{resourceManager.getString('resources','contact.field.name')}"> Once you've completed all of these changes, your main MXML file for the sample application should look like this:
<?xml version="1.0" encoding="utf-8"?>
<s:Application xmlns:fx="http://ns.adobe.com/mxml/2009"
xmlns:s="library://ns.adobe.com/flex/spark"
xmlns:mx="library://ns.adobe.com/flex/mx">
<fx:Script>
<![CDATA[
[Bindable]
private var locales:Array = [{label:"English (United States)", locale:"en_US"},
{label:"German (Germany)", locale:"de_DE"},
{label:"French (France)", locale:"fr_FR"},
{label:"Japanese (Japan)", locale:"ja_JP"}];
private function comboChangeHandler():void
{
resourceManager.localeChain = [localeComboBox.selectedItem.locale];
}
]]>
</fx:Script>
<fx:Metadata>
[ResourceBundle("resources")]
</fx:Metadata>
<s:layout>
<s:VerticalLayout horizontalAlign="center" verticalAlign="middle" />
</s:layout>
<s:Panel title="{resourceManager.getString('resources','contact.title')}" color="black" borderAlpha="0.15" width="350">
<s:layout>
<s:VerticalLayout horizontalAlign="center" paddingLeft="10" paddingRight="10" paddingTop="10" paddingBottom="10" />
</s:layout>
<mx:Form width="100%" color="0x323232">
<mx:FormItem label="{resourceManager.getString('resources','contact.field.name')}">
<s:TextInput />
</mx:FormItem>
<mx:FormItem label="{resourceManager.getString('resources','contact.field.streetAddress')}">
<s:TextInput />
</mx:FormItem>
<mx:FormItem label="{resourceManager.getString('resources','contact.field.city')}">
<s:TextInput />
</mx:FormItem>
<mx:FormItem label="{resourceManager.getString('resources','contact.field.state')}">
<s:TextInput />
</mx:FormItem>
<mx:FormItem label="{resourceManager.getString('resources','contact.field.zipCode')}">
<s:TextInput />
</mx:FormItem>
<mx:FormItem label="{resourceManager.getString('resources','contact.field.country')}">
<s:TextInput />
</mx:FormItem>
<mx:FormItem>
<s:Button label="{resourceManager.getString('resources','contact.submit')}" />
</mx:FormItem>
</mx:Form>
</s:Panel>
<mx:Spacer height="15" />
<s:HGroup width="350" verticalAlign="middle">
<mx:Spacer width="100%" />
<mx:Image source="{resourceManager.getString('resources','contact.flagImg')}"/>
<mx:ComboBox id="localeComboBox" dataProvider="{locales}" change="comboChangeHandler()"/>
</s:HGroup>
</s:Application>
Localization is a key feature for any global application or website. As you've seen, with only a few simple steps, you can localize a Flex application quite easily. It's not only efficient, but scalable as well. With all the preparation done, your application can easily grow to support more localization targets and locales as your user audience expands. There are other ways to achieve localization as well (including loading resources at run time, which I'll discuss in Part 2), but this is one of the simplest and most common methods. Adhere to the steps covered above, and you'll be localizing your applications in no time.
For a more thorough look at localization in Flex, including alternative methods, additional features, and common pitfalls that are beyond the scope of this article, refer to the Flex 4 Localization documentation.