** 原文发表在:https://www.xiaolei0808.com/2016/04/24/Localized-iOS/ **

一个iOS应用程序,如果想要在多个国家和地区的AppleStore上架,是很简单的一件事情。如果想要每个国家和地区的用户都能获得良好的使用体验,首先需要做的一件事情就是能够让用户打开App的第一时间,看到的是自己熟悉的语言。也就是说App能够根据用户当前所使用的语言或者用户手动选择的语言,实时的改变App内的语言。这就是iOS国际化所要实现的目的。

国际化开发的两种情况

1.在App开发之初,就已经有了国际化开发的Future,这种情况下进行国际化是很容易的,只要在开发过程中把需要国际化的字符串进行简单的处理即可。

2.已经开发完毕,开发之初并没有进行国际化适配,突然来需求说需要进行国际化,此时面对项目中成百上千的字符串,内心一定是崩溃的。

接下来,我会分别对这两种情况来说一下开发过程。

注:演示所使用的Xcode版本为7.3。

新启动的工程

项目国际化配置

1.找到Project的Localizations选项,点击加号(+),添加需要国际化的语言(一般工程中默认支持英文,为了方便演示,我只添加了中文简体支持)。此时会弹出一个选择框,选择你所要支持的Xib文件或StoryBoard文件。不需要支持Xib或StoryBoard文件则不勾选。

这里Use Base Internationalization开启状态下,每个国际化资源文件会有个Base选项,主要针对String,Xib,Storyboard作为一个基础的模板。

是否添加Xib支持

添加多语言支持

2.创建多语言文件,一般命名为Localizable.string。如果在开发过程中不指定文件名,系统会默认在Bundle中寻找这个名称的文件。当然,也可以任意命名,在开发过程中手动指定一下文件名即可。

添加多语言文件

3.找到并选中刚刚新建的Localizable.string文件,点击Inspector下Localization选项下的Localize按钮,任意选择一个语言(我选择的是English),然后点击Localize按钮,此时Localization选项会出现应用支持的语言列表,选择需要国际化的语言,Localizable.string文件下则会多出和所选择语言对应的子文件。

点击Localize按钮

选择语言

出现语言列表

添加需要国际化的语言

代码中对国际化内容的适配

1.我在ViewController中初始化了一个Label,并用NSLocalized宏对这个Label的字符串进行国际化适配。

- (void)viewDidLoad {[super viewDidLoad];UILabel *localizationLabel = [[UILabel alloc] initWithFrame:CGRectMake(150, 200, 100, 20)];[self.view addSubview:localizationLabel];//利用NSLocalizedString宏对字符串进行国际化适配localizationLabel.text = NSLocalizedString(@"Hello", @"description for this key.");}

既然用到了NSLocalizedString宏,我们就有必要了解一下这个宏到底干了什么。

NSLocalizedString宏探秘

点进宏定义文件:

#define NSLocalizedString(key, comment) \[[NSBundle mainBundle] localizedStringForKey:(key) value:@"" table:nil]
#define NSLocalizedStringFromTable(key, tbl, comment) \[[NSBundle mainBundle] localizedStringForKey:(key) value:@"" table:(tbl)]
#define NSLocalizedStringFromTableInBundle(key, tbl, bundle, comment) \[bundle localizedStringForKey:(key) value:@"" table:(tbl)]
#define NSLocalizedStringWithDefaultValue(key, tbl, bundle, val, comment) \[bundle localizedStringForKey:(key) value:(val) table:(tbl)]

我们会发现国际化相关所定义的4个宏。

  • NSLocalizedString(key, comment)

NSLocalizedString其实是从mainBundle中默认读取了Localizable.string中的key所对应的value。comment参数则是对key的描述,有利于翻译人员理解这个key所适用的场景。

  • NSLocalizedStringFromTable(key, tbl, comment)

NSLocalizedStringFromTable则是从mainBundle中读取指定多语言文件中的key所对应的value。tbl参数就是用于指定多语言文件名的参数。

  • NSLocalizedStringFromTableInBundle(key, tbl, bundle, comment)

NSLocalizedStringFromTableInBundle会读取指定Bundle中所指定的多语言文件中的key所对应的value。bundle参数就是用于传入所指定的Bundle。

  • NSLocalizedStringWithDefaultValue(key, tbl, bundle, val, comment)

NSLocalizedStringWithDefaultValue则是从指定Bundle中读取指定多语言文件中的key所对应的value,如果取不到对应的value,允许指定一个默认的value。val参数就是用于传入默认的value值。

2.了解了各个宏定义所代表的含义,我们继续往下写。

在Localizable.strings(English)中加入如下键值对:

"Hello" = "Hello";

在Localizable.strings(Chinese(Simplified))中加入如下键值对:

"Hello" = "你好";

编译运行:

系统语言为英文时显示效果:

英文运行结果

系统语言为中文时显示效果:

中文运行结果

可见,文本会随着系统语言的改变而改变。至此,一个简单的可以跟随系统语言切换的Demo就完成了。

已开发多个版本的工程

工程开发了许久,代码也写了几万行了,这时Boss突然说要进行国际化适配。

What the ***!!!

淡定,除了女朋友,还有什么能难道程序猿哥哥的事情呢?

下面开始。

添加应用需要国际化的语言

在Project的Localizations选项,点击加号(+),添加需要国际化的语言(一般工程中默认支持英文,为了方便演示,我只添加了中文简体支持)。

批量替换字符串

既然要在已有工程上进行适配,首先要做的就是给需要进行国际化的字符串加上NSLocalizedString宏了。

  • 2B程序猿

会一处一处的修改每个文件的每处字符串,直到天荒地老、海枯石烂。

  • 非主流程序猿

各种shell、Python脚本齐上阵。

  • 文艺程序猿

Xcode大法好。正则大法好。

我选择第三种-。-

首先,我们需要一个正则,去匹配工程中所有需要替换的文本。如果你不太了解正则,点我点我!!。

下面这个正则可以匹配到所有符合OC字符串格式的包含有中文的字符串。如果你用Swift,请去掉@

@"[^"]*[\u4E00-\u9FA5]+[^"\n]*?"

然后,重点来了。Command+Shift+F,进入全局搜索引擎,切换为Replace模式,并把匹配模式改为Regular Expression。

在搜索条件里输入(@"[^"]*[\u4E00-\u9FA5]+[^"\n]*?"),在下面替换内容里输入NSLocalizedString($1, nil)。此处正则表达式两边加括号的目的是为了能够在替换时用$1获取原有字符串的值,在替换时把原有值放入宏定义内key的位置。然后,搜索,可以看到搜索结果,点击Replace All,即可完成替换。

正则搜索

生成多语言文件

替换完了原有字符串,下面就是生成多语言文件了。作为一个文艺程序猿,我是不可能一处一处的把项目中的字符串挑出来再写到Localizable.strings文件里的。

好在Xcode自带了一个命令行工具genstrings。我们可以利用这个工具生成所需的多语言文件。

首先,我们需要先新建所需语言的文件夹。

cd 工程目录
mkdir en.lproj
mkdir zh-Hans.lproj

然后,遍历所有.m文件,根据每个文件内的需要国际化的字符串生成key和value。

find . -name *.m | xargs genstrings -o en.lproj
find . -name *.m | xargs genstrings -o zh-Hans.lproj

此时,en.lprojzh-Hans.lproj文件夹中就应该有了相应的Localizable.string文件了。

我们把这两个文件夹拖到工程里,然后在相应的Localizable.strings文件中,修改每个key所对应的value值就行了(这个应该是翻译干的事儿)。

至此,项目的国际化已经适配完成。

应用内动态更新语言

以上所做的国际化,只会跟随系统语言进行改变,并且需要Kill掉App重新打开才会有效果。如果有一种需求,在应用内有一个语言列表,只要选中其中一种语言,点击确定后就能立刻更新应用内所有界面的语言,此时该怎么做呢?目前有好多大厂应用,比如微信、支付宝等都支持这种切换方式(微信和支付宝的实现方式不太一样,咱们稍后再叙)。

替换系统国际化宏定义

由系统宏定义可知,如果使用了系统的NSLocalizedString宏,它是默认是从mainBundle中读取Localizable.strings中的value的。使用其他的3个宏则可以指定文件名或是Bundle,但是使用起来也是不太灵活。为了使用起来更加方便灵活,我们可以自定义一个国际化的宏,实现其内部的逻辑。

下面,给出一种我自己的实现方式。

//
//  LELocalizedHelper.h
//  Created by 金小白 on 16/4/23.
//  Copyright © 2016年 xiaolei.jin. All rights reserved.
//  国际化#import <Foundation/Foundation.h>#define LELocalizedString(key) [[LELocalizedHelper standardHelper] stringWithKey:key]@interface LELocalizedHelper : NSObject+ (instancetype)standardHelper;- (NSBundle *)bundle;- (NSString *)currentLanguage;- (void)setUserLanguage:(NSString *)language;- (NSString *)stringWithKey:(NSString *)key;@end
//
//  LELocalizedHelper.m
//  Created by 金小白 on 16/4/23.
//  Copyright © 2016年 xiaolei.jin. All rights reserved.
//  国际化#import "LELocalizedHelper.h"static NSBundle *_bundle;static NSString *const kUserLanguage = @"kUserLanguage";@implementation LELocalizedHelper+ (instancetype)standardHelper {static LELocalizedHelper *helper;static dispatch_once_t onceToken;dispatch_once(&onceToken, ^{helper = [[LELocalizedHelper alloc] init];});return helper;
}- (instancetype)init {if (self = [super init]) {if (!_bundle) {NSUserDefaults *defaults = [NSUserDefaults standardUserDefaults];NSString *userLanguage = [defaults valueForKey:kUserLanguage];//用户未手动设置过语言if (userLanguage.length == 0) {NSArray *languages = [[NSBundle mainBundle] preferredLocalizations];NSString *systemLanguage = languages.firstObject;userLanguage = systemLanguage;}if ([userLanguage isEqualToString:@"zh-HK"] || [userLanguage isEqualToString:@"zh-TW"]) {userLanguage = @"zh-Hant";}NSString *path = [[NSBundle mainBundle] pathForResource:userLanguage ofType:@"lproj"];_bundle = [NSBundle bundleWithPath:path];}}return self;
}- (NSBundle *)bundle {return _bundle;
}- (NSString *)currentLanguage {NSUserDefaults *defaults = [NSUserDefaults standardUserDefaults];NSString *userLanguage = [defaults valueForKey:kUserLanguage];if (userLanguage.length == 0) {NSArray *languages = [[NSBundle mainBundle] preferredLocalizations];NSString *systemLanguage = languages.firstObject;return systemLanguage;}return userLanguage;
}- (void)setUserLanguage:(NSString *)language {NSUserDefaults *defaults = [NSUserDefaults standardUserDefaults];NSString *path = [[NSBundle mainBundle] pathForResource:language ofType:@"lproj"];_bundle = [NSBundle bundleWithPath:path];[defaults setValue:language forKey:kUserLanguage];[defaults synchronize];
}- (NSString *)stringWithKey:(NSString *)key {if (_bundle) {return [_bundle localizedStringForKey:key value:nil table:@"Localizable"];}else {return NSLocalizedString(key, nil);}
}@end

使用的时候,只需把原来NSLocalizedString(key, nil)的地方替换为LELocalizedString(key)即可。此时如果用户没有手动更改过语言,默认是跟随系统语言变化的。

动态刷新所有页面

替换完了宏定义,下面就是全局刷新界面了。实现方式上来说,我目前共想出了3种,实现方式上来说各有优劣。

重新载入rootViewController

这个方法应该是编码成本最低的方法了,只需要把原有的rootViewController移除并清空,然后重新设置一遍rootViewController就行了。但是这种实现方式会重新加载已经原来已经加载好的所有界面。

语言改变发送通知

在用户切换语言的时候,发送一个通知,然后在各个界面接收通知,更新所有需要更新的文本即可。这种方法适合新建的项目,在代码编写之初就预留好更新文本的方法,收到通知后调用此方法就行。如果已经是一个已上线项目,则改动成本比较高,需要改动的地方比较多。

.h暴露一个更新文字的方法

在用户切换语言的时候,遍历所有已经加载的界面,调用更新文字的方法。这种实现也是比较适合新建的项目,在代码编写之初就预留好更新文本的方法。如果项目已上线,则改动成本较高。

上文说过,微信和支付宝的实现方式不太一样。根据我的观察和判断,微信使用的是上面的第一种方法,也就是重新载入rootViewController的方法。因为微信切换完语言之后,迅速的切换到了根页面,又迅速的push到了设置界面,有一个界面跳跃的过程,而且原来所有的已经滑到底部的列表全部都重置到了最顶部。根据我的推断,微信项目在编写之初也是没有考虑到后期国际化的需求,迫于过大的改动成本,只好使用第一种方法。而支付宝切换过程就比较完美,实现了无缝切换,和有可能是前期编码过程中就预留了更新文本的方法,后期直接调用就可以(不排除后期投入精力进行重构的可能)。

以上就是全部的iOS文字国际化的过程。

图片国际化

网络图片国际化

很简单,只要在请求的时候根据不同的语言环境调用不同的接口就可以。

本地图片国际化

本地图片的国际化也有两种实现方式。

根据不同语言指定不同的图片名称

这种方法可以在初始化图片名称的时候使用国际化宏定义,然后在对应语言的多语言文件中,根据图片对应的key指定相应语言的value即可。

利用Xcode生成

这种方法不用对代码进行改动,只需要在工程目录中新建一个Group,放入所有需要国际化的原有图片。然后选中图片,点击右侧的Localization,选中需要支持的语言即可在原有图片下生成选中语言所对应的子文件。然后替换掉对应语言的子图片即可。

注:图片名必须和原有名字一致

生成国际化图片

国际化图片列表

英文图片

中文图片

这样,在更改系统语言的时候,图片也会随之改变了。

以上就是我总结的所有的有关iOS国际化的操作了,如果有疏漏的地方,请各位看官多多指正。共勉。

作者:金小白先生
链接:https://www.jianshu.com/p/7cb0fad6d06f

iOS开发之国际化(本地化)相关推荐

  1. iOS开发技巧-国际化(Localization),只看一篇就够了

    转:https://www.jianshu.com/p/f8edd7b7a217 本文主要涉及iOS的国际化,网上虽然有很多相关的文章,但是仔细阅读下来感觉都不太全面,因此重开一篇总结,记录项目中遇到 ...

  2. iOS开发——高级技术本地化与国际化详解

    本地化与国际化详解 效果如下: 英语:                                                                    中文: 具体实现如下: 一 ...

  3. iOS开发:国际化之app支持多种语言切换

    iOS国际化:如何切换语言 1.国际化就是将标签.提示信息等信息放到资源文件中,随着程序需要的语言提供对应的资源文件.以key/value对存储,每个资源的key值不变,value随着需求改变. 一般 ...

  4. IOS开发之国际化(中英语言版本设置)

    语言国际化 会根据系统语言自动替换app的语言 添加Localization,选择地区 新建String File 文件(不能乱写) 关于app名称为InfoPlist.strings 关于代码的名称 ...

  5. ios开发语言本地国际化_开发人员软件本地化最终语言指南

    ios开发语言本地国际化 There are lots of great guides out there for how to prep your product for international ...

  6. iOS开发 - App语言国际化

    前言 语言本地化,又叫做语言国际化.是指根据用户操作系统的语言设置,自动将应用程序的语言设置为和用户操作系统语言一致的语言.往往一些应用程序需要提供给多个国家的人群使用,或者一个国家有多种语言,这就要 ...

  7. iOS开发 国际化/多语言适配

    史上最详细的多语言本地化 iOS中,国际化适配,大概有下面几种情况需要适配. 1,App名称/图标本地化 2,启动页本地化 3,代码中字符串本地化 4,xib/storyboard本地化 5,图片的本 ...

  8. swift5 ios的国际化(本地化,全球化,多语言)(最主要博客)

    文章目录 1.我主要参考的是这位大神的博客 1.1 要注意的地方1 1.2 要注意的地方2 2.storyboard的国际化 3. 在APP内切换语言 3.1 代码 LocalizableManage ...

  9. iOS开发里的Bundle是个啥玩意?!

    初学iOS开发的同学,不管是自己写的,还是粘贴的代码,或多或少都写过下面的代码 [[NSBundle mainBundle] pathForResource:@"someFileName&q ...

  10. ios开发问题汇总(一)

    教程汇总 IOS比较好的网络教程:IOS编程浅蓝教程 IOS编程教程(五)自定义UITableView的表单元格 菜鸟教程-iOS教程 开发问题 实现页面切换,网上某些文章写的是: [self.nav ...

最新文章

  1. html css3d效果,html,css的3D变形
  2. win8 C盘空间不足的几种解决方法
  3. python统计单词平均长度_统计学的Python实现-014:几何平均数(衡量样本集中趋势)...
  4. COGS 930. [河南省队2012] 找第k小的数 主席树
  5. 在SQL Server中导入和使用CSV文件
  6. php 实现一致性哈希,PHP一致性哈希实现。。
  7. python 小程序搜索排名-用python2.7.9 写个小程序搜索某个目录下行有某关键字
  8. AcWing 4243. 传递信息(单源最短路)
  9. PHP中的错误处理set_error_handler()与trigger_error()的问题
  10. 题解 P3835 【【模板】可持久化平衡树】
  11. VSCode使用Windows用户名而不是config中设置的User
  12. 四元数——概念以及相关数学公式 实现绕坐标轴旋转以及获取旋转角和旋转轴
  13. python哥德巴赫猜想_Python验证哥德巴赫猜想
  14. ubuntu系统上进行usb相机端口绑定
  15. 西工大机考《劳动与社会保障法》大作业网考
  16. 中专计算机学数学,科学计算器在中职数学教学中的意义
  17. springCloud笔记——微服务介绍
  18. split()方法,limit参数作用
  19. eter测试软件,AcCellerator高通量单细胞力学荧光测试分析系统
  20. 实例!自动化物流系统规划设计(立库,输送,分拣,WMS)

热门文章

  1. VS2005最近项目和最近文件清除
  2. 什么是闭包?如何理解及使用闭包?
  3. E - Elevator
  4. mysql主从复制与主主复制
  5. Integer与int的种种比较
  6. IOS contentOffset该如何理解
  7. shell脚本中的日期处理
  8. Mac配置环境变量(Java,Android,Gradle,Maven,Hosts)
  9. [导入]SQL Server存储过程编程经验技巧
  10. AudioSwitcher for mac(音频控制工具)v3.08 版本支持M1芯片