国际化


Mac OS X是一个国际化的操作系统。比如:它不仅易于软件资源(文本,图像,声音等等)的本地化,而且它还可以显示包含多种语系的文本。然而,Mac OS X没有开发者的合作就不能完全满足国际化的要求。您需要参与并确信任何面向您自已国家和地区以外市场的软件被适当的国际化和本地化。您还应该确信您的应用程序能够支持多语系文本的显示。

在进一步讨论之前,初步地认识一下本地化,国际化和多语系支持等相关术语或许是很有帮助的。

除了用户界面的改编以外,本章节并没有涵盖有关本地化的其他内容,因为这些工作不属于软件开发的范畴。文本翻译通常由翻译专家来完成,而图像和声音的再现则是由画师和技师来完成的。当然,开发人员通常也可以由自己来实现这些功能,但这些工作都不需要他们去修改任何源代码。然而,对于开发人员来说,致力于实现本地化是很重要的。举个例子,开发人员始终应该检查用户界面中的翻译文本能否符合每个用户界面组件的要求。在这种情况下,要么适当地调整这些组件,要么就重新进行翻译。

 

国际化您的应用程序


国际化就是一种使您的应用程序独立于语言的过程,通过这种方式使用户能够选择使用应用程序的某一个语言版本,应用程序针对各种不同语言和地区中的某一部分实现了本地化。被本地化的仅仅是应用程序的资源(例如:文本,图像,声音等等),而该应用程序的所有被本地化版本中使用的可执行文件都是相同的。

使您的应用程序国际化就能使您的应用程序本地化。也就是说,通过将针对特定语言的文本,图像和声音以文件形式保存在您工程目录中的各个“语言特定”子目录内,以及通过适当使用“语言区识别(locale-savvy)”API来访问这些资源,您就可以建立应用程序的本地化支持。

即使您没有立即计划在您的应用程序中支持多语言,也应该明确将您的应用程序设计成能够支持国际化是很有益处的。如果您的应用程序设计恰当,您将来就不必改动源代码来引入国际化。因此,您也不会在以后植入必要的分支程序时,需冒产生错误的风险。再者,您也可以用最初只附带一种语言的产品来测试本地化代码,以使得将来为任何本地化版本所需的测试开销最小化。

Mac OS X中的国际化系统依赖着大量的技术支持。

之所以成为一个合理的国际化应用程序,是因为其可以识别Unicode,以及还能够包含多语系支持(请参见“加入多语系支持”

当然,必要的字体库以及提供输入服务的特殊程序必须被安在Mac OS X系统中。

 

语言预置以及束资源

“国际化”系统预置的“语言”设置面板让用户可以为各自的计算环境设定他们自己喜欢的语言和语言区(就是,一种语言在不同区域的变种)的顺序。正如在“预置系统”一章中所描述的,预置系统为每个用户在AppleLanguages关键字下,单独保存了语言和语言区的顺序列表。这样的话,对于一个懂多种语言的用户来说,如果一个应用程序没有包含用户首选语言的本地化版本,它可以指定第二种语言选择。

图12-1系统预置的国际化模块中的语言设置面板

语言列表中的每个字符串都潜在对应了束中资源目录中的一个.lproj目录名。系统中束管理例程用这个字符串来查找相对应的.lproj目录中的本地化资源。如果对应于首选语言的.lproj目录不存在,就会用第二种语言预置来搜索束中的本地化版本。它将持续查找只到找到一个本地化版本为止,默认的本地化语言版本就是开发时所用的语言。

核心基础束服务(CFBundle,Core Foundation Bundle Services)为Carbon和Java应用程序提供了这个搜索功能;对Cocoa应用程序而言,这一功能是由NSBundle类来提供的。一旦您的应用程序包含了“语言特定”资源的翻译版本,它就能根据用户的语言预置从适当的文件中装载本地化资源。因此,您的应用程序将自动使用用户所预设的语言中的一种向每个用户显示。在这里,使用用户的首选语言将是最为理想的(但也不是必需的)。

关于束是如何存储资源的信息请参见“束”一章。

 

指定语言和语言区

Mac OS X给予您三种不同的方式来表示语言预置和束的本地化,且每种方法都具有不同程度的特性。语言指定可以是:

推荐的方法是使用ISO 639语言缩写,或如果合适,也可使用ISO 3166区域缩写。然而,CFBundle和NSBundle都能够识别符合Mac OS 语言代码的语言名称,并可以将ISO 639缩写对应成这些名称。这可以让您使用这些名称来指示语言,诸如:English, French, German, Japanese, Chinese, Spanish, Italian, Swedish, and Portuguese等。然而,我们不鼓励使用这些语言名称。

注意:要获得ISO 639 和 ISO 3166 标准的复件,请访问国际标准化组织(the International Standards Organization)网站http://www.iso.ch

由于系统会试图寻找与语言预置最匹配的本地化资源,所以用户的语言预置应尽可能得详细,且存储在束中的本地化版本应尽可能的具有普遍性。如前面所提及的,系统束例程试着将语言预置中指定的语言与束中lproj目录名称相匹配,如未能确切匹配,它将试图在一个更普遍的水平上寻找本地化资源。

一个例子将帮助阐明这一点。假设有一个用户指定了首选语言预置为U.S. English (“en_US”)。用户启动了包含有两个本地化资源的应用程序,French.lproj 和English.lproj。当系统被要求要取回一个本地化资源时,它便会首选查找名为en_US.lproj的目录,然后是en.lproj目录,最后找到English.lproj目录中的资源。

当束例程在找寻资源时,会检查某一语言区的本地化资源,如果这种资源不存在,则查找该语言区所使用语言的本地化资源。这种行为使您能够将适用于多个语言区并通用一种语言的资源放入它们自已的lproj目录中,还可将这些资源从逻辑上组合在一起。系统先查找一"语言区特定"的本地化资源(如:en_US.lproj),如果没有找到需要找的资源,它便会寻找一"语言特定"的本地化资源,例如:en.lproj or English.lproj。如果在那里也不能找到的话,它便会继续寻找用户下一个预先选择的语言和语言区。Apple建议对于那些拥有针对特定语言区本地化版本的应用程序应,他们应该包含一个相对应语言的本地化版本,这个本地化版本中应包含有对这一语言通用的所有资源。

由于参照了ISO 639标准中的缩写,CFBundle 和 NSBundle能处理大多数已知的语言。(其覆盖范围非常广泛,在这些语言中甚至包括了Manx, Faroese, 和 Oromo。)您也可以用MacLocales.h中的 Carbon函数来将ISO 639缩写转换成与特定语言所对应的用户可视的语言名称。您还可以使用CFBundle 和 NSBundle无法理解的语言或语言区缩写。然而,如果您这样做了,那么对于语言的缩写,您就必须保证在语言预置和lproj目录名之间存在一个正确的匹配。

 

国际化和本地化的工具

在某种程度上,Mac OS X的国际化应用程序是将一种特定语言或区域的本地化资源放在束中适当的位置。某些情况下,您或许必须手动做这项工作,例如用代码段管理器的应用程序(CFM,Code Fragment Manager)(详情请见“CFM执行程序”)幸运的是,在多数情况下有工具可以来帮助您。

Project Builder提供了文件引用检测器(File Reference Inspector)来帮助您实现国际化。要国际化一个资源文件,请完成以下步骤:

1.将资源文件加入到Project Builder中。

1.从“Groups and Files(组与文件)”窗口面板中选择资源目录作为目标源(您需点击“Files(文件)”标签来打开“Groups and Files(组与文件)”窗口面板。)

2.从“Project(项目)”菜单中选择“Add Files(添加文件)”

3.用文件浏览器来查找这个资源,选中并点击“Open(打开)”。

4.在Project Builder所显示的对话框中,选择“Copy into group folder(复制到组文件夹)”,选择其中一个“关联”的引用类型结构(举个例子,“Project Relative(项目关联)”),确定选择了正确的目标后,点击“Add(添加)”。

2.选取资源文件并从“Project(项目)”菜单中选择“Show Info(显示信息)”。

3.在文件引用信息(File Reference Info)窗口中(图12-2),从 “本地化及平台(Localization & Platforms)”弹出式菜单中选择“Make Localized(使本地化)”。

4.在出现的对话框中,从弹出式菜单中选择一种标准语言或是手工输入一种列表中没有列出的语言。

如果已经有一个存在的资源,您想将其作为模板来建立另一个本地化资源,可选择“Add Localized Variant(添加本地化变种)”,并选取(或输入)一种其他的语言。Project Builder就会复制该资源到另一个.lproj目录中。

5.如果资源是一个文本文件,从“File Encoding(文件编码)”弹出式菜单中选择Unicode。

图12-2 Project Builder的文件引用检测器(File Reference Inspector)

要创建“strings” 字符串文件(包括嵌入在资源代码中的字符串的本地化版本),您可以用genstrings命令行工具程序或手动创建这些文件。更多信息请参阅“本地化字符串”

最后,对于使用该工具来本地化资源,有一句话我们必须说。对于图像和声音,我们可以使用适当的应用程序(如,Photoshop)来完成本地化。对于文本,通常可以使用字处理软件或是能够处理UTF-16编码格式的文本编辑器。TextEdit应用程序就包含了Mac OS X所提供的这些功能。如果您可以用一个诸如Interface Builder的应用程序来定义和归档用户界面,您就应该提供这些界面文档的不同本地化版本。关于此主题的更多信息请参见接下来的章节。

 

本地化用户界面

Mac OS X本机的集成开发环境由Project Builder,Interface Builder和一套编译,调试和执行工具组成。开发人员可以使用Interface Builder来为他们的应用程序创建用户界面。Interface Builder将这些界面保存为称为nib文件的XML文档。这样,您就可以本地化nib文件,就如同您可以本地化图像和声音文件一样。

注意:这一章节谈论的是Interface Builder和它的nib文件。然而,许多所讨论的问题也可适用于由其他IDE创建的本地化用户界面文档。

Nib文件存储了一个应用程序的用户界面,包括:窗口,对话框和用户界面组件(诸如:按钮,滚动条,文本对象)及这些组件的帮助标签。当用户激活控件时, Nib文件还维护着这些引起执行动作的对象之间的连接。一旦Nib文件都被典型地本地化,在得到一个Nib文件后,便需要翻译其所有用户可视的字符串,并做出其他必要的调整(例如调整可视组件的大小)。

在任何中等的或大型的应用程序中,将每个窗口或面板(也就是,对话框)放在它自已的Nib文件中是一个好的方法。这种方式不仅使按需装载用户界面(也就是,在必要时装载它)成为可能,而且还保证了能用更多增加的步骤来开展本地化。另外,把应用程序的菜单放在一个独立分开的Nib文件中也是一个好主意。

您应当使用Interface Builder来本地化Nib文件。为此,您需要打开所有在某一language.lproj目录中的Nib文件,本地化所有的字符串,改变用户界面组件的大小来适应新的字符串,并保存Nib文件。另外,还有其他的一些事情也值得注意:

 

本地化字符串

strings文件使您能具体化和本地化那些嵌入在您应用程序源代码中的字符串。他们被称作strings文件是因为他们具有strings扩展名,例如:Localizable.strings。一个束的每个本地化资源(也就是lproj目录)通常至少有一个strings文件。

注意strings文件对出现在归档用户界面中的字符串不起作用(比例,一个nib文件是由Interface Builder创建的)。对于这样的字符串,您可以用适当的开发程序来本地化他们(请参见“本地化用户界面”

还要牢记有两种内嵌的字符串:用户看得到的和用户看不到的。下面一段程序中包含了用户看不到的字符串的一个例子。

if (CFStringHasPrefix(value, CFSTR(“-”)) { CFArrayAppendValue(myArray, value);};

由于“-”字符串您从未看到过,所以它不必被本地化。它不会对用户看到的任何东西产生影响。另外,出现在警告对话框中的字符串也需要被本地化。

 

编写Strings文件

将需要被本地化的字符串写入strings文件,以下说明其格式:

/* A comment */
"Yes" = "Oui";
"The same text in English" = "Le même texte en fran?ais";

Strings文件中左边的字符串作为放在右边字符串代码的关键字。Carbon和Cocoa程序为从strings文件中访问本地化字符串提供了API。Cocoa程序会用以下的宏从strings文件中解读字符串。

NSLocalizedString(key, comment)
NSLocalizedStringFromTable(key, table, comment)

Carbon和其他非Carbon程序应该使用在核心基层束服务(CFBundle ,Core Foundation Bundle Services)中定义的相同的宏。

CFCopyLocalizedString(key, comment)
CFCopyLocalizedStringFromTable(key, table, comment)
CFCopyLocalizedStringFromTableInBundle(key, table, bundle, comment)

举个实际的例子,假设法语本地化被选定:

NSLocalizedString (@"Yes", @"")

会从以上的表中返回“Oui”,以下是上面宏命令的参数说明:

Key

用于查找本地化值的字符串

Table

要被搜索的strings文件的文件名(默认为“Localizable”,它会引发宏命令查找Localizable.strings)。

comment

strings文件生成时被放入strings文件的注解。

一些函数和方法(例如Cocoa的 stringWithFormat方法和Core Foundation的CFStringCreateWithFormat函数)允许接受带有格式字符的字符串参数。用这些函数和方法,您可以在关键字和值中的指定格式字符,举个例子:

"Windows must have at least %d columns and %d rows." =
"Les fenêtres doivent être composes de %d colonnes et %d lignes au minimum.";
"File %@ not found." = "Le fichier %@ n'existe pas.";

注意:“%@”描述符是标准的printf()格式字符的一个扩展,用于显示任何Cocoa 和 Core Foundation 对象。描述符的完整列表请参见“Cocoa:面向对象编程”和“Objective-C语言”。

如果必要,被翻译字符串的参数可以被记录下来。如果一个字符串包含了多个变量参数,您可以通过使用n$修饰符来改变参数的须序,其中n指的是参数的顺序。举个例子来说:

/* Message in alert dialog when something fails */
"%@ Error! %@ failed!" = "%2$@ blah blah, %1$@ blah!";

就如同在C语言中,一些字符必须加上反斜杠前缀,才能被适当的包含在字符串中。这些字符包括双引号,反斜杠,和回车(CR)。您也可以使用\n来表示回车:

"File \"%@\" cannot be opened" = " ... ";
"Type \"OK\" when done" = " ... ";

字符串中可以包含用\U后跟相当于四个表示Unicode字符的十六进制数字来指示任何Unicode字符。举个例子,空格的十六进制代码是20,它被表示为\U0020。如果字符串中包含的Unicode字符由于某些原因不能被键入,选择这种方式是很有用的。Unicode格式的Strings文件被最优化地存储。这一方式保证了其编码的独立性,并在一个应用程序装载strings文件时简化了其编码过程。TextEdit应用程序能够以Unicode格式来存储文件。您可以从纯文本模式下的存储对话框中选择编码方式,或将其作为TextEdit的一般预置。

 

生成strings文件

虽然您可以手动创建一个strings文件,但您也可以用命令行程序genstrings从您的源代码中自动生成产strings文件。

这个应用程序通过解析您指定的源代码,从每次对Cocoa的NSLocalizedString宏(及参数)和Core Foundation的CFCopyLocalizedString宏(及参数)的调用中解读信息,并将这些信息加入到适当的strings文件中去。每次从一个相关宏命令的调用中生成的输入项被放在一个名为table.strings文件当中,其中的table是来自于宏的“table”参数(如果没有指明table参数,就是默认的Localizable.strings文件)用单独的table来为多组字符串创建单独的域,并允许根据上下文环境对相同的字符串进行不同的翻译。

在这些调用中提供的注释也被写进了string文件,使翻译者可以更好的理解这个字符串的作用是什么。它对于了解genstrings为每一个对相关宏的调用生成一个入口和复制任何相同的入口都是非常重要的。如果您的代码中包含了不只一个具有相同参数的那些宏,在运行genstrings后,您将必须编缉string文件来删除多余的入口。虽然一个关键字可以在一个源文件中出现多次,但一个strings文件中的每个关键字都必须是唯一的。(然而,对于每个本地化资源,您都可以拥有多个strings文件或“tables”,并且每个文件都可以包含相同的关键字)。

是自动生成还是手工创建strings文件,这取决于您自己。在您进行程序开发的过程当中,有时您或许会发觉生成strings文件很容易,那么就可以选择手工创建它。然而,在大多数情况下,无论是在修改或是增加任何本地化字符串时,从源文件当中生成新的strings文件会比较好。

 

加入多语系支持


一个包含多语系支持的应用程序能够同时准确的以各种语系显示文本。这样的应用程序可以在同一文档中接受包含有不同语系的文本的输入,并能显示和打印这种文本,而不用考虑用户的语言预置。如果一个应用程序未提供多语系支持,这个文本的某些地方可能会出现混淆。

多语系支持正变得越来越重要,所期望的功能可以是针对操作系统,也可以是针对第三方应用程序的。伴随着国际化的操作系统,例如:Mac OS X,一些用户希望能够用一种语言和语系来创建文档,而一旦改变用户语言预置后,再打开此文档时,它也不会发生任何变化,就如同最近一次保存它时的一样。此外,互联网对这一支持也抱以了更大的期望,因为用户常常需要下载与其首选语言不同的外语文本。

在一般层度上,您通过使用适当的Unicode技术和 API来获得Mac OS X上的多语系支持。 以下明确地讲述了对于Carbon程序的这一方法:

GetIndString是基于语系系统的,因此它不能显示多语系文本。CFCopyLocalizedString可以显示这样的文本,因为它能返回一个基于CFString的对象。一般来说,您的代码应在静态文本上使用动态的文本处理(诸如“本地化字符”一章中所描述的本地化字符串的机制)。

通过使用特别的核心服务(Core Services)框架和核心基础(Core Foundation),您应该能够获得内核环境中的大部分功能(特别是BSD和Mach调用)。尽可能的避免直接调用BSD函数。对于文件系统的访问,可使用核心基础URL 服务(Core Foundation URL Services ,CFURL)、文件管理器(File Manager)的数据类型FSRef 或是(在Cocoa中的) NSFileManager。

TextEdit 的API能够处理多语系文本,然而,它要求您自己管理语系字体与风格。MLTE提供了一个更简单的API来处理基于Unicode的多语系文本。

您不能再假设所有的文本数据都是用MacRoman编码或是忽视文本编码问题。您必须对处理文本编码有所准备。没有附带语系代码的未标记文本数据在系统语系(Roman语系)中不再是必须的。如果这种假设是错误的话(常常会这样),就会向用户显示乱七八糟的文本。更糟的是,它会产生异常,导致破坏用户数据,甚系统崩溃。

被适当使用的Cocoa API会自动提供多语系支持。

关于Mac OS X文件编码的更多信息,请参见“文件系统”一章中“文件编码与字体”

 

[ 返回 ]