最近一个一直在迭代的老项目收到一份新的开发需求,项目需要做国际化适配,简体中文+英文。由于项目中采用了storyboard和纯代码两种布局方式,所以国际化也要同时实现。上网查了些资料,实现了更改系统语言后,修改app内语言的问题。具体国际化方式可以参考下文:

3分钟实现iOS语言本地化/国际化

这篇文章讲的比较详细,很容易实现。

这个需求实现后不久,产品又给我提了一个需求,让我要在app内实现语言切换。还好之前的国际化也做了些准备,不慌不慌。

接下来就是方案的选定,通过广泛查阅资料,得出两个备选方案:

方案一:在原国际化版本的基础上做修改,在info.plist文件中新增key="appLanguage"的键值对,保存用户设定的语言类别。通过切换语言类别来改变语言。(例子:微信)

优点:之前有国际化操作的基础,执行起来并不复杂。

缺点:切换完语言后,需要重新创建app keywindow的跟控制器,会有个跳转的过程,用户体验不好。

方案二:切换语言后,发送通知,每个控制器收到通知后,更改语言。(例子:新浪微博)

优点:很自然的切换语言,选择语言后即可切换,不需要重置根控制器,用户体验好。

缺点:每个控制器都得注册接收通知,工作量太大,而且storyboard也得单独处理。

综合两个方案的优缺点,我们选择方案一。

中英切换,就是让App根据自身设置的语言去读取对应的国际化文件。在NSUserDefault中有一个字段:"AppleLanguages",这个字段就是负责存储App语言的字段,默认这个字段会根据系统语言去变动,中文系统他就存储中文,英文系统就存储英文。

废话少说,切换语言的过程上代:

// NTVLocalized.h

#import <Foundation/Foundation.h>

static NSString * const AppLanguage = @"appLanguage";

@interface NTVLocalized : NSObject
+ (NTVLocalized *)sharedInstance; //初始化多语言功能
- (void)initLanguage; //当前语言
- (NSString *)currentLanguage; //设置要转换的语言
- (void)setLanguage:(NSString *)language; //设置为系统语言
- (void)systemLanguage; @end
// NTVLocalized.m

#import "NTVLocalized.h"

@implementation NTVLocalized
+ (NTVLocalized *)sharedInstance {
static NTVLocalized *instance = nil;
static dispatch_once_t onceToken;
dispatch_once(&onceToken, ^{
instance = [[NTVLocalized alloc] init];
});
return instance;
} - (void)initLanguage{
NSString *language=[self currentLanguage];
if (language.length>) {
NSLog(@"自设置语言:%@",language);
}else{
[self systemLanguage];
}
} - (NSString *)currentLanguage{
NSString *language=[[NSUserDefaults standardUserDefaults]objectForKey:AppLanguage];
return language;
} - (void)setLanguage:(NSString *)language{
[[NSUserDefaults standardUserDefaults] setObject:language forKey:AppLanguage];
} - (void)systemLanguage{
NSString *languageCode = [[NSUserDefaults standardUserDefaults] objectForKey:@"AppleLanguages"][];
NSLog(@"系统语言:%@",languageCode);
if([languageCode hasPrefix:@"zh-Hans"]){
languageCode = @"zh-Hans";//简体中文
}else if([languageCode hasPrefix:@"en"]){
languageCode = @"en";//英语
}
[self setLanguage:languageCode];
} @end

当语言设置完成后,需要重新设置keywindow的rootViewController才可以实现语言的切换。
然而这样设置后,我们发现只有NSLocalizedString(key, comment)设置的语言才能正常显示我们需要的语言,storyBoard和xib配置的页面语言不跟着切换。
设置AppleLanguages字段的话,只会在下次启动App才会生效,在App启动后就已经生成了一个Bundle,里面识别好了对应着AppleLanguages的国际化文件,在App运行期间设置这个字段,是不生效的,所以我们去修改这个Bundle,写一个NSBundle的扩展。

// NSBundle+language.h

#import <Foundation/Foundation.h>

@interface NSBundle (language)
// 设置语言
+ (void)setLanguage:(NSString *)language;
@end
// NSBundle+language.m

#import "NSBundle+language.h"
#import <objc/runtime.h> static const char _bundle = ; @interface BundleEx : NSBundle @end @implementation BundleEx - (NSString *)localizedStringForKey:(NSString *)key value:(NSString *)value table:(NSString *)tableName {
NSBundle *bundle = objc_getAssociatedObject(self, &_bundle);
return bundle ? [bundle localizedStringForKey:key value:value table:tableName] : [super localizedStringForKey:key value:value table:tableName];
} @end @implementation NSBundle (Language) + (void)setLanguage:(NSString *)language {
static dispatch_once_t onceToken;
dispatch_once(&onceToken, ^{
object_setClass([NSBundle mainBundle], [BundleEx class]);
}); objc_setAssociatedObject([NSBundle mainBundle], &_bundle, language ? [NSBundle bundleWithPath:[[NSBundle mainBundle] pathForResource:language ofType:@"lproj"]] : nil, OBJC_ASSOCIATION_RETAIN_NONATOMIC);
} @end

重新写一下设置语言的方法:

- (void)setLanguage:(NSString *)language{
[NSBundle setLanguage:language];
[[NSUserDefaults standardUserDefaults] setObject:language forKey:AppLanguage];
[[NSUserDefaults standardUserDefaults] synchronize];
}

综上所述,只是修改appleLanguage,在不重启应用的情况下,不能修改语言。所以我们选择修改bundle的方法。
代码在github上可以下载到:
https://github.com/FrankiezZZ/NTVLocalized

欢迎各位小伙伴加入iOS交流群:140147825

iOS开发——iOS国际化 APP内语言切换的更多相关文章

  1. iOS多语言(国际化)开发(尾随系统 + APP内手动设置)

    一:尾随系统切换语言 1>创建好项目project后, 新建一个多语言文件: 2>加入要设置的语言类型: 3>加入成功 细心的朋友可能会发如今English后面写的是3 Files ...

  2. iOS开发之多表视图滑动切换示例(仿"头条"客户端)---优化篇

    前几天发布了一篇iOS开发之多表视图滑动切换示例(仿"头条"客户端)的博客,之所以写这篇博客,是因为一位iOS初学者提了一个问题,简单的写了个demo做了个示范,让其在基础上做扩展 ...

  3. iOS开发UI篇—APP主流UI框架结构

    iOS开发UI篇—APP主流UI框架结构 一.简单示例 说明:使用APP主流UI框架结构完成简单的界面搭建 搭建页面效果:                                二.搭建过程和 ...

  4. iOS开发中,应用内直接跳转到Appstore

    iOS开发中,应用内直接跳转到Appstore 1.进入appstore中指定的应用NSString *str = [NSString stringWithFormat:                ...

  5. iOS开发之提交App中断出现:Cannot proceed with delivery: an existing transporter instance is currently uploading this package

    iOS开发之提交App中断出现:Cannot proceed with delivery: an existing transporter instance is currently uploadin ...

  6. iOS开发-iOS 10 由于权限问题导致崩溃的那些坑

     iOS开发-iOS 10 由于权限问题导致崩溃的那些坑 6月份的WWDC大会结束有一段时间了,相信很多开发者也是在努力工作的闲时用着Xcode8 Beta版学习着新的特性吧. 使用Xcode8写自己 ...

  7. iOS应用内语言切换功能

    当我们的应用仅仅面向国内用户群,一般仅支持一种语言--中文就可以了.当面向国外用户时就需要进行国际化了,不仅仅是语言的转变,也可能包括设计风格,页面布局.交互效果的转变,如微信,微博,QQ这类应用都有 ...

  8. iOS开发系列之app的一天

    本文主要讲述我对 iOS 开发的一些理解,希望能通过 app 从启动到退出,将一些的知识整合起来,形成一条知识链,目前涉及到的知识点有 runloop.runtime.文件存储.界面布局.离线推送.内 ...

  9. 读ios开发有感——建立APP开发体系

    前言:ios开发和现在的大前端.跨端开发在底层上的道理是相通的,因此通过学习ios开发,可以形成对APP开发体系的理解. 一.app开发的知识体系 基础 应用开发 原理 原生与前端 二.基础模块 按照 ...

随机推荐

  1. Cookie禁用 获取session

    转自:http://blog.csdn.net/u010433704/article/details/40950599 Cookie与 Session,一般认为是两个独立的东西,Session采用的是 ...

  2. echarts legend 重叠 (转载)

    解决方案:  1. 调整option中的grid.top值才能避免重叠:(可以设置定制,也可以定义了一个计算公式) 2. 文档注明[特殊字符串 ''(空字符串)或者 '\n' (换行字符串)用于图例的 ...

  3. 菜鸟之旅——.NET垃圾回收机制

    .NET的垃圾回收机制是一个非常强大的功能,尽管我们很少主动使用,但它一直在默默的在后台运行,我们仍需要意识到它的存在,了解它,做出更高效的.NET应用程序:下面我分享一下我对于垃圾回收机制(GC)的 ...

  4. C++学习笔记第三天:类、虚函数、双冒号

    类 class Box { public: double length; // 盒子的长度 double breadth; // 盒子的宽度 double height; // 盒子的高度 }; 类成 ...

  5. hdu 2045 递推

    从n>=4开始考虑,只考虑n-1和1的颜色是否相等情况.推出公式F(n)=F(n-1)+2*F(n-2) AC代码: #include<cstdio> const int maxn= ...

  6. SSRF漏洞总结

    SSRF漏洞:(服务端请求伪造)是一种由攻击者构造形成由服务端发起请求的一个安全漏洞.一般情况下,SSRF攻击的目标是从外网无法访问的内部系统.(正是因为它是由服务端发起的,所以它能够请求到与它相连而 ...

  7. docker-compose 完整打包发布, 多服务,多节点SPRING CLOUD ,EUREKA 集群

    这里不再使用 端口映射的方式,因为不同主机上,Feign 根据 docker hostname访问会有问题. 把打包的好jar copy到docker镜像里 有几个服务,就复制几个dockerfile ...

  8. C语言拼接字符串以及进制转换

    #include<stdio.h> #include<stdlib.h> #include<string.h> char *join1(char *, char*) ...

  9. java读取文件乱码

    List<String> lines=new ArrayList<String>(); BufferedReader br = new BufferedReader(new F ...

  10. linux RHCS集群 高可用web服务器

    RHCS集群,高可用服务器 高可用 红帽集群套件,提供高可用性,高可靠性,负载均衡,快速的从一个节点切换到另一个节点(最多16个节点)负载均衡 通过lvs提供负载均衡,lvs将负载通过负载分配策略,将 ...