Using Resource Bundles in MXML for simple strings

There are a few ways developers can use resource bundles in a flex application. When using a resource bundle, in particular a simple string, inside of an mxml file you can gain access to the resource using the resourceManager or by using the @Resource directive. For simple strings, meaning strings you are not going to tokenize you should be using the @Resource directive instead of the resourceManager.

Lets examine a simple test app. Below you will see a simple app with two labels, both look for the same string in the same bundle and display them the same way. For all intents and purposes these two labels are exactly the same, except they are actually rather different.

sample app

<?xml version="1.0" encoding="utf-8"?>
<mx:Application xmlns:mx="http://www.adobe.com/2006/mxml" layout="vertical">
 
	<mx:Label text="@Resource(key='testString', bundle='labels')" />
	<!--
	<mx:Label text="{resourceManager.getString('labels', 'testString')}" />
	-->
 
</mx:Application>

If you add the generate as output argument to your compiler we can see what is happening under the covers here

compiler args

-locale en_US -source-path+=../locale/{locale} -keep-generated-actionscript

once Flex is done building you can easily see how the compiler has handled the resource bundle @directive

labels_properties.as

package
{
import mx.resources.ResourceBundle;
 
[ExcludeClass]
public class en_US$labels_properties extends ResourceBundle
{
 
    public function en_US$labels_properties()
    {
		 super("en_US", "labels");
    }
 
    override protected function getContent():Object
    {
        var content:Object =
        {
            "testString": "This is a test"
        };
        return content;
    }
}
}

main-generated.as (truncated…)

package
{
...
public class main
	extends mx.core.Application
{
	//	Container document descriptor
private var _documentDescriptor_ : mx.core.UIComponentDescriptor =
new mx.core.UIComponentDescriptor({
  type: mx.core.Application
  ,
  propertiesFactory: function():Object { return {
    childDescriptors: [
      new mx.core.UIComponentDescriptor({
        type: mx.controls.Label
        ,
        propertiesFactory: function():Object { return {
          text: ResourceManager.getInstance().getString("labels", "testString")
        }}
      })
    ]
  }}
})
 
	//	constructor (Flex display object)
    /**
     * @private
     **/
	public function main()
	{
		super();
 
		mx_internal::_document = this;
 
		//	our style settings
 
 
		//	ambient styles
		mx_internal::_main_StylesInit();
 
		//	properties
		this.layout = "vertical";
 
		//	events
 
	}
 
    /**
     * @private
     **/
	override public function initialize():void
	{
 		mx_internal::setDocumentDescriptor(_documentDescriptor_);
		super.initialize();
	}
 
	mx_internal static var _main_StylesInit_done:Boolean = false;
 
	mx_internal function _main_StylesInit():void
	{
		//	only add our style defs to the StyleManager once
		if (mx_internal::_main_StylesInit_done)
			return;
		else
			mx_internal::_main_StylesInit_done = true;
 
		var style:CSSStyleDeclaration;
		var effects:Array;
 
		StyleManager.mx_internal::initProtoChainRoots();
	}
}
}

now reverse the commented section so Flex builds using the resourceManager() inside the label instead of using the @Resource directive.

labels_properties.as

package
{
import mx.resources.ResourceBundle;
 
[ExcludeClass]
public class en_US$labels_properties extends ResourceBundle
{
 
    public function en_US$labels_properties()
    {
		 super("en_US", "labels");
    }
 
    override protected function getContent():Object
    {
        var content:Object =
        {
            "testString": "This is a test"
        };
        return content;
    }
}
}

main-generated.as (truncated…)

package
{
...
public class main
	extends mx.core.Application
	implements mx.binding.IBindingClient
{
 
	//	instance variables
/**
 * @private
 **/
	public var _main_Label1 : mx.controls.Label;
 
 
	//	type-import dummies
 
 
	//	Container document descriptor
private var _documentDescriptor_ : mx.core.UIComponentDescriptor =
new mx.core.UIComponentDescriptor({
  type: mx.core.Application
  ,
  propertiesFactory: function():Object { return {
    childDescriptors: [
      new mx.core.UIComponentDescriptor({
        type: mx.controls.Label
        ,
        id: "_main_Label1"
      })
    ]
  }}
})
 
	//	constructor (Flex display object)
    /**
     * @private
     **/
	public function main()
	{
		super();
 
		mx_internal::_document = this;
 
		//	our style settings
 
 
		//	ambient styles
		mx_internal::_main_StylesInit();
 
		//	properties
		this.layout = "vertical";
 
		//	events
 
	}
 
	//	initialize()
    /**
     * @private
     **/
	override public function initialize():void
	{
 		mx_internal::setDocumentDescriptor(_documentDescriptor_);
 
		var bindings:Array = _main_bindingsSetup();
		var watchers:Array = [];
 
		var target:main = this;
 
		if (_watcherSetupUtil == null)
		{
			var watcherSetupUtilClass:Object = getDefinitionByName("_mainWatcherSetupUtil");
			watcherSetupUtilClass["init"](null);
		}
 
		_watcherSetupUtil.setup(this,
					function(propertyName:String):* { return target[propertyName]; },
					bindings,
					watchers);
 
		for (var i:uint = 0; i < bindings.length; i++)
		{
			Binding(bindings[i]).execute();
		}
 
		mx_internal::_bindings = mx_internal::_bindings.concat(bindings);
		mx_internal::_watchers = mx_internal::_watchers.concat(watchers);
 
 
		super.initialize();
	}
 
	//	scripts
	//	end scripts
 
 
    //	supporting function definitions for properties, events, styles, effects
 
	//	binding mgmt
    private function _main_bindingsSetup():Array
    {
        var result:Array = [];
        var binding:Binding;
 
        binding = new mx.binding.Binding(this,
            function():String
            {
                var result:* = (resourceManager.getString('labels', 'testString'));
                var stringResult:String = (result == undefined ? null : String(result));
                return stringResult;
            },
            function(_sourceFunctionReturnValue:String):void
            {
 
                _main_Label1.text = _sourceFunctionReturnValue;
            },
            "_main_Label1.text");
        result[0] = binding;
 
        return result;
    }
 
    private function _main_bindingExprs():void
    {
        var destination:*;
		[Binding(id='0')]
		destination = (resourceManager.getString('labels', 'testString'));
    }
 
    /**
     * @private
     **/
    public static function set watcherSetupUtil(watcherSetupUtil:IWatcherSetupUtil):void
    {
        (main)._watcherSetupUtil = watcherSetupUtil;
    }
 
    private static var _watcherSetupUtil:IWatcherSetupUtil;
 
	//	initialize style defs for main
 
	mx_internal static var _main_StylesInit_done:Boolean = false;
 
	mx_internal function _main_StylesInit():void
	{
		//	only add our style defs to the StyleManager once
		if (mx_internal::_main_StylesInit_done)
			return;
		else
			mx_internal::_main_StylesInit_done = true;
 
		var style:CSSStyleDeclaration;
		var effects:Array;
 
 
		StyleManager.mx_internal::initProtoChainRoots();
	}
 
 
	//	embed carrier vars
	//	end embed carrier vars
 
	//	binding management vars
    /**
     * @private
     **/
    mx_internal var _bindings : Array = [];
    /**
     * @private
     **/
    mx_internal var _watchers : Array = [];
    /**
     * @private
     **/
    mx_internal var _bindingsByDestination : Object = {};
    /**
     * @private
     **/
    mx_internal var _bindingsBeginWithWord : Object = {};
 
}
}

Notice the addition of a change watcher to bind this string to the label. Now considering, again, this is a simple string, it will never change, we are not tokenizing it there for it will be everlasting throughout the application without the need to change therefore binding to this string is needless. You may also notice that the compiled swf using resourceManager is 256kb on disk. The compiled swf using @Resource is 248kb on disk, not a major difference but a difference none the less.




1 Comment

speak up

Add your comment below, or trackback from your own site.

Subscribe to these comments.

Be nice. Keep it clean. Stay on topic. No spam.

You can use these tags: <a href="" title=""> <abbr title=""> <acronym title=""> <b> <blockquote cite=""> <cite> <code> <del datetime=""> <em> <i> <q cite=""> <strike> <strong> <pre lang="" line="" escaped="">

*Required Fields