加入收藏 | 设为首页 | 会员中心 | 我要投稿 李大同 (https://www.lidatong.com.cn/)- 科技、建站、经验、云计算、5G、大数据,站长网!
当前位置: 首页 > 百科 > 正文

Flex本地化开发——第二部分:在运行时加载资源

发布时间:2020-12-15 01:04:32 所属栏目:百科 来源:网络整理
导读:在本系列的第 1 部分中,我讲解了如何通过把资源直接编译到应用程序中在 Flex 中启用本地化。在第 2 部分中,继续第 1 部分中的讨论,讲解另一种本地化方法,即单独编译资源属性文件并在运行时装载它们。还要讨论每种方法的好处和缺点,以及对所有应用程序进

在本系列的第 1 部分中,我讲解了如何通过把资源直接编译到应用程序中在 Flex 中启用本地化。在第 2 部分中,继续第 1 部分中的讨论,讲解另一种本地化方法,即单独编译资源属性文件并在运行时装载它们。还要讨论每种方法的好处和缺点,以及对所有应用程序进行本地化的一般方法。

通过创建属性文件并把它们编译到应用程序中,现在已经成功地在应用程序中启用了本地化。编译到应用程序中之后,属性文件被称为资源包 (resource bundle),Flex 资源管理程序通过访问它们提取本地化的值。在本教程的这一部分中,我将解释如何从应用程序中消除编译的资源包,改为把它们编译成资源模块 (resource module)。资源模块是资源包的集合,可以在运行时装载它们,供资源管理程序访问。

目录

  • 回顾
  • 继续
  • 判断必需的资源包
  • 创建自己的资源模块
  • 修改编译器选项
  • 在运行时装载自己的资源模块
  • 好处和缺点以及适合 Flex 开发人员的一般方法
  • 后续研究

要求

为了充分利用本文,您需要以下软件和文件:

Flash Builder 4

  • 试用
  • 购买

范例文件:

  • localization-part-ii-start.zip
  • localization-part-ii-end.zip

必备知识

要想完成本文中的步骤,您需要对 Flex 开发有一定的了解和经验,使用 Flash Builder(以前的 Flex Builder)或通过 SDK 使用命令行都可以。不需要具备本地化知识。

回顾

在继续讨论之前,先回顾一下在第 1 部分中完成的步骤。

  1. 设置项目和适当的目录结构。
  2. 为希望支持的地区创建属性文件。
  3. 确认本地化框架文件已经就位。
  4. 通过设置 Flex 编译器选项启用本地化并指定要支持的地区。
  5. 开始本地化!

继续

本系列的第 2 部分是第 1 部分的延续,因此继续使用第 1 部分结束时完成的项目。最初的项目 localization-part-ii-start 实际上就是第 1 部分最终的项目?localization-part-i-end。以这个项目作为起点,按本文中的步骤把属性文件外部化并在运行时装载它们。

完成第 1 部分中的步骤之后,只需再完成四个步骤就能够外部化并装载资源包。它们是:

  1. 判断项目应该包含哪些必需的资源包。
  2. 创建自己的资源模块(每个地区一个)并用它们替代属性文件。
  3. 修改编译器选项以包含适当的资源包,并指定只使用资源模块。
  4. 在运行时在应用程序中装载资源模块。

判断必需的资源包

应用程序在执行期间将使用许多资源包。即使没有与应用程序相关的本地化,许多核心 Flex 框架类也依靠资源包对运行时和编译时的警告和错误进行本地化。因此,在创建自己的资源模块(它们实质上是资源包的集合)之前,必须先查明要包含哪些资源 包。可以使用 Flex 编译器很轻松地完成这个步骤。只需在编译应用程序时使用 -resource-bundle-list 编译器选项,例如:

mxmlc -locale= -resource-bundle-list=used-resource-bundles.txt Main.mxml

注意:可以在通过命令行直接执行 mxmlc 时使用这个编译器选项,也可以在 Flash Builder 中的 Additional Compiler Arguments 设置中添加它。

bundles = collections components controls core effects layout resources skins styles textLayout

创建自己的资源模块

既然知道了应用程序要使用哪些资源包,现在就可以编译自己的资源模块了。为此,必须通过命令行执行 mxmlc。目前还不能在 Flash Builder 中编译资源模块。

要想编译资源模块,只需指定四个编译器选项:

  • locale—这是要为其创建资源模块的地区。
  • source-path—这个资源模块要使用的属性文件的位置。
  • include-resource-bundles—在前一步中查明的应用程序必须使用的资源包列表。
  • output—将生成的输出 SWF 文件。这就是您的资源模块!

注意:不指定要编译的 MXML 文件。

  1. 要想为示例应用程序编译地区 en_US 的资源模块,应该执行以下命令:
    mxmlc
    locale=en_US
    source-path=locale/{locale}
    include-resource-bundles=collections,components,controls,core,effects,layout,resources,skins,styles,textLayout -output resources.swf

    注意:可以按您喜欢的目录结构给资源模块命名,只要在应用程序中相应地装载它们即可,具体做法见在运行时装载自己的资源模块。

    这会使用 locale/en_US/ 中的属性文件为地区 en_US 创建资源模块 resources.swf,其中包含前面查明的其他资源包。

  2. 为地区 en_US 创建 resources.swf 之后,只需把它放在 localeen_US 中,与 en_US 属性文件放在一起。注意:这个项目不再需要属性文件,但是最好保留它们,因为以后可能需要修改它们。
  3. 对于另外三个地区重复步骤 1 和 2,见图 1。图 1. 为每个地区创建一个 resources.swf 文件。注意:可能会在项目中看到以下错误:Unable to resolve resource bundle ‘resources’。这是因为现在引用了一个不再存在的资源包,它已经被刚才创建的资源模块替代了。在下一节中修改编译器选项时将纠正这个错误。

修改编译器选项

刚才创建的资源模块已经就位了,现在可以修改编译器选项以包含适当的资源包,并指定只使用资源模块。

  • 要想包含适当的资源包,应该使用 -include-resource-bundles 编译器参数并指定前面生成的资源包列表。
  • 要想指定只使用资源模块,应该使用 -locale 编译器标志并加上等号 “=”,后面不加任何参数。这个步骤是可选的,但是因为这个应用程序确实只使用资源模块,最好让编译器知道这一情况。

按以下步骤设置编译器选项:

  1. 右键单击项目并选择 Properties。
  2. 选择左边的 Flex Compiler,使用下面的代码作为 Additional Compiler Arguments 设置:
    locale= -source-path ./locale/{locale} -include-resource-bundles collections components controls core effects layout resources skins styles textLayout

    注意:当通过 Flash Builder 修改编译器选项时,值不是逗号分隔的。

    注意:可能会收到一条警告,它指出地区的源路径是项目源路径的子目录。使用下面的编译器选项允许源路径重叠,就可以解决这个问题:-allow-source-path-overlap=true

在运行时装载自己的资源模块

最后一步是修改应用程序以在运行时装载资源模块。在第 1 部分中,已经在地区组合框上添加了更改事件处理函数,它会根据在这个组合框中选择的语言更改地区。这个事件处理函数的代码如下:

private function comboChangeHandler():void {
resourceManager.localeChain = [localeComboBox.selectedItem.locale];
}

可以这样做是因为必需的资源包(包括自己的定制 resources 资源包)被编译并装载到应用程序中了。因此,资源管理程序可以立即访问资源包。但是,现在资源包没有直接编译到应用程序中,所以必须手工装载它们。为此, 要调用 ResourceManager 的 loadResourceModule 函数。装载了资源模块之后,可以像上面的 comboChangeHandler 函数一样通过修改资源管理程序的 localeChain 属性更改地区。

让 comboChangeHandler 事件处理函数更改地区实际上只需要做一处修改,而且逻辑非常简单。首先,检查是否已经装载了想要的地区的资源模块。如果还没有,就装载它。否则,像正常情况下一样更改地区。

  1. 在 Source 视图中编辑 Main.mxml。
  2. 把现有的 comboChangeHandler 函数替换为以下代码:
            import mx.events.ResourceEvent;
    private function comboChangeHandler():void
    {
            var newLocale:String = String(localeComboBox.selectedItem.locale);
    
            // 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 = "./locale/" + newLocale + "/" + "resources.swf";
    
                    var eventDispatcher:IEventDispatcher = resourceManager.loadResourceModule(resourceModuleURL);
                                            eventDispatcher.addEventListener(ResourceEvent.COMPLETE,completeHandler);
            }
    
            function completeHandler(event:ResourceEvent):void
            {
                    resourceManager.localeChain = [localeComboBox.selectedItem.locale];
            }
    }

    代码首先用一个简单的 if 语句检查是否已经装载了所选的地区的资源模块。如果已经装载了,就调用 completeHandler 函数,这个函数使用与原来的 comboChangeHandler 函数相同的代码行更改资源管理程序的地区。如果还没有 装载资源,就装载它。首先,代码识别资源模块的位置,然后调用 resourceManager.loadResourceModule 函数。装载资源模块之后,调用 completeHandler 函数。

    注意:不要在调用 loadResourceModule 之后马上使用资源模块。ResourceManager 的 loadResourceModule 函数异步地执行调用,所以当调用完成时资源模块可能还没有 装载,还无法使用。相反,一定要 连接一个事件处理函数以监听 ResourceEvent.COMPLETE 事件。只有当派发这个事件时,才能够确定资源模块已经准备好了。

  3. 运行应用程序。当装载应用程序时,您会注意到表单中根本没有显示文本。目前,当在组合框中选择一种语言时,这个应用程序会装载适当的资源模块并更改地区。但是,在应用程序最初运行时,没有装载资源模块,所以不显示文本。为了解决这个问题,只需在主应用程序中添加 creationComplete 事件处理函数。当调用这个函数时,它装载默认地区 en_US。因为组合框在默认情况下显示英语,所以只需通过调用 comboChangeHandler 函数模拟选择英语的情况。
  4. 在 Main.mxml 中添加以下函数:
    private function init():void { comboChangeHandler(); }
  5. 最后,在主标记中添加 creationComplete=”init”。完成这些修改之后,示例应用程序的主 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"
                   creationComplete="init()">
    
        <fx:Script>
    
            <![CDATA[
                import mx.events.ResourceEvent;
    
                [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 init():void
                {
                    comboChangeHandler();
                }
    
                private function comboChangeHandler():void
                {
                    var newLocale:String = String(localeComboBox.selectedItem.locale);
    
                    // 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 = "./locale/" + newLocale + "/" + "resources.swf";
    
                        var eventDispatcher:IEventDispatcher = resourceManager.loadResourceModule(resourceModuleURL);
                        eventDispatcher.addEventListener(ResourceEvent.COMPLETE,completeHandler);
                    }
    
                    function completeHandler(event:ResourceEvent):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>

现在完成了!构建应用程序、运行它并选择不同的语言,应该会看到联系人表单在运行时装载适当的资源模块。如果遇到任何问题,请参考 localization-part-ii-end.zip 中完成后的项目文件。

好处和缺点以及适合 FLEX 开发人员的一般方法

现在,您已经学完了这个分两部分的教程!我们使用了两种方法在 Flex 框架中实现本地化:

  • 把资源包直接编译到应用程序中。
  • 在外部编译资源包,在运行时把它们装载到应用程序中。

既然已经了解了这两种方法,现在有必要比较一下每种方法的好处和缺点,这样就能够在下一个应用程序中实现本地化时采用适当的技术。

表 1.?直接编译的优点和缺点

优点 缺点
  • 肯定是更容易、更快的方法。
  • 属性文件容易读取和修改。
  • 不会由于装载资源模块增加应用程序的装载时间。
  • 属性文件转换为资源包,资源包被直接编译到应用程序中。根据属性文件的数量和大小不同,这可能对应用程序的 SWF 的大小产生显著影响。
  • 如果对属性文件进行任何修改,就需要完全重新编译整个项目。

表 2.?外部编译的优点和缺点

  • 因为资源包独立于应用程序单独地编译为资源模块,所以它们不会影响应用程序的主 SWF 的大小。
  • 可以修改本地化字符串而不需要重新编译整个项目。
  • 如果把应用程序设置为动态地读取可用的地区,那么实际上可以在任何时候添加新的地区。
  • 生成并装载资源模块的过程略微复杂一点儿。
  • 如果修改本地化字符串,就需要重新编译资源模块。
  • 与直接编译到应用程序中相比,在运行时装载资源模块最初花费的时间要长一点儿。另外,根据设置应用程序的方式不同,这可能需要额外的网络调用。应该测试这个场景,看看应用程序在启动时有什么改进(如果有的话)。

您可能想知道,对于自己的应用程序,应该采用哪种方法。一般来说,对于支持的地区比较少的应用程序,使用编译时资源是最合适的。对于支持许多地区、具有大量本地化字符串的大应用程序,使用资源模块更好。

但是,这并不意味着您只能采用某一种方法。对于许多应用程序,混合式方法非常有用。例如,对于默认地区或最常用的地区(比如英语和法语),可能希望 使用编译时资源。对于其他地区,可以使用资源模块并在运行时装载它们。这样就可以快速访问常用的两个地区,同时通过资源模块支持许多其他地区,而不会增加 应用程序 SWF 的大小。

后续研究

对于面向全球用户的任何应用程序,本地化都是重要的特性。为了确保您的应用程序不但支持适当的地区,而且高效地使用框架,一定要了解可用的两种方法以及实现它们的方式。应该了解这两种方法以及它们的好处和缺点,这会帮助您为应用程序选择最合适的方法。

关于作者:

Charles Bihis

Charles Bihis

blogs.adobe.com/charles

原文链接:http://www.wefdc.com/?p=523

(编辑:李大同)

【声明】本站内容均来自网络,其相关言论仅代表作者个人观点,不代表本站立场。若无意侵犯到您的权利,请及时与联系站长删除相关内容!

    推荐文章
      热点阅读