简介
国际化(internationalisation,i18n):一个程序或软件可给特定的人群使用而无须修改或重新编译源代码。对于 iOS 来说就是,使App能够适用于不同的语言,地区,文化的过程。
本地化 (localisation,l10n):一个程序或软件在支持国际化的基础上,给定程序特定区域的语言信息使其在信息的输入输出等处理上适应特定区域人群的使用。对于 iOS 来说就是,将App的内容翻译为多种语言的过程。
总的来说,国际化是开发者的任务,是一个一般化的过程;而本地化则是翻译者所做的事情,是一个具体的过程。国际化的运作为本地化工作提供了可能。一个软件的国际化实现需要本地化的支持。
用户设置对于国际化的影响
在 iOS 设置应用中的通用->语言与地区
中可以分别设置语言,地区和日历。一个支持国际化的应用会根据语言的设置选择相应的本地化包,语言的改变会导致系统重新启动,以便所有应用重新应用新的语言设置。地区主要影响日期,时间,数字,货币等数据的格式。用户可以通过日历选择不同的历法。地区和日历的设置都是即时的,不需要重新启动系统。另外,在语言与地区中还可以设置首选语言顺序列表,应用会以此为依据选择本地化语言包(按顺序找第一个应用支持的本地化语言包)。
使应用支持国际化
使用Base Internationalization国际化界面文本
从Xcode5之后,工程默认支持Base Internationalization。
Base Internationalization将界面文本与.storyboard和.xib文件分离,使得项目只需要一套.storyboard和.xib文件。在.storyboard和.xib文件中使用你设置的开发语言填写界面文本,这套.storyboard和.xib文件就叫做Base Internationalization。之后在本地化时,将以开发语言为资源翻译成多种语言,这些语言以.strings格式的文本文件对应相应的.storyboard和.xib文件。
一般情况下,每种语言相对应的文件会放在相应的语言包下,比如en.lproj、zh.lproj等。但是所有的.storyboard和.xib文件会放在一个名为Base.lproj的文件夹内,这就是为了共用同一套.storyboard和.xib文件,这样,在其他语言包内就可以只存放相应的.strings格式的文本文件了。由于.storyboard和.xib文件中已经使用开发语言填写了界面文本,所以在开发语言的语言包内就不需要再有相对应的.strings文件了。
关于开发语言的设置:
- 在项目的.xcodeproj文件中打开project.pbxproj
- 搜索developmentRegion,并将该key的值改为所要设置的开发语言对应的语言ID,比如en、zh等
-
保存,效果如下图所示
使用Auto Layout辅助国际化界面文本
因为所支持的语言所占界面空间不同,Auto Layout可以使一套界面适配布局不同的文字。使用时注意:
- 显示文字的组件不使用固定宽度的约束,否则在某些语言下文字可能显示不完全,text fields和labels默认的行为都是自动适配到内容的合适的尺寸,完全可以使用这种方式。
- 添加水平间距约束时,使用leading和trailing,这样针对左右顺序不同的语言可互换左右间距值。
- 因为语言不同视图组件所占空间不同,所以约束应与相邻视图组件建立,这样当语言改变时,其他视图组件也会自动适配。
国际化代码中的文本
在项目中,一些在界面上显示的文本是需要在代码中提供的(比如错误信息提示),而对这部分文本国际化的方式是将文本写入.strings文件中,之后使用宏NSLocalizedString
去从文件中获取。在.strings文件中键值对的格式为
"key1" = "value1";
"key2" = "value2";
使用NSLocalizedString
去取值的方式为
NSLocalizedString("key1", "comment");
NSLocalizedStringFromTable("key1", "tableName", "comment");
其中标准的NSLocalizedString
函数会从main bundle中的Localizable.strings文件中找到相应键的值,而comment是对该键值对的解释。同理NSLocalizedStringFromTable
函数的第二个参数可以指定其他.strings文件的文件名。
国际化数据格式
不同的国家和地区有着不同的日期,时间,货币,数值等的格式,所以要在代码中根据用户设置的地区来正确的格式化这些数据。
格式化时用到NSLocale类,NSLocale类封装了某一个地区的相应的格式化信息,如果要获得用户当前设置地区的NSLocale实例可以使用[NSLocale currentLocale]
或者[NSLocale autoupdatingCurrentLocale]
,两者的区别是,后一个类方法返回的值会根据用户设置的改变而改变,而前者不会。可以通过NSLocal查看很多这一地区的数据格式化信息,例如(其他key值请查阅相关文档):
NSNumber *metricSystem = [[NSLocale currentLocale] objectForKey:NSLocaleUsesMetricSystem];
NSString *currencySymbol = [[NSLocale currentLocale] objectForKey:NSLocaleCurrencySymbol];
// 用当前地区的语言显示语言ID
NSLocale *zhHansLocal = [NSLocale localeWithLocaleIdentifier:@"zh-Hans"];
NSString *currentLocalZH = [zhHansLocal displayNameForKey:NSLocaleIdentifier value:@"zh-Hant-TW"];
NSString *currentLocalEN = [zhHansLocal displayNameForKey:NSLocaleIdentifier value:@"en-US"];
// 获取该地区所使用的引号
NSString *bQuote = [locale objectForKey:NSLocaleQuotationBeginDelimiterKey];
NSString *eQuote = [locale objectForKey:NSLocaleQuotationEndDelimiterKey];
// 国际化大小写转换
NSString *localizedUppercaseString = [string uppercaseStringWithLocale:[NSLocale currentLocale]];
NSString *localizedlowercaseString = [string lowercaseStringWithLocale:[NSLocale currentLocale]];
NSString *localizedCapitalizedString = [string capitalizedStringWithLocale:[NSLocale currentLocale]];
当使用[NSString stringWithFormat]
去拼装字符串时,如果传入的参数带有数值,日期等需要格式化的内容,最好使用以下方式(更好的方式是使用formatter进行转换):
// 使[NSLocale systemLocale]
NSString *localizedString = [NSString localizedStringWithFormat:@"%3.2f", myNumber];
NSString *localizedString = [[NSString alloc] initWithFormat:@"%@" locale:[NSLocale localeWithLocaleIdentifier:@"zh"], [NSDate date]];
使用formatter格式化日期和时间时的国际化
// 使用预设的格式
NSString *localizedDateTime = [NSDateFormatter localizedStringFromDate:[NSDate date] dateStyle:NSDateFormatterMediumStyle timeStyle:NSDateFormatterShortStyle];
// 使用自定义的格式
NSDateFormatter *dateFormatter = [NSDateFormatter new];
NSString *localeFormatString = [NSDateFormatter dateFormatFromTemplate:@"dMMM" options:0 locale:dateFormatter.locale];
dateFormatter.dateFormat = localeFormatString;
NSString *localizedString = [dateFormatter stringFromDate:[NSDate date]];
对于数值型数据的格式化主要包括小数、千位分割、货币、百分比。同样也需要支持国际化。
NSString *localizedString = [NSNumberFormatter localizedStringFromNumber:myNumber numberStyle:NSNumberFormatterDecimalStyle];
同理对于NSCalendar的使用也受NSLocale的影响。
地区和时区的设置发生变化的通知分别是NSCurrentLocaleDidChangeNotification
和NSSystemTimeZoneDidChangeNotification
国际化支持相反的语言方向
有一些语言,比如阿拉伯语等,方向是从右向左的。使用
Base Internationalization和Auto Layout在大部分情况下可以很好的支持这些语言,一些不支持的情况,可以在代码中进行如下判断:
if ([UIView userInterfaceLayoutDirectionForSemanticContentAttribute:view.semanticContentAttribute] == UIUserInterfaceLayoutDirectionRightToLeft) {
…
}
本地化应用
当我们使应用支持国际化后,就可以配合翻译人员完成应用本地化的工作了。大致的过程是,通过 Xcode 将开发语言的文本资源导出为 XLIFF (XML Localisation Interchange File Format) 文件,翻译人员在完成该文件内的相应翻译内容后,再通过 Xcode 将文件导入,这时所翻译的语言资源就会被加入到工程中了。
导出 XLIFF
- 在 Xcode 中选中工程或 target。
- 选择 Editor > Export For Localization。
之后 Xcode 会将 .xliff 文件导出到你指定的目录中。如果你在工程的 Localizations 设置项中还没有添加过其他的语言,而只有开发语言(如 English)一种,那么导出的文件为 en.xliff。这时的 en.xliff 文件中并没有指明要翻译的目标语言,而这会导致在翻译完成后文件无法正常导入,需要在文件源码中添加target-language=""
字段。更好的做法是,在创建工程时就把要从开发语言翻译的其他语言(如 Chinese)添加到 Localizations 中,这样导出的文件就为 zh.xliff,且其中已标明目标语言,可以正常的导入。另一个要注意的地方是,.strings
文件支持国际化时,开始的开发语言版本不要放到Base.lproj文件夹中,Base.lproj文件夹中存放的全部是界面文件,而是应直接放入对应的开发语言的.lproj文件中。
命令行方式:
xcodebuild -exportLocalizations -localizationPath <dirpath> -project <projectname> [[-exportLanguage <targetlanguage>]]
在等待翻译资源的时候,你并不希望界面或者仅仅是界面中的文本再发生变化,这个时候可以使用 Xcode 的一项特性 Locking Views。可以只针对某一 view 修改,在该 view 的 Identity inspector 中修改 Lock 项。也可设置整个 nib 文件的该属性,选中对应 nib 文件后,修改 Editor > Localization Locking 菜单项。
导入 XLIFF
- 在 Xcode 中选中工程或 target。
- 选择 Editor > Import Localizations。
Xcode 会从 XLIFF 文件中解析出翻译内容的 .strings 文件,然后放到对应语言的 .lproj 目录中,而在工程中,nib 文件和 .strings 文件都以组的形式管理。
命令行方式:
xcodebuild -importLocalizations -localizationPath <filepath> -project <projectname>
其他资源
除了文本资源外,其他的资源文件,比如图片、音视频文件等可能也需要针对不同地区使用不同内容。
在国际化资源文件后,就可以将本地化版本的文件加到对应的 .lproj 目录中。
最佳实践
对于大部分的国内开发者来说,其应用主要针对使用中文的用户,而鉴于翻译资源的有限,可能针对其他地区用户仅能支持国际通用的英文。在这种情况下,最合适的流程是,在开发过程中,开发者使用中文填写界面文本,而之后由翻译人员翻译为英文,最后使应用在所有不匹配中文地区的设备上,都能使用英文资源。
要达到上述效果,首先要设置工程的开发语言为中文,如上文所述,修改工程文件中的字段 developmentRegion 为 zh,同时确保需要翻译的英文已添加在列表中。在完成国际化的工作后,就可导出 en.xliff 文件交由翻译人员翻译,并最终导入。最后一步,是要确认 Info.plist 文件中的 CFBundleDevelopmentRegion 字段设置为 en,该字段决定在用户当前地区未匹配到翻译资源时,使用应用已有的哪一套翻译资源作为界面文本显示。
需要注意的一点是,尽管文档中提到:
You can choose from more than 100 different languages and dialects designated by regions to localize your app. However, the more general you make your localized resources, the more regions you can support with a single set of resources. This can save a lot of space in your app bundle and help reduce localization costs. For example, if you don’t need to distinguish between different regions that use the English language, you can add English to support users in the United States, United Kingdom, and Australia. Even if you provide region-specific resources always provide a complete set of language-specific resources for all the languages you support.
但当用户设备的语言设置为繁体中文时,并不会匹配到中文(zh)的语言资源,所以在上述配置后,最终在繁体中文的设备上,应用会使用英文资源。如果想要所有中文设备都显示作为开发语言的简体中文,最后需要多添加一种语言 zh-Hant,但不需要进一步翻译,直接以开发语言为模板生成即可。
测试
在 Xcode 中,可以使用预览功能,在不运行应用的情况下,检测国际化和本地化的结果。选择一个 .storyboard 或 .xib 文件,打开辅助编辑器,在相关文件中选择 Preview,通过右下角语言选项,可以在国际化后选择 Double-Length Pseudolocalizations 进行检测,本地化后选择对应语言进行检测。
预览过后,可以通过设置应用启动时的参数,在设备上测试国际化和本地化的结果,而不需要修改设备的设置。编辑 Scheme,选择 Run -> Options,在 Application Language 一项中,可以选择对应语言资源,Double-Length Pseudolocalizations 以及 Right to Left Pseudolocalizations。勾选 Show non-localized strings 项,可以检测未本地化的文本,其会以大写形式显示。
网友评论