Archive

Archive for August, 2009

Adobe Flex 3: How to create localized UI component / control

August 12th, 2009 8 comments

In a previous post, I wrote an article describing some of the localization weaknesses in Flex 3.

–>  Adobe Flex 3.x Localization / Internationalization (i18n) Weaknesses

One of issues outlined in that post is that the Flex UI components are not localization aware, or more simply put, the UI components do not have any built in support for resource localization.   Below we will recap the current method you use to implement localization strings and then a proposed alternative embedding localization handling directly into the UI controls.

The current de-facto methods used to render localized text for each control include either a compiler directive or run-time code for each property you want localized.

In this example the compiler directive @Resource() is used to define the resource string for the text property:

<mx:Label text="@Resource(bundle='myResources', key='text')"/>


To support dynamic locale changes, a runtime binding expression accessing the ResourceManager class is used instead of the compiler directive: property:

<mx:Label text="{resourceManager.getString('myResources', 'text')}"/>


The two implementations above are perfectly functional, but very cumbersome to implement when localizing a large Flex application.


Why not embed the resource localization logic directly into each UIComponent and expose resourceName and resourceBundle as design time properties?

flex-resource-design


Well, that exactly what I did!  I created wrapper controls derived from the mx controls that add the resourceBundle and resourceName design time properties.



See the screenshot here where these properties are accessible in the FlexBuilder designer – control properties tool window.


With this concept (borrowed from ASP.NET) a resource string naming convention is also needed to actually provide localized strings for each string property of the control.  For example  with a Label control you may want to provide localized strings for the Label.text property and Label.toolTip property.  Since this implementation only exposes a single resourceName property for the control I adopted a convention that allows me to defined the resource strings in the resource property files with a dot property name appended to the control resourceName.

myLabel.text=This is the label text
myLabel.toolTip=This is the label toolTip


Note, the resource strings above are named with the control’s resourceName and then have “.text” and “.toolTip” appended.  This convention enables me to define a single resourceName on each control and gives me the flexibility to define multiple resource strings for the individual control properties.   The convention outlined here can greatly simplify the localization burden on the Flex developer in large Flex applications.

 

A complete detailed example and source code is available below.  
… However we can walk through the basic  logistics here:

First, create a UI control class that extends an existing UI Control such as ‘Label’
Then add private class member variables for a  resource name string and resource bundle string.

[codesyntax lang="actionscript3" title="class definition"]

public class Label extends mx.controls.Label
{
   // resource localization variables
   private var _resourceName:String;
   private var _resourceBundle:String;

[/codesyntax]
Add a class constructor to register two event listeners.
The first event listener listens for when the UI components is ADDED to the layout/stage.
The second event listener is on the resourceManager and listens for changes to the resourceManager.
Both of these event listeners define the same callback handler method.
[codesyntax lang="actionscript3" title="class constructor"]

public function Label()
{
super();
// register event listener to handle resource localization when object is added
addEventListener(Event.ADDED,resources_LocalizationHandler);
// register as a weak listener for 'change' events from the ResourceManager.
// this is to capture runtime resource manager changes of locale
resourceManager.addEventListener(Event.CHANGE, resources_LocalizationHandler, false, 0, true);
}

[/codesyntax]
Next, we need to add public property getters and setters to expose the ‘resourceBundle’ and ‘resourceName’ component properties.  Note the ‘Inspectable’ annotation/metadata, this allows these properties to be exposed in the Flex 3 GUI Designer properties window.
[codesyntax lang="actionscript3" title="public resource properties"]

[Inspectable(category="Localization")]
public function get resourceBundle():String
{
   return _resourceBundle;
}

public function set resourceBundle(value:String):void
{
   // set new resource bundle
   if (_resourceBundle != value)
   {
      _resourceBundle = value;
   }
}

[Inspectable(category="Localization")]
public function get resourceName():String
{
   return _resourceName;
}

public function set resourceName(value:String):void
{
   // set new resource name
   if (_resourceName != value)
   {
      _resourceName = value;
   }
}

[/codesyntax]

The last step is to add the event handler method registered in the two event listeners defined earlier.
Here is where we will implement the actual resource lookup and replacement for the control’s properties.

[codesyntax lang="actionscript3" title="event handler"]

private function resources_LocalizationHandler(event:Event):void
{
// ensure the resource bundle and resource name properties are not empty
if(resourceBundle != null && resourceName != null)
{
// get the localized resource strings for all localized properties
var localizedText:String = resourceManager.getString(resourceBundle, resourceName + ".text");
var localizedToolTip:String = resourceManager.getString(resourceBundle, resourceName + ".toolTip"); // apply the localized resource string for 'text' property
if(localizedText != null && localizedText != '')
this.text = localizedText; // apply the localized resource string for 'toolTip' property
if(localizedToolTip != null && localizedToolTip != '')
this.toolTip = localizedToolTip;
}
}

[/codesyntax]
This type of implementation is highly dependent on establishing resource naming conventions for each control’s set of properties that you wish to localize, but it greatly simplifies the resource localization implementation of proliferated controls throughout a large Flex application.

Sample Application Links

Categories: Adobe Flex