Flash Player中的flash.globalization包(part4):选择一个区域
在使用flash.globalization包提供的服务之前,您必须选择用户的文化。将区域(locale)想象成为 对一个团体(community)而言特定的文化习俗的一个集合(例如,澳大利亚的说英语的人) 。
区域标识符
每个区域都使用一个约定的编码(conventional code)来唯一标识 , 该编码存储在一个字符串(String),并符合 Unicode技术标准(Unicode Technical Standard)#35。概括地说,一个区域标识符看起来像这样: en-Latn-CA。第一部分是两个或三个字母的语言代码(在这个例子中,en 代表英语(English))。接着是可择的四个字母的代码,用以标识文字(script)种类( Latn 代表拉丁字母(Latin alphabet)。最后是一个可选的两到三个大写字母代码(或者,在特殊情况下,3位数字代码),用以指示该区域(CA 代表加拿大(Canada))。更为少见的情况是,使用一个第四部分来指定一个变种(variant)。
在一个区域标识符中唯一需要的组成部分是语言代码(language code)。但是,共享一种语言并不能保证文化习俗被同等地共享。例如,同是说英语,在美国的人写日期的方式就与在英国的人不同。因此通常是要指明地区(region)。
许多语言在书写时值使用一种文字(script)。例如,德语只使用拉丁字母书写。在这些情况下,文字通常被从区域标识符中忽略 , 因此文字一般是暗含的(如 de-AT ,表示在澳大利亚说德语的人)。相比之下,塞尔维亚语(Serbian)可能使用Cyrillic或拉丁字母来书写。如果您不指定文字,Flash Player会自动地选择常用的选项。为了避免歧义,建议使用用 sr-Cyrl-RS或者sr-Latn-RS 。
LocaleID类
一般来说,您可以简单地使用一个String对象来存储区域标识符;但是,如果您想获得与一个区域相关的信息,LocaleID类就提供了达到此目的的方式。
创建LocaleID对象是简单的:
import flash.globalization;
var localeId:LocaleID = new LocaleID("de");
在使用标识de构造LocaleID对象之后,方法getScript()将会返回Latn,这说明拉丁文(Latin)是书写德语的最佳书写系统;同时,方法getRegion()将返回DE,意味着德国是默认的选项。
LocaleID类中的一个特别有用的方法,即 isRightToLeft(),该方法可以让您知道一种语言通常的书写方向。在适当地对文字进行排版时,这些信息一般时必需的。例如,一个为区域ar-SA(阿拉伯、沙特阿拉伯)创建的日期格式化器将提供使用阿拉伯语书写的文字(月和一周各天的名字),这些都必须从右至左排序。知道格式化器提供的文本的方向,可以允许您使用Flash Player的文本布局框架(Text Layout Framework)适当地地对其进行显示。
区域备用
每当您要使用一个文化感知的服务(culturally aware service)(例如,一个数字格式化器)时,您必须指定需要使用的区域。由于一个操作系统和另一个操作系统所能够支持的区域不尽相同,所以您所要求的区域(以用户的名义)可能是不可用的。在这种情况下,Flash Player会尝试从可以获得的区域中选择最合适的一个。这是通过一下步骤来完成:首先,尝试匹配您所要求区域的语言;然后,通过尝试匹配书写系统和地区(region)来进行选择的优化。例如,如果您要求的是 de-CH,但是只有de-DE 可用,那么后者会被选中。如果您没有指定域(field)(例如,书写系统或地区),那么一个默认值(基于超群(preeminence))将会被自动地假设。例如,如果您指定 de,那么Flash Player将尝试匹配de-Latn_DE。
由于区域备用通常会为您提供最好的可用选择,所以您可以简单地继续使用您所实例化的服务。如果您想要更多的控制,那么在构造之后立即检查服务的lastOperationStatus属性:LastOperationStatus.USING_FALLBACK_WARNING表示一个备用的区域被选中了(它仍将匹配您所要求的语言,但其他域(filed),像地区(region),可能会有所不同);LastOperationStatus.USING_DEFAULT_WARNING 表示备用的区域是从操作系统获得的用户偏好(LocaleID.DEFAULT),作为最后的补救办法;在这种情况下,即使是语言也可能与您要求的不同。
此外,您总是可以检查所要求区域的标识符,也可以检查通过使用服务对象的requestedLocaleIDName和actualLocaleIDName属性有效地获得的区域标识符:
var numberFormatter:NumberFormatter = new NumberFormatter("de-DE"); if(numberFormatter.lastOperationStatus != LastOperationStatus.NO_ERROR) { //自定义函数warnUserOfFallbackLocale()由以您管用程序实现。 //它可以显示一个警报提醒用户, //数字值将显示使用一种非预期的习俗进行显示。 warnUserOfFallbackLocale(numberFormatter.requestedLocaleIDName, numberFormatter.actualLocaleIDName); }
注意,仅仅比较要求的和实际的区域标识符是否相等(requestedLocaleIDName == actualLocaleIDName)可能会产生误导性的结果)。例如,要求的fr-Latn-FR将来可能返回fr-FR;虽然标识符不是完全匹配的,但是它们都指向相同的有效的区域。
一个区域不能控制它们所有
理想情况下,每个用户一个区域就可以应用于所有的函数(functionalities),但实际情况可能会有所不同。因为翻译的代价比较高,所以应用程序的用户界面的不同区域版本在数量上是有限的。相反,flash.globalization包中的文化感知服务(culturally aware services)可以在不给您(应用程序开发者)增加额外代价的前提下支持更多的多样性。例如,如果您只提供了一个支持美国英语,法语和日语版本的用户界面,那么一个伦敦的用户可能为用户界面选择en-US(英语,美国),但是为数字和日期格式选择使用en-GB(英语,(大不列颠)联合王国)。对于排序规则(用于搜索和排序),同一用户也可能选择另一个区域。主流的操作系统(比如Mac OS X)都支持这种选择的自由,但是利用它需要使用几个区域标识符,每个函数(functionality)一个(区域标识符)。
常量LocaleID.DEFAULT表示对于每个服务用户的区域偏好,由操作系统指出。例如,如果用户已配置系统为数字格式化使用区域en-GB(英语,(大不列颠)联合王国),这表示一个使用LocaleID.DEFAULT的NumberFormatter将产生一个根据区域en-GB配置的格式化器。如果同样的用户已配置系统为日前格式化使用区域en-IN(英语,印度),这表明使用LocaleID.DEFAULT的DateTimeFormatter将产生一个为区域en-IN配置的格式化器。换句话说,按照用户的选择,对不同的服务LocaleID.DEFAULT可以很好地表示不同的区域。
决定使用哪个区域
在您的应用程序启动后的早期,您可能想确定最适合用户的区域。几种策略是可能的,而选择正确的一种则需要看您的应用程序的性质。
一个AIR应用程序通常应该就像任何其他桌面系统上安装的应用程序一样工作,并因此采用操作系统中用户所选择的区域。对于flash.globalization包提供的服务,您只需要使用特殊值LocaleID.DEFAULT: 对正被请求的服务,它会被自动地匹配到用户的选择。与此相反,对于它们用户界面的语言,AIR应用程序应该使用属性 flash.system.Capabilities.languages 来从操作系统检索(retrieve)用户的偏好。请注意,这里是languages,而不是language,flash.system.Capabilities.language也存在,但绝对是不同的:
- 属性language返回操作系统的用户界面语言,而不是用户的首选区域,并支持比languages较少的区域。
- 属性languages返回一个区域标识符数组。如果,像Mac OS X,操作系统允许用户指定首选语言环境列表,该数组包含那个列表,以降序排列用户的偏好(换句话说,用户首选的区域在数组中的第一个);其后是备用的首选区域。否则(例如,在Windows上),该数组包含一个单独项(用户区域)。即使在这种情况下,它也比属性language更可靠的。请注意,属性languages只适用于AIR应用程序。
如果您是在开发一个需要很好地整合到一个较大的网站中的在线SWF应用程序,您可能会想让两者使用相同的区域。在浏览该网站时,用户可能已经通过浏览器的设置选择了一个区域,或者是隐式地,或者是通过通过一个用户界面(由网站上的其他一些代码实现的)显示进行的。使用Flash Player的FlashVars属性(或者是一个URL查询字符串)来使HTML页面传递区域标识符到SWF文件。您可以通过this.root.loaderInfo.parameters或者,在Flex中,通过Application.application.parameters来检索(retrieve)这些值。
最后,如果您在创建一个大的客户-服务器应用程序,那么您可能想让用户通过您的应用程序首选项面板来进行区域选择。将这些设置存储在本地的一个 flash.net.SharedObject中,或者,如果您的应用程序需要用户登录,与用户账户信息一起存储在您的服务器上。为登录页面选择默认区域可以通过以下两种方法进行:从存储在本地的一个共享对象中检索(retrieve)该值,或者从一个HTML页面获得浏览器的语言设置(如前面所说)。
使用区域链
正如我之前解释的那样,使用用户做出的选择(在操作系统内为文化感知(culturally aware)服务所做的选择)是简单的:只要在您实例化一个服务时使用LocaleID.DEFAULT就可以了。附带的好处是,基本上可以保证这些由用户在操作系统内选择的区域是可用的,因为它们是从系统支持列表中挑选出来的。
然而,还有其他的情况,即不能保证用户的首选区域是可用的:
- 应用程序的用户界面区域首选项:用户可能已经表示了其首选是Dutch,但是不能保障一个给定的应用程序的使用该语言的用户界面是可用的。
- 区域被选择并存储在应用程序本身中(例如,为一个客户-服务器应用程序将用户帐户信息以存储在一个服务器上):用户可以从运行着不同操作系统的并支持不同区域列表的机器上,使用相同的用户帐户访问相同的应用程序。
在这些情况下,不能保证用户的首选区域实际上是可用的,更可能使用备用区域。然后这就变得有吸引力了,让用户将备用形成一个降序排列的区域列表(有时也称为区域连锁),而不是单一的区域选择(对于给定的服务)。列表中的第一个区域将会被使用(如果可用的话);否则,尝试列表中的下一个区域,如此一直尝试。例如,如果用户要求 ro-RO、fr-FR、it、en-GB,则应用程序应首先尝试使用区域ro-RO(或者,默认情况下,另一个Romanian-language区域);如果系统不支持该区域,应用程序应当接着尝试区域fr-FR ,等等。最后,如果用户的选择都不可用,那么应用程序应该依靠LocaleID.DEFAULT,因为它是被保证被安装了的,并且显然是用户可以理解的。
不用每次应用程序需要一个全球服务的时候都重复遍历这个首选区域链,在启动时,通过交叉一个给定服务的可用区域列表和由用户为该服务指定的首选区域列表,您可以决定使用哪个区域。LocaleID类恰好有为此目的的一个方法:determinePreferredLocales()。使用它很简单:您提供一个字符串vector(vector是一个类型数组(typed array)),其中包含首选区域列表和可用区域列表。它返回可用区域列表,这些区域都在首选列表上,并按偏好程度排序。然后,您可以安全地选择返回列表中的第一个区域。
不是提供一个严格的两份名单的交集,determinePreferredLocales()方法将完成一定数量的后备以便选择最适合的区域,赋予语言比对书写系统和地区更多的权值。例如,如果用户要求de-AT、fr-FR,但是只有de-DE、en-US、fr-FR 可用(而不是要求的de-AT),然后de-DE、fr-FR 将被返回。虽然没有出现在列表的首选区域中,de-DE出现在结果列表的第一个位置 ,因为它与de-AT最匹配。
您如何找出对于一个给定服务可用的区域呢?flash.globalization包中的每个服务类都有一个名为getAvailableLocaleIDNames()的静态方法,它准确地返回这样一个列表。如果您坚持尝试去为应用程序用户界面确定最合适的语音选择,那么提供了一个函数,让它返回这样一个列表。对于一个在线应用程序,该列表应可以很好地被从一个来自服务器的数据文件中进行初始化,允许新的语言包稍候被加入,然后自动地被请求它们的用户找到。
在下面的例子中,我们将假设您的应用程序提供了一个名为getUserPreferredLocaleIDsForNumberFormatting()的函数,它返回一个由用户为数字格式化器指定的区域链,形式是一个字符串的vector:
import flash.globalization; var availableLocales:Vector.<String> var preferredLocales:Vector.<String> = getUserPreferredLocaleIDsForNumberFormatting(); //检查普通的数字格式化器。 availableLocales = NumberFormatter.getAvailableLocaleIDNames(); preferredLocales = LocaleID.determinePreferredLocales(preferredLocales, availableLocales, ""); //如果必要,退而依靠默认的区域。</code> localeForNumberFormatting = (preferredLocales.length < 0 ? preferredLocales[0] : LocaleID.DEFAULT);
一次创建,经常重用
一旦您获得了最合适区域的标识符,您可能想要实例化那些将在整个应用程序中会经常地地需要的服务对象。这将避免建立多个服务对象,从而节省内存和执行时间:
//普通数字格式化器。 var defaultNumberFormatter:NumberFormatter = new NumberFormatter(localeForNumberFormatting); //使用欧元货币的货币格式化器。 var defaultEURMoneyFormatter:CurrencyFormatter = new CurrencyFormatter(localeForCurrencyFormatting); defaultEURMoneyFormatter.setCurrency("EUR","€"); //日期和时间格式化器,用于短日期和短时间。 var defaultShortDateFormatter:DateTimeFormatter = new DateTimeFormatter(localeForDateTimeFormattingDateTimeStyle.SHORT,DateTimeStyle.NONE); var defaultShortTimeFormatter:DateTimeFormatter=newDateTimeFormatter(localeForDateTimeFormatting.NONE, DateTimeStyle.SHORT); //用于排序和匹配的校对机(collat or) var defaultSortingCollator:Collator = new Collator(localeForCollation, CollatorMode.SORTING); var defaultMatchingCollator:Collator = new Collator(localeForCollation, CollatorMode.MATCHING); //文本转换。 var defaultTextUtilities = new StringTools(localeForTextTransformations);

.gif)
.gif)




.gif)
发表新评论