Home > Adobe Flex > Adobe Flex 3: Load localization resources at runtime using XML

Adobe Flex 3: Load localization resources at runtime using XML

October 23rd, 2009 Leave a comment Go to 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

I had mentioned the concept of loading resources at runtime via a XML formatted document. In this article I will discuss how I accomplished this and provide a working sample and source code.


A fully working example and the source code are provided at the bottom of this article.


The Flex method for creating resource bundles for localization compiling them directly into SWF files works well for many applications and is an efficient method for handling localization.  They even go as far as allowing you to load different localization bundle SWFs at runtime to reduce the size of the main application by only loading the resource files that you need.  However, this method is not ideal for certain scenarios such as if you are creating a distributable application and want to allow your customers to edit or create resource files.  It can also become annoying to have to recompile a SWF just to make a small change to a resource string.   So for these types of scenarios you may prefer a resource solution that can load a simple text (XML) file at runtime.   Fortunately Flex does provide a means of dynamically creating resource files programmatically.

I have created a XmlResourceLoader class that uses the URLLoader to load the necessary XML resource files at runtime and dynamically generate the resource bundles in the Flex ResourceManager.   Since you may want to include a number of different fallback languages the  XmlResourceLoader class accepts a chain Array on the load method.  This allows you to define a locale specific resource chain such as “en_GB”, “en“.  Using this chain, the XmlResourceLoader will load both the “en_GB.xml” resource file and the “en” resource file.

        /**
        *  this function will dynamically load the XML resource
        *  files via HTTP if they have not already been
        *  previously loaded into memory.
        */
        public function load(localeChain:Array):void


This function will skip locales in the chain that have already been loaded.  So if you allow users to change selected locales at runtime, then subsequent calls to the XmlResourceLoader load function will waste time and resources re-fetching the same content XML.


If you are interested in what specific files were loaded after the load method was invoked, you can access the ArrayCollection of loaded resource files using this method:

        /**
        *  returns a list of resource files in use
        *  for the loaded locale chain.
        */
        public function get resourceFiles():ArrayCollection


The XML resource files are simply formatted like this:

  1. <resources>
  2. <resourceBundle name="myResources">
  3. <resource name="myResourceOrigin" value="English Lanugage; Culture Neutral"/>
  4. <resource name="myLocalizedLabel" value="Hello World!" />
  5. <resource name="myLocalizedButton" value="Color"/>
  6. <resource name="myResourceFlagImage" value="assets/images/english-flag.png"/>
  7. </resourceBundle>
  8. </resources>


Each XML file may contain one or more resource bundles (<resourceBundle name=”myResources”>).  Each resource bundle section may contain one or more resource definitions (<resource name=”myLocalizedButton” value=”Color”/>).  Each resource definition contains two attributes: name and value.  The name attribute is the resource key name used to resolve the resource string and the value is the localized value string that is returned for the Flex ResourceManager when attempting to resolve a named resource.


Sample Application Links



Categories: Adobe Flex
  1. October 26th, 2009 at 12:23 | #1

    This is an awesome solution to this problem. I’ve never been satisfied with the traditional “compiled” resource bundle solution, especially when integrating with other technologies. I agree that the compiled solution is very fast, but it requires a recompilation each time there is a new language/locale added. I don’t find recompilation useful and feel it has haunted Flex for awhile now, especially if there is a need to localize at runtime.

    Thanks and great work!

  2. October 26th, 2009 at 18:02 | #2

    Glad you like it! I’m sure there is room for improvement, but this code should provide a nice start for the runtime loading of resources.

    Thanks for stopping by!
    -Robert

  3. Richard
    November 14th, 2009 at 10:04 | #3

    Reminds me of an alternate translation scheme from years ago in an MS-Access application.

    Only 1 other idea: when you are sitting looking at source code
    label=”{resourceManager.getString(‘myResources’, ‘myLocalizedButton’)}”

    It’d be nice to do an instant lookup from IDE to reassure yourself: “is this string what I think it is?”.

    Or, a capability to insert/update a special format trailing comment… with the actual text in the default language ??

    I am using FlashDevelop right now, that’s the thing about Flex is the variety of IDEs or source editors people use. But if it was an external executable, it could be used by most IDEs that can invoke a command line utility and capture output.

  4. November 14th, 2009 at 10:44 | #4

    Hi Richard,

    I agree and wish there were better tooling for the localization effort.
    Take a look at this post, I personally don’t like the idea of explicitly defining a resource manager string lookup every single place I need to perform localization, so I take this approach:
    http://www.savage7.com/index.php/2009/08/adobe-flex-3-how-to-create-localized-ui-component-control/

    Thanks
    -Robert

  5. Pascal
    March 18th, 2010 at 09:02 | #5

    Hey Richard,

    I have a question regarding the resourceManager.update();
    If you set the localechain it already executes the update event so this class does the update function twice and it dispatches the change event two times.

    Is there a reason for the resourceManager.update(); to execute in this class?

    thanks in advance,
    pascal

  6. April 9th, 2010 at 20:07 | #6

    @Pascal
    Hi Pascal,

    Thanks for pointing that out, I did not realize the update was happening automatically on the setting of the locale chain.

  7. August 4th, 2010 at 12:40 | #7

    How can I use this to load icons dynamically?

  8. September 15th, 2010 at 14:52 | #8

    Patrick :

    1
    How can I use this to load icons dynamically?

    Hi Patrick, not sure what you mean … the sample is loading graphic images dynamically based on the localized properties defined in each XML file.

  9. Durrab Jami Khan
    October 7th, 2010 at 01:14 | #9

    I am trying to use your XMLLoader Component with Flex 4 (Spark) for runtime localization.

    But I am getting the following below error. Except that it is not showing the changes if I select the locales and make the changes exactly what you did.

    Need some urgent help

    ReferenceError: Error #1069: Property -1 not found on __AS3__.vec.Vector. and there is no default value.
    at spark.components::Label/truncateText()[E:\dev\4.0.0\frameworks\projects\spark\src\spark\components\Label.as:1246]
    at spark.components::Label/http://www.adobe.com/2006/flex/mx/internal::composeTextLines()[E:\dev\4.0.0\frameworks\projects\spark\src\spark\components\Label.as:485]
    at spark.components.supportClasses::TextBase/measure()[E:\dev\4.0.0\frameworks\projects\spark\src\spark\components\supportClasses\TextBase.as:533]
    at mx.core::UIComponent/measureSizes()[E:\dev\4.0.0\frameworks\projects\framework\src\mx\core\UIComponent.as:8042]
    at mx.core::UIComponent/validateSize()[E:\dev\4.0.0\frameworks\projects\framework\src\mx\core\UIComponent.as:7966]
    at mx.managers::LayoutManager/validateSize()[E:\dev\4.0.0\frameworks\projects\framework\src\mx\managers\LayoutManager.as:617]
    at mx.managers::LayoutManager/doPhasedInstantiation()[E:\dev\4.0.0\frameworks\projects\framework\src\mx\managers\LayoutManager.as:733]
    at mx.managers::LayoutManager/doPhasedInstantiationCallback()[E:\dev\4.0.0\frameworks\projects\framework\src\mx\managers\LayoutManager.as:1072]

  10. December 1st, 2010 at 06:07 | #10

    Hi Robert-
    Nice work!
    I added the following line (any place you want) –

    Click the button before you select a language – you will see the button with ‘OK’label
    Then select language other that en or en_US
    Click the button – you will see the button with ‘null’ label
    I assume that we some default resource has been overwritten – any clue what is the problem?
    Thanks
    Charlie

  11. December 1st, 2010 at 06:09 | #11

    @Charlie
    the missing line should have button that shows alert in the click handler
    click=”{Alert.show(‘Hi there’,'Test Alert’)}”

  12. Karl
    December 12th, 2010 at 10:00 | #12

    Hello there, how can I change the location from the XML file is read? I’ve tried modifying the line:
    public static const RESOURCE_FILE_SERVER_PATH:String = “assets/resources/”;

    How can I modify this to get the file from anywhere I want in the project? I’ve tried different folders but it doesn’t work, it just works on the bin-debug folder.

  13. December 12th, 2010 at 11:12 | #13

    Hi Karl,

    In my example, the XML files are not embedded inside the SWF at compile time, therefore they must be located in a path that will be deployed to the web server and resolvable at runtime for the web browser/flex app. If you wanted them compiled in, you could certainly do that, but you would need to modify the logic inside ‘XmlResourceLoader’ that loads the resource files for further processing.

    Thanks – Robert

  14. December 12th, 2010 at 11:16 | #14

    Karl, One other note … The source resource XML files are located in a subfolder under the ‘html-template’ directory. When you run/deploy these get copied to the ‘bin-debug’ (or whatever output folder you have configured in your project settings) path.

    If you want to modify the XML files, make the changes the the files in the ‘html-template’ path, otherwise if you make changes to them in the ‘bin-debug’ path you changes will get overwritten anytime you recompile/run/deploy.

  15. December 12th, 2010 at 11:50 | #15

    Hi Charlie,

    I looked into this issue briefly and I believe this is caused because the default Flex resource files are using the locale “en_US”. In this sample project, anytime a non US locale is selected, the new locale chain created omits “en_US” from the list. For example, selecting “Spanish (Mexico)” results in a locale chain of “es_MX,es,en”. So “en” is included as a root locale, but “en_US” is not. In the XMLResourceLocalizationSample.mxml file, try adding “en_US in each in the supportedLocales:XML variable. This will at least give the resource manager the ability to attempt resource resolution in the Flex default resources.

    Thanks – Robert

  16. December 12th, 2010 at 11:54 | #16

    Attention!

    If you are getting Flex Error #2148 …. Only local-with-filesystem and trusted local SWF files may access local resources. … then take a look at this article:

    http://www.brettwidmann.com/2010/03/how-to-remedy-flex-error-2148/

    Basically as a temporary fix to test this sample, you will need to add the compiler argument “-use-network=false“.

  17. Karl
    December 13th, 2010 at 16:39 | #17

    Hello again Robert. How does the source on the html folder gets copied to bin debug? is this programmed in your class file or is it copied by default?

  18. December 13th, 2010 at 16:55 | #18

    @Karl
    That is a default task performed by FlexBuilder/FlashBuilder whenever it compiles. If you were to build from command line or from an external tool like Maven, you would probably have to manually perform this task to copy any necessary files.

  19. Karl
    January 4th, 2011 at 14:48 | #19

    Greetings Robert

    I got the following error, it’s similar to one written before

    ReferenceError: Error #1069: Property -1 not found on __AS3__.vec.Vector. and there is no default value.

    and several lines referring to methods like truncateText() ,validateSize() , measureSize()

    This error only appears when I put a small sized button, then I believe that the problem is when the button isnt large enough for the label. Has this happened to you?

  20. Karl
    January 7th, 2011 at 11:57 | #20

    Robert, do you think the fact that all my alerts appear with null buttons no matter what, has something to do with me using your class for localization?

  21. January 7th, 2011 at 17:53 | #21

    Hi Karl,

    Yes, it is. I have had several people comment on this issue. I need to create another article to address the issue. The main issue is that the locale chain for a non-English languages do not include “en_US”. “en_US” is where Adobe includes all it’s default framework resources. To get the default English strings to show up instead of “NULL”, you can modify the local chain to always include “en_US” at the end of the chain, so that if no overriding resource property is found, it will at least use the default Adobe provided English strings instead of “NULL”.

    See Comment #15 for additional details.

  22. Paul
    January 24th, 2011 at 05:27 | #23

    Hi Robert,

    Great work!
    I’ve managed to apply format Dates for different locales, but they all display the formatted Dates in English. How can I get them to show the translated day and month strings?

    Thanks in advance

  23. January 24th, 2011 at 09:20 | #24

    To override the date formatting strings for different locales, you have to create framework resources. Please see this article for more information: http://www.savage7.com/index.php/2011/01/adobe-flex-3-load-framework-localization-resources-at-runtime-using-xml/

  24. Paul
    January 25th, 2011 at 09:20 | #25

    Hi Robert,
    I couldn’t find a way to prevent the xml files from caching without editing your class.
    It would be nice if an additional parameter could be passed to xmlResourceLoader.load( localeChain, cacheControl ), so this could be used if supplied to prevent caching.

    Cheers
    Paul

  25. Gonzo
    February 8th, 2011 at 11:33 | #26

    @Karl

    Karl :
    Greetings Robert
    I got the following error, it’s similar to one written before
    ReferenceError: Error #1069: Property -1 not found on __AS3__.vec.Vector. and there is no default value.
    and several lines referring to methods like truncateText() ,validateSize() , measureSize()
    This error only appears when I put a small sized button, then I believe that the problem is when the button isnt large enough for the label. Has this happened to you?

    Hi, I got that issue when using different controls, not only buttons. Any solving?

  26. June 29th, 2011 at 06:30 | #27

    Amazing work, saved me a few hours of development!

    Thanks !
    Fabien

  1. January 7th, 2011 at 19:23 | #1