要本地化Flex2应用,我们需要将本地化资源文档编译为SWC库文档,然后在Flex应用中使用ActionScript或MXML访问资源集(resource bundles )中的本地化值。
Flex2的本地化特性面向以以下人员:
Web应用研发人员
Web应用翻译人员
Flex框架研发人员
Flex框架翻译人员(中文版?!嘿嘿...)
本地化应用流程:
要本地化Flex代码,我们需要改变我们MXML和ActionScript代码,创建本地化属性文档和类,运行compc工具创建SWC库文档,最后使用mxmlc工具将我们的应用编译成SWF文档。
使用ResourceBundle API
要本地化Flex代码第一步是使用 mx.resource.ResourceBundle API替换期待本地化的硬编码内容。我们能够在ActionScript和MXML代码中使用ResourceBundle API。
ResourceBundle是ActionScript 3.0语言规范的一部分,其包含如下和本地化资源交互的方法:
static getBundle(name:String):ResourceBundle,这里name指的是属性文档名或ResourceBundle子类名。
getString(key:String):String, 这里key指的是属性文档或ResourceBundle子类中明值对名称
getObject(clsName:String):Object
使用本地化字符串
在下面的例子的ActionScript代码中,ResourceBundle API被用来配置某一按钮的label值,ResourceBundle.getBundle()方法获取某一资源集,然后使用 ResourceBundle.getString() 方法资源集中某一键值。
...
varmyBundle:ResourceBundle=ResourceBundle.getBundle(getSystemManager(),
’MyBundle’);
myButton1.label=myBundle.getString(’myButton1_label’);
...
varmyBundle:ResourceBundle=ResourceBundle.getBundle(getSystemManager(),
’MyBundle’);
myButton1.label=myBundle.getString(’myButton1_label’);
...
在MXML中,我们指定资源集名称和键名给@Resource指令来获取特点资源集中的特定值。假如,我们只标明键名,默认资源集名称为当前类名称。资源集名称为包含特定键的属性文档或ResourceBundle子类名称。@Resource有以下两种形式以下例子使用@Resource指令配置Button控件的label属性:
<mx:Buttonid="myButton1"label="@Resource(bundle=’MyButtonResources’,
key=’myButton1_label’)"
click="ti1.text=’myButton1.label=’+myButton1.label;"/>
key=’myButton1_label’)"
click="ti1.text=’myButton1.label=’+myButton1.label;"/>
在本地化字符串中使用绑定(Using binding with localized strings)
我们能够使用绑定表达式将@Resource指令的键参数绑定到相应属性文档的键值中,以下MXML代码使用绑定表达式作为@Resource指令的键参数: <mx:Label id=”lab” text="@Resource('lab.text', {product.name})"/>
以下示例是相应属性文档中键值对,{0}将会被product.name替代:
lab.text=Wedonothave{0}instock.
我们也能够使用多个参数,例如在@Resource指令有多个参数时的:{0}和{1}。
假如需要的话,我们必须确保product.name是本地化的。
掉换本地化字符串顺序
我们能够基于区域使用某一本地化字符串或其他,例如,默认的英语属性文档可能包含如下键:
MYTEXT={0}and{1}
而另外一个English属性文档可能包含如下值:
MYTEXT={1}and{0}
某一MXML文档可能包含如下@Resource指令:
@Resource('MYTEXT', "My name is Bill.", "I am a developer.");
以上两个字符串在第二个区域中被掉换了。
以下是和以上@Resource指令等价的ActionScript代码:
varr:ResourceBundle;
r=ResourceBundle.getBundle(sm,"MyComponent1");
StringUtil.substitute(r.MYTEXT,"MynameisAnant","IamintheFlexteam");
r=ResourceBundle.getBundle(sm,"MyComponent1");
StringUtil.substitute(r.MYTEXT,"MynameisAnant","IamintheFlexteam");
使用本地化对象和嵌入资源
在应用中,假如要使用ActionScript类或嵌入资源,如图像,我们能够调用ResourceBundle.getObject()方法,当我们获取一个ResourceBundle子类后,能够使用该ResourceBundle子类的getObject()方法从资源集中获取特定的类:
varbundle:ResourceBundle=ResourceBundle.getBundle(sm,"LocaleClasses");
varobj:Object=bundle.getObject("FormattingClass");
varobj:Object=bundle.getObject("FormattingClass");
因为这里并没有到类的直接引用,我们必须使用ActionScript增加任意的可视子对象,例如:
varbundle:ResourceBundle=ResourceBundle.getBundle(sm,"LocaleClasses");
varobj:DisplayObject=DisplayObject(bundle.getObject("FormattingClass"));
myLocaleParent.add(obj);
varobj:DisplayObject=DisplayObject(bundle.getObject("FormattingClass"));
myLocaleParent.add(obj);
以上示例中,LocaleClasses是某一我们创建的用来存放嵌入类的ResourceBundle子类, 该类引用了被ResourceBundle的getContent()方法返回的对象的类(这句有些拗口:This class references the classes that are needed in the ResourceBundle in an Object returned from its getContent() method. )。以下LocaleClasses示例:
publicclassLocaleClassesextendsResourceBundle{
publicfunctionLocaleClasses(){
super();
}
overrideprotectedstaticfunctiongetContent():Object{
varcontentObj:Object=newObject();
contentObj.push("FormattingClass",FormattingClass);
contentObj.push("Class2",Class2);
//Moreclassescanbyaddedhere.
returncontentObj;
}
}
publicfunctionLocaleClasses(){
super();
}
overrideprotectedstaticfunctiongetContent():Object{
varcontentObj:Object=newObject();
contentObj.push("FormattingClass",FormattingClass);
contentObj.push("Class2",Class2);
//Moreclassescanbyaddedhere.
returncontentObj;
}
}
处理的过程类似嵌入资源,一共有三个步骤,首先我们必须使用基于类版本的嵌入,这就意味着我们必须为每个需要嵌入的资源创建一个类,例如,假如我们有一个JPG图片需要本地化,我们能够将以下RedJpg类添加到本地化目录中:
package{
importmx.core.SkinSprite;
[Embed(source=’red_jpg.jpg’)]
publicclassRedJpgextendsSkinSprite{
}
}
importmx.core.SkinSprite;
[Embed(source=’red_jpg.jpg’)]
publicclassRedJpgextendsSkinSprite{
}
}
第二步,将RedJpg类添加到某一扩展ResourceBundle的类中,这样是为了让编译器就有个需要处理的资源集了 。通常我们将任何需要的类放置在同一个资源集类中。
以下是个包含RedJpg类的ResourceBundle子类:
package{
importmx.resource.ResourceBundle;
publicclassMyClassesBundleextendsResourceBundle{
publicfunctionMyClassesBundle()
{
super();
}
overrideprotectedstaticfunctiongetContent():Object{
varcontentObj:Object=newObject();
content.push("RedJpg",RedJpg);
//addmoreclassreferenceshere
returncontentArr;
}
}
}
importmx.resource.ResourceBundle;
publicclassMyClassesBundleextendsResourceBundle{
publicfunctionMyClassesBundle()
{
super();
}
overrideprotectedstaticfunctiongetContent():Object{
varcontentObj:Object=newObject();
content.push("RedJpg",RedJpg);
//addmoreclassreferenceshere
returncontentArr;
}
}
}
在我们创建包含资源集的SWC文档后,我们的第三步在ActionScript中使用ResourceBundle.getObject()方法获取该对象并且将其添加到我们应用需要的任意地方。以下是使用RedJpg对象的示例:
...
<mx:Imageid="testJPG"/>
<mx:Script>
importmx.resource.ResourceBundle;
importmx.core.SkinSprite;
publicfunctioninitialize(){
//Wegetthebundleherethatisthenameoftheclassinstep2.
ResourceBundlebundle=ResourceBundle.getBundle(sm,
"MyClassesBundle");
//herewespecifythenameoftheclassfromstep1
SkinSpritesprite=SkinSprite(ResourceBundle.getObject("RedJpg"));
//andnowwesetuptheImage
testJPG.source=sprite;
}
<mx:Script>
<mx:Imageid="testJPG"/>
<mx:Script>
importmx.resource.ResourceBundle;
importmx.core.SkinSprite;
publicfunctioninitialize(){
//Wegetthebundleherethatisthenameoftheclassinstep2.
ResourceBundlebundle=ResourceBundle.getBundle(sm,
"MyClassesBundle");
//herewespecifythenameoftheclassfromstep1
SkinSpritesprite=SkinSprite(ResourceBundle.getObject("RedJpg"));
//andnowwesetuptheImage
testJPG.source=sprite;
}
<mx:Script>
使用本地化属性文档和ResourceBundle子类
属性文档和目录结构
我们将存放需要本地化的字符串属性的属性文档放置在某一用户创建的本地目录中。
为了避免MXML @Resource指令的bundle参数,我们能够将属性文档名命名为和类的相同的名称。当然,标明资源集名称是个很好的练习。假如我们没有标明bundle参数,那么属性文档名必须和类名称一致,例如,/myApp/MyAlert.as的属性文档将为:/ fr_FR/myApp/MyAlert.properties,fr_FR为区域(locale )标识,类似的,我们能够在多个区域目录中包含多个属性文档,区域(locale )通过compc的locale选项配置,Locale不能在运行时使用Locale类修改。
locale目录必须为compc 的ActionScript类路径的一部分,但是不能为mxmlc编译主SWF文档时的ActiongScript类路径的一部分。
本地化属性文档和Java属性文档的格式一致,都是简单文本格式的名值对,例如:
Button1_label=Button1
Link1_label=Link1
CheckBox1_label=CheckBox1
RadioButton1_label=RadioButton1
RadioButton2_label=RadioButton2
RadioButton3_label=RadioButton3
PopUpButton1_label=PopUpButton1
Link1_label=Link1
CheckBox1_label=CheckBox1
RadioButton1_label=RadioButton1
RadioButton2_label=RadioButton2
RadioButton3_label=RadioButton3
PopUpButton1_label=PopUpButton1
属性文档中任何的文本必须为Latin-1 或(和)Unicode-encoded (\udddd 符号)编码。
我们能够使用Java的native2ascii工具转换其他的格式,对于要处理大量的属性文档的情况,我们能够使用Ant的native2ascii任务批量转换属性文档为ASCII格式。
本地化文档和类搜索顺序
我们将本地化属性文档和ResourceBundle子类添加到相应的locale名称的目录下,更多本地化ActiongScript类信息,请查看“Using localized objects and embedded assets” 。
compc工具使用特定的locale法则搜索文档:精确locale名称、不带变种和国家的locale名称、最后是en_EN。
以下表格说明假如我们在使用compc命令编译本地化SWC文档时配置locale为fr_FR时的属性文档搜索顺序:
本地化文档 描述
/en_EN/Grape.as未使用该文档,因为在fr_FR目录下有一个同名文档,该文档的优先级比更高
/en_EN/AppCommon.properties该文档被使用,因为没有其他版本或更高优先级的文档。
/fr/Grape.as未使用该文档,因为在fr_FR目录下有一个同名文档,该文档的优先级比更高
/fr/Apple.as未使用该文档,因为在fr_FR目录下有一个同名文档,该文档的优先级比更高
/fr_FR/Grape.as该文档被使用,因为其优先级最高
/fr_FR/Orange.as该文档被使用,因为其优先级最高
/en_EN/AppCommon.properties该文档被使用,因为没有其他版本或更高优先级的文档。
/fr/Grape.as未使用该文档,因为在fr_FR目录下有一个同名文档,该文档的优先级比更高
/fr/Apple.as未使用该文档,因为在fr_FR目录下有一个同名文档,该文档的优先级比更高
/fr_FR/Grape.as该文档被使用,因为其优先级最高
/fr_FR/Orange.as该文档被使用,因为其优先级最高
我们能够和本地化我们自己代码相同的方法本地化Flex框架资源文档集,Flex框架的en_EN区域属性文档在Flex Builder安装目录的Flex Framework 2/ frameworks/locale/en_EN 目录下。包括Adobe用来创建缺省Flex框架SWC文档的属性文档:framework_rb.swc和包含给Flex框架使用的如用于日期、验证和格式化的字符串和符号的名值对的SharedResources.properties属性文档。
创建SWC文档
我们必须使用compc工具将本地化属性文档和ActionScript类打包进SWC文档中,我们能够使用以下compc参数创建SWC文档:
compc选项 描述
actionscript-classpath 该选项标明用户创建的本地化目录,我们必须使用{locale}符号,假如我们的文档在 / myfiles/locale_dir/en_EN 和/myfiles/ locale_dir/ja_JP两个位置,那么actionscript-classpath值为:/myfiles/ locale_dir/{locale}.
include-resource-bundles 标明需要包含进SWC文档的资源集文档,能够是属性文档名(名称不应包含前缀或基本文档路径)和ResourceBundle 子类名称。
output 要创建的SWC文档名称,必须指定。
locale locale选项标明要打包进SWC文档的locale,假如有多个locale,必须以不同的locale选项运行compc工具多次。
以下例子使用compc命令创建fr_FR资源集SWC文档:
compc -locale fr_FR -actionscript-classpath locale/{locale} -include-resource-bundles HelloWorld -output locale/fr_FR/HelloWorld.swc
更多compc工具信息,请查看: “Using the Command Line Compilers。”
创建应用SWF文档
我们使用mxmlc工具创建应用SWF文档。使用mxmlc命令的include-library选项标明我们要使用的本地化SWC文档位置,任何的SWC文档内容将在SWF文档创建的时候静态链接进SWF文档中。我们必须为每个区域创建相应的SWF文档。
注意:无需在mxmlc中指定locale选项
以下使用mxmlc命令创建一个en_EN资源集的本地化SWF文档:
mxmlc -include-libraries locale/en_US/HelloWorld.swc locale/en_EN/framework_rb.swc -- HelloWorld.mxml
当我们使用mxmlc的include-libraries选项时,我们必须标明framework_rb.swc的位置,该文档是给framework.swc使用的,更多mxmlc工具信息,请看出 “Using the Command Line Compilers。”
创建一个简单的本地化应用
以下步骤组合了之前我们讨论的创建本地化应用的各章节。
1. 创建文档:locale/en_US/HelloWorld.properties,包含如下内容:
hello=HelloWorld</p>
2. 创建文档:locale/en_FR/HelloWorld.properties,包含如下内容:
hello=Salut le Monde
3. 创建文档:HelloWorld.mxml,包含如下代码:
<mx:Applicationxmlns:mx="http://www.macromedia.com/2005/mxml"
width="400"height="400">
<mx:Labeltext="@Resource(key=’hello’,bundle=’HelloWorld’)"/>
</mx:Application>
width="400"height="400">
<mx:Labeltext="@Resource(key=’hello’,bundle=’HelloWorld’)"/>
</mx:Application>
4. 使用compc命令编译en_US区域资源:
compc-localeen_US-actionscript-classpathlocale/{locale}-include-resource-bundlesHelloWorld-outputlocale/en_US/HelloWorld.swc
5. 使用compc命令编译fr_FR区域资源:
compc-localefr_FR-actionscript-classpathlocale/{locale}-include-resource-bundlesHelloWorld-outputlocale/fr_FR/HelloWorld.swc
6. 运行mxmlc命令使用en_US资源集编译SWF:
mxmlc-include-librarieslocale/en_US/HelloWorld.swc${FlexFrameWork安装位置}/locale/en_EN/framework_rb.swc--HelloWorld.mxml
使用mxmlc的include-libraries,必须标明framework_rb.swc的位置以给framework.swc使用,运行以上命令后,将HelloWorld.swf重命名为HelloWorld_en_US.swf或其他类似的名称。
7. 运行mxmlc命令使用fr_FR资源集编译:
mxmlc -include-libraries locale/fr_FR/HelloWorld.swc ${Flex FrameWork安装位置}/locale/en_EN/framework_rb.swc -- HelloWorld.mxml
运行以上命令好,将HelloWorld.swf重新命名为HelloWorld_fr_FR.swf。
8. 运行以上两个swf文档将会看到 "Hello World"和"Salut le Monde".