• iOS开发——iOS国际化 APP内语言切换


    最近一个一直在迭代的老项目收到一份新的开发需求,项目需要做国际化适配,简体中文+英文。由于项目中采用了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>0) {
            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"][0];
        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 = 0;
    
    @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

  • 相关阅读:
    图床_OpenStack-镜像服务
    图床_OpenStack-认证服务
    图床_OpenStack-基础环境
    #linux包之tcpdump之tcpdump命令
    利用OpenCms9提供的模块创建新站点
    Cocos2d-x3.0下实现循环列表
    Modbus读写模拟量寄存器具体解释
    C++ 实践总结
    spring Quartz基于配置文件和注解的实现
    EEPLAT学习
  • 原文地址:https://www.cnblogs.com/FrankieZ/p/8552830.html
Copyright © 2020-2023  润新知