本地化是使得你的Flex应用程序或任何其它应用程序适用于国际应用的过程。 因此,本地化显然是任何拥有世界用户的应用程序的一个重要功能。 Flex具有一个功能强大的本地化框架,它允许你通过使用简单的、基于文本的属性文件,方便而有效地实现本地化功能。 这些属性文件必须在它们能够使用之前载入你的应用程序,它们通常以下列两种方式之一进行装载。
- 直接将本地化属性文件编译至你的应用程序之中
- 独立编译本地化属性文件,将它们放置于你的应用程序外部,然后在运行时将它们载入。
本文通过逐步讨论一个基本Flex应用程序的本地化过程,介绍其第一个(也是较为简单的)选项。 我将在本系列文章的第二部分介绍第二种方法。
概述
本地化是任何旨在拥有世界用户的应用程序的一个重要功能。 这看起来是一项令人畏惧的任务,但通过Flex的本地化功能的帮助,你将发现这竟是如此的简单。 本文通过逐步讨论一个基本Flex应用程序的本地化过程,介绍其第一个(也是较为简单的)选项。 为了简单起见,我已经提供了一个初学者项目(localization-part-i-start), 你可以将其用作你的基础。 它是一个具有许多本地化字段(例如“姓名”、“街道地址”等等)的简单Flex联系人表格。 它还包含一个下拉菜单,该菜单能够用于改变语言(尽管在本练习的开始阶段,它还不能实现这一任务)。 从这一种子项目开始,你可以按照本文给出的步骤对它进行本地化,甚至在运行时能够支持语言的变更。 但是,在你钻研该范例之前,有必要总体上了解相关过程。
在对你的应用程序进行本地化之前,基本上必须完成下列四项任务:
- 建立具有相应目录结构的项目
- 创建你希望支持的地区的属性文件。
- 确保本地化框架文件处于正确位置
- 设置Flex编译器选项以便支持本地化并且指定你希望支持的地区。
上述的前两步涉及设置应用程序,这样你的属性文件将能够进行存取和使用。 第三步和第四步将通过包含最新创建的属性文件和使用适当的编译器标志和本地化框架文件,以确保你的应用程序能够被正确编译。 一旦上述步骤执行完毕,你的属性文件将被编译到资源包(resource bundles)之中。 你的应用程序通过Flex ResourceManager类可以使用资源包。 在此之后,所有剩余的任务由第五步完成。
- 开始本地化! (这是较简单部分。)
建立项目和目录结构
首先在Flash Builder中导入启动项目。 你将发现这与一个全新的项目非常相似,除了下面一些微小变化:
- Main.mxml 不为空。 它已经具有基本联系人表格的内容。
- 在该项目中增加了下面两个目录:
- /src/assets/ – 该目录保存项目中使用的任何assets (在本例中,保存的是你希望本地化的目标国家的国旗图案)。
- /src/locale/ – 这是应用程序支持的地区的所有属性文件的父目录。
运行该项目并且熟悉相关代码。 你应该看到下列情形:
//swfobject.embedSWF("/content/dam/Adobe/en/devnet/flex/articles/flex_localization_pt1/localization-part-i-start.swf", "articlecontentAdobe-generic", "500", "376", "9.0.0", "", {}, {play: "true", loop: "true", menu: "true", scale: "showall", wmode: "opaque", swliveconnect: "false", devicefont: "false", allowscriptaccess: "samedomain", seamlesstabbing: "true", allowfullscreen: "true", allownetworking: "all" }, { "id":"articlecontentAdobe-generic", "name":"articlecontentAdobe-generic" }); //
在locale文件夹中,有4个子文件夹,每个子文件夹用于应用程序的4个地区之一。 命名一个地区的惯例如下所示:
{language}_{country code}
例如,en_US 表示在美国使用的英语。 地区en_CA表示(也许你已经猜到)在加拿大使用的英语。 该范例应用程序能够支持4种常用语言:英语、法语、德语和日语(参见图1)。
注: 上述目录结构不是标准的结构,尽管它是一个可接受的惯例。 你可以以任何你喜欢的方式对你的本地化文件进行命名和安排,但你应该考虑到在你的编译器参数中反映这些变化。 关于设置编译器参数的更多详细信息,请参见 指定编译器选项。
创建属性文件
属性文件实际上是一个文本文件,它定义本地化目标将其相应值。 你应该将每个属性文件放置于其相应地区的子文件夹中。 总体来说,属性文件能够在你的需要本地化的应用程序中完全定义所有本地化目标。 作为一个范例,按照下面步骤创建你的第一个地区en_US 的属性文件。
- 在/src/locales/en_US中创建一个新的文本文件,将其命名为resources.properties,然后将其以UTF-8格式保存。
- 将下列内容复制到该文件中:
## resources.properties file for locale en_US ## # contact-form labels and assets contact.title=Contact Form contact.flagImg=assets/us.gif contact.submit=Submit # contact-form fields contact.field.name=Name contact.field.streetAddress=Street Address contact.field.city=City contact.field.state=State contact.field.zipCode=ZIP Code contact.field.country=Country
注: 你可以将文件命名为你喜欢的任何名称;resources.properties是一个常用名称,但它不是一个必需的名称。 你可以根据任何对你的应用程序有意义的惯例对属性文件进行命名。 此外,你还可以拥有你希望的属性文件数量。 例如,如果你希望区分本地化的图像和asset源以及文本标签,你可能需要使用一个文件assets.properties用于包含你的assets,以 及使用另一个文件dictionary.properties包含你的文本标签。
正如你看到的那样,属性文件是一个简单的文本文件,它具有一个描述本地化目标和值的基本key/value对结构。 在本例中,key和value是利用一个等号(=)进行隔离的。 你也可以像使用一个分号(:)或空格对它们进行隔离。 例如:
- key = value
- key : value
- key value
在属性文件中注释行是以一个#或!开头的。 ; for example:
! This is a comment # This is also a comment
注: 关于属性文件句法和用法的更多规则,请参见 属性文件句法。
在你已经看到范例应用程序中的en_US属性文件的内容之后,你可以创建其它文件,并且将它们放置于相应的地区文件夹中。
- 利用下面内容创建fr_FR的属性文件:
## resources.properties file for locale fr_FR ## # contact-form labels and assets contact.title=Nom contact.flagImg=assets/fr.gif contact.submit=Soumettre # contact-form fields contact.field.name=Nom contact.field.streetAddress=Adresse contact.field.city=City contact.field.state=État contact.field.zipCode=Code Postal contact.field.country=Pays
- 利用下面内容创建de_DE的属性文件:
## resources.properties file for locale de_DE ## # contact-form labels and assets contact.title=Kontaktformular contact.flagImg=assets/de.gif contact.submit=Senden # contact-form fields contact.field.name=Name contact.field.streetAddress=Strasse und Hausnummer contact.field.city=City contact.field.state=Staat contact.field.zipCode=Postleitzahl contact.field.country=Land
- 最后,利用下面内容创建ja_JP的属性文件:
## resources.properties file for locale ja_JP ## # contact-form labels and assets contact.title=お問い合わせフォーム contact.flagImg=assets/jp.gif contact.submit=送信 # contact-form fields contact.field.name=名contact.field.streetAddress=ストリートアドレス contact.field.city=市 contact.field.state=状態contact.field.zipCode=郵便番号 contact.field.country=国
确保本地化框架文件处于正确位置
对于你在应用程序中支持的每个地区来说,你必须确保拥有该地区的框架资源。 实际上,对于你的应用程序的每个地区来说,必须在合适位置具有一个SWC的特定集合,以便你的应用程序能够正常编译和运行。 你可以在下面的文件夹中看到这些文件:
FLEX_HOME/sdks/x.x.x/frameworks/locale/en_US/
例如,如果你希望你的应用程序支持意大利语(it_IT) ,你需要确保在frameworks/locale 文件夹中的en_US旁边的it_IT 文件夹中还具有必要的本地化文件。 为方便起见,Flex SDK 提供一款名称为copylocale的工具,该工具能够简化这一过程。 你将会在下列位置找到它:
FLEX_HOME/sdks/x.x.x/bin/ copylocale
只需打开一个终端,然后使用下列语句调用相关命令:
copylocale original_locale new_locale
该工具能够在frameworks目录中为新的地区创建新的文件夹,然后将必要的框架文件复制到该文件夹中。 你需要在frameworks文件夹中为你的应用程序支持的每个地区定义一个地区。
注: Flash Builder和Flex 4 SDK已经能够支持16个最常用的地区,这意味着这些文件夹已经存在并且添加了必要的文件。 在创建你自己的内容之前,请核查locale文件夹以便查看哪些地区已经支持。 如果你希望支持的所有地区均已经存在,则你不需要在这里做任何工作。 你只需对那些没有看到的地区使用该工具。
在本教程范例中,你需要的文件夹为en_US、de_DE、fr_FR和ja_JP。 en_US文件夹是默认存在的 (你也可能拥有所有其它文件夹)。 使用copylocale工具添加对其它三个没有存在的地区的支持功能。 如果你没有看到fr_FR文件夹,在命令行运行下列命令:
copylocale en_US de_DE copylocale en_US ja_JP
注: 如果你在运行该工具时没有看到创建的文件夹,则你需要admin权限。 在Windows系统中,确保以Administrator身份运行终端。 在Max OS X系统中,确保使用sudo。
现在,在你的frameworks/locale文件夹中,你应该至少具有下列4个文件夹:
- en_US
- fr_FR
- de_DE
- ja_JP
指定编译器选项
利用创建的目录结构、合适的属性文件和复制的必要框架文件,你只需通知编译器你希望启动本地化操作。 通过指定下列两个编译器选项,你可以完成这一任务:
- locale—用于应用程序支持的更多地区
- source-path—用于至每个地区的属性文件的路径
有多种设置这些选项的方法,但两种最简单的方法是通过命令行和Flash Builder。
通过命令行设置附加地区和源路径
当通过命令行设置附加地区和源路径时,只需在调用mxmlc时添加–locale标志和–source-path 标志即可;例如:
mxmlc –locale=en_US,fr_FR,de_DE,ja_JP –source-path=./locale/{locale}
通过改变Flash Builder的编译器参数设置附加地区和源路径
当在Flash Builder中设置附加地区时,你可以将它们添加到编译器参数中即可:
- 右击你的项目,然后选择Properties。
- 选择左侧的Flex Compiler,然后将下列语句添加到Additional Compiler Arguments设置中:
-locale en_US de_DE fr_FR ja_JP –source-path ./locale/{locale}
注: 当以这一方法修改编译器参数时, 不使用等号(=)并且地区之间不使用逗号进行隔离。
- 点击OK按钮。
每个方法的source-path值的结尾部分的{locale}可以用于动态地为应用程序指定相应的地 区。 可以使用- locale选项通过你指定的每个地区值来替代{locale}。 因此,如果你修改你的locale文件夹的名称,你必须确保这些更改应该在编译器参数中反映出来。 此外,你也可以手工添加每个源路径(例如,src/locale/en_US、rc/locale/de_DE等等)。
注: 你可能会收到一条编译器警告提示:“源路径入口‘PROJECT_HOME/localization-part-i-endsrclocale en_US’, 是源路径入口 ‘PROJECT_HOMElocalization-part-i-endsrc’ 的一个子目录”(“Source path entry, ‘PROJECT_HOME/localization-part-i-endsrclocaleen_US’, is a subdirectory of source path entry, ‘PROJECT_HOMElocalization-part-i-endsrc’”)。 这是正常情形,它不会阻止你的应用程序按预期的方式正常运行。 然而,如果你希望删除该警告提示,则必须添加下面编译器参数“-allow-source-path-overlap=true”。
LOCALIZE!
至此为止,你已经建立了你的项目,它将属性文件编译到资源包中并且你的应用程序可以使用它们。 当你将所有这些工作安排妥当,所有艰难的工作已经完成, 你可以使用ResourceManager类引用属性文件中的值。 ResourceManager类实际上是一个Singleton,它能够负责处理你希望在你的应用程序中使用的所有资源包。 首先,你必须对你希望使用的资源进行声明。 在上述步骤中,你对属性文件resources.properties进行命名,因此这些资源包被称为resources。
- 在 Main.mxml 的标签的下面添加下列 MXML:
<fx:Metadata> [ResourceBundle("resources")] </fx:Metadata>
Alternatively, you can make the declaration in ActionScript using the following code:
[ResourceBundle("resources")] public class MyComponent extends UIComponent { ... }
- 下一步,你需要将一个变化处理程序添加至相应语言ComboBox控件,以便检测地区变化。 在标签中添加下面代码:
// within the Script tag private function comboChangeHandler():void { resourceManager.localeChain = [localeComboBox.selectedItem.locale]; }
- 为该ComboBox控件添加一个change处理程序:
<mx:ComboBox id="localeComboBox" dataProvider="{locales}" change="comboChangeHandler()"/>
- 最后,利用可本地化的值在你的应用程序中替换任何文本或assets。 例如,查找”Name”的Label:
<mx:FormItem label="Name">
And change it to:
<mx:FormItem label="{resourceManager.getString('resources','contact.field.name')}">
在你完成所有变更之后,你的范例应用程序的主MXML文件应该如下所示:
<?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"> <fx:Script> <![CDATA[ [Bindable] private var locales:Array = [{label:"English (United States)", locale:"en_US"}, {label:"German (Germany)", locale:"de_DE"}, {label:"French (France)", locale:"fr_FR"}, {label:"Japanese (Japan)", locale:"ja_JP"}]; private function comboChangeHandler():void { resourceManager.localeChain = [localeComboBox.selectedItem.locale]; } ]]> </fx:Script> <fx:Metadata> [ResourceBundle("resources")] </fx:Metadata> <s:layout> <s:VerticalLayout horizontalAlign="center" verticalAlign="middle" /> </s:layout> <s:Panel title="{resourceManager.getString('resources','contact.title')}" color="black" borderAlpha="0.15" width="350"> <s:layout> <s:VerticalLayout horizontalAlign="center" paddingLeft="10" paddingRight="10" paddingTop="10" paddingBottom="10" /> </s:layout> <mx:Form width="100%" color="0x323232"> <mx:FormItem label="{resourceManager.getString('resources','contact.field.name')}"> <s:TextInput /> </mx:FormItem> <mx:FormItem label="{resourceManager.getString('resources','contact.field.streetAddress')}"> <s:TextInput /> </mx:FormItem> <mx:FormItem label="{resourceManager.getString('resources','contact.field.city')}"> <s:TextInput /> </mx:FormItem> <mx:FormItem label="{resourceManager.getString('resources','contact.field.state')}"> <s:TextInput /> </mx:FormItem> <mx:FormItem label="{resourceManager.getString('resources','contact.field.zipCode')}"> <s:TextInput /> </mx:FormItem> <mx:FormItem label="{resourceManager.getString('resources','contact.field.country')}"> <s:TextInput /> </mx:FormItem> <mx:FormItem> <s:Button label="{resourceManager.getString('resources','contact.submit')}" /> </mx:FormItem> </mx:Form> </s:Panel> <mx:Spacer height="15" /> <s:HGroup width="350" verticalAlign="middle"> <mx:Spacer width="100%" /> <mx:Image source="{resourceManager.getString('resources','contact.flagImg')}"/> <mx:ComboBox id="localeComboBox" dataProvider="{locales}" change="comboChangeHandler()"/> </s:HGroup> </s:Application>
- 编译应用程序,运行应用程序,然后选择不同语言以查看联系人表格的标签变更。 你应该看到下列情形:
// swfobject.embedSWF("/content/dam/Adobe/en/devnet/flex/articles/flex_localization_pt1/localization-part-i-end.swf", "articlecontentAdobe-generic_0", "500", "376", "9.0.0", "", {}, {play: "true", loop: "true", menu: "true", scale: "showall", wmode: "opaque", swliveconnect: "false", devicefont: "false", allowscriptaccess: "samedomain", seamlesstabbing: "true", allowfullscreen: "true", allownetworking: "all" }, { "id":"articlecontentAdobe-generic_0", "name":"articlecontentAdobe-generic_0" }); //
下一步阅读方向
本地化是任何全球化应用程序或网站的一个重要功能。 正如你已经看到的那样,通过若干简单的步骤,你可以非常简单地对Flex应用程序进行本地化操作。 它不仅有效,而且可以升级。 在所有的准备工作完成之后,当你的用户群扩展时,你的应用程序能够方便地升级以支持更多本地化目标和地区。 目前,也有其它实现本地化的方法(包括在运行时载入资源,我将在第二部分讨论这一话题),但上述方法是最简单和最常用的方法之一。 利用上述讨论的步骤,你将立刻能够将你的应用程序本地化。