国际化本身并不是一个复杂的东西,所以只会简要介绍其中的一些点。
国际化基础配置
还是要简单介绍一下项目国际化需要的配置以及XIB和代码中字符串的国际化。
首先我们要在PROJECT->Localizations中添加所要支持的语言,同时会有自动弹框选中需要国际化的XIB文件。
|
完成之后,在相应的XIB文件locallzation配置中,选择需要支持的语言,xcode会在XIB文件下生成对应的国际化文件,内容格式(文本控件ID.txt = "该语言下的文字";
)
XIB国际化有一个关于更新内容的问题会在XIB国际化脚本中介绍
对于代码中字符串国际化,我们需要新建一个字符文件,command + n,在弹出的选择面板中搜索string,选中图中编辑的文件模板,并命名Localizable.strings
接下来的操作和上述XIB的类似,在文件配置中选择国际化需要支持的语言,同时会为该文件自动生成相应语言的语言文件(Localizable.strings(对应语言)),文件内容为(需要国际化的文字 = "该语言下的文字";
)
文字key就是代码中的NSLocalizedString(key, comment: “”)
同样也面临一个更新繁琐的问题会在genStrings的使用中介绍
XIB国际化脚本
一个项目的实现不可能是一步到位的,必然会对XIB进行多次修改,那么问题就来了:
- 如果新增/删除一个Label,xcode并不会自动更新该XIB对应的国际化文件,我们为了更新这个Label的国际化,方式①在XIB的配置界面中
Localization
中取消所有的语言选中,再重新勾选,使XIB重新进行国际化;方式②以sourceCode的方式打开这个XIB,找到个Label的id,手动增加(id.text = "该语言下的文字"
)或者删除这个Label的国际化信息。难道每次更新XIB有关文本控件的时候,都要进行这个操作,显然这是很恶心的。 - 接上,如果选择了方式①,重新勾选该XIB支持的语言之后,会有一个弹框提示你是使用之前的国际化文件还是替换掉国际化文件, 如果勾选了Use File,那么国际化文件还是得不到更新,那只能选择Replace File,但是你会发现,这个操作会把之前已经国际化好的内容给干掉,再次被坑。
为了避免上面提到的问题,有人给出了一个XIB自动国际化的脚本AutoGenStrings,在项目的Build Phases->New Run Script Phase配置脚本路径
好处:
- 在XIB中添加UILabel,编译之后,会自动在添加其对应的
id.text = "等待国际化的文字"
- 在XIB中删除UIlabel,编译之后,会自动注释掉其对应的
id.text = "该语言下的文字"
- 是增量修改,并不会覆盖之前已经国际化好的内容
- 提供时间日志,虽然没什么用
genStrings的使用
在前面已经简单介绍了代码中字符串的国际化,但是如果我们每次在代码中增加/删除NSLocalizedString(key, comment: "")
,就要到Localizable.strings(对应语言)文件中去添加/删除相应的"key" = "该语言下的文字";
,也是相当恶心的。
终端genStringsd指令的作用就是遍历项目中NSLocalizedString("key", comment: "")
字符串,并且用遍历的数据覆盖掉Localizable.strings(对应语言)文件,不足之处就不能增量修改,而是覆盖重写,之前已经国际化好的内容会被覆盖掉。
终端命令的使用方式,到项目的根目录下,
- swift项目终端输入en.lproj这是英语文件,我们在配置项目语言的时候可以看到每个语言的缩写,从而生成其他的语言文件
1
find ./ -name "*.swift" -print0 | xargs -0 genstrings -o en.lproj
- OC项目终端输入en.lproj解释同上。
1
find ./ -name *.m -print0 | xargs -0 genstrings -o en.lproj
复杂字符串的国际化
对于一些包含可变内容的字符串就不能使用NSLocalizedString("key", comment: "")
的方式了。
看一下和手机系统当前语言相关的两个API。1
Bundle.main.preferredLocalizations
a subset of this bundle’s localizations, re-ordered into the preferred order for this process’s current execution environment; the main bundle’s preferred localizations indicate the language (of text) the user is most likely seeing in the UI
从解释中可以看出它是APP本地化的一个子集,并且根据偏好语言列表重新排序。最有可能(不是100%)指示出APP要显示的语言,项目中也是用该API也进行包含可变子字符串的国际化。
1 | NSLocale.preferredLanguages |
An ordered list of the user’s preferred languages.
它所指示的是手机中的用户偏好语言列表,每一个元素为语言-地区,比如设置语言法语,地区中国即是fr-CN
实际中,也有很多人使用该它就是当前语言的判断,但是这是错误的,即使你看到了正确的结果,也是因为没有相应情况的测试用例。
我们手机上设置当前语言的时候,或者把偏好语言列表进行排序的时候,手机当前语言一定是它所返回列表中的第一个语言信息,那为什么不能根据它来进行国际化呢?假如我们APP支持的语言为中文、英文,我们把手机当前语言的语言设置为法语,可以打印他们的返回值如下:
1 | print(Bundle.main.preferredLocalizations) |
从结果看,他们的差别就很明显了,因为APP并不支持法语,API-1并没有包含法语,那为什么是英文呢?在前面提到了API-1不仅和本地化有关,还会根据偏好语言列表进行排序,列表中APP支持的第一语言就是英文了,而API-2就只是用户偏好语言列表,和APP无关。如果我们把APP支持的语言设置为中文、英文、法语,那打印结果如下:
1 | print(Bundle.main.preferredLocalizations) |
这就是前面提到缺少的测试用例了。
图片的国际化
图片的国际化有两种方式
方式一是和XIB和.string文件国际化一样,在侧边栏选择需要支持的语言,然后到项目中语言.lproj的文件夹中放该语言下的图片,但是图片就不能放到asset中了,这也是缺点,失去了asset对该图片的优化处理,而且比较繁琐,要多次到语言.lproj文件夹中替换,同时2x、3x还要同样处理
推荐方式二:使用复杂字符串的国际化判断当前语言,UIimage(named: "语言图片.png")
Info.plist的国际化
同代码中字符串国际化一样,新建一个__.string文件,然后在文件侧边栏选择需要支持的语言,同样会自动生成相应的__.string(语言)的国际化文件,以Source code的方式打开Info.plist文件把属性名粘贴出来,添加到国际化文件中完成国际化1
CFBundleName = "其他语言下的名字";