If you want to make your application available to a large number of people, you won't be able to internataionalize your application. Flex comes with great support for this making this usually pretty complex task really easy.
Instead of defining text constants you simply define these in property files and reference the key values from your application. Depending on the selected language Flex will make sure the correct I18N value is used.
Example without I18N:
<?xml version="1.0" encoding="utf-8"?> <s:Application xmlns:fx="http://ns.adobe.com/mxml/2009" xmlns:s="library://ns.adobe.com/flex/spark" xmlns:mx="library://ns.adobe.com/flex/mx" minWidth="955" minHeight="600"> <s:Label text="Hello World." /> </s:Application>
The same code using Flex' I18N features:
<?xml version="1.0" encoding="utf-8"?> <s:Application xmlns:fx="http://ns.adobe.com/mxml/2009" xmlns:s="library://ns.adobe.com/flex/spark" xmlns:mx="library://ns.adobe.com/flex/mx" minWidth="955" minHeight="600"> <fx:Metadata> [ResourceBundle("myresources")] </fx:Metadata> <s:Label text="{resourceManager.getString('myresources','greeting')}" /> </s:Application>
Or programmatically:
<?xml version="1.0" encoding="utf-8"?> <s:Application xmlns:fx="http://ns.adobe.com/mxml/2009" xmlns:s="library://ns.adobe.com/flex/spark" xmlns:mx="library://ns.adobe.com/flex/mx" minWidth="955" minHeight="600" initialize="onInitialize(event)"> <fx:Metadata> [ResourceBundle("myresources")] </fx:Metadata> <fx:Script> <![ import mx.events.FlexEvent; private function onInitialize(event:FlexEvent):void { label.text = resourceManager.getString("myresources", "greeting"); } ]]> </fx:Script> <s:Label id="label" /> </s:Application>
The values Flex displays for a given locale, are provided in the project structure in property-files named "myresources.properties" (Has to match the name used in the "ResourceBundle")
If for example you wanted to support English and German, the directory structure would be the follwing:
src main locales en_EN myresources.properties de_DE myresources.properties
The content of both files would be obviously simple
greeting=Hello World.
Or for German:
greeting=Hallo Welt.
Configuring I18N with Flexmojos
In general there are two ways how the I18N data can be bundled.
- Compiles Locales, where the locale data for each supported language is compiled in to the binary
- Runtime Locales, where the locale data is loaded at runtime with each supported language providing a dedicated language bundle
Both options have their pro and cons
- Compiled Locales
- Pro:
- don't require a second call to the server and can be faster
- eventually better suited for mobile applications in which when switching a language the mobile connection could be a problem
- code for changing locales is really easy
- Con:
- make the binary bigger
- are not extensible, so if you decide to add a language to have to re-compile everything
- Pro:
- Runtime
- Pro:
- highly extensible, you can add new languages any time
- smaller binaries
- Con:
- require a call to the server whenever you switch the language
- might be slower to ba available as they require another roundtrip to the server
- the code to handle language changes is a lot more complex
- Pro:
Configuring Compiled Locales
Compiled locales are by far the easiest way to provide locales support:
<plugin> <groupId>net.flexmojos.oss</groupId> <artifactId>flexmojos-maven-plugin</artifactId> <extensions>true</extensions> <configuration> <localesCompiled> <locale>en_US</locale> <locale>de_DE</locale> </localesCompiled> </configuration> </plugin>
Simply by listing the locales you want to have compiled in within a "localesCompiled" tag, takes care of everything.
The following output will be created in the target directory:
target classes surefire-reports fonts.ser swf-1.0.0-SNAPSHOT.swf swf-1.0.0-SNAPSHOT-configs.xml swf-1.0.0-SNAPSHOT-link-report.xml swf-1.0.0-SNAPSHOT-size-report.xml
The "copy-flex-resources" goal will create the following output in the war directory:
war-1.0.0-SNAPSHOT history META-INF WEB-INF expressInstall.swf index.html swf-1.0.0-SNAPSHOT.swf swfobject.js
See an example project of this at: https://github.com/apache/flex-utilities/tree/develop/maven-flex-plugin/examples/i18n/compiled-locales
Configuring Runtime Locales
The configuration of runtime locales is actually equally simple, it's just a different tag:
<plugin> <groupId>net.flexmojos.oss</groupId> <artifactId>flexmojos-maven-plugin</artifactId> <extensions>true</extensions> <configuration> <localesRuntime> <locale>en_US</locale> <locale>de_DE</locale> </localesRuntime> </configuration> </plugin>
The main difference is the output and how you have to make it available. While with compiled locales a single SWC or SWF will be output, with runtime locales more files are created:
target classes surefire-reports fonts.ser swf-1.0.0-SNAPSHOT.rb.swc swf-1.0.0-SNAPSHOT.swf swf-1.0.0-SNAPSHOT-configs.xml swf-1.0.0-SNAPSHOT-de_DE.swf swf-1.0.0-SNAPSHOT-de_DE-configs.xml swf-1.0.0-SNAPSHOT-de_DE-link-report.xml swf-1.0.0-SNAPSHOT-de_DE-size-report.xml swf-1.0.0-SNAPSHOT-en_US.swf swf-1.0.0-SNAPSHOT-en_US-configs.xml swf-1.0.0-SNAPSHOT-en_US-link-report.xml swf-1.0.0-SNAPSHOT-en_US-size-report.xml swf-1.0.0-SNAPSHOT-link-report.xml swf-1.0.0-SNAPSHOT-rb.properties swf-1.0.0-SNAPSHOT-size-report.xml
The "copy-flex-resources" goal will create the following output in the war directory:
war-1.0.0-SNAPSHOT history locales swf-1.0.0-SNAPSHOT-de_DE.swf swf-1.0.0-SNAPSHOT-en_US.swf META-INF WEB-INF expressInstall.swf index.html swf-1.0.0-SNAPSHOT.swf swfobject.js
Notice the "locales" directory which contains the locale SWFs for each of the runtime locales defined in the SWF project.
See an example project of this at: https://github.com/apache/flex-utilities/tree/develop/maven-flex-plugin/examples/i18n/runtime-locales
Locale Chains
<plugin> <groupId>net.flexmojos.oss</groupId> <artifactId>flexmojos-maven-plugin</artifactId> <extensions>true</extensions> <configuration> <localesCompiled> <locale>en_US</locale> <locale>en_GB,en_US</locale> <locale>de_DE</locale> <locale>de_AT,de_DE</locale> </localesCompiled> </configuration> </plugin>
Please note this is not the same mechanism as providing a localization chain with the "resourceManager" inside the application, it just prevents compilation-failures for if we are missing resource bundles for any language.
In order to fully demonstrate the difference between locale-chains in a pom.xml and a locale chain in the application, have a look at the example in: https://github.com/apache/flex-utilities/tree/develop/maven-flex-plugin/examples/i18n/locale-chains