定場詩
鋤禾日當午,
碼農(nóng)真辛苦叼风。
對著小屏幕取董,
周一到周五。
額无宿,突發(fā)奇想茵汰,想寫首詩,不要問我為什么這么有才華孽鸡。
目標
這篇文章將教你怎么給你的App帶來國際化效果蹂午,也就是中文系統(tǒng)顯示中文、英文系統(tǒng)顯示英文彬碱。豆胸。。等等巷疼。
還會教你如何做出微信設置里面的切換App語言的效果晚胡。
一、國際化文件
其實國際化跟我們的NSDictionary差不多嚼沿,我們要支持中文和英文估盘,就會生成兩個國際化文件(.string為后綴名),然后在兩個國際化文件中骡尽,設置一個Key忿檩,在中文的國際化文件中這個Key對應的NSString值就是中文的,在英文的國際化文件中這個Key對應的NSString值就是英文的爆阶,這么說太不好理解了,我們先把國際化文件生成出來,然后使用一下辨图,你就明白了班套。
首先新建一個項目,然后創(chuàng)建一個Localizable.strings文件故河。
這時找到這個新創(chuàng)建的文件吱韭,然后找到他的屬性欄,點擊他右側(cè)的鱼的,Localize...按鈕理盆。
然后找到如下圖的地方,就可以添加國際化文件了
然后點擊步驟4的加號凑阶,添加語言文件猿规,我們這里添加英文和簡體中文
在彈出的頁面上勾選全部,然后finish
這時我們展開Localizable.strings宙橱、Main.storyboard和LaunchScreen.storyboard姨俩,會看到這些文件。
我們這里需要著重注意的是Localizable.strings中的兩個文件师郑,我們在代碼中使用的NSString字符串主要都是在這里面給他進行國際化的环葵。
這里就是我們上面解釋過的一個Key對應中文、英文宝冕,在對應的語言系統(tǒng)下尋找對應的值张遭。我們再試著打印一句話,這里NSString的使用就要換一種方式了地梨。
要使用NSLocalizedString(,)這個方法菊卷,第一個參數(shù)就是我們所說的Key,第二個參數(shù)是備注湿刽,就是為了給自己一個標識的烁,方便分辨而已。
打印出來是這樣的
二诈闺、搭建頁面
這里我們就用一個tabbarController上面帶幾個navigationController這樣的結(jié)構(gòu)了渴庆。
首先寫個自己的tabbarController子類,因為我們在切換語言的時候雅镊,需要把整個App的頁面重新刷新下襟雷,又由于tabbarController是appDelegate中的window屬性的rootViewController,比如我們之前的App語言是中文的仁烹,現(xiàn)在切換成英文的耸弄,點擊按鈕,將window的rootViewController置空卓缰,再新聲明一個tabbarController计呈,作為window的rootViewController就OK了砰诵。
這里我就不寫怎么寫頁面了,貼下appDelegate中代碼捌显。
- (BOOL)application:(UIApplication *)application didFinishLaunchingWithOptions:(NSDictionary *)launchOptions {
// 創(chuàng)建主頁面
self.window = [[UIWindow alloc] initWithFrame:[UIScreen mainScreen].bounds];
self.window.rootViewController = [[ZHTabBarController alloc] init];
[self.window makeKeyAndVisible];
return YES;
}
這里ZHTabBarController是繼承自UITabBarController的類茁彭,在初始化的時候就放進去三個UINavigationController。模擬器上運行結(jié)果如下(英文系統(tǒng)):
三扶歪、中英文切換
中英切換理肺,就是讓App根據(jù)自身設置的語言去讀取對應的國際化文件。
在NSUserDefault中有一個字段:"AppleLanguages"善镰,這個字段就是負責存儲App語言的字段妹萨,默認這個字段會根據(jù)系統(tǒng)語言去變動,中文系統(tǒng)他就存儲中文炫欺,英文系統(tǒng)就存儲英文乎完。試著打印下,結(jié)果就是英文竣稽。
在finder中查看我們的國際化文件
你會發(fā)現(xiàn)Localizable.strings文件在en.lproj和zh-Hanz.lproj中都存在囱怕,而"en"和"zh-Hanz"正代表英文和中文。我們試著把zh-Hanz存儲到AppleLanguages字段中毫别⊥薰看看效果
那么我們就去寫切換語言功能吧。
在第三個頁面我們有兩個切換按鈕
- (IBAction)chineseBtnAction:(id)sender {
[self changeLanguageTo:@"zh-Hans"];
}
- (IBAction)englishBtnAction:(id)sender {
[self changeLanguageTo:@"en"];
}
- (void)changeLanguageTo:(NSString *)language {
[[NSUserDefaults standardUserDefaults] setObject:[NSArray arrayWithObjects:language, nil] forKey:@"AppleLanguages"];
[[NSUserDefaults standardUserDefaults] synchronize];
// 我們要把系統(tǒng)windown的rootViewController替換掉
ZHTabBarController *tab = [[ZHTabBarController alloc] init];
[UIApplication sharedApplication].keyWindow.rootViewController = tab;
// 跳轉(zhuǎn)到設置頁
tab.selectedIndex = 2;
}
看看效果岛宦。
沒有生效台丛,這是因為設置AppleLanguages字段的話,只會在下次啟動App才會生效砾肺,在App啟動后就已經(jīng)生成了一個Bundle挽霉,里面識別好了對應著AppleLanguages的國際化文件,在App運行期間設置這個字段变汪,是不生效的侠坎,所以我們?nèi)バ薷倪@個Bundle,寫一個NSBundle的擴展裙盾。
.h
#import <Foundation/Foundation.h>
@interface NSBundle (Language)
+ (void)setLanguage:(NSString *)language;
@end
.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)changeLanguageTo:(NSString *)language {
// 設置語言
[NSBundle setLanguage:language];
// 然后將設置好的語言存儲好实胸,下次進來直接加載
[[NSUserDefaults standardUserDefaults] setObject:language forKey:@"myLanguage"];
[[NSUserDefaults standardUserDefaults] synchronize];
// 我們要把系統(tǒng)windown的rootViewController替換掉
ZHTabBarController *tab = [[ZHTabBarController alloc] init];
[UIApplication sharedApplication].keyWindow.rootViewController = tab;
// 跳轉(zhuǎn)到設置頁
tab.selectedIndex = 2;
}
appDelegate中的方法修改為:
- (BOOL)application:(UIApplication *)application didFinishLaunchingWithOptions:(NSDictionary *)launchOptions {
if ([[NSUserDefaults standardUserDefaults] objectForKey:@"myLanguage"] && ![[[NSUserDefaults standardUserDefaults] objectForKey:@"myLanguage"] isEqualToString:@""]) {
[NSBundle setLanguage:[[NSUserDefaults standardUserDefaults] objectForKey:@"myLanguage"]];
}
// 創(chuàng)建主頁面
self.window = [[UIWindow alloc] initWithFrame:[UIScreen mainScreen].bounds];
self.window.rootViewController = [[ZHTabBarController alloc] init];
[self.window makeKeyAndVisible];
return YES;
}
修改后的運行效果
而且再次運行還會保持上次的語言。
總結(jié)
綜合上面的實踐番官,我們發(fā)現(xiàn)修改AppleLanguages的方法僅適用于重新啟動才生效的語言切換庐完,而修改bundle的方法,可以不用重啟應用直接生效徘熔。
覺得我講的比較亂的门躯,可以下載demo看看源碼
https://github.com/ZhaoheMHz/ZHInternatinalDemo/tree/master