Resource modules are SWF files, separate from your application
SWF file, that contain resources bundles for a single locale. Your
application can preload one or more resource modules as it starts
up, before it displays its user interface. It can also load resource
modules later, such as in response to the user selecting a new locale.
The ResourceManager interacts with all resource bundles the same, whether
the bundles it manages were originally compiled into the application
or loaded from resource modules.
Resource modules can be a better approach to localization than
compile-time resources because you externalize the resource modules
that can be loaded at run time. This creates a smaller application
SWF file, but then requires that you load a separate SWF file for
each resource module that you use. The result can be an increased
number of network requests and an aggregate application size that is
larger than if you compiled the locale resources into the application.
However, if you have many locales, then loading them separately
should save resources in the long run.
You are limited as to when you can use resources in resource
modules during the application initialization sequence. The earliest
that you can access a resource bundle in a resource module is during
the application’s preinitialize event handler. You should not try
to access a resource at class initialization time or during preloading.
Creating resource modules
To create a resource module, you must do the following:
Determine the required resource bundles
Create the resource module SWF file
The following sections describe these tasks.
Determining the required resource bundles to include in a resource module
Before you can compile a resource module, you must know
which resource bundles to put into it. In other words, you must
know which resource bundles your application — and all of its framework
classes — actually require. This includes not just the custom resource
bundles that you create, but also the framework resource bundles
that are required by the application.
To determine which resource bundles an application needs, you
use the resource-bundle-list compiler option. When
you compile an application, this option outputs a list of the needed
bundles by examining the [ResourceBundle] metadata
on all of the classes in your application.
The resource-bundle-list option takes a filename
as its argument. This filename is where the compiler writes the
list of bundles. On the Macintosh OS X, you must specify an absolute
path for this option. On all other operating systems, you can specify
a relative or absolute path.
When using the resource-bundle-list option,
you must also set the value of the locale option
to an empty string.
The following command-line example generates a resource bundle
list for the application MyApp:
In Flash Builder, you add the locale and resource-bundle-list options to
the Additional Compiler Arguments field on the Flex Compiler pane
in the project’s properties. On Windows, the output file’s location
is relative to the Flash Builder directory, not the project’s directory.
You can specify an absolute path instead. On Macintosh, the option
must be an absolute path.
If you use custom resource bundles, those will be included in
this list. In this example, the name of the resource properties
file is RegistrationForm. The others are bundles containing framework
resources.
You use this list to instruct the compiler which resource bundles
to include when you compile a resource module.
Compiling a resource module
To compile a resource module, you must use the mxmlc command-line
compiler. You cannot compile resource modules by using Flash Builder.
The output is a SWF file that you can then load at run time.
To compile a resource module on the command line, use the following
guidelines:
You can compile the resources for only a single locale into each
resource module. As a result, you cannot specify more than one locale
for the locale option.
You should use a common naming convention for all of your locales’
resource modules. For example, specify the locale in the SWF file’s
name, but keep the rest of the file name the same for all locales.
This is because when you load the resource module, you want to be
able to dynamically determine which SWF file to load. In the previous
example, the resource module for the en_US locale is named en_US_ResourceModule.swf.
If you then generated a resource module for the es_ES locale, it
would be named es_ES_ResourceModule.swf.
Loading resource modules at run time
To load a resource module at run time, you use the ResourceManager’s loadResourceModule() method.
After the resource module has finished loading, you set the value
of the ResourceManager’s localeChain property to the
newly-loaded locale.
The ResourceManager’s loadResourceModule() method
asynchronously loads a resource module. It works similarly to the loadStyleDeclarations() method
of the StyleManager, which loads style modules.
The loadResourceModule() method takes several
parameters. The first parameter is the URL for the resource modules’s
SWF file. This is the only required parameter. The second parameter
is update. You set this to true or false, depending
on whether you want the resource bundles to immediately update in the
application. For more information, see Updating resource modules. The final two parameters are applicationDomain and securityDomain.
These parameters specify the domains into which the resource module
is loaded. In most cases, you should accept the default values (null)
for these parameters. The result is that the resource module is
loaded into child domains of the current domains.
The loadResourceModule() method returns an instance
of the IEventDispatcher class. You can use this object to dispatch ResourceEventtypes
based on the success of the resource module’s loading. You have
access to the ResourceEvent.PROGRESS, ResourceEvent.COMPLETE,
and ResourceEvent.ERROR events of the loading process.
You should not call the loadResourceModule() method
and then immediately try to use the resource module because the
resource module’s SWF file must be transferred across the network
and then loaded by the application. As a result, you should add
a listener for the ResourceManager’s ResourceEvent.COMPLETE event.
When the ResourceEvent.COMPLETE event is dispatched,
you can set the localeChain property to use the
newly-loaded resource module.
The following example loads a resource module when the user selects
the locale from the ComboBox control. It builds the name of the
SWF file (in this case, it is either en_US_ResourceModule.swf or
es_ES_ResourceModule.swf), and passes that file name to the loadResourceModule() method.
<?xml version="1.0"?>
<!-- resourcebundles/ResourceModuleApp.mxml -->
<s:Application
xmlns:fx="http://ns.adobe.com/mxml/2009"
xmlns:mx="library://ns.adobe.com/flex/mx"
xmlns:s="library://ns.adobe.com/flex/spark"
creationComplete="initApp()">
<fx:Script><![CDATA[
import mx.resources.ResourceBundle;
import mx.controls.Alert;
import mx.events.ResourceEvent;
[Bindable]
private var locales:Array = [ "es_ES","en_US" ];
private function initApp():void {
/* Set the index to -1 so that the prompt appears
when the application first loads. */
localeComboBox.selectedIndex = -1;
}
private function registrationComplete():void {
Alert.show(resourceManager.getString('RegistrationForm', 'thanks'));
}
private function comboChangeHandler():void {
var newLocale:String = String(localeComboBox.selectedItem);
/* Ensure that you are not loading the same resource module more than once. */
if (resourceManager.getLocales().indexOf(newLocale) != -1) {
completeHandler(null);
} else {
// Build the file name of the resource module.
var resourceModuleURL:String = newLocale + "_ResourceModule.swf";
var eventDispatcher:IEventDispatcher =
resourceManager.loadResourceModule(resourceModuleURL);
eventDispatcher.addEventListener(ResourceEvent.COMPLETE, completeHandler);
}
}
private function completeHandler(event:ResourceEvent):void {
resourceManager.localeChain = [ localeComboBox.selectedItem ];
/* This style is not bound to the resource bundle, so it must be reset when
the new locale is selected. */
b1.setStyle("downSkin", resourceManager.getClass("RegistrationForm", "flag"));
}
]]></fx:Script>
<s:layout>
<s:VerticalLayout/>
</s:layout>
<fx:Metadata>
[ResourceBundle("RegistrationForm")]
</fx:Metadata>
<s:Image source="{resourceManager.getClass('RegistrationForm', 'flag')}"/>
<mx:ComboBox id="localeComboBox"
prompt="Select One..."
dataProvider="{locales}"
change="comboChangeHandler()"/>
<s:Form>
<s:FormItem label="{resourceManager.getString('RegistrationForm','personname')}">
<s:TextInput/>
</s:FormItem>
<s:FormItem label="{resourceManager.getString('RegistrationForm','street_address')}">
<s:TextInput/>
</s:FormItem>
<s:FormItem label="{resourceManager.getString('RegistrationForm','city')}">
<s:TextInput/>
</s:FormItem>
<s:FormItem label="{resourceManager.getString('RegistrationForm','state')}">
<s:TextInput/>
</s:FormItem>
<s:FormItem label="{resourceManager.getString('RegistrationForm','zip')}">
<s:TextInput/>
</s:FormItem>
</s:Form>
<s:Button id="b1"
label="{resourceManager.getString('RegistrationForm','submit_button')}"
click="registrationComplete()"/>
</s:Application>
The executing SWF file for the previous example is shown below:
To compile an application that uses only resource modules, do
not specify any locales to be compiled into the application. You
do this by setting the value of the locale option
to an empty String. For example, on the command line, you can compile
an application named MyApp.mxml with the following command:
mxmlc -locale= MyApp.mxml
In Flash Builder, you add the following option to the Additional
Compiler Arguments field on the Flex Compiler pane in the project’s
properties:
-locale=
If you compile an application that uses both compiled-in resources
and resource modules, then you specify the locale(s) for the compiled-in
resources with the locale option.
You should try to avoid loading the same resource module more
than once in the application. To do this, you can use the ResourceManager’s getLocales() method.
This method returns an Array of locales. You can compare this list against
the resource module’s locale that you are about to load.
You can find out which resource bundles exist for a specified
locale by using the getBundleNamesForLocale() method.
You can get a reference to a particular locale’s resource bundle
by calling the getResourceBundle() method. Once
you have a reference to a ResourceBundle, you can use a for-in loop
to iterate over its content object. For more information, see Enumerating resources.
Loading remote resource modules
Loading a remote resource module typically requires a crossdomain.xml
file that gives the loading application permission to load the SWF
file. You can do without a crossdomain.xml file if your application
is in the local-trusted sandbox, but this is usually restricted
to SWF files that have been installed as applications on the local
machine. For more information about crossdomain.xml files, see Using cross-domain policy files.
Also, to use a remote resource module, you must compile the loading
application with network access (have the use-network compiler
option set to true, the default). If you compile
and run the application on a local file system, you might not be
able to load a remotely accessible SWF file.
Updating resource modules
The second parameter of the loadResourceModule() method
is update. Set the update parameter
to true to force an immediate update of the resource
bundles in the application. Set it to false to
avoid an immediate update of the resource bundles in the application.
The resources are updated the next time you call this method or
the unloadResourceModule() method with the update property
set to true.
Each time you call the loadResourceModule() method
with the update parameter set to true,
Adobe Flash Player and AIR reapply all resource bundles in the application,
which can degrade performance. If you load multiple resource modules
at the same time, you should set the update parameter
to false for all but the last call to this method.
As a result, Flash Player and AIR only apply the resource bundles
once for all new resource module SWF files rather than once for each
new resource module SWF file.
Preloading resource modules at run time
You can load a resource module when the application starts
up by calling the loadResourceModule() method from
your application initialization code, and then specifying the value
of the localeChain property after the module loads.
This is useful if you have a default locale that you want all users
to start the application with. However, you can also specify the
locale that the application should load on startup by passing flashVars properties
in the HTML wrapper. This lets you specify a locale based on some
run time value such as the Accept-Language HTTP
header or the Capabilities.language property in ActionScript.
The following table describes the flashVars properties
that you pass to set the preloaded resource modules:
flashVars property
Description
localeChain
A comma-separated list of locales that initializes
the localeChain property of the ResourceManager
class. If the localeChain property is not explicitly
set, then it is initialized to the list of locales for which the
application was compiled, as specified by the locale compiler
option.
resourceModuleURLs
A comma-separated list of URLs from which
resource modules will be sequentially preloaded. Resource modules
are loaded by the same class as RSLs, but are loaded after the RSLs.
The
URLs can be relative or absolute.
As with URL parameters, you must separate these values with an
ampersand (&). You must also ensure that the values are URL
encoded.
If you write your own HTML template, you can pass variables as flashVars properties
in the <object> and <embed> tags.
The following example specifies that the es_ES locale’s resource
module is preloaded when the application launches:
If you are using the SWFObject 2 template that Flex uses by default,
define and pass the flashVars object to the embedSWF() JavaScript
method, as the following example shows:
Using a combination of compile-time resources and resource modules
You might have a default locale that you want all users
of your application to start with. You can compile this locale’s
resources into the application. You can then load external resource
modules if the user changes the locale.
To do this, you compile the resource module as you normally would.
When you compile the application, rather than specifying an empty
String for the locale option, you set it to the
locale that you want to compile into the application. This compiled-in
locale’s resource bundles become the default bundles when the application
starts. You can then load a resource module SWF file as you normally would
at run time.
Unloading resource modules at run time
You can unload a resource module when you are no longer
using it. For example, if the user changes to a different locale,
you can unload the resource module for one locale after loading
the resource module for the new locale. This can reduce the memory
footprint used by the application.
To unload a resource module, you can use the ResourceManager’s unloadResourceModule() method.
This removes the resource module’s SWF file from memory. Its resources
cannot be used until that module is reloaded.
Resource module SWF files are cached by the browser just like
any other SWF file. As a result, if you unload a resource module,
and then later want to reload it, Flash Player and AIR will load
it from the browser’s cache rather than make another network request.
If the browser’s cache was cleared, though, then Flash Player and
AIR will load the resource module’s SWF file with a network request
again.
You can unload individual resource bundles rather than the entire
resource module. You do this with the ResourceManager’s removeResourceBundle() method.
This method takes a locale and the resource bundle’s name, which
you can access with the getBundleNamesForLocale() method.
Rather than iterate over the resource bundle names, you can use
the removeResourceBundlesForLocale() method, which
removes all resource bundles for a locale.