Flex localization example

Tagged:  

Earlier I posted how to do Flash localization. Now it's time for an example of Flex localization. Flex localization is a bit more difficult to do, but it's a lot better done. Follow along with the example attached at the bottom of the post.

This example is for Runtime localization. This means that the resource bundles will be external swf files and will not be compiled into your main application.

The official flex documentation for localization can be found here.
I plan on just writing a quick-start example.

Localization file structure

Create the folders and property files you'll need. In this example, let's use English and German.

yourFlexProject
  bin-debug 
  src
  libs
  locale
      en_US
         myBundle.properties
      de_DE
         myBundle.properties

Creating the property files

Create the .properties files in their respective folders, and then set their text file encoding to UTF-8. If you don't do that, characters with accents and such will just show up as empty squares.
Right click the file, then go to properties.

# locale/en_US/myBundle.properties
greeting=Hello
goodbye=Goodbye, come back soon!

# locale/de_DE/myBundle.properties
greeting=Hallo
goodbye=Auf wiedersehen!

Compiling the resource bundles

Now here's the tricky part. Flex Builder has no easy way to compile these resources we just created automatically. So the best way to do this is using ANT.
ANT will come installed by default in Eclipse, but in Flex Builder, you will need to add it. Flex Builder comes with some strange crippled version of ANT, I don't quite understand that.
Installing Ant in Flex Builder Stand-alone

Once you have ANT installed, you will need to create your script to tell the Flex compiler to create swf files out of your language bundles.
In order for ANT to know how to use the flex compiler, we need to copy two files over from your flex directory.
In your Flex Builder 3\extras directory, there are two files; flexTasks.jar and flexTasks.tasks. Copy flexTasks.jar to your flex project libs directory (the directory should exist by default), and copy flexTasks.tasks to the root directory of your project.

Now that ant is installed and has what it needs, create an xml file in your root project directory called antBuild.xml:

<?xml version="1.0" encoding="utf-8"?>
<project name="Example resource bundle builder" basedir="." default="main">
	<taskdef resource="flexTasks.tasks"
		classpath="${basedir}/libs/flexTasks.jar"/>
 
	<!-- CHANGE TO YOUR FLEX DIRECTORY //-->
	<property name="FLEX_HOME" value="C:/Program Files/Adobe/Flex Builder 3/sdks/3.0.0"/>
 
	<property name="APP_ROOT" value="myApp"/>
	<target name="main">
		<antcall target="en_US"></antcall>
		<antcall target="de_DE"></antcall>
	</target>
	<target name="en_US">
		<mxmlc>
			<locale>en_US</locale>
			<source-path>locale/{locale}</source-path>
			<include-resource-bundles>mainBundle</include-resource-bundles>
			<!--<include-resource-bundles>anotherBundle</include-resource-bundles>-->
			<output>bin-debug/Resources_en_US.swf</output>
		</mxmlc>
	</target>
	<target name="de_DE">
		<mxmlc>
			<locale>de_DE</locale>
			<source-path>locale/{locale}</source-path>
			<compiler.library-path dir="${FLEX_HOME}/frameworks" append="false">
				<include name="libs" />
			</compiler.library-path>
 
			<include-resource-bundles>mainBundle</include-resource-bundles>
			<!--<include-resource-bundles>anotherBundle</include-resource-bundles>-->
			<output>bin-debug/Resources_de_DE.swf</output>
		</mxmlc>
	</target>
</project>

To use this script, open your ANT view, click the Add Buildfiles button, and add that xml file we just created. Because we set default="main", we can just double click the "Resource bundle builder" icon we now should see in the ANT pane.
If everything worked, there will be two new files in your bin-debug directory: Resources_en_US.swf, and Resources_de_DE.swf

If you've gotten this far, the hardest part is over, so keep with me here =-)

We now need to tell Flex where to look for the bundles. For that, we need to add a FlashVar entry.
I know this is annoying, but there's three places we need to modify to change FlashVars in Flex.
Open your index.template.html page. Here you will see three major parts:
Version Check
if ( hasProductInstall && !hasRequestedVersion )
AC_FL_RunContent
Javascript Embed
else if (hasRequestedVersion)
AC_FL_RunContent
And noscript HTML object

The flashVar parameters we need to add are: resourceModuleURLs=Resources_en_US.swf&localeChain=en_US
This will tell Flex what locale to load first on startup.
If you know how to add that into the three places, go ahead, if not, look at the index.template.html file in the example I have attached at the bottom.

Now we need to tell Flex not to compile any language files into the main application. To do this, go into your project properties, flex compiler, and under additional compiler arguments, change -locale=en_US to simply -locale=

Using the resource strings

Ok, the localization should finally be ready to use!
For mxml components, use binding expressions to bind the localized strings:

For actionscript, just use:
resourceManager.getString('myBundle', 'greeting')

If the locale changes at any point, the text will automatically change, at least that part is easy.

To change the locale at runtime:

var eventDispatcher:IEventDispatcher = resourceManager.loadResourceModule("Resources_de_DE.swf");
var localeChain:Array = ["de_DE", "en_US"];
resourceManager.localeChain = localeChain;
eventDispatcher.addEventListener(Event.COMPLETE, languageChangeComplete);

So there you go. Setting this up for the first time can be a troublesome process, but once you know how, it's very easy to use.

AttachmentSize
FlexLocalizationExample.zip504.66 KB

We have a problem where when the browser language preference is set to a language other than en_US, which is set as Locale in project properties, the application fails during the reading of login parameters not in English. Is there a way to set the locale to en_US in main,xml in the init method so that browser parameters being used in flex application to login are translated back to English on the fly?

One of the biggest issues with Flex/Flash localization is its "intrusive" approach and the requirement that your source code must be modified to support localization and "pull" in appropriate settings. As the application complexity grows this becomes a nightmare. And in Flex localization support "destroys" the Design view usability.
BabelFx is an open-source IoC (inversion of Control) engine that fits easily with any Flex application and works with any architectural framework. I recommend that users check it out:

https://github.com/BabelFx

Hi,

i'm trying to localize my flex application but depending on the locale that i specify in the build path first (above)... it chooses the locale.

eg. if i specify english first it'll show all the msges in english and if i specify japanese first, it shows all the msges in japanese.

if i dnt specify any build path then it shows an error as cannot find resource bundle.

can you please tell me where and what i'm missing?

Thanks in advance,
vaibhav

It was very helpful. Thanks! :)

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

Not natively, but Adobe has some examples on how to it.
A quick search brings me to: http://www.savage7.com/index.php/2009/10/adobe-flex-3-load-localization-...

re

Thanks for reply,

But i have done through first loading file through urlloader and then create resource bundle dynamically. But i think Adobe should give this by default like they have given for .swf file. Why everyone should create swf for theri resource and more over u change a single value then again compile n create swf.... dont understand this concept

Aashish

Hi,

Your example was very useful in me setting up my localized environment. Especially i had problems in compiling the resource module for any language other than en_US which was solved using the ANT Script. It would be great if you can added support for different types of assets other than text in the same example.

Regards

Krishnan G

I have an xml file with ant script. I try to run the 'ant' at command prompt
but i got an error like..

Unable to locate tools.jar. Expected to find it in C:\Program Files\Adobe\Flex Builder 3\lib\tools.jar
Buildfile: build.xml does not exist!
Build failed
The system cannot find the batch label specified - end

How can i fix it. Any help is appreciable.
-vijayakumar

a trivial errata,notice the name as mainBundle in the resourcebunldle.xml ,whereas we created the property file as myBundle.properties.

many thanks for the tips on UTF-8 encoding, my Spanish version gave me some problems and I wasn't quite sure how to solve it. UTF-8 did the trick.

Tour de Flex has an localization example, it looks as a simpler way, comment at the bigging says:
<!--
Before compiling this application on your system:

1. Add the following compiler arguments: -locale=en_US,fr_FR -source-path=locale/{locale}

2. Open a Command prompt/shell, navigate to the bin directory of your Flex SDK (for example:
C:\Program Files\Adobe\Flex Builder 3 Plug-in\sdks\3.0.1\bin), and execute the following command:

copylocale en_US fr_FR
-->
and it uses
<mx:Application>
<mx:Metadata>
[ResourceBundle("myResources")]
</mx:Metadata>

I had to use:
compiler.library-path dir="${FLEX_HOME}/frameworks/locale/en_US" append="false"

Thank you for posting this useful article. Still, I have a question for you:

I use the way that you described to build the resources swf file. My application works perfectly fine with this resource file, except that the 'OK' and 'Cancel' button labels of the alert boxes (alert.show) are displayed as 'null' (literally). Of course, those OK / Cancel button labels are not defined in properties.

Do you have any idea how I can solve this problem?

Thanks
Dominic

Re:

Hi Dominic,

You can solve that problem like this:
Alert.noLabel = resourceManager.getString('myBundle', 'noLabel');
Alert.cancelLabel = resourceManager.getString('myBundle', 'cancelLabel');

I know that what you'd expect is to not have to do that and just see english, but unfortunately I think my example is missing the inclusion of the flex native bundles. The english bundles flex uses are:
collections containers controls core effects formatters logging skins states styles utils validators
Flex only has these bundles in english and japanese, so I pretty much just set the text for things like I just mentioned.

THank you for your reply.

Do you mean that every time I use Alert.Show, I need to put the following statement (s)before it?

Alert.okLabel = ...
Alert.noLabel = ...

Or, do you mean that I only put them only once for the whole life cycle of the application?

Thanks
Dominic

Re:

They are static variables, so you would only have to do it once. However, setting Alert.okLabel = resourceManager.getString(... is not a binding expression, so if you change languages, you would have to update those labels.

To do this, somewhere, probably your main Application, override the resourcesChanged method.

override protected function resourcesChanged():void {
super.resourcesChanged();
Alert.okLabel = resourceManager.getString( ....
}
The resourcesChanged method will get called anytime the locale changes. I should also mention that resourcesChanged gets called before initialization, so if you have references to components in your resourcesChanged method, you should add this line at the top:
if (!initialized) return;

How can I change the locale of the Flash built components within Flex ? I need to build some Flash Components used in Flex but can I change the Flash Components locale by changing Flex Resource Manager localeChain property ? Flex and Flash employ a totally different way in localization, it is very odd and confused to me. Any ideas ?

Re:

That's a tricky one. You're not going to be able to do it with the flex code, you'll need to use Flash's Locale.loadLanguageXML method. Although you might have to use getDefinitionByName to resolve the Locale class after you load the flash component, I'm not sure about that. Let me know when you figure it out.

I made an update to the example and to resourceBundles.xml

If I tried to compile another language, I would get the error:
flex-config.xml(70): Error: unable to open 'locale/de_DE'
The problem is that in the flex-config.xml, there is a line:
locale/{locale}, which causes problems during compile.
If you comment that out, you can then compile the resource bundles, but then your projects that don't use runtime resource bundles will break.
So instead, we add the following to our ant script.

<compiler.library-path dir="${FLEX_HOME}/frameworks" append="false">
	<include name="libs" />
</compiler.library-path>

This keeps Flex from trying to find the locale/{locale} bundles that don't exist.

this helped me

Hey!

Excellent Article! Why can´t Adobe have somthing this simple in the livedocs!
anyway just thought I shoud tell you that you forgot to add the example index.template.html to the end of the post.

Keep up the good work.

David

Ah, thanks, I should have mentioned; the index.template.html to which I'm referring is in the zip file attached, within the html-template folder.

Very nice article.
I can't see any attachment file. Could you please paste index.template.html content.