本文記錄iOS 多語言全局適配解決方案雷客,適用于項目中后期快速適配多語言游沿;
實現(xiàn)思路:runtime method swizzling滓鸠,攔截UILabel 的setText:
方法猜敢、UIViewController 的 setTitle:
方法卦绣、UINavigationItem 的setTitle:
方法耐量;
一、多語言基本適配:
該部分請參考:VV木公子
作品:
3分鐘實現(xiàn)iOS語言本地化/國際化(圖文詳解)!
二滤港、多語言配置讀壤妊选:
NSString *GlobalLanguePath;
- (BOOL)application:(UIApplication *)application didFinishLaunchingWithOptions:(NSDictionary *)launchOptions {
[self configAppLangue];
}
-(void)configAppLangue{
//根據(jù)NSUserDefaults的key去取多語言類型, k_AppLaguageKey為與用戶相關(guān)的 Key
NSString *laguageType = [[NSUserDefaults standardUserDefaults] objectForKey:k_AppLaguageKey];
if (laguageType == nil) { // 如果沒有用戶偏好則根據(jù)系統(tǒng)第一語言配置啟動,并且不做偏好設置記錄
NSString *preferredLanguage = [NSLocale preferredLanguages][0];
if ([preferredLanguage hasPrefix:@"en"]) {
laguageType = @"en";
}else{
laguageType = @"zh-Hans";
}
}
NSLog(@"當前語言環(huán)境:%@",laguageType);
GlobalLanguePath = [[NSBundle mainBundle] pathForResource:laguageType ofType:@"lproj"];
}
為了方便使用,pch 來個宏定義:
// 語言加載路徑 全局變量
extern NSString *GlobalLanguePath;
#define k_LangueKey(key) [[NSBundle bundleWithPath:GlobalLanguePath] localizedStringForKey:key value:nil table:@"Localizable"]
使用如下:
UILabel *label = [UILabel new];
label.text = k_LangueKey(@"你所配置的key");
一點注意: 如若手動切換語言環(huán)境溅漾,而不是跟隨系統(tǒng)語言環(huán)境變化山叮,則在語言切換之后重新初始化 window.rootViewController ,然后代碼 push 到切換語言之前的 controller(如XXSettingViewController) 即可添履;
三屁倔、全局修改方式:
到此處可以使用 k_LangueKey() 一處一處修改了,然后在項目后期何其麻煩又是何其繁瑣暮胧,所以自然想到攔截 UILabel 的 setText 方法:
#import "NSObject+swapMethod.h"
#import <UIKit/UIKit.h>
@implementation UILabel (Langues)
+(void)load{
static dispatch_once_t onceToken;
dispatch_once(&onceToken, ^{
[self swapSelector:@selector(setText:) toSelector:@selector(langues_setText:)];
});
}
-(void)langues_setText:(NSString *)text{
[self langues_setText:k_LangueKey(text)];
}
@end
然而锐借,此時也許你會發(fā)現(xiàn) 導航欄 title 和 tabbarItem title 全變黑了,So ...
#import "NSObject+swapMethod.h"
@implementation UINavigationItem (Langues)
+(void)load{
static dispatch_once_t onceToken;
dispatch_once(&onceToken, ^{
[self swapSelector:@selector(setTitle:) toSelector:@selector(langues_setTitle:)];
});
}
-(void)langues_setTitle:(NSString *)title{
[self langues_setTitle:k_LangueKey(title)];
}
@end
#import "NSObject+swapMethod.h"
@implementation UIViewController (Langues)
+(void)load{
static dispatch_once_t onceToken;
dispatch_once(&onceToken, ^{
[self swapSelector:@selector(setTitle:) toSelector:@selector(langues_setTitle:)];
});
}
-(void)langues_setTitle:(NSString *)title{
[self langues_setTitle:k_LangueKey(title)];
}
@end
最后附上 swapSelector:toSelector方法:
#import "NSObject+swapMethod.h"
#import <objc/runtime.h>
@implementation NSObject (swapMethod)
+(void)swapSelector:(SEL)systemSelector toSelector:(SEL)customSelector{
SEL org_Selector = systemSelector;
SEL new_Selector = customSelector;
Method org_method = class_getInstanceMethod([self class], org_Selector);
Method new_method = class_getInstanceMethod([self class], new_Selector);
BOOL isAdd = class_addMethod(self, org_Selector, method_getImplementation(new_method), method_getTypeEncoding(new_method));
if (isAdd) {
class_replaceMethod(self, customSelector, method_getImplementation(new_method), method_getTypeEncoding(new_method));
}else{
method_exchangeImplementations(org_method, new_method);
}
}
@end
storyboard 手動切換語言環(huán)境的實現(xiàn):
基本配置略過叔壤,加載過程替換 bundle 即可:
+(void)load{
static dispatch_once_t onceToken;
dispatch_once(&onceToken, ^{
[self swapSelector:@selector(localizedStringForKey:value:table:) toSelector:@selector(langues_localizedStringForKey:value:table:)];
});
}
// 強行切換 bundle 資源文件
-(NSString *)langues_localizedStringForKey:(NSString *)key value:(NSString *)value table:(NSString *)tableName{
BOOL isSystemBundle = [self.bundleIdentifier containsString:@"com.apple"];
if (isSystemBundle) {
return [self langues_localizedStringForKey:key value:value table:tableName];
}else{
return [[NSBundle bundleWithPath: GlobalLanguePath] langues_localizedStringForKey:key value:value table:tableName];
}
}
然而你會發(fā)現(xiàn)一些第三方(比如mjrefresh)的多語言加載失敗瞎饲,也是強行切換bundle資源帶來的隱患,所以需將第三方的多語言文件復制到自己的 Localizable.strings 文件當中炼绘。