Adobe Flex 3 Help

Creating resource bundles at run time

You can edit or create resource bundles programmatically. The process for creating a resource bundle is as follows:

  1. Create a new ResourceBundle with the new operator.
  2. Set the resource key/value pairs on the content object of the new ResourceBundle.
  3. Add the bundle to the ResourceManager with the addResourceBundle() method.
  4. Call the ResourceManager's update() method to apply the new changes.

The following example creates a new resource bundle for the fr_FR locale with two values:

var moreResources:ResourceBundle = new ResourceBundle("fr_FR", "moreResources");
moreResources.content["OPEN"] = "Ouvrez";
moreResources.content["CLOSE"] = "Fermez";
resourceManager.addResourceBundle(moreResources);
resourceManager.update();

After you add the resource bundle to the ResourceManager, you can use the ResourceManager's methods to find the new resources; for example:

resourceManager.localeChain = [ "fr_FR" ];
trace(resourceManager.getString("moreResources", "OPEN")); // outputs "Ouvrez"

If you use the addResourceBundle() method to add another bundle with the same locale and bundle name, the new one will overwrite the old one. However, creating new bundle values does not update the application. You must also call the ResourceManager's update() method to update existing resource bundles.

The following example replaces some of the existing resources in the en_US locale's RegistrationForm resource bundle with new values.

<?xml version="1.0"?>
<!-- l10n/CreateReplacementBundle.mxml -->
<mx:Application xmlns:mx="http://www.adobe.com/2006/mxml" creationComplete="initApp()"> 
    <mx:Script><![CDATA[
        import mx.resources.ResourceBundle;
        import mx.controls.Alert;

        [Bindable]
        private var locales:Array = [ "es_ES","en_US" ];

        private function initApp():void {
            // Initialize the ComboBox to the first locale in the locales Array.
            localeComboBox.selectedIndex = locales.indexOf(resourceManager.localeChain[0]);
        }

        private function registrationComplete():void {
            Alert.show(resourceManager.getString('RegistrationForm', 'thanks'));
        }  

        private function comboChangeHandler():void {
            // Set the localeChain to either the one-element Array
            // [ "en_US" ] or the one-element Array [ "es_ES" ].
            resourceManager.localeChain = [ localeComboBox.selectedItem ];            
        }
        
        private function createReplacementBundle():void {
            var newRB:ResourceBundle = new ResourceBundle("en_US", "RegistrationForm");
            
            newRB.content["registration_title"] = "Registration Form";
            newRB.content["submit_button"] = "Submit This Form";
            newRB.content["personname"] = "Enter Your Name Here:";
            newRB.content["street_address"] = "Enter Your Street Address Here:";
            newRB.content["city"] = "Enter Your City Here:";
            newRB.content["state"] = "Enter Your State Here:";
            newRB.content["zip"] = "Enter Your ZIP Code Here:";
            
            resourceManager.addResourceBundle(newRB);
            
            resourceManager.update();            
        }
    ]]></mx:Script>

    <mx:Metadata>
        [ResourceBundle("RegistrationForm")]
    </mx:Metadata> 

    <mx:Image source="{resourceManager.getClass('RegistrationForm', 'flag')}"/>

    <mx:ComboBox id="localeComboBox" 
        dataProvider="{locales}"
        change="comboChangeHandler()"
    />

    <mx:Form>
        <mx:FormItem label="{resourceManager.getString('RegistrationForm','personname')}">
            <mx:TextInput/>
        </mx:FormItem>
        <mx:FormItem label="{resourceManager.getString('RegistrationForm','street_address')}">
            <mx:TextInput/>
        </mx:FormItem>
        <mx:FormItem label="{resourceManager.getString('RegistrationForm','city')}">
            <mx:TextInput/>
        </mx:FormItem>
        <mx:FormItem label="{resourceManager.getString('RegistrationForm','state')}">
            <mx:TextInput/>
        </mx:FormItem>
        <mx:FormItem label="{resourceManager.getString('RegistrationForm','zip')}">
            <mx:TextInput/>
        </mx:FormItem>
    </mx:Form>
    <mx:Button id="b1" label="{resourceManager.getString('RegistrationForm','submit_button')}" click="registrationComplete()"/>
    
    <mx:Button id="b2" label="Change Bundle" click="createReplacementBundle()"/>
    
</mx:Application>

The executing SWF file for the previous example is shown below:

You can also programmatically create a new locale and new resource bundles for that locale. However, you should only create a new locale programmatically if you compiled with that locale's framework resources, as described in Adding new locales.

If you programmatically create your own bundles for a new locale but do not create any framework bundles for that locale prior to compiling the application, you will get run-time exceptions when the framework components try to access framework bundles for the new locale. For example, suppose you programmatically create bundles for the fr_FR locale but do not compile with the fr_FR framework bundles. If you then set the localeChain property to ["fr_FR"], you will get run-time exceptions when the framework components try to access framework resources for the fr_FR locale. As a result, if you plan on creating bundles for the fr_FR locale at run time, you should compile the application with the fr_FR framework bundles. You can then set the localeChain property to ["fr_FR"] without getting run-time errors.

When programmatically creating bundles, you cannot put the class of a run-time loaded image into the bundle because its class did not exist at compile time. Classes representing images are created only at compile time, for embedded images. As a result, you should explicitly set the source of an image rather than get the source of that image from a resource bundle.

The following example creates a new bundle for the fr_FR locale at run time. It explicitly assigns the source of the image when the fr_FR locale is selected rather than loading it from the resource bundle because the image's class was not available at compile time.

<?xml version="1.0"?>
<!-- l10n/CreateNewLocaleAndBundle.mxml -->
<mx:Application xmlns:mx="http://www.adobe.com/2006/mxml" creationComplete="initApp()"> 
    <mx:Script><![CDATA[
        import mx.resources.ResourceBundle;
        import mx.controls.Alert;
        import flash.display.*;

        [Bindable]
        private var locales:Array;

        private function initApp():void {
            locales =  [ "es_ES","en_US" ];
            
            /* Initialize the ComboBox to the first locale in the locales Array. */
            localeComboBox.selectedIndex = locales.indexOf(resourceManager.localeChain[0]);
            
            updateFlag();
        }

        private function registrationComplete():void {
            Alert.show(resourceManager.getString('RegistrationForm', 'thanks'));
        }  

        private function comboChangeHandler():void {
            /* Set the localeChain to either the one-element Array
               [ "en_US" ] or the one-element Array [ "es_ES" ]. */
            resourceManager.localeChain = [ localeComboBox.selectedItem ];            

            updateFlag();
        }
        
        private var newRB:ResourceBundle;
        
        private function updateFlag():void {
            if (resourceManager.localeChain[0] == "fr_FR") {
                /* Explicitly change the value of the flagImage source when the 
                   locale is fr_FR because there was no class at compile time. */
                flagImage.source = "france.gif";            
            } else {
                /* Get the class from the resource bundle; this assumes that the classes
                   for all other locales were embedded in the resource bundles at 
                   compile time. */
                flagImage.source = resourceManager.getClass('RegistrationForm', 'flag');        
            }            
        }
        
        private function createNewBundle():void {
            locales.push("fr_FR");

            newRB = new ResourceBundle("fr_FR", "RegistrationForm");

            newRB.content["registration_title"] = "La Forme d'Enregistration";
            newRB.content["submit_button"] = "Soumettez La Forme";
            newRB.content["personname"] = "Nom";
            newRB.content["street_address"] = "Rue";
            newRB.content["city"] = "Ville";
            newRB.content["state"] = "Etat";
            newRB.content["zip"] = "Code postal";
            newRB.content["thanks"] = "Merci de l'enregistrement!";                                    

            updateFlag();

            resourceManager.addResourceBundle(newRB);            
            resourceManager.update();            
        }
        
        private function resetApp():void {
            resourceManager.removeResourceBundlesForLocale("fr_FR");
            initApp();
            resourceManager.update();            
        }
    ]]></mx:Script>

    <mx:Metadata>
        [ResourceBundle("RegistrationForm")]
    </mx:Metadata> 

    <mx:Image id="flagImage"/>

    <mx:ComboBox id="localeComboBox" 
        dataProvider="{locales}"
        change="comboChangeHandler()"
    />

    <mx:Form>
        <mx:FormItem label="{resourceManager.getString('RegistrationForm','personname')}">
            <mx:TextInput/>
        </mx:FormItem>
        <mx:FormItem label="{resourceManager.getString('RegistrationForm','street_address')}">
            <mx:TextInput/>
        </mx:FormItem>
        <mx:FormItem label="{resourceManager.getString('RegistrationForm','city')}">
            <mx:TextInput/>
        </mx:FormItem>
        <mx:FormItem label="{resourceManager.getString('RegistrationForm','state')}">
            <mx:TextInput/>
        </mx:FormItem>
        <mx:FormItem label="{resourceManager.getString('RegistrationForm','zip')}">
            <mx:TextInput/>
        </mx:FormItem>
    </mx:Form>

    <mx:Button id="b1" 
        label="{resourceManager.getString('RegistrationForm','submit_button')}" 
        click="registrationComplete()"
    />

    <mx:HRule width="100%" strokeWidth="1"/>    
    
    <mx:HBox>
        <mx:Button id="b2" label="Add New Bundle" click="createNewBundle();"/>
        <mx:Button id="b3" label="Reset" click="resetApp();"/>
    </mx:HBox>

</mx:Application>

The executing SWF file for the previous example is shown below:

Adding, removing, or changing individual resources

You can add, remove, or change individual resources within a resource bundle in ActionScript. To do this, you first get a reference to the ResourceBundle with the getResourceBundle() method. You pass the locale and the name of the resource bundle to this method. You then edit the content property of the ResourceBundle, which is an object with key/value pairs for its resources.

The following example adds a new resource to the RegistrationForm resource bundle:

var rb:ResourceBundle = resourceManager.getResourceBundle("en_US", "RegistrationForm");
rb.content["cancel_button"] = "Cancel";

You can change an existing value by specifying the key, as the following example shows:

rb.content["cancel_button"] = "Quit";

To delete a resource from a resource bundle, you use the delete keyword, followed by the key in the content object. The following example deletes the cancel_button resource that was added in the previous example:

delete rb.content["cancel_button"];

Enumerating resources

You can enumerate all resources in a resource bundle by using a for in loop ActionScript. To do this, you get a reference to the resource bundle, and then loop over the content object.

Methods that you might use when enumerating resources include getLocales(), getBundleNamesForLocale(), and getResourceBundle().

The getLocales() method returns an Array such as ["en_US", "ja_JP"] which contains, in no particular order, all of the locales for bundles that exist in the ResourceManager. The getBundleNamesForLocale() method returns an Array such as ["controls", "containers"] which contains all of the bundle names for the specified locale. The getResourceBundle() method takes a locale and a bundle name and returns a reference to the specified resource bundle.

The following example prints the keys and values for all resource bundles in all locales in the ResourceManager. This includes the framework bundles for the locales, in addition to any custom resources such as RegistrationForm.properties.

<?xml version="1.0"?>
<!-- l10n/EnumerateAllBundles.mxml -->
<mx:Application xmlns:mx="http://www.adobe.com/2006/mxml" creationComplete="enumerateBundles()"> 
    <mx:Script><![CDATA[
        import mx.resources.ResourceBundle;
        import mx.controls.Alert;

        private function registrationComplete():void {
            // Use the ResourceManager to set localized values in ActionScript.
            Alert.show(resourceManager.getString('RegistrationForm', 'thanks'));
        } 
        
        private function enumerateBundles():void {
            for each (var locale:String in resourceManager.getLocales()) {
                ta1.text += "****************************************\n";
                ta1.text += "locale: " + locale + "\n";
                ta1.text += "****************************************\n";
                for each (var bundleName:String in resourceManager.getBundleNamesForLocale(locale)) {
                    ta1.text += "  --------------------------------------\n";
                    ta1.text += "  bundleName: " + bundleName + "\n";
                    var bundle:ResourceBundle = ResourceBundle(resourceManager.getResourceBundle(locale, bundleName));
                    for (var key:String in bundle.content) {
                        ta1.text += "    -" + key + ":" + bundle.content[key]  + "\n";
                    }
                }
            }        
        }
    ]]></mx:Script>

    <mx:Metadata>
        [ResourceBundle("RegistrationForm")]
    </mx:Metadata> 

    <mx:Form>
        <mx:FormItem label="@Resource(key='personname', bundle='RegistrationForm')">
            <mx:TextInput/>
        </mx:FormItem>
        <mx:FormItem label="@Resource(key='street_address', bundle='RegistrationForm')">
            <mx:TextInput/>
        </mx:FormItem>
        <mx:FormItem label="@Resource(key='city', bundle='RegistrationForm')">
            <mx:TextInput/>
        </mx:FormItem>
        <mx:FormItem label="@Resource(key='state', bundle='RegistrationForm')">
            <mx:TextInput/>
        </mx:FormItem>
        <mx:FormItem label="@Resource(key='zip', bundle='RegistrationForm')">
            <mx:TextInput/>
        </mx:FormItem>
    </mx:Form>
    <mx:Button id="b1" label="@Resource(key='submit_button', bundle='RegistrationForm')" click="registrationComplete()"/>
    
    <mx:TextArea id="ta1" width="100%" height="100%"/>
</mx:Application>

The executing SWF file for the previous example is shown below: