ios 本地化国际化

时间:2022-03-30 08:01:23
个人对这个研究得比较久,也实际项目测过每一种方式;自认为是相对网上各种,是最全最详细的。欢迎大家交流!


需要国际化的内容:
  • 文本信息国际化(代码国际化):包括应用名称(InfoPlist.strings),按钮,警告提示信息以及界面中显示的静态文字;
  • Xib/Storyboard 国际化:同一个界面和场景可以提供多个本地化版本的xib和storyboard 文件;
  • 资源文件国际化:包括图片和音频等资源;图片国际化包括应用图标和一般图片的国际化;

demo 地址:(由于csdn不能上传附件,我放到资源里去了)
http://download.csdn.net/download/lixin88/10050869


一. InfoPlist.strings-应用名称国际化
1:创建 InfoPlist.strings
在xcode6 之前的版本中InfoPlist.strings会自动创建;
本例子是xcode8,需要自己创建,new file,选择Strings File,命名为 InfoPlist.strings; 创建的文件名必须是InfoPlist.strings且不需要写任何代码;

ios 本地化国际化





2: 先给整个project添加语言支持
如果需要使用某种语言,需要先给整个project添加支持,比如简体中文,如下添加好;

ios 本地化国际化


3.实现InfoPlist.strings本地化
InfoPlist.strings文件中添加  CFBundleDisplayName=" 国际化"
选中 InfoPlist.strings文件,打开文件检查器,选中Localize,如下:

ios 本地化国际化



会弹出对话框,由于之前添加了中文支持,则此处有简体中文和英文2个选项:
ios 本地化国际化

下拉列表中,选择Chinese(Simple) ; 然后在右边红色框中勾选English,则会生成相应左边红色框的文件,在文件里面修改key对应的value即可;


ios 本地化国际化



现在来看下整个目录结构,注意这个和project 一个层级,会生成语言.lproj 目录,下面放着对应的 InfoPlist.strings
ios 本地化国际化





二.程序代码输出的静态文本国际化
1.默认命字符串资源文件
Localizable.strings, 创建参考上文的InfoPlist.strings,创建后,添加英文版和简体中文版本支持,生成的文件结构如下图,然后修改对应的值即可。
 ios 本地化国际化

调用方式如下:
Localizable.strings多语言文件,用于本地化App内容的字符串,用户创建时必须这样命名,与之对应的调用方法是(这个宏在Foundation框架中):
#define NSLocalizedString(key, comment) \
[NSBundle.mainBundle localizedStringForKey:(key) value:@"" table:nil]
例如:label.text = NSLocalizedString(@"labelText", @"中国”);


2.自定义字符串资源文件
我们通过一个 Localizable.strings 文件来存储每个语言的文本,它是iOS默认加载的文件,如果想用自定义名称命名,在使用 NSLocalizedString 方法时指定tableName为自定义名称就好了,但你的应用规模不是很大就不要分模块搞特殊了。比如自定义命名为 Language.strings;

调用方式如下:
Language.strings 同样是多语言文件,用于本地化APP内容的字符串,不同于Localizable的是,用户创建时可以随意取名,与之对应的方法是:
#define NSLocalizedStringFromTable(key, tbl, comment) \
[NSBundle.mainBundle localizedStringForKey:(key) value:@"" table:(tbl)]
例如:label.text = NSLocalizedStringFromTable(@"labelText",@"Language",@"中国");

genstrings工具批量静态文本国际化
代码中即.m文件的国际化首先在你需要进行国际化处理的字符串外面加一层NSLocalizedString,注意中文也是可以的哦

NSLocalizedString是一个定义在NSBundle.h中的宏,其用途是寻找当前系统语言对应的Localizable.strings文件中的某个key的值。
第一个参数是key的名字,第二个参数是对这个“键值对”的注释,在用genstrings工具生成Localizable.strings文件时会自动加上去。
当我们把所有的.m文件都修改好了,就可以动用genstrings工具了

1. 启动终端,进入工程所在目录。
2. 新建两个目录,推荐放在资源目录下。
目录名会作用到Localizable.strings文件对应的语言,不能写错了。这里zh-Hans指简体中文,注意不能用zh.lproj表示。
mkdir zh-Hans.lproj
mkdir en.lproj

3. 生成Localizable.strings文件
genstrings -o zh-Hans.lproj *.m
genstrings -o en.lproj *.m
-o <文件夹>,指定生成的Localizable.strings文件放置的目录。
*.m,扫描所有的.m文件。这里支持的文件还包括.h, .java等。

上面genstrings指令只能是该目录下的文件遍历,但不能实现递归遍历,这样在一些大工程里面明显不能满足需求,于是在工程里更普遍的用法是
find ./ -name *.m | xargs genstrings -o en.lproj





三.xib 和故事板文件国际化
使用Base 国际化技术
Base 国际化 是Xcode 4.5 之后新的解决国际化的技术,用来解决标识故事板和xib文件的国际化问题。
在4.5 之前如果storyboard支持多语言,则会有多份"语言.lproj”,每个子目录下都有一份Main.storyboard,如果需要修改,则需要维护多份;
在4.5 之后,只需要在Base.lproj 中存一份,其他本地化语言,只生成Main.strings文件来存放信息即可;


storyboard 国际化语言支持也和上面一样, 打开文件检查器,选中Localize,如下右边框,则会生成对应左边框内;

ios 本地化国际化


宏观目录结构如下:
ios 本地化国际化


新增控件怎么办?
方法1. 手动添加
如果需要新添加一个控件,比如输入框,如下方式找到ID,然后加到你需要本地化的语言 Main.strings文件中;
比如在中文版的 Main.strings中添加:
 “ IOr-1q-mE7 ”=“查询”;
ios 本地化国际化

注意:使用auto layout 设置,来保证 “标签+文本框” 在国际化前后能保持固定的宽度;



方法2.   ibtool工具 自动添加
              相应语言的strings一旦生成后,Base Storyboard有任何编辑都不会影响到strings,这就意味着如果我们删除或添加了一个UILabel的text,strings也不能同步改动
还好,Xcode为我们提供了ibtool工具来生成Storyboard的strings文件。

ibtool Main.storyboard --generate-strings-file ./NewTemp.string

但是ibtool生成的strings文件是BaseStoryboard的strings(默认语言的strings),且会把我们原来的strings替换掉。所以我们要做的就是把新生成的strings与旧的strings进行冲突处理(新的附加上,删除掉的注释掉),这一切可以用这个pythoy脚本来实现,见 AutoGenStrings.py 。然后我们将借助 Xcode 中 Run Script 来运行这段脚本。这样每次Build时都会保证语言strings与Base Storyboard保持一致

ios 本地化国际化



三.资源文件国际化

图片本地化
本地化图片,有两种方式,第一种方式和本地化代码中的字符串一样,通过NSLocalizedString(key,comment)来获取相应的字符串,然后根据这个字符串再获取图片。

方式一:自定义文本命名

ios 本地化国际化
利用文本国际化的方式,在代码中调用
UIImage(named: NSLocalizedString("search_logo",comment: ""))

不推荐,一是因为做法太low了,工作量明显加大。二是不能在Storyboard或XIB中使用


方式二: 原生支持

将图片添加到工程,选中某个图片,打开其文件检查器,点击Localization 中的Localized 按钮,同上,选择要支持的语言,这样该资源文件就被移动到 对应的”语言.lproj”目录下面了;

ios 本地化国际化

使用这种方式,在XIB或Storyboard中引用图片时如果只使用名称是实时显示不了的,一定要加上后缀名。如avater.png
使用方式不变,iOS会自动找相应语言(xxx.lproj)下的图片
1
UIImage(named:  "avater" )



2.声音资源


新版Xcode中Images.xcassets不支持国际化(属性页面中没有 Localization ),Xcode5以前是支持的;
正确姿态应该是需要国际化的图片放在自定义Group里面,不需要国际化的图片放在Images.xcassets




四.如何测试

  • 设置运行语言环境
有时我们第一次安装APP时不想默认跟随系统,那么可以通过Xcode的scheme来指定特定语言
或者在系统设置中,切换语言测试
ios 本地化国际化






五.应用内切换语言

ios 本地化国际化

应用启动时,首先会读取NSUserDefaults中的key为AppleLanguages的内容,该key返回一个String数组,存储着APP支持的语言列表,数组的第一项为APP当前默认的语言。
1
2
//获取APP当前语言
(NSUserDefaults.standardUserDefaults().valueForKey( "AppleLanguages" ) as! Array)[0]
那么我们要实现语言切换改变AppleLanguages的值即可,因为苹果没提供给我们直接修改APP默认语言的API,我们只能通过NSUserDefaults手动去操作,且AppleLanguages的值改变后APP得重新启动后才会生效(才会读取相应语言的lproj中的资源,意义着就算你改了,资源还是加载的APP启动时lproj中的资源),猜测应该是框架层在第一次加载时对AppleLanguages的值进行了内存缓冲
1
2
3
4
//设置APP当前语言
var   def = NSUserDefaults.standardUserDefaults()
def.setValue([“zh-Hans”], forKey: "AppleLanguages" )
def.synchronize()

那么问题来了,如何做到改变AppleLanguages的值就加载相应语言的lproj资源?
其实,APP中的Storyboard的加载,图片与字符串的加载都是在NSBundle.mainBundle()上操作的,那么我们只要在语言切换后把NSBundle.mainBundle()替换成当前语言的bundle就行了,这样系统通过NSBundle.mainBundle()去加载资源时实则是加载的当前语言bundle中的资源