国际化

demo

  1. storyboard中的文字
  2. 代码中的文字
  3. app名称的展示
  4. 资源文件的国际化
  5. 国际化脚本

国际化原理

核心思想就是为每种语言单独定义一份资源。
iOS就是通过xxx.lproj目录来定义每个语言的资源,这里的资源可以是图片,文本,Storyboard,Xib等。
每种语言都有自己的 语言代码.lproj文件夹,加载资源时只需要加载相应语言文件夹下的资源就OK
例如:根目录下英语的为en.lproj,中文的为zh-Hans.lproj。

国际化过程

  1. 首先添加国际化配置
    • 选中project->Info->Localizations,然后点击"+",添加需要国际化/本地化的语言,如下图(默认需要勾选Use Base Internationalization)
      图片引用于:VV木公子
      image
    • 点击+后,选择后缀为Chinese (Simplified)(zh-Hans)简体中文,后缀为(zh-Hant)为繁体中文。
    • 在这说一句后缀问题,所有iOS支持的语言及后缀,都可以在点击+后出现的语言中找到,其中最下面的other下是全部的集合。其中英语的后缀为(en)
  2. 应用名称
    • 选中Info.plist(或者其他你想创建的位置,现在创建在info.plist所在的文件),按下键盘上的command + N,选择Strings File(iOS->Resource->Strings File)

    • 文件名字命名为InfoPlist,且必须是这个名字

    • 选中InfoPlist.strings,在Xcode右侧选中文件标志->选中Localize,目的是选择我们需要本地化的语言 如下图:

      image

    • 点击Localize后,在弹出框中->点击base->展开的列表中选择English->随后选中右下角的Localize

    • 此时右侧会变成下图模样,勾选Chinese

      image

    • 此时InfoPlist.strings变成了文件夹,文件中有两个文件。程序启动时,会根据操作系统设置的语言,自动加载InfoPlist.strings文件下对应的语言文件,然后显示应用程序的名字。

      • 在InfoPlist.strings(english)文件中加入如下代码:
      // Localizable App Name是App在英语环境环境下显示的名称
      CFBundleDisplayName = "Localizable App Name";
      或者
      "CFBundleDisplayName" = "Localizable App Name";
      
      • 在InfoPlist.strings(Chinese(Simplified))中加入如下代码
      CFBundleDisplayName = "国际化App名称";
      
    • app展示名字本地化结束
      补充

      InfoPlist.strings文件是对Info.plist这个配置文件进行的国际化,这个文件的国际化,不单单是app名称的设置,还包括权限的申请等的配置。关键在于这个文件的配置KEY是固定值,例如: app名字的key CFBundleDisplayName, 相机权限的申请key NSCameraUsageDescription等

      • 首先你将需要配置的属性添加到Info.plist文件中
      • 其次查看这个属性的key, 点击这个文件的任意一项,两个指头同时点击,选择弹出框的Show Raw Keys/Values,文件的展示就变成了key-value格式,此时你就可以找到你想要国际化属性的key
      • 最后在InfoPlist.strings文件中,做对应的配置即可
      • 详细操作参考 iOS10权限声明国际化
  3. 代码中字符串的本地化
    • 与上类似,创建一个Localizable.strings的文件,创建步骤与上面一致。
    • 然后我们只需要在Localizable.strings下对应的文件中,分别以Key-Value的形式,为代码中每一个需要本地化的字符串赋值
    // Localizable.strings (Simplified)文件中
    localization = "本地化";
    internationalizartion = "国际化";
    //Localizable.strings (English)文件中
    localization = "localization";
    internationalizartion = "internationalizartion";
    
    在要使用这些字段的.m文件中
    // NSLocalizedString(key, comment) 本质
    // NSlocalizeString 第一个参数是内容,根据第一个参数去对应语言的文件中取对应的字符串,第二个参数将会转化为字符串文件里的注释,可以传nil,也可以传空字符串@""。
    //#define NSLocalizedString(key, comment) [[NSBundle mainBundle] localizedStringForKey:(key) value:@"" table:nil]
    NSString *localization = NSLocalizedString(@"localization", nil);
    NSString *internationalizartion = NSLocalizedString(@"internationalizartion", nil);
    self.array = @[localization, internationalizartion];
    取得并使用
    
    • 代码中字符串的本地化结束
    • 我们不需要在Localizable.strings(English)文件添加Key-Value。原因如下:系统根据某个key去获取对应的字符串时,如果没有找到,那么就会以key作为value返回。
    • 模拟不同的语言环境,不需要在模拟器中的设置中去做。在Xcode中,command+shift+<出现的界面中做如下设置:
      Run -> Arguments -> Arguments Passed On launch 中添加-AppleLanguages (en)和-AppleLanguages (zh-Hans)然后选中其中一个,运行的app中的语言设置就是相应语言的
      image
  4. 多人开发情况下的字符串本地化
    • 上面介绍的代码中字符串的本地化是使用的是默认的文件名"Localizable",因为启动程序时,系统将根据语言加载相应的文件得到其对应的字符串文件,这个字符串可以通过系统将NSLocalizedString中的宏生成名为“Localizable.strings”的文件。那么如何让系统加载我们自己命名的本地化文件而非系统默认的Localizable.strings呢?这就是 NSLocalizedStringFromTable(<#key#>, <#tbl#>, <#comment#>)的用处。
      也就是说,如果你的strings文件名字不是Localizable而是自定义的话,如VVS.strings,那么你就得使用NSLocalizedStringFromTable这个宏来读取本地化字符串。
    // key:系统根据key取字符串
    // tbl:自定义strings文件的名字
    // comment:可以不传
    NSLocalizedStringFromTable(<#key#>, <#tbl#>, <#comment#>)
    
    .m文件中
    NSString *title = NSLocalizedStringFromTable(@"click", @"VVS", nil);
    [self.btn setTitle:title forState:UIControlStateNormal];
    
  5. 图片本地化
    • Assets.xcassets 不支持本地化,所以需要本地化的,可以单独放到一个新的文件目录下
    • 拖拽一张需要本地化的图片到Xcode中/或者自定义的文件下统一处理这些需要本地化的图片
    • 在Localizable.strings文件下相应文件中设置key-value,通过NSLocalizedString(key,comment)来获取相应的字符串,然后根据这个字符串再获取图片。
    NSString *imageName = NSLocalizedString(@"icon", nil);
    UIImage *image = [UIImage imageNamed:imageName];
    self.imageView.image = image;
    **缺点**
    1. 工作量很大
    2. storyboard/xib中不能直接使用,需要代码中判断重新取正确的图像名,并重新赋值
    
    • 或者**把这张图片当做InfoPlist.strings去处理, 即选中图片 - 点击Localize 这些操作 ** 。然后这个图片会变成文件夹模式,点击任意一个文件,找到文件所在位置,然后替换成你想要显示的文件即可(文件名保持一致)。
    **优点**
    就当做正常的图片使用即可。系统会根据语言设置找到对应的图片
    
  6. 查看/切换本地语言
    • 应用启动时,首先会读取NSUserDefaults中的key为AppleLanguages对应的value,该value是一个String数组,也就是说,我们访问这个名为AppleLanguages的key可以返回一个string数组,该数组存储着APP支持的语言列表,数组的第一项为APP当前默认的语言。
    NSArray *languages = [[NSUserDefaults standardUserDefaults] valueForKey:@"AppleLanguages"];
    NSString *currentLanguage = languages.firstObject;
    NSLog(@"模拟器当前语言:%@",currentLanguage);
    
    • 同理,既然我们可以通过AppleLanguages这个key从NSUserDefaults中取出语言数组,那么我们也可以给AppleLanguages这个key赋值来达到切换本地语言的效果,从此以后,我们就无需频繁的去模拟器的设置->通用->语言与地区 中切换语言
    // 切换语言前
    NSArray *langArr1 = [[NSUserDefaults standardUserDefaults] valueForKey:@"AppleLanguages"];
    NSString *language1 = langArr1.firstObject;
    NSLog(@"模拟器语言切换之前:%@",language1);
    
    // 切换语言
    NSArray *lans = @[@"en"];
    [[NSUserDefaults standardUserDefaults] setObject:lans forKey:@"AppleLanguages"];
    
    // 切换语言后
    NSArray *langArr2 = [[NSUserDefaults standardUserDefaults] valueForKey:@"AppleLanguages"];
    NSString *language2 = langArr2.firstObject;
    NSLog(@"模拟器语言切换之后:%@",language2);
    
    • 与第三条中的最后一条相对比,其实本质上就是给NSUserDefaults中名为AppleLanguages的key赋值
    • 还有一种方式如下图
      images
    • app内的语言切换。一个App切换语言的Demo
  7. storyboard/Xib 的本地化
    • 在这个Xib/storyboard文件,完成的差不多的时候,对他进行本地化,无外乎,点中文件,Xcode右侧本地化操作,操作步骤与上面类似
    • 本地化后,在有所改变,已经本地化的文件不会变化,所以需要随时更新。一个笨的方法就是,去掉勾选的English和Chinese,然后会提示remove->选中delete选项,然后在勾选English和Chinese,然后会重新生成
    • 友情提示,在Xib/storyboard中生成的文件中,主要使用ObjectID,先删除然后重新生成,同一个控件的ObjectID不会发生变化。这样就可以记录之前的,然后对最新的略微改变即可。
    /* Class = "UILabel"; text = "国际化测试"; ObjectID = "knJ-x1-3Rk"; */
    "knJ-x1-3Rk.text" = "国际化测试";
    
  8. 脚本
  9. 第8项的脚本适应用Excel表格数据与配置文件的转化。本项的适用于,项目工程开始很久后,突然想要国际化配置,整个工程很多地方都需要处理。
    • 第一项代码中的待处理项

      • 如果你最开始就在代码中已经预先设置了NSLocalizedString(@"使用帮助", nil)类似的字段,只差生成对应的key-value时,你可以
        首先切换到需要处理的目录下
        cd ****
        其次创建对应的文件
        mkdir zh-Hans.lproj
        mkdir en.lproj
        最后查找目录下后缀为.m的文件,然后生成对应的数据存储到对应文件夹下
        find ./ -name *.m | xargs genstrings -o en.lproj
        find ./ -name *.m | xargs genstrings -o zh-Hans.lproj
        
    • 如果你什么也没配置,就是简单的将相关展示文字设置为对应的中文字符

      • 首先你需要全局替换需要配置的中文字符,并以已经设置的中文字符为key
        首先以正则表达式: (@"[^"]*[\u4E00-\u9FA5]+[^"\n]*?")\s* 来全局查找类似于 @"我的" 这个格式的字符
        然后在工程中 点击搜索框 -> 替换Find 为 replace, 然后点击紧挨着的text 替换为Regular Expression
        上面输入:(@"[^"]*[\u4E00-\u9FA5]+[^"\n]*?")\s*
        下面输入:NSLocalizedString\($1\, nil)
        中间的in ** 你可以点击一下后,选择你需要处理的文件夹
        最后开始替换
        
      • 随后你就可以参考上一个选项进行处理, 或者你可以使用 iOS 多语言版本的开发(三)这个教程中的工具进行处理
      • 简单的使用以上基本包括,更复杂的使用,例如:动态字体,日期展示,数字展示等相关的,请查看字符串本地化这篇介绍。
    • 第二项是xib或者storyboard中的待处理项

      • 首先就是基础操作,对每个需要进行配置的xib文件,仿照第7项操作。即手动开启每个的本地化。
      • 然后就是对这些xib的自动化更新配置了。即每次如果xib有改动,需要更新本地化数据时。让其自动化处理。脚本代码文件。原始操作流程参考iOS国际化详解
      • 简单步骤描述
        • 将存放脚本文件的文件夹,导入脚本文件到项目的根目录

          脚本文件夹 RunScript/AutoGenStrings.py
          导入到     Desktop/cf-ios/CF/RunScript/AutoGenStrings.py
          Desktop桌面, cf-ios 工程所在的文件夹名字, CF为工程名字
          
        • 选择项目 -> targes -> Build Phases -> + -> New Run Script Phase,将下面代码copy到对应的路径

          #!/bin/sh
          python ${SRCROOT}/${TARGET_NAME}/RunScript/AutoGenStrings.py ${SRCROOT}/${TARGET_NAME}
          
          详细步骤参考
        • Build Setting -> Deployment -> Deployment Location / Deployment Postprocessing -> Yes

          详细步骤参考

        • 注意文件路径中不能拥有空格,否则Xcode脚本会找不到文件的错误

        • 注意开启了Deployment Location / Deployment Postprocessing 后,会导致工程无法调试(debug),关闭后即可

        • 注意运行后可能出现This app could not be installed at this time.提示,关闭Deployment Location / Deployment Postprocessing设置,然后clean工程,重新运行即可。如果这个方式无法解决,可以尝试重启Xcode, 清楚模拟器的缓存或者重启模拟器。

        • 重点需要时在开启,不需要时请关闭,防止意外情况。

参考资料
简书:VV木公子
简书:iOS 国际化的设置大全
简书:iOS App的国际化,以及App内的语言切换
简书:iOS国际化
iOS国际化——通过脚本使storyboard翻译自增

简书:iOS国际化详解
简书:本地化 genstrings
很全的介绍:字符串本地化
iOS 多语言版本的开发(一)
iOS 多语言版本的开发(二)
iOS 多语言版本的开发(三)
iOS10权限声明国际化
Info.plist的秘密(raywenderlich笔记)
plist字段列表,很全

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

推荐阅读更多精彩内容