国际化的实质是根据不同的语言加载对应的
.lproj
资源文件。.lproj
中包含InfoPlist、Localizable、Main等资源文件。每新增一种语言,就会在工程目录下生成与之对应的.lproj
资源文件夹。
国际化的步骤
1.新增语言
添加语言后,会在工程目录下生成
xx.lproj
文件夹(xx是语言的编码)。eg: 添加Chinese(Simplified)(zh-Hans) 对应生成 zh-Hans.lproj
2.Main.storyboard国际化(主要针对带文本的控件)
- 1.Localization国际化: 选择Localize, 勾选多语言,会在对应
xx.lproj
的文件夹下新增Main.strings
,并且Main.storyboard会变成文件夹的形式,可以查看所有语言的Main.strings
。 - 2.使用:
/*————配置UI控件的文本内容————*/
// Main.strings(English)
"PBP-pq-8OJ.text" = "Localizable";
// Main.strings(English)
"PBP-pq-8OJ.text" = "国际化";
3.Info.plist国际化
Info.plist主要是App信息和权限的配置。Info.plist国际化的常见使用在:App的名称、权限开启的提示等。
eg: 1. 名称: 国内 抖音小视频 海外 TikTok
2. 权限提示: 相机/相册权限开启的多语言提示等
-
1.新建InfoPlist.strings文件(固定命名)
- Localization国际化(操作同Main.storyboard)
- 3.定义:
/*————配置App信息————*/
// InfoPlist.strings(English) App在English语言系统下的名称
"CFBundleDisplayName" = "Localizable";
// InfoPlist.strings(Traditional) App在Traditional语言系统下的名称
"CFBundleDisplayName" = "国际化";
配置InfoPlist.strings,那么Info.plist会在不同的语言系统下,展示不同的内容。
4.字符串的国际化
- 新建Localizable.strings文件(固定命名,操作同Info.plist国际化)
- Localization国际化(操作同Info.plist国际化)
- 使用:
/*——————————定义文字内容——————————*/
// Localizable.strings(English)
"Language" = "English";
// Localizable.strings(Traditional)
"Language" = "繁体";
// 使用
let language = Bundle.main.localizedString(forKey: "Language", value: nil, table: nil)
5.图片国际化
将图片添加到对应的语言环境下。
注意:
Assets.xcassets
是不能国际化的,和Main、Info.plist、Localizable不同的是:图片不能新建.strings
文件,并且图片国际化之后还是保存在Assets.xcassets
中,并不会存储在对应语言的.lproj
文件夹下。
国际化的调试方法
- 1、首先想到的当然是切换iPhone系统的语言系统,来调试国际化。这是最标准的方案,但是频繁的操作还是比较繁琐的。
- 2、Xcode提供了切换语言的功能。
在Arguments Passed On Launch添加-AppleLanguages (语言编码)
,然后选则需要的语言运行。
缺点:InfoPlist.strings的国际化不会生效。
国际化的实践
1. Main.storyboard自动更新
问题:在实践国际化中如果使用storyboard,会发现Main.strings
不会同步storyboard,这是很糟糕的问题。
解决方案:
- 手动同步
如果还没有配置Main.strings
具体的内容,可以先删除Main.strings
,再新建。这样storyboard的控件会同步到Main.strings
。
但是如果开发过程中修改storyboard(Main.strings
有国际化的内容),就不能这样操作了。
只能获取控件的ObjectID,手动编辑Main.strings
。(获取控件的ObjectID办法:可以在对比storyboard的修改中查找ObjectID)
手动同步无疑是低效的
- 手动同步
-
- 自动同步
自动同步是通过脚本的方式来实现。
- 2.1 将
AutoGenStrings.py
脚本放置在${SRCROOT}/${TARGET_NAME}/RunScript/
目录下,也就是项目根目录的RunScript
的文件夹下,没有就新建文件夹。 - 2.2 配置Run Script
添加运行命令:
python ${SRCROOT}/${TARGET_NAME}/RunScript/AutoGenStrings.py ${SRCROOT}/${TARGET_NAME}
- 自动同步
-
2.3 修改
Deployment Postprocessing
为Yes
Deployment Postprocessing: 指定二进制文件是否接受部署后处理。
Deployment Postprocessing
最好是在需要的时候开启,不需要时关闭。
AutoGenStrings
的命名和路径并不是固定的,可以自定义。但是存放的路径和Run Scrip
t配置的必须是一致的,否则找到不到脚本。
注明:AutoGenStrings
是其他作者的作品,因为没有找到真正的出处,所有没有标注。
2. 应用内切换语言环境
App内切换语言,这是很常见的需求。
前面说过: 国际化的实质是根据不同的语言设置加载对应的.lproj
资源文件夹。所以切换语言就是切换.lproj
。
大致的步骤:
- 2.1 切换
.lproj
,并保存当前语言信息在本地。 - 2.2 重置整个应用。
@objc private func setLanguage() {
let languages = Localize.availableLanguages()
let index = Int.random(in: 1..<3)
Localize.setCurrentLanguage(languages[index])
let story = UIStoryboard(name: "Main", bundle: BundleEx.main)
let viewCtrl = story.instantiateViewController(withIdentifier: "RootVC")
DispatchQueue.main.async {
if #available(iOS 13.0, *) {
let windows = UIApplication.shared.windows.filter { $0.isKeyWindow }.first
guard windows != nil else {
return
}
windows?.rootViewController = viewCtrl
} else {
UIApplication.shared.keyWindow?.rootViewController = viewCtrl
}
}
}
具体的实践可以查看Localizable示例
问题:
App内切换语言,按照上面 图片国际化 的操作,是无法切换图片的,因为国际化的图片不存储在.lproj
中。所以要想同时切换图片,只能将 图片名称国际化 ,使用字符串国际化的方式。
其他:
因为示例中设置语言
放在一级页面,所以直接重置rootViewController,如果放在层级比较深的页面,常见的做法是:用一个蒙层遮住整个屏幕,然后屏幕下重置rootViewController,并且按之前的push栈中的层级,一层层的push到设置语言
的页面。可参考iPhone的设置语言或者微信的设置语言。
3. Excel导出Localizable.strings
如果App设置的语言版本,以及内容太多,手动去编写Localizable.strings
无疑是很耗时的。
TCZLocalizableTool是一个国际化工具,能帮助将Excel表转化为多版本的Localizable.strings
,并且还提供多个关于国际化检测的功能。