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


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM