最近寫項目的時候遇到這樣一個需求,要求實現(xiàn)類似微信的多語言功能,
- 可在App內立即切換多語言,不需要重啟App
- 下次進入App要記住之前的設置
我在網(wǎng)上找到很多關于多語言的博客,但是絕大多數(shù)都是需要重啟App,或者下次進入App無法記住之前的設置,還有些就是直接貼了人家代碼過來根本不知道為什么這么寫。我在看過網(wǎng)上的博客之后,自己寫了一個demo,供大家參考。
下面這是效果圖:

Demo源代碼解析
1.項目配置

2.創(chuàng)建多語言源文件
選擇Strings File
給文件起個名,最好叫Localizable,因為我們后面獲取語言包就用這個名字

3.點擊項目中的文件

4.點擊本地化按鈕(Localize...)

5.出現(xiàn)彈窗,選擇本地化

6.把對應的語言勾選上

這時項目中會多出幾個文件,這些文件就是多語言的源文件

7.根據(jù)自身項目的需求,按照下面的格式寫入對應的語言對



至此,準備工作完成!
8.接下來我們要寫一個工具類,管理多語言的切換
下面是源碼:
//
// NSBundle+Language.h
// App內切換多語言
//
// Created by 崇 on 2018.
// Copyright ? 2018年 崇. All rights reserved.
//
#import <Foundation/Foundation.h>
#define GCLocalizedString(KEY) [[NSBundle mainBundle] localizedStringForKey:KEY value:nil table:@"Localizable"]
@interface NSBundle (Language)
+ (void)setLanguage:(NSString *)language;
@end
//
// NSBundle+Language.m
// App內切換多語言
//
// Created by 崇 on 2018.
// Copyright ? 2018年 ChinaChong. All rights reserved.
//
#import "NSBundle+Language.h"
#import <objc/runtime.h>
static NSString *const GCLanguageKey = @"AppLanguagesKey";
@interface BundleEx : NSBundle
@end
@implementation BundleEx
- (NSString *)localizedStringForKey:(NSString *)key value:(NSString *)value table:(NSString *)tableName {
// 當前語言
NSString *currentLanguage = [[NSUserDefaults standardUserDefaults] objectForKey:GCLanguageKey];
// 設置默認語言
currentLanguage = currentLanguage ? currentLanguage : @"zh-Hans";
// 每次需要從語言包查詢語言鍵值對的時候,都按照當前語言取出當前語言包
NSBundle *currentLanguageBundle = currentLanguage ? [NSBundle bundleWithPath:[[NSBundle mainBundle] pathForResource:currentLanguage ofType:@"lproj"]] : nil;
// 下面return中普通 bundle 在調用 localizedStringForKey: 方法時不會循環(huán)調用,雖然我們重寫了 mainBundle 單例的 localizedStringForKey: 方法,但是我們只修改了 mainBundle 單例的isa指針指向,
// 也就是說只有 mainBundle 單例在調用 localizedStringForKey: 方法時會走本方法,而其它普通 bundle 不會。
return currentLanguageBundle ? [currentLanguageBundle localizedStringForKey:key value:value table:tableName] : [super localizedStringForKey:key value:value table:tableName];
}
@end
@implementation NSBundle (Language)
+ (void)load {
static dispatch_once_t onceToken;
// 保證只修改一次 mainBundle 單例的isa指針指向
dispatch_once(&onceToken, ^{
// 讓 mainBundle 單例的isa指針指向 BundleEx 類
object_setClass([NSBundle mainBundle], [BundleEx class]);
});
}
+ (void)setLanguage:(NSString *)language {
// 將當前手動設置的語言存起來
[[NSUserDefaults standardUserDefaults] setObject:language forKey:GCLanguageKey];
[[NSUserDefaults standardUserDefaults] synchronize];
}
@end
工具類的大致思路:
工具類本身是
NSBundle的類目,用來增加一個切換多語言的方法,
即+ (void)setLanguage:(NSString *)language.h里面定義了一個宏GCLocalizedString(KEY),用來快速方便的調用方法localizedStringForKey:。.m里定義了一個繼承自NSBundle的BundleEx類,BundleEx類中重載的父類的localizedStringForKey:方法,代碼中的注釋解釋了為什么修改isa指向的類后不會循環(huán)調用,這里不再贅述。每一次查詢多語言鍵值對,都是通過當前語言獲取的語言包,所以App切換多語言是立即執(zhí)行的,不用重啟App。.m中后面的部分+ (void)load方法目的是讓程序在啟動后,[NSBundle mainBundle]返回的單例屬于BundleEx類,這樣[NSBundle mainBundle]返回的單例調用localizedStringForKey:方法就會走BundleEx類中重載的方法,確保取到正確的語言包。+ (void)setLanguage:(NSString *)language方法就是單純的存儲當前語言。-
工具類的精髓在于:
- 避免再寫一個單例,直接利用
mainBundle這個現(xiàn)有的單例,減少內存占用。 - 修改
mainBundle的isa指向,就會走我們重載的方法。 - 重載的
localizedStringForKey:方法是其父類NSbundle的方法,用來獲取對應語言包中的語言鍵值對。
- 避免再寫一個單例,直接利用
9.工具類的使用
//
// ViewController.m
// App內切換多語言
//
// Created by 崇 on 2018.
// Copyright ? 2018年 崇. All rights reserved.
//
#import "ViewController.h"
#import "NSBundle+Language.h"
@interface ViewController ()
@property (weak, nonatomic) IBOutlet UILabel *label;
@end
@implementation ViewController
- (void)viewDidLoad {
[super viewDidLoad];
[self updateLabel];
}
- (IBAction)switchToChinese:(id)sender {
[NSBundle setLanguage:@"zh-Hans"];
[self updateLabel];
}
- (IBAction)switchToEnglish:(id)sender {
[NSBundle setLanguage:@"en"];
[self updateLabel];
}
- (IBAction)switchToKorean:(id)sender {
[NSBundle setLanguage:@"ko"];
[self updateLabel];
}
- (void)updateLabel {
self.label.text = GCLocalizedString(@"皇帝");
}
聲明:本文主要結構代碼是在網(wǎng)上眾多博客參考而來,加上自己理解后加上了一些自己的改動。并非我自己絕對的原創(chuàng),但是大多數(shù)的博客都粘貼復制相同的代碼,找不到是誰的原創(chuàng),如果真身看到了此篇博客還請指出,我會貼上您原作的地址!??????