iOS语言国际化/本地化-实践总结

Build Apps for the World

1 添加要支持的国际语言

  1. 添加语言后面的括号内容是该语言的国际标准缩写名 html

  2. 如选择添加日语后,会弹出以下对话框,选择Finish便可 java

  3. 以下选择添加日语,法语,简体中文,繁体中文后,能够发现相应的变化 python

2 本地化应用名

本地化应用名:App的名称,根据设备语言的设置,显示成对应名称(~如微信App,在简体中文语言下显示成微信,在英文语言下显示weChat~)git

2.1 选中info.plist文件,右键选择新建文件

2.2 选择建立文件类型为Strings File

2.3 指定名称为InfoPlist.strings(~名称必须是InfoPlist~)

2.4 建立成功后

2.5 选中InfoPlist.strings,在Xcode的File inspection(Xcode右侧文件检查器)中点击Localize,目的是选择咱们须要本地化的语言,以下图:

注意:在点击Localize以前,必定要保证第1步已经添加了须要国际语言程序员

2.6 弹出确认对话框,默认选择English,你可展开优选选择你须要本地化的语言,或者直接按默认,后续能够继续添加你须要的国际语言

2.7 选择本地化的语言后,能够看到InfoPlist.strings文件在文件检查器栏的Locaization栏发生变化

2.8 将其余国际语言都勾上后,能够看到InfoPlist.strings文件也出现了多个子项的变化

2.9 从项目文件夹方向看看发生了什么

多语言本地化的核心思想 就是为每种语言单独定义一份资源,iOS就是经过xxx.lproj目录来定义每一个语言的资源,这里的资源能够是图片,文本,Storyboard,Xib等github

每种语言都有本身的 语言代码.lproj 文件夹,加载资源时只须要加载相应语言文件夹下的资源,这步能够系统为咱们完成,也能够手动去作shell

2.10 先设置demo的display name为:本地化测试Demo

  • info.plist 文件中会出现display name的key value展现 编程

  • 咱们知道display name 的名字就是App安装后再设备上显示的名称 swift

  • 经过显示info.plist中的raw key value来获取修改display name对应的key:CFBundleDisplayName c#

看看官方解析咯 CFBundleDisplayName CFBundleName info.plist 的全部key查看 -Core Foundation Keys

CFBundleDisplayName

因此CFBundleDisplayName是能够用在infoPlist.strings上的。

2.11 分别在不一样的语言所对应InfoPlist.strings上设置本地化的App名称

// InfoPlist.strings(English) 文件
CFBundleDisplayName = "EnglishDemo";


// InfoPlist.strings(Chinese(Simplified)) 文件
CFBundleDisplayName = "简体Demo";


// InfoPlist.strings(Chinese(Tradictional)) 文件
CFBundleDisplayName = "繁体Demo";


// InfoPlist.strings(Japanese) 文件
CFBundleDisplayName = "日语Demo";


// InfoPlist.strings(French) 文件
CFBundleDisplayName = "法语Demo";
复制代码

备注:CFBundleDisplayName可使用双引号,也能够不使用双引号!

2.12 获取当前模拟器当前设置的语言

// ViewController.m
@implementation ViewController

- (void)viewDidLoad {
    [super viewDidLoad];
    
    NSArray *languages = [[NSUserDefaults standardUserDefaults] valueForKey:@"AppleLanguages"];
    NSLog(@"AppleLanguages 语言有 %@", languages);
    NSString *currentLanguage = languages.firstObject;
    NSLog(@"模拟器当前语言:%@",currentLanguage);

}
复制代码

2.13 设置模拟器的语言环境

在iOS设备上设置语言

2.14 运行程序后各个语言本地化的效果展现

  1. 繁体环境下(模拟器当前语言:zh-Hant-HK)
// 运行结果
2018-09-04 16:49:40.056223+0800 LanguageLocalizationDemo[92506:3273624] AppleLanguages 语言有 (
    "zh-Hant-HK",
    "zh-Hans-US",
    en
)
2018-09-04 16:49:40.056505+0800 LanguageLocalizationDemo[92506:3273624] 模拟器当前语言:zh-Hant-HK
复制代码

  1. 英语环境下(模拟器当前语言:en)
// 运行结果
2018-09-04 17:00:37.811874+0800 LanguageLocalizationDemo[92874:3283615] AppleLanguages 语言有 (
    en
)
2018-09-04 17:00:37.812133+0800 LanguageLocalizationDemo[92874:3283615] 模拟器当前语言:en
复制代码

  1. 日语环境下(模拟器当前语言:ja-US)
// 运行结果
2018-09-05 10:33:16.423697+0800 LanguageLocalizationDemo[46412:14218145] AppleLanguages 语言有 (
    "ja-US",
    en
)
2018-09-05 10:33:16.423941+0800 LanguageLocalizationDemo[46412:14218145] 模拟器当前语言:ja-US
复制代码

  1. 简体中文环境下(模拟器当前语言:zh-Hans-US)
// 运行结果
2018-09-05 10:36:18.376366+0800 LanguageLocalizationDemo[46510:14225868] AppleLanguages 语言有 (
    "zh-Hans-US",
    "zh-Hant-US",
    "ja-US",
    en
)
2018-09-05 10:36:18.376628+0800 LanguageLocalizationDemo[46510:14225868] 模拟器当前语言:zh-Hans-US
复制代码

  1. 法语环境下(模拟器当前语言:fr-US)
// 运行结果
2018-09-05 10:47:12.397641+0800 LanguageLocalizationDemo[46634:14239902] AppleLanguages 语言有 (
    "fr-US",
    "zh-Hans-US",
    "zh-Hant-US",
    "ja-US",
    en
)
2018-09-05 10:47:12.398086+0800 LanguageLocalizationDemo[46634:14239902] 模拟器当前语言:fr-US

复制代码

固然,模拟器设置对应的语言以后,模拟器重启完成时对应 App 的名称就会随系统语言而变动,不须要从新 run 这个项目,而上述结果每次都进行 run 操做的目的是观察系统语言的变化及肯定所设置的语言是否正确

2.15 影响经过AppleLanguageskey 从NSUserDefaults中获取的支持语言的缘由

  1. 根据设备曾经添加过的语言返回结果
NSArray *languages = [[NSUserDefaults standardUserDefaults] valueForKey:@"AppleLanguages"];
复制代码

上面得到的NSArray *languages内容是根据当前设备已经添加过哪些语言决定的,模拟器默认只有英文,因此你会看到2.14中打印的不一样结果

  1. 受到 Xcode 的语言设定影响 假设设备已经添加了简体中文、繁体中文、英文、法语、日语。 2.1 设备添加了对应语言

2.2 Xcode 中的缘由按默认设置为跟随系统

那么此时运行下面代码得到的数组是:

NSArray *languages = [[NSUserDefaults standardUserDefaults] valueForKey:@"AppleLanguages"];
复制代码
2018-09-05 10:47:12.397641+0800 LanguageLocalizationDemo[46634:14239902] AppleLanguages 语言有 (
    "fr-US",
    "zh-Hans-US",
    "zh-Hant-US",
    "ja-US",
    en
)
2018-09-05 10:47:12.398086+0800 LanguageLocalizationDemo[46634:14239902] 模拟器当前语言:fr-US
复制代码

打印结果是设备正常已添加的语言。

2.3 Xcode 中的语言设置为指定某一语言(~此处设为English~)时,结果是:

2018-09-05 10:58:06.445970+0800 LanguageLocalizationDemo[46726:14250118] AppleLanguages 语言有 (
    en
)
2018-09-05 10:58:06.446199+0800 LanguageLocalizationDemo[46726:14250118] 模拟器当前语言:en
复制代码

AppleLanguages数组中只有一个en 元素 但模拟器真实语言环境没有变化,仍是法语,且 App 名称一样仍是根据设备环境显示成法语的名称

这里做出的对比,是但愿之后再开发调试时候,留意这些影响设备语言获取的因子

同时须要注意的是,App 的名称不会随 Xcode 的 application langue变化而变化,它仅仅跟随设备实际设置的语言而变

3 本地化 代码中的字符串

本地化 代码中的字符串是指程序内的字符串在不一样的语言环境下显示不一样的内容,好比首页一词,在简体中文下显示就是首页,而在英文下则会显示Home

本地化 代码中的字符串流程与本地化 App 名称基本一致,一样下面也会给出各个步骤的操做贴图

3.1 选中要存放新建文件位置的文件夹后,经过 command + n 快速建立文件

3.2 选择建立文件类型为Strings File

3.3 指定 Strings File 文件名称为 Localizable

使用这个名字缘由它是系统默认加载本地化文件名称,后面会提到经过自定义其余名称来模块化处理本地化及解耦

3.4 Localize Localizable.strings文件

3.5 勾选其余语言

到目前为止,上述步骤与本地化 App 名称是同样的,不一样点是 strings 文件的名称

3.6 在对应语言文件中按 key-value 的形式写入须要本地化的字符串

// Localizable.strings(English) 文件
"home" = "home";

// Localizable.strings(Chinese(Simplified)) 文件
"home" = "简体主页";

// Localizable.strings(Japanese) 文件
"home" = "日语主页";

// Localizable.strings(Chinese(Traditional)) 文件
"home" = "繁体主页";

// Localizable.strings(French) 文件
"home" = "法语主页";
复制代码

3.7 经过NSLocalizedString(key, comment)这个系统提供的宏,使用本地化文件中的内容

  1. 环境语言的切换能够经过设备的语言设置Xcode中Scheme设置,这里推荐经过 Xcode 进行快速设置,这样省去等待模拟器的重启时间
  2. 下面是设置运行效果
  • 简体中文

  • 英文

  • 法语

  • 繁体中文

  1. NSLocalizedString宏定义解析

  2. localizedStringForKey:value:table: - NSBundle

3.8 NSLocalizedString 使用小技巧

  1. 使用NSLocalizedString按照给定的 key 查找对应 strings 文件时,若是找不到该 key 对应value 时,默认返回的值就是 key。
  • Localizable.strings(English)文件什么都没写
  • NSLocalizedString使用的 key 为 lala
  • 当查找不到时,就会将 key 返回,以下图:
  1. 假设你使用的是英文的名称做为 key,那么通常状况下,Localizable.strings(English)文件中的键值对应该是这样的"home" = "home";,即键值同样,那就能够利用上面的第一点,查找不到是返回 key 的特性,省去在Localizable.strings(English)文件中补上键值的状况(~固然,这是不建议的😆~)

4 模块化管理本地化

4.1 模块化管理的缘由

  1. 从第3大点上能够知道,经过构建一个系统默认的名称的Localizable.strings文件,能够将项目中全部须要本地化语言的代码字符串统一放在Localizable.strings文件中。
  2. 可是都放在一个地方虽然能够统一管理,但随着项目的模块的增多等状况,该文件内容一定会存在内容臃肿状况,虽然可经过注释或者#pragma mark - <#desc#>来分层管理,但面向多人编程时,同时修改一个文件致使的问题更复杂

4.2 自定义.strings文件,实现模块化管理

  1. 经过NSLocalizedStringFromTable宏,手动指定查找 strings 文件。
NSLocalizedStringFromTable(<#key#>, <#tbl#>, <#comment#>)
复制代码
  1. 自定义名称·strings文件(Module1.strings)

  2. 使用NSLocalizedStringFromTable

5 本地化图片

5.1 方式1:相似本地化代码字符串方式,经过NSLocalizedString获取语言的图片名称,从Assets.xcassets中获取相应图片

  • 使用代码示例

  • Assets.xcassets图片命名

  • 对应 Localizable.strings 内容

// Localizable.strings(English) 文件
"image-languge" = "english";

// Localizable.strings(Chinese(Simplified)) 文件
"image-languge" = "simplify";

// Localizable.strings(Japanese) 文件
"image-languge" = "japan";

// Localizable.strings(Chinese(Traditional)) 文件
"image-languge" = "french";

// Localizable.strings(French) 文件
"home" = "法语主页";
复制代码
  • 运行效果
    法语
    英语
    其余请参考 demo

5.2 方式2:指定 bundle 的图片,让其具备本地化属性(~即把图片资源放到对应的语言lproj文件夹中~)

  1. 拖拽一张图片至项目 bundle 中

  2. 本地化图片

  3. 将其余语言选上

  4. 在对应图片的本地化文件夹内均可以看到有一张 icon 图

  5. 将对应语言的.lproj文件夹内的 icon 图替换成同名的其余 icon 图

    其余语言同样操做

  6. 完成第5步后回到项目,点击对应的语言.strings文件看到对应的 icon

  7. 经过 icon 名称langueIcon做为 key,使用NSLocalizedString获取应语言字符串

  • 运行效果如5.1

本地化图片须要多张图片相似的图片,若是一次适配的语言较多状况下,那么包体积变大是不可避免的事情,这一点可考虑一下动态获取图片的方法。这样按需获取在多语言状况下比较可行

6 本地化 Xib

6.1 本地化 Xib

  1. 建立 xib 的 vc

  2. Localize xib 文件,注意:直接选择 Base,不要选其余

  • 选其余的话,会没有生成对应的 key-value
  1. 勾选其余的语言

相比于其余的.strings文件,xib 或 sb 本地化以后,对应语言的.strings 文件是能够变换成特定 xib 样式的

你能够选择 让其余语言以 strings 文件形式来 基于Base 的 xib;或者每一个语言都成为独立的 xib 文件 可是不建议使用独立 xib 的形式,固然若是不一样语言不一样布局的话,也是可使这样形式的

  1. 选择 Base 的 String 自动生成strings 文件内容浏览 系统会根据当前 xib 中的子控件(~限文本控件,如:Label、Button等~),的 Object ID 生成内容键值

  2. 根据语言修改对应 value 值便可,系统会自动获取xib 中控件 ID 而后匹配系统语言进行内容赋值

  3. 修改 Xcode 的语言设置,查看运行结果

  • 英文

  • 法语

6.2 在Interface Builder中预览本地化

在Interface Builder中,您能够在不运行应用程序的状况下预览用户界面的本地化。

  1. 在项目导航器中,选择要预览的文件.storyboard或.xib文件

  2. 选择视图>辅助编辑器>显示助手编辑器

  3. 在助手编辑器跳转栏中,打开“助手”弹出菜单,滚动并选择“预览”项,而后从子菜单中选择.storyboard或.xib文件(~若是应用程序用户界面的预览未显示在助理编辑器中,请在图标或大纲视图中选择要预览的窗口或视图~)

  4. 在助理编辑器中,从右下角的语言弹出菜单中选择要预览的本地化。(~本地化的预览显示在助理编辑器中。若是选择实际语言,则不须要本地化或须要本地化但当前不是本地化的字符串将以大写形式显示~)

6.3 添加新控件至 XIB

  1. 不会联动变化 咱们发现,添加新控件后,相应的 strings 文件没有自动发生变化⁉️

注意:Xib相应语言的strings一旦生成后,Base Xib有任何编辑都不会影响到strings,即删除或添加了一个Label,strings也不会同步作相应的改动

  1. 手动添加咯(~固然是能够的~)
  • 获取到对应 Label 的 ObjectID,而后参考以前生成 strings 以前已经添加到 xib 的 label 处理格式,分别修改对应语言的 strings 文件,以下:

  • 运行效果

6.3 自动化更新 strings 文件

  1. 方式1:使用ibtool生成新的.strings文件(~后续会分析这个的使用步骤~)
  • Xcode 为咱们提供了 ibtool 工具来生成 Xib 的 strings 文件,命令以下 ibtool XibController.xib --generate-strings-file ./XibController.strings
  • 可是这个ibtool翻译的键值对中的值是按照xib上控件上填写的文原本显示的,通常不是咱们想要的,若是要实现更新,咱们须要将XibController.strings和以前对应语言文件夹fr.lproj等的XibController.strings比较,将XibController.string中多出来的key-value取出来,追加到Main.string的尾部(~实在麻烦~)
  1. 方式2:使用脚原本实现自动追加新 key-value,删除再也不存在的 key-value 脚本内仍是经过使用 ibtool
  • 逻辑是:假设原来咱们就有翻译文件A,添加控件后,咱们再执行一次国际化指令,生成文件B,咱们拿A和B对比,把B中多出来的键值对插入A文件的尾部,将A中有而B中没有的键值对删掉(即控件被删除),这样咱们就算是更新了storyboard的翻译文件了

  • 参照上述的逻辑,咱们能够借助脚本文件来实现,Xcode的Run Script也提供了脚本支持,可让咱们在Build后执行脚本

2.1 新建 py 脚本

AutoGenStrings.py参考 demo 工程

2.2 选择:Target -> Build Phases -> New Run Script Phase,在shell里面写入下面指令

#!/bin/bash
python ${SRCROOT}/${TARGET_NAME}/RunScript/AutoGenStrings.py ${SRCROOT}/${TARGET_NAME}
复制代码

2.3 你也能够选择Run script only when installing,这样在编译是不会云脚本,只有install的时候才会运行脚本

2.4 新添加控件以后,编译一下,对应的 strings 文件会增长新控件的 key-value 对,而删除的控件的的 key-value 对会被注释

以后有空会补上AutoGenStrings.py的解读,参考的脚本原先只有 storyboard 的处理,这里扩展至 xib

7 本地化Storyboard

  • 与 Xib 操做流程一致,请参考 Xib 的本地化流程

8 说说NSLocalizedString(key, comment)中 comment 参数的使用

第一个参数是:key的名字 第二个参数是:对这个“键值对”的注释,在用genstrings工具生成Localizable.strings文件时会自动加上去

通常状况下,语言翻译的操做并非咱们程序员源来作的(~固然,nb的猿都会nb地接手这些工做~),那么怎样才可以将语言本地化strings文件分发出去同时又可以很好的按流程工做呢?

8.1 直接在代码中使用NSLocalizedString进行臆想本地化实现

  • 此时的状况是本地没有任何 strings 文件,利用NSLocalizedString的查找逻辑,key 不存在时直接返回 key 值
  • 因此开发过程时,界面显示的就是 key 值,而推荐使用英文表示 key 的优势就是:当超出所支持语言时,默认使用英语。那使用英语翻译的 key 正好知足条件

8.2 经过 genstrings 将使用了NSLocalizedStringviewController.m文件,生成对应语言环境的 strings 文件

  • 当全部的.m文件都使用NSLocalizedString修改好以后,就能够动用genstrings工具了
  1. 启动终端,进入工程所在目录。
  2. 新建须要支持的语言.lproj 文件夹,位置默认放在项目根目录下 目录名会做用到Localizable.strings文件对应的语言,因此目录名称不能写错了。
mkdir zh-Hans.lproj
mkdir en.lproj
复制代码
  • 推荐经过 Xcode 帮咱们生成,参考文章 “第1点:添加要支持的国际语言”,这样你还能够省去语言简写目录名的烦恼,直接从 Xcode 中选择你想要支持的国际语言

  • 选择语言

  • 生成的.lproj文件夹

  • 发现没有 en.lproj 文件夹,不要紧,点选 main.storyboard,在文件的 localize 位置勾上 English 选项,同理 launch.storyboard 也一样操做

  • 出现了 en.lproj

  1. 生成Localizable.strings文件
genstrings -o zh-Hans.lproj *.m
genstrings -o en.lproj *.m
genstrings -o ja.lproj *.m
复制代码

-o <文件夹>,指定生成的Localizable.strings文件放置的目录。 *.m,扫描全部的.m文件。这里支持的文件还包括.h, .java等。

  • 执行完genstrings -o zh-Hans.lproj *.m命令以后,对应的zh-Hans.lproj文件夹多了Localizable.strings,其余同理
  1. 生成Localizable.strings文件都拖拽到工程中,Xcode会自动合并成一个,而且对应生成的内容是按照前面NSLocalizedString(@"home", @"这个是用来在生成 strings 文件时,在对应的 key-value 行上的注释,用来提示翻译员或者猿们的相关提示")生成的。

  2. 以后咱们将这些文件分发到翻译员(~或者你本身手里~)

注意:genstrings指令只能是该目录下的文件遍历,但不能实现递归遍历,要实现递归变量,可使用下述命令 find ./ -name *.m | xargs genstrings -o en.lproj 这是shell组合指令find+xargsfind ./ -name *.m 会递归全部.m文件并存在一个数组中,这个数组经由pipe传递给了下一个指令,而xargs会将收到的数组一一分割,并交给genstrings执行。

9 应用内设置语言(~实践后补上~)

10 指定语言 bundle 获取本地化字符串(~实践后补上~)

  • 宏使用例子补充
#define NSLocalizedString(key, comment) \
	    [NSBundle.mainBundle localizedStringForKey:(key) value:@"" table:nil]
#define NSLocalizedStringFromTable(key, tbl, comment) \
	    [NSBundle.mainBundle localizedStringForKey:(key) value:@"" table:(tbl)]
#define NSLocalizedStringFromTableInBundle(key, tbl, bundle, comment) \
	    [bundle localizedStringForKey:(key) value:@"" table:(tbl)]
#define NSLocalizedStringWithDefaultValue(key, tbl, bundle, val, comment) \
	    [bundle localizedStringForKey:(key) value:(val) table:(tbl)]
复制代码

11 启动图本地化(~实践后补上~)

12 优化(~实践后补上~)

Demo

LanguageLocalizationDemo - 第1-7点使用

LocalizationGenStringsDemo - 第8点使用

未完~

REF


文/Jacob_LJ(掘金做者)

PS:如非特别说明,全部文章均为原创做品,著做权归做者全部,转载需联系做者得到受权,并注明出处,全部打赏均归本人全部!

相关文章
相关标签/搜索