Localizing your ARP application.

ARP, Flash 3 Comments »

Another update to my ARP lab. I have been thinking about localization for a while but didn't really have the time to work something out untill now. Continuing on the e-learning project we are working on, we came to the point where we needed to have multi-lingual user interfaces. So why not write a generic way in the ARP framework instead of having a custom implementation for our project.

Download the sample files here.

How it works (Nils, you won't like this!)

Each locale has its own XML file that holds the localized strings. In the application, there is a LocaleManager class that knows what the current locale is and, when a new locale is set, will load and parse the localized strings. This loading and parsing happens in a class called ResourceBundle, which "bundles" the "resources", the localized strings, into a collection.

The XML files look like this.

XML:
  1. <?xml version="1.0" encoding="UTF-8"?>
  2. <resources>
  3.     <resource key="firstname" value="Firstname"/>
  4.     <resource key="lastname" value="Name"/>
  5.     <resource key="submit" value="Submit"/>
  6. </resources>

XML:
  1. <?xml version="1.0" encoding="UTF-8"?>
  2. <resources>
  3.     <resource key="firstname" value="Voornaam"/>
  4.     <resource key="lastname" value="Familienaam"/>
  5.     <resource key="submit" value="Verzenden"/>
  6. </resources>

This is pretty much the same idea as the XML files to configure your ARP application with the AppSettings class. Each string has a key and a value. Notice that the keys should be the same for the different resource files. The XML files are saved with the following naming convention: they start with "resources_" and a string representation of the locale is appended to it. Example names are "resources_en.xml", "resources_du_BE.xml" or "resources_du_NL.xml". As you can see, we have a common resource file for English strings and 2 more specific ones for Dutch. One for Belgium and one for The Netherlands.

When the application starts, each view/form that is interested in localized content should:
- register as a listener with the LocaleManager
- implement the LocaleListener interface which makes it possible to be added as a listener to the LocaleManager and which forces the form to implement the localeChanged() event handler.

From the example, here is what the RegistrationForm class looks like.

Actionscript:
  1. import mx.controls.*;
  2. import mx.utils.*;
  3.    
  4. import org.osflash.arp.ArpForm;
  5. import org.osflash.arp.util.*;
  6.  
  7. class com.herrodius.localization.view.RegistrationForm extends ArpForm implements LocaleListener{
  8.   var language_cb:ComboBox;
  9.   var firstname_lbl:Label;
  10.   var lastname_lbl:Label;
  11.   var submit_btn:Button;
  12.  
  13.   public function RegistrationForm(){
  14.   }
  15.  
  16.   /**
  17.     * toString.
  18.     */
  19.   public function toString():String{
  20.     return "[com.herrodius.localization.view.RegistrationForm]";
  21.   }
  22.  
  23.   function onLoad():Void{
  24.     TRACE(Flashout.INFO);
  25.  
  26.     //listeners
  27.     LocaleManager.getInstance().addListener(this);
  28.     language_cb.addEventListener("change", Delegate.create(this, languageComboBox_Change));
  29.  
  30.     //selected item in combobox
  31.     language_cb.selectedIndex = 2;
  32.   }
  33.  
  34.   /**
  35.     * The user chooses another language from the combobox.
  36.     * We need to create a new locale and set it in the LocaleManager.
  37.     */
  38.   function languageComboBox_Change(evt:Object):Void{
  39.     var locale:Locale = Locale.fromString(evt.target.selectedItem.data);
  40.     LocaleManager.getInstance().setLocale(locale);
  41.   }
  42.  
  43.   /**
  44.     * The locale has changed.
  45.     * Change the labels text and the button label.
  46.     */
  47.   function localeChanged():Void{
  48.     var localeManager:LocaleManager = LocaleManager.getInstance();
  49.     firstname_lbl.text = localeManager.getString("firstname");
  50.     lastname_lbl.text = localeManager.getString("lastname");
  51.     submit_btn.label = localeManager.getString("submit");
  52.   }
  53. }

Notice that a new locale is created when the user chooses a different language from the combobox. Here the locale is created through a static method called fromString() because we allready have all the locale details we need in a string. You can ofcourse also instantiate a new locale by calling the Locale's constructor and passing in the language and the region. After creating the locale, we assign it to the LocaleManager through the setLocale() method. This will create a new resourcebundle and load the localized content. As you can see, I implemented it in a way so that you don't have to take care of the resourcebundles yourself. The LocaleManager does it for you. Finally, when the content is loaded and parsed, the localeChanged() method gets called. This is the method you use to update your view. You can fetch the localized strings with the getString() method on the LocaleManager. When the string is not found in the resourcebundle, an error is thrown.

Download

You can download the example here. The following classes should be added in the package "org.osflash.arp.util":
- Locale
- LocaleListener
- LocaleManager
- ResourceBundle

Related content:

- Configuring your ARP application


Add to Bloglines - Digg This! - del.icio.us - Stumble It! - Twit This! - Technorati links - Share on Facebook - Feedburner
 

Configuring your ARP application

ARP, Flash 2 Comments »

There was a recent post on the ARP mailinglist about how an application could be configured. Since there is (still) not a uniform way of doing so in ARP I thought I'd share the solution I came up with. The whole idea is based on an XML file that contains key/value pairs, pretty much like the appsettings implementation in .NET. The XML file, called "appsettings.xml", gets loaded in the ArpApplication class. This is a new class I introduced to the framework that all Application forms extend. The Application form being the applications point of entry.

Before diving into any code examples, please note that these are my personal additions to the framework and that they are not in any official release. Other additions from the ARP Advisory Committee members are available as well: Peter Hall, Jesse Warden, Shannon Jackson and the ARP labs overview.

appsettings.xml

Here's an example of the appsettings.xml file. As you can see all entries consist of a key/value pair. In order for your application to find the appsettings file, you should either:
- name it "appsettings.xml" and put it in a folder where your swf can read it without changing folders.
- use flashvars in the html file that embeds the swf and create a var called "appSettingsPath". Point its value to the appsettings file in any directory. Note that the name "appsettings.xml" can be changed then and that it can even be a serverside page that generates a dynamic config.

XML:
  1. <?xml version="1.0" encoding="utf-8"?>
  2. <appsettings>
  3.     <add key="applicationBackground" value="0x999999"/>
  4.     <add key="menuItems" value="Home,News,Projects,Contact"/>
  5.     <add key="menuBackground" value="0xCCCCCC"/>
  6.     <add key="content" value="Lorem Ipsum is simply ..."/>
  7. </appsettings>

To access one of the values, use the AppSettings class.

Actionscript:
  1. var menuItems:String = AppSettings.getInstance().getValue("menuItems");
  2. var menuBackground:Number = Number(AppSettings.getInstance().getValue("menuBackground"));

Note that these values can only be fetched when the appsettings file has been loaded and parsed. Therefore your Application class needs to extend the ArpApplication class. To know when the loading and parsing is done, you need to implement the onAppSettingsLoad() method. This is a (abstract) method in ArpApplication that gets called when the values have been parsed.

In the following code we set the backgroundcolor of the application to a value in the appsettings and then call the show() method on 2 subforms: menuForm and contentForm.

Actionscript:
  1. /**  
  2. * Overwritten from ArpApplication.
  3. */
  4. function onAppSettingsLoad(){
  5.   trace(toString() + " - onAppSettingsLoad");
  6.  
  7.   var applicationBackgroundColor:Color = new Color(background_mc);
  8.   applicationBackgroundColor.setRGB(Number(AppSettings.getInstance().getValue("applicationBackground")));
  9.            
  10.   menuForm.show();
  11.   contentForm.show();   
  12. }

I overwrote the show() method in these subclasses because they also need values from the appsettings file. And now that I think about it, doing so isn't the best idea. I can see how pretty intense operations are called everytime we hide/show the forms. Either letting the application form dispatch events when the settings are loaded could be a better solution or if there was any way of intercepting the onLoad() handler of the subforms, that could be a good solution too. That way, we could trigger the onLoad() handler on the subforms only when the appsettings are loaded. (In fact, I have been trying to catch the onLoad() before it fires without success. So if anyone knows, please let me know.)

Here is a zip file with a small example and the ArpApplication and the AppSettings class.
Put the AppSettings class in the package org.osflash.arp.config.* and the ArpApplication class in org.osflash.arp.view.*


Add to Bloglines - Digg This! - del.icio.us - Stumble It! - Twit This! - Technorati links - Share on Facebook - Feedburner
 
WP Theme & Icons by N.Design Studio
Entries RSS Comments RSS Login