为了国际化的应用,本地化是预备开发你的Flex程序的必要阶段-或者任何的程序。 鉴于此,它很明显是任何一个拥有全球用户的软件的重要功能。 Flex有一个很强大的本地化框架,可以让你通过使用简单的基于文本的属性文件,轻易的、更有效率的实现本地化。 这些属性文件在被使用之前,必须预先载入到你的程序中,可以用以下两种方法实现:
- 直接打包本地化属性文件到你的程序里。
- 单独的编译本地化属性文件,将其放在程序外部,并在运行时加载。
这篇文章通过一个基本的Flex程序的本地化进程步骤,说明了第一种(更简单的)选择。 在系列文章的第二部分,我会讨论第二种办法。
要求
为了充分利用本文,您需要以下软件和文件:
Flash Builder 4
范例文件:
必备知识
为了完成这篇文章的阶段练习,你需要对Flex开发有一定的理解和体会,或者是了解Flash Builder(先前叫Flex Builder)或带命令行的SDK的使用。并不需要预先了解本地化的知识。
前言
对于任何面向国际化的程序来说,本地化是一个非常重要的功能。它看起来很困难,不过在Flex的本地化功能的帮助下,实现起来很容易。为了描述该过程,这篇文章会以一个简单的Flex应用为例,一步步的说明。为了简洁起见,我用了一个初步的项目供大家使用(localization-part-i- start)。它是一个简单的Flex联系方式,有一些区域项,比如名称,街道地址等等。它还包含一个下拉菜单,以便用户更改语言(当然在练习的开始,它还不能运行)。以这个基础的项目开始,大家可以照着问着一步步来完成本地化,甚至能在运行时改变语言!不过,在你动手之前,理解整个的操作步骤很有帮助。
完成本地化呢,基本上必须先达到四个任务。
- 以合适的目录结构创建项目。
- 创建那些你想实现本地化地区的属性文件。
- 确保本地化框架文件到位了。
- 设置Flex编译选项点选了本地化并指定了那些你希望支持的地区。
将PDT和Flash Builder结合的设置就完成了!
头两个步骤解决了程序的设置,从而保证你的属性文件可以访问到。第三第四步确保了你的程序的编译过程,包含了新创建的属性文件并使用了合适的编译标记和本地化框架文件。这些完成之后,你的属性文件就被打包到resource bundles里了。resource bundles可通过Flex的ResourceManager类被你的程序使用。之后,就剩余第五步了。
- 开始本地化吧! (这部分比较简单)
创建项目和目录结构
从导入初始项目到Flash Builder开始。 你会注意到它几乎就像是一个全新的项目,除了一些小的改动:
- Main.mxml不是空白的。它已经包含了基本的联系表单内容。
- 项目里额外增加了两个目录。
- /src/assets/ -包含项目中用到的所有assets(在本范例中,指准备本地化的每个国家的国旗图片)。
- /src/locale/ -这个是程序将会支持的各个地区用到的所有属性文件的上级目录。
运行下项目。 你会看到如下图示内容:
在本地化的文件夹内,有四个子文件夹,每个都对应程序里的四个本地化内容之一。常规的本地区命名如下:
{language}_{country code}
例如,en_US代表美国的官方语言。地区en_CA的意思,你也能猜到,就是代表加拿大地区的英语。范例程序将支持四个语言:英语,法语,德语和日本语(见图1)。

图1. 项目文件结构图
这里的目录结构并非是一个标准,尽管它是约定俗成的。你可以以你喜欢的方式来命名和组织你的本地化文件,但你需要在编译参数里小心的映射这些改动内容。参考特定的编译选项来了解更多的设置编译参数细节内容。
创建PROPERTIES FILES
一个properties files本质上是一个文本文件,定义了本地化的目标和它们的对应键值。你把这些文件放在各自对应的地区子文件夹下。完整的看,所有的 properties files定义了你的程序中所有的本地化目标。跟着下面的步骤,来创建你的第一个properties files吧,以本地化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只是常用的一个名称,但并非强制要求。根据程序的需要你可以起名为任何有意义的名称。同样,你也可以根据需要创建很多的properties file。比如,如果你要区分本地化中的图像和作为文本标签的asset资源,你可以使用一个文件assets.properties来作为你的 assets,用另一个文件dictionary.properties,来作为文本标签使用。
如你所见,properties file就是一个拥有基本的键/值配对的文本文件,以这种结构来描述本地化目标和值。本范例里,键和值是以一个等号来划分(=)的。你可以用冒号(:)或格的比如:
- 键=值
- 键:值
- 键 值
properties file里的注释是以#
或!
开始的。比如:
! This is a comment # This is also a comment
注意:其他的properties file的语法规则和范例,可以看Properties File Syntax。
现在你已经了解了范例程序里针对en_US的properties file是什么样的。你可以创建其他的文件,并放在对应的本地化文件夹里。
- 用下面的内容来创建针对fr_FR的properties file:
## 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的properties file:
## 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的properties file:
## 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/
所以呢,举例来说,为了支持在你的程序里Italian(it_IT),你需要确保必要的本地化文件也在一个it_IT文件夹里,里面包含着 frameworks/locale文件夹,类似于en_US。方便的是,Flex SDK提供了一个工具,名叫copylocale,简化了这个过程。你可以在下面的路径找到它:
FLEX_HOME/sdks/x.x.x/bin/ copylocale
直接打开一个terminal,并用下面的语句执行命令:
copylocale original_locale new_locale
该工具会在框架目录里创建一个新文件夹并复制需要的框架文件进去。每个程序将支持的地区都需要一个各自的文件。
注意:Flash Builder 和 the Flex 4 SDK已经内置支持多达16种常用地区,意味着这些文件已经存在了。在你创建任何文件之前,检查下locale文件夹里是否已经有了。如果所有你希望支持的地域都有了,那就没必要做什么改动。只在你发现缺失的情况下,才运行工具来创建。
拿本范例来说,你需要en_US, de_DE, fr_FR和ja_JP这些文件夹。en_US文件夹是默认存在的(你很可能有全部的这几个文件)。使用copylocale工具来创建缺失的其他3个文件夹。在命令行里,如果你没发现有fr_FR文件夹就执行该命令:
copylocale en_US de_DE copylocale en_US ja_JP
注意:如果在运行了工具后没发现有生成对应文件夹,你需要管理员权限。在windows,确保以管理员身份运行terminal。在Max OS X,确保使用sudo。
现在,在你的frameworks/locale文件夹里,你应该至少有了下面的四个文件夹:
- en_US
- fr_FR
- de_DE
- ja_JP
特定的编译选项
随着目录结构的创建,properties file的建立,需要的框架文件的复制之后,你只需要告诉编译器可以创建本地化了。 需要指定下面的两个编译选项
- locale—指程序支持的那些额外地区。
- source-path—指每个地区对应的properties file路径。
有很多方法来设置这些选项,最简单的是通过Flash Builder来执行命令行。
通过命令行来设置新增的地区和源文件路径
要通过命令行来设置新增的地区和源文件路径,直接在调用mxmlc的时候添加–locale flag
和–source-path flag
mxmlc –locale=en_US,fr_FR,de_DE,ja_JP –source-path=./locale/{locale}
通过改变Flash Builder里的编译参数来设置新增的地区和源文件路径
要在Flash Builder里设置新增区域,你可以直接把它们添加到编译参数里:
- 右键点击你的项目并选择属性。
- 选择左边的Flex Compiler ,添加下面的内容到Additional Compiler Arguments设置里:
-locale en_US de_DE fr_FR ja_JP –source-path ./locale/{locale}
Note: When modifying the compiler arguments this way, there is no equal sign (=) and the locales are not comma-separated.
- 点击OK。
source- path
的最后一个值{locale}
是为程序动态的指定地区。{locale}
会被你在- locale
选项里指定的每个地区值替代。因此,如果你改变了你的地区文件夹名称,确保这些改变也映射在编译参数里了。相对的,你也可以手动的添加每个 source path(比如:src/locale/en_US,src/locale/de_DE等等)。
注意:你可能得到一个编译警告,Source path entry, 'PROJECT_HOME/localization-part-i-end\src\locale\en_US', is a subdirectory of source path entry, 'PROJECT_HOME\localization-part-i-end\src'".这很正常,别因此而终止程序的发布。当然,你想去掉这个警告的话,可以添加一个编译参数 "-allow-source-path-overlap=true".
本地化!
之后呢,你要设置项目把properties files编译到resource bundles里面,使得它们在你的程序里可用。这些都做完之后,所有艰巨的工作就完成了。要引用properties files的值,你可以使用ResourceManager类。ResourceManager类实际上是一个单件类,主要负责你在程序里用到的所有 resource bundles。首先,你要声明你想使用的资源名。前面的步骤里,我们命名properties files为resources.properties,因此resource bundles被命名为resources
。
- 在Main.mxml里的
标记下,添加下面的MXML:</fx:Script>
<fx:Metadata> [ResourceBundle("resources")] </fx:Metadata>
当然,你也可以用下面的代码在ActionScript做声明:
[ResourceBundle("resources")] public class MyComponent extends UIComponent { ... }
- 下面,你需要为语言控制的组件ComboBox添加一个变化事件回调,来监测地区的改变。在<fx:Script>的标记里加下面的内容:
// 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">
将其改成:
<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 (Denmark)", 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>
- 运行一下程序,并选择不同的语言,来看看联系表单中的标签页的变化。 如下所示:
下一步做什么
对于全球性的程序或网站,本地化是一个主要的功能。如你所见,只需要几步简单的工作,你可以容易的本地化一个Flex应用。它不仅高效,而且易扩展。所有的前期工作完成后,伴随用户的增加,你的程序可以任意的增加更多的地区支持。也有其他的方法来完成本地化(包括在运行时加载资源,我准备在第二部分讨论),不过这个是最简单和通用的方法。依照上面的步骤,你可以即时的完成程序的本地化。
要更详细的了解Flex中的本地化,包括可选方法,更多的功能,本篇文章没涉及到的常规规范,可以参考Flex 4本地化文档。