本文部分转载于 Internationalization Tutorial for iOS [2014 Edition],由 iOS应用国际化教程(2014版)翻译。
在你开始学习本教程之前,很重要的一点是了解国际化和本地化的不同之处,很多人经常会把这两个概念搞混。
简单说,国际化是一个应用程序国际兼容性设计的过程,比如:
国际化是一项你和开发者通过利用系统提供的API来实现的活动,并在代码上做一些补充和修改,从而让应用的中文版、阿拉伯语版本和英文版一样好。
相比之下,本地化仅仅是把应用的用户界面和资源翻译成不同的语言,这是你可以也应该交个别人做的工作,除非你能精通app应该支持的每种语言。
多语言本地化主要本地化四个方面的问题:
第一步是 download iLikeIt项目,我们将会在整个教程中使用它。
在Xcode中打开该项目,并在模拟器上运行,你将会看到以下界面:
从截图中看出,你需要本地化四个项目:
UI元素: Hello Label
UI元素: You like? Button
销售数据文本: Yesterday you sold 1000000 apps
图片文本: I LIKE IT
花一小会儿时间浏览文件和文件夹来熟悉下项目结构。 Main.storyboard包含单个屏幕,它是ViewController类的实例。
目前,应用展示的所有文本都是以硬编码字符串存在于Main.storyboard和ViewController里。为了本地化这些字符串,你需要把它们放在一个单独的文件中。
你将会在包中简单地引用这些字符串,而不是在你的方法中进行硬编码。
Xcode使用带有 “.strings” 扩展名的文件来储存和检索app中使用的所有字符串,以支持每种语言。根据iOS设备当前使用的语言,代码中一个简单的方法调用将会查找并返回要求的字符数串。
试试看,打开 File>New>File,选择Resource中Strings Fils,如图:
点击下一步,为文件命名为Localizable.strings
,然后点击save。
注意:Localizable.strings是iOS用来本地化文本默认的文件名称。请抑制以其他内容给它命名的冲动,否则以后你每次引用本地化字符串的时候要一次次输入.strings 文件名。
现在,你已经创建了Localizable.strings文件,你需要添加所有的文本–当前硬编码在app中的文本。你需要遵从一个特定但简单的格式:
"KEY" = "CONTENT";
这些键/内容对功能就像NSDictionary ,惯例是使用默认的内容翻译作为内容的键:比如You Like?,你应该写:
"You like?" = "You like?";
Key/content对也可以包含格式化字符串:
"Yesterday you sold %@ apps" = "Yesterday you sold %@ apps";
现在切换至ViewController.m,找到viewDidLoad方法,现在app会为likeButton和salesCountLabel设置文本,展示如下:
_salesCountLabel.text = [NSString stringWithFormat:@"Yesterday you sold %@ apps", @(1000000)];
[_likeButton setTitle:@"You like?" forState:UIControlStateNormal];
取而代之的方法是,你需要从此前创建的Localizable.strings文件中读入字符串。用一个名为NSLocalizedString的宏修改这两行代码如下所示:
_salesCountLabel.text = [NSString stringWithFormat:NSLocalizedString(@"Yesterday you sold %@ apps", nil), @(1000000)];
[_likeButton setTitle:NSLocalizedString(@"You like?", nil) forState:UIControlStateNormal];
宏包将一个稍长的代码片段包裹为一个更易于管理的长度,它使用#define指令创建。如果你想知道NSLocalizedString宏是什么,可按住Control键并在NSLocalizedString点击,可以看到它的定义如下:
#define NSLocalizedString(key, comment)
[[NSBundle mainBundle] localizedStringForKey:(key) value:@"" table:nil]
在当前的语言中,NSLocalizedString宏使用localizedStringForKey方法查找给定键值的字符串。它为table name传递nil,所以它使用默认的字符串文件名(Localizable.strings)。更多细节,可查看苹果的 NSBundle Class Reference。
注意:这个宏把注释作为一个参数,但似乎没什么用。不像此前那样需要手动把每个key/value对键入Localizable.strings,你还可以使用iOS SDK带的一个叫做genstrings的工具来自动处理(非常适用于大型项目)。
如果使用这个方法,你可以为每个字符串加上一个注释,注释会显示在默认的字符串边上,作为translator的辅助。比如你可以添加一个注释指出字符串在哪里使用。
已经有了足够的背景信息,现在开始吧!
创建并运行你的项目,并且它应该像之前一样在主屏幕上展示相同的文本,但是西班牙文在哪里?现在你的应用已经进行了本地化设置,添加翻译是小事一桩。
想要添加支持另一种语言,你可以点击左窗格中的iLikeIt项目文件夹,在旁边的窗格中选择Project(不是 Target),然后在Info标签下你会看到一个Localizations分区。点击点击“+”,然后选择Spanish (es)。
下个屏幕会询问你哪些文件需要本地化。选中所有文件并点击Finish。注意:Localizable.strings没有展示在这个列表中,不过不用惊慌!
在这一点上,Xcode已经在幕后设置好了一些目录,针对你选择的语言,这些目录包含不同版本的InfoPlist.strings和Main.storyboard。你可以使用Finder打开项目文件夹看看,你会看到如图所示:
看到en.lproj和es.lproj了吗?它们包含文件的特定语言版本。
en是English的本地化代码,es是Spanish的本地化代码。关于其他语言,可参看完整的语言代码列表。
从现在开始,当你的app想要获得某个文件的英文版,它就会去en.lproj中查找,而当它想要某个文件的西班牙语版时,它就会去es.lproj找。非常简单!把你的资源文件放在合适的文件夹里,剩下的事情就交给iOS负责了。
但是等等,Localizable.strings呢?想让Xcode知道你想将它本地化,那你可以在左窗格里选中文件,然后在右窗格中打开File Inspector。
你会看到一个Localize标签,点击并选择英语(因为当前是英语),最后点击Localize。
现在File Inspector面板将会展示文件所属的语言。目前,正如你所看到的,文件只针对英文进行本地化。可通过点击Spanish左边的框框添加西班牙语本地化。
回到左窗格并点击Localizable.strings旁边的箭头,它会显示出子元素。现在文件已经有了两个版本:一个是英文本,一个是西班牙语版。
想修改西班牙语的文本,可选择Localizable.strings (Spanish),并用如下内容替代它的内容:
"Yesterday you sold %@ apps" = "Ayer le vendió %@ aplicaciones";
"You like?" = "~Es bueno?~";
恭喜!现在你的应用支持两种语言了!
为了测试和验证所有事情都正常工作,你可以在模拟器/设备上把展示语言更改为Spanish,方法是打开设置应用,然后选择:General -> International -> Language -> Espanol.
如果 Xcode debugger仍在运行中,你可以在Xcode中点击“stop”,然后点击“Build & Run”,你将会看到:
100万是个相当不错的销售数据,我们可以为它添加一些格式让它看起来更好!
打开ViewController.m并将为_salesCountLabel设置文本的代码行替换为:
NSNumberFormatter *numberFormatter = [[NSNumberFormatter alloc] init];
[numberFormatter setNumberStyle:NSNumberFormatterDecimalStyle];
NSString *numberString = [numberFormatter stringFromNumber:@(1000000)];
_salesCountLabel.text = [NSString stringWithFormat:NSLocalizedString(@"Yesterday you sold %@ apps", nil), numberString];
编译并运行应用程序,那么数字就会更容易辨认一些。
这对美国人来说非常棒,但在西班牙,100万写作“1.000.000″而不是“1,000,000″。在西班牙文环境下运行应用程序,你将会看到逗号用来隔开0。在iOS中,数字格式化是基于地区/国家,而不是语言,所以为了了解某个西班牙人如何查看销售数据,可打开Settings.ap,并通过导航改变区域:General -> International -> Region Format -> Spanish -> Spain
在此编译和运行应用程序,现在你会看到正确的数字格式:
一点额外的前期工作,NSNumberFormatter会自动为合适的区域格式化你的数字。可能的情况下,请拒绝重新发明轮子,因为在iOS上,通常按照苹果的方式做才能有回报。
Storyboard中的元素,比如标签、按钮以及图片可以在代码中或者直接在storyboard中设置。在设置文本编程时,你已经学会了如何支持多种语言,但是屏幕顶部的“Hello”标签没有IBOutlet,只能在Main.storyboard中设置它的文本。
你可以添加一个IBOutlet,将其连接到Main.storyboard中的label上,然后使用NSLocalizedString设置其文本属性,就像使用likeButton和 salesCountLabel那样,但是这里有一个本地化storyboard元素更简单的方法,不需要任何附加代码。
打开Main.storyboard左侧的小三角形,你会看到Main.storyboard (Base)和Main.storyboard (Spanish)。点击Main.storyboard (Spanish)打开编辑器,你会看到storyboard中的本地化文本。你已经有了一个Hello标签入口,如下:
/* Class = "IBUILabel"; text = "Hello"; ObjectID = "pUp-yc-27W"; */
"pUp-yc-27W.text" = "Hello";
用西班牙语翻译的“Hola”替换两个“Hello”:
/* Class = "IBUILabel"; text = "Hola"; ObjectID = "pUp-yc-27W"; */
"pUp-yc-27W.text" = "Hola";
注意:绝对不要直接改变自动生成的ObjectID,也不要复制和粘贴上边的代码行,因为标签的ObjectID可能已经跟上边展示的不一样了。
由于应用程序使用了包含英语文本的图片,所以你需要把图片本地化,因为零零散散的英文文本会让你的西班牙应用看起来很不专业,并且也有损于应用的整体易用性和市场潜力。
本地化图片,首先需要下载西班牙语版本的图片(在大多数浏览器上是右键点击>保存为):
打开Images.xcassets,拖放此前下载的图片megusta.png并添加至左侧的图片列表,从而把图片添加至资产Asset catalog。Asset catalogs不能被国际化,所以你需要有一个方法来本地化图片。
打开Localizable.strings (English) ,并添加如下内容:
"imageName" = "ilike";
把以下代码添加至Localizable.strings (Spanish)文件:
"imageName" = "megusta";
从现在开始,你将使用imageName key来检索本地化版本的图片。打开ViewController.m并把如下代码添加到viewDidLoad方法中:
[_imageView setImage:[UIImage imageNamed:NSLocalizedString(@"imageName", nil)]];
如果需要,将模拟器/设备切换到西班牙语,编译并运行,然后你会看到本地化图片的展示。
现在你已经有了将应用程序针对多种不同语言本地化所需的所有工具。
作为最后的奖励,我们来本地化应用的名字。Info.plist有一个特殊的文件(InfoPlist.strings),你可以在里边用字符串覆盖其他语言。为给应用程序一个不同的西班牙语名字,可打开Supporting Files > InfoPlist.strings (Spanish),并插入以下代码:
"CFBundleDisplayName" = "Me Gusta";
它改变了应用的名称,像Springboard上展示的那样。