demo
- storyboard中的文字
- 代码中的文字
- app名称的展示
- 资源文件的国际化
- 国际化脚本
国际化原理
核心思想就是为每种语言单独定义一份资源。
iOS就是通过xxx.lproj目录来定义每个语言的资源,这里的资源可以是图片,文本,Storyboard,Xib等。
每种语言都有自己的 语言代码.lproj文件夹,加载资源时只需要加载相应语言文件夹下的资源就OK
例如:根目录下英语的为en.lproj,中文的为zh-Hans.lproj。
国际化过程
- 首先添加国际化配置
- 选中project->Info->Localizations,然后点击"+",添加需要国际化/本地化的语言,如下图(默认需要勾选Use Base Internationalization)
图片引用于:VV木公子 - 点击+后,选择后缀为Chinese (Simplified)(zh-Hans)简体中文,后缀为(zh-Hant)为繁体中文。
- 在这说一句后缀问题,所有iOS支持的语言及后缀,都可以在点击+后出现的语言中找到,其中最下面的other下是全部的集合。其中英语的后缀为(en)
- 选中project->Info->Localizations,然后点击"+",添加需要国际化/本地化的语言,如下图(默认需要勾选Use Base Internationalization)
- 应用名称
选中Info.plist(或者其他你想创建的位置,现在创建在info.plist所在的文件),按下键盘上的command + N,选择Strings File(iOS->Resource->Strings File)
文件名字命名为InfoPlist,且必须是这个名字
-
选中InfoPlist.strings,在Xcode右侧选中文件标志->选中Localize,目的是选择我们需要本地化的语言 如下图:
点击Localize后,在弹出框中->点击base->展开的列表中选择English->随后选中右下角的Localize
-
此时右侧会变成下图模样,勾选Chinese
-
此时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权限声明国际化
- 代码中字符串的本地化
- 与上类似,创建一个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中的语言设置就是相应语言的
- 多人开发情况下的字符串本地化
- 上面介绍的代码中字符串的本地化是使用的是默认的文件名"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];
- 上面介绍的代码中字符串的本地化是使用的是默认的文件名"Localizable",因为启动程序时,系统将根据语言加载相应的文件得到其对应的字符串文件,这个字符串可以通过系统将NSLocalizedString中的宏生成名为“Localizable.strings”的文件。那么如何让系统加载我们自己命名的本地化文件而非系统默认的Localizable.strings呢?这就是 NSLocalizedStringFromTable(<#key#>, <#tbl#>, <#comment#>)的用处。
- 图片本地化
- 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 这些操作 ** 。然后这个图片会变成文件夹模式,点击任意一个文件,找到文件所在位置,然后替换成你想要显示的文件即可(文件名保持一致)。
**优点** 就当做正常的图片使用即可。系统会根据语言设置找到对应的图片
- 查看/切换本地语言
- 应用启动时,首先会读取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赋值
- 还有一种方式如下图
- app内的语言切换。一个App切换语言的Demo
- 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" = "国际化测试";
- 脚本
- iOS项目中处理国际化文件数据导入导出脚本
- 这个脚本readme.md在介绍时有些地方不是最新版,要记得微调。例如第二版的:---.py的名字
- 这个脚本适用于要适配很多个语言,每个语言有很多项
-
第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
- 如果你最开始就在代码中已经预先设置了NSLocalizedString(@"使用帮助", nil)类似的字段,只差生成对应的key-value时,你可以
-
如果你什么也没配置,就是简单的将相关展示文字设置为对应的中文字符
- 首先你需要全局替换需要配置的中文字符,并以已经设置的中文字符为key
首先以正则表达式: (@"[^"]*[\u4E00-\u9FA5]+[^"\n]*?")\s* 来全局查找类似于 @"我的" 这个格式的字符 然后在工程中 点击搜索框 -> 替换Find 为 replace, 然后点击紧挨着的text 替换为Regular Expression 上面输入:(@"[^"]*[\u4E00-\u9FA5]+[^"\n]*?")\s* 下面输入:NSLocalizedString\($1\, nil) 中间的in ** 你可以点击一下后,选择你需要处理的文件夹 最后开始替换
- 随后你就可以参考上一个选项进行处理, 或者你可以使用 iOS 多语言版本的开发(三)这个教程中的工具进行处理
- 简单的使用以上基本包括,更复杂的使用,例如:动态字体,日期展示,数字展示等相关的,请查看字符串本地化这篇介绍。
- 首先你需要全局替换需要配置的中文字符,并以已经设置的中文字符为key
-
第二项是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字段列表,很全