Localization - 国际化

国际化的实质是根据不同的语言加载对应的.lproj资源文件。.lproj中包含InfoPlist、Localizable、Main等资源文件。每新增一种语言,就会在工程目录下生成与之对应的.lproj资源文件夹。


国际化的步骤
1.新增语言

add localization.png

添加语言后,会在工程目录下生成xx.lproj文件夹(xx是语言的编码)。
eg: 添加Chinese(Simplified)(zh-Hans) 对应生成 zh-Hans.lproj

2.Main.storyboard国际化(主要针对带文本的控件)
Main.storyboard.png
  • 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文件(固定命名)


    InfoPlist.png
    1. Localization国际化(操作同Main.storyboard)
  • 3.定义:
/*————配置App信息————*/ 
// InfoPlist.strings(English) App在English语言系统下的名称
"CFBundleDisplayName" = "Localizable";
// InfoPlist.strings(Traditional) App在Traditional语言系统下的名称
"CFBundleDisplayName" = "国际化";

配置InfoPlist.strings,那么Info.plist会在不同的语言系统下,展示不同的内容。

4.字符串的国际化
    1. 新建Localizable.strings文件(固定命名,操作同Info.plist国际化)
    1. Localization国际化(操作同Info.plist国际化)
    1. 使用:
/*——————————定义文字内容——————————*/ 
// Localizable.strings(English) 
"Language" = "English";
// Localizable.strings(Traditional) 
"Language" = "繁体";
// 使用
let language = Bundle.main.localizedString(forKey: "Language", value: nil, table: nil)
5.图片国际化
image.png

将图片添加到对应的语言环境下。

注意:
Assets.xcassets是不能国际化的,和Main、Info.plist、Localizable不同的是:图片不能新建.strings文件,并且图片国际化之后还是保存在Assets.xcassets中,并不会存储在对应语言的.lproj文件夹下。

国际化的调试方法
  • 1、首先想到的当然是切换iPhone系统的语言系统,来调试国际化。这是最标准的方案,但是频繁的操作还是比较繁琐的。
  • 2、Xcode提供了切换语言的功能。
    Arguments.png

    在Arguments Passed On Launch添加-AppleLanguages (语言编码),然后选则需要的语言运行。
    缺点:InfoPlist.strings的国际化不会生效。

国际化的实践
1. Main.storyboard自动更新

问题:在实践国际化中如果使用storyboard,会发现Main.strings不会同步storyboard,这是很糟糕的问题。

解决方案:

    1. 手动同步
      如果还没有配置Main.strings具体的内容,可以先删除Main.strings,再新建。这样storyboard的控件会同步到Main.strings
      但是如果开发过程中修改storyboard(Main.strings有国际化的内容),就不能这样操作了。
      只能获取控件的ObjectID,手动编辑Main.strings。(获取控件的ObjectID办法:可以在对比storyboard的修改中查找ObjectID)
      手动同步无疑是低效的
    1. 自动同步
      自动同步是通过脚本的方式来实现。
    • 2.1 将AutoGenStrings.py脚本放置在${SRCROOT}/${TARGET_NAME}/RunScript/目录下,也就是项目根目录的RunScript的文件夹下,没有就新建文件夹。
    • 2.2 配置Run Script
      AutoGenStrings.png

      添加运行命令:
      python ${SRCROOT}/${TARGET_NAME}/RunScript/AutoGenStrings.py ${SRCROOT}/${TARGET_NAME}
  • 2.3 修改Deployment PostprocessingYes
    Deployment Postprocessing: 指定二进制文件是否接受部署后处理。

    Deployment Postprocessing.png

Deployment Postprocessing最好是在需要的时候开启,不需要时关闭。

AutoGenStrings的命名和路径并不是固定的,可以自定义。但是存放的路径和Run Script配置的必须是一致的,否则找到不到脚本。

注明: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,并且还提供多个关于国际化检测的功能。

相关资源

TCZLocalizableTool

最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 197,273评论 5 462
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 82,905评论 2 374
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 144,281评论 0 325
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 52,817评论 1 267
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 61,690评论 5 358
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 46,491评论 1 275
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 36,886评论 3 388
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 35,513评论 0 254
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 39,810评论 1 293
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 34,839评论 2 314
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 36,642评论 1 328
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 32,455评论 3 316
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 37,901评论 3 300
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 29,091评论 0 19
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 30,381评论 1 255
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 41,895评论 2 343
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 41,104评论 2 338