iOS開發(fā)——iOS國(guó)際化 APP內(nèi)語(yǔ)言切換

最近一個(gè)一直在迭代的老項(xiàng)目收到一份新的開發(fā)需求,項(xiàng)目需要做國(guó)際化適配,簡(jiǎn)體中文+英文。由于項(xiàng)目中采用了storyboard和純代碼兩種布局方式,所以國(guó)際化也要同時(shí)實(shí)現(xiàn)。上網(wǎng)查了些資料,實(shí)現(xiàn)了更改系統(tǒng)語(yǔ)言后,修改app內(nèi)語(yǔ)言的問(wèn)題。具體國(guó)際化方式可以參考下文:

3分鐘實(shí)現(xiàn)iOS語(yǔ)言本地化/國(guó)際化

這篇文章講的比較詳細(xì),很容易實(shí)現(xiàn)。

這個(gè)需求實(shí)現(xiàn)后不久,產(chǎn)品又給我提了一個(gè)需求,讓我要在app內(nèi)實(shí)現(xiàn)語(yǔ)言切換。還好之前的國(guó)際化也做了些準(zhǔn)備,不慌不慌。

接下來(lái)就是方案的選定,通過(guò)廣泛查閱資料,得出兩個(gè)備選方案:

方案一:在原國(guó)際化版本的基礎(chǔ)上做修改,在info.plist文件中新增key="appLanguage"的鍵值對(duì),保存用戶設(shè)定的語(yǔ)言類別。通過(guò)切換語(yǔ)言類別來(lái)改變語(yǔ)言。(例子:微信)

優(yōu)點(diǎn):之前有國(guó)際化操作的基礎(chǔ),執(zhí)行起來(lái)并不復(fù)雜。

缺點(diǎn):切換完語(yǔ)言后,需要重新創(chuàng)建app keywindow的跟控制器,會(huì)有個(gè)跳轉(zhuǎn)的過(guò)程,用戶體驗(yàn)不好。

方案二:切換語(yǔ)言后,發(fā)送通知,每個(gè)控制器收到通知后,更改語(yǔ)言。(例子:新浪微博)

優(yōu)點(diǎn):很自然的切換語(yǔ)言,選擇語(yǔ)言后即可切換,不需要重置根控制器,用戶體驗(yàn)好。

缺點(diǎn):每個(gè)控制器都得注冊(cè)接收通知,工作量太大,而且storyboard也得單獨(dú)處理。

綜合兩個(gè)方案的優(yōu)缺點(diǎn),我們選擇方案一。

中英切換,就是讓App根據(jù)自身設(shè)置的語(yǔ)言去讀取對(duì)應(yīng)的國(guó)際化文件。在NSUserDefault中有一個(gè)字段:"AppleLanguages",這個(gè)字段就是負(fù)責(zé)存儲(chǔ)App語(yǔ)言的字段,默認(rèn)這個(gè)字段會(huì)根據(jù)系統(tǒng)語(yǔ)言去變動(dòng),中文系統(tǒng)他就存儲(chǔ)中文,英文系統(tǒng)就存儲(chǔ)英文。

廢話少說(shuō),切換語(yǔ)言的過(guò)程上代:

// NTVLocalized.h

#import <Foundation/Foundation.h>

static NSString * const AppLanguage = @"appLanguage";

@interface NTVLocalized : NSObject
+ (NTVLocalized *)sharedInstance;

//初始化多語(yǔ)言功能
- (void)initLanguage;

//當(dāng)前語(yǔ)言
- (NSString *)currentLanguage;

//設(shè)置要轉(zhuǎn)換的語(yǔ)言
- (void)setLanguage:(NSString *)language;

//設(shè)置為系統(tǒng)語(yǔ)言
- (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(@"自設(shè)置語(yǔ)言:%@",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(@"系統(tǒng)語(yǔ)言:%@",languageCode);
    if([languageCode hasPrefix:@"zh-Hans"]){
        languageCode = @"zh-Hans";//簡(jiǎn)體中文
    }else if([languageCode hasPrefix:@"en"]){
        languageCode = @"en";//英語(yǔ)
    }
    [self setLanguage:languageCode];
}

@end

當(dāng)語(yǔ)言設(shè)置完成后,需要重新設(shè)置keywindow的rootViewController才可以實(shí)現(xiàn)語(yǔ)言的切換。
然而這樣設(shè)置后,我們發(fā)現(xiàn)只有NSLocalizedString(key, comment)設(shè)置的語(yǔ)言才能正常顯示我們需要的語(yǔ)言,storyBoard和xib配置的頁(yè)面語(yǔ)言不跟著切換。
設(shè)置AppleLanguages字段的話,只會(huì)在下次啟動(dòng)App才會(huì)生效,在App啟動(dòng)后就已經(jīng)生成了一個(gè)Bundle,里面識(shí)別好了對(duì)應(yīng)著AppleLanguages的國(guó)際化文件,在App運(yùn)行期間設(shè)置這個(gè)字段,是不生效的,所以我們?nèi)バ薷倪@個(gè)Bundle,寫一個(gè)NSBundle的擴(kuò)展。

// NSBundle+language.h

#import <Foundation/Foundation.h>

@interface NSBundle (language)
// 設(shè)置語(yǔ)言
+ (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

重新寫一下設(shè)置語(yǔ)言的方法:

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

綜上所述,只是修改appleLanguage,在不重啟應(yīng)用的情況下,不能修改語(yǔ)言。所以我們選擇修改bundle的方法。
代碼在github上可以下載到:
https://github.com/FrankiezZZ/NTVLocalized

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

?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
【社區(qū)內(nèi)容提示】社區(qū)部分內(nèi)容疑似由AI輔助生成,瀏覽時(shí)請(qǐng)結(jié)合常識(shí)與多方信息審慎甄別。
平臺(tái)聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀點(diǎn),簡(jiǎn)書系信息發(fā)布平臺(tái),僅提供信息存儲(chǔ)服務(wù)。

相關(guān)閱讀更多精彩內(nèi)容

  • 你們說(shuō)過(guò) 她是你們唯一的依靠 所以 她一定會(huì)努力讓你們開心 讓你們驕傲 讓你們放心 你們說(shuō)過(guò) 書是她的最愛 于是在...
    卡布奇諾zxb0815閱讀 232評(píng)論 0 0
  • 你的身邊有沒有這樣的一些孩子,他們什么也不愿意做,連打游戲也懶得打,整天就只是在家里發(fā)呆。當(dāng)家長(zhǎng)很焦慮的像別人...
    一切都那么美好閱讀 734評(píng)論 0 0
  • 近日,IBM發(fā)布第四季度以及全年財(cái)報(bào),相比去年同期下降不少。作為PC行業(yè)巨頭,凈利潤(rùn)連年持續(xù)降低,IBM已經(jīng)踏走在...
    耿彪閱讀 395評(píng)論 0 1
  • 6.25 感謝慶玲的見證,讓我感覺自己太不懂得用肢體語(yǔ)言了,我也應(yīng)該聽了就去行。黃蘭英勇敢地邁出第一步...
    黃蘭英閱讀 274評(píng)論 0 0

友情鏈接更多精彩內(nèi)容