前言
关于多语言国际化的介绍,现在越来越多的App走向国际,因此多语言/国际化就变得比较常见,我呢比较喜欢偷懒,也比较喜欢整理,因此我封装了一套下面的工具来方便大家一起使用。
关于怎么去配置国际化的信息,我就不做多余的赘述,这些文章就挺详细 iOS 国际化开发、3分钟实现iOS语言本地化/国际化
Xib快捷显示:
简单说明工具类
1、KJLoadLanguageViewController:简单的切换加载控制器
2、NSBundle+KJLanguage:工具的核心,当前语言获取和设置
3、UIButton+KJLanguage:按钮多语言
4、UILabel+KJLanguage:文本多语言
5、UITextField+KJLanguage:TextField多语言
分别介绍每个类对应的 API & Property
一、KJLoadLanguageViewController
@interface KJLoadLanguageViewController : UIViewController @property(nonatomic,strong)UIActivityIndicatorView *indicatorView; @property(nonatomic,assign)CGFloat time; @property(nonatomic,readwrite,copy)void(^loadEnd)(void); @end
indicatorView
:系统自带加载控件
time
:加载时间
loadEnd
:加载结束的回调处理
二、NSBundle+KJLanguage
这个是本工具的核心,那么我就多介绍一下,先看看 API & Property
/// 自定义strings文件,默认Localizable.strings @property(nonatomic,strong,class)NSString *customStringsName; /// 当前语言 @property(nonatomic,strong,readonly,class)NSString *currentLanguage; /// 设置语言,传nil恢复系统默认语言 + (void)kj_setCurrentLanguage:(NSString*_Nullable)language complete:(void(^_Nullable)(void))complete; /// 切换动画,备注Xib设置的多语言会自动切换 + (void)kj_switchoverLanguage:(UIViewController*(^_Nullable)(KJLoadLanguageViewController *loadvc))block complete:(void(^_Nullable)(void))complete;
customStringsName
:自定义strings文件,默认Localizable.strings,这个主要是后面控件使用,如果你的strings文件名字不是Localizable而是自定义的话,那么你就得使用NSLocalizedStringFromTable来读取本地化字符串
if (NSBundle.customStringsName) { self.text = NSLocalizedStringFromTable(LocalizedKey,NSBundle.customStringsName,nil); }else{ self.text = NSLocalizedString(LocalizedKey, nil); }
currentLanguage
:获取App当前语言,这个其实是存储在NSUserDefaults当中,多说一句这个语言并不是App系统语言,而是用户设置语言,当然第一次未设置的时候则取App系统语言
static NSString *kAppLanguageKey = @"KJ_CURRENT_LANGUAGE_KEY"; + (NSString*)currentLanguage{ NSString *language = [[NSUserDefaults standardUserDefaults] objectForKey:kAppLanguageKey]; if (language == nil) { language = [[NSLocale preferredLanguages] firstObject]; } return language; }
kj_setCurrentLanguage:complete:
:设置语言,传nil恢复系统默认语言,中文zh-Hans
、英文en
,其他的按这种格式就行
+ (void)kj_setCurrentLanguage:(NSString*)language complete:(void(^)(void))complete{ NSUserDefaults *userDefaults = [NSUserDefaults standardUserDefaults]; if (language) { [userDefaults setObject:language forKey:kAppLanguageKey]; }else{ [userDefaults removeObjectForKey:kAppLanguageKey]; } [userDefaults synchronize]; if (complete) complete(); }
kj_switchoverLanguage:complete:
:我封装的一款简单的切换动画,当然你觉得不好看什么的,你可以自己选择,KJLoadLanguageViewController
控制器可以用来承载你想要的切换动画效果
/// 切换动画,自带菊花加载界面 + (void)kj_switchoverLanguage:(UIViewController*(^)(KJLoadLanguageViewController *loadvc))block complete:(void(^)(void))complete{ if (block) { KJLoadLanguageViewController *__vc = [KJLoadLanguageViewController new]; __vc.time = .5; __block UIViewController *vc = block(__vc); if (vc) { __vc.loadEnd = ^{ [vc.view.subviews enumerateObjectsUsingBlock:^(__kindof UIView * _Nonnull obj, NSUInteger idx, BOOL * _Nonnull stop) { if ([obj isKindOfClass:[UIButton class]]) { UIButton *button = (UIButton*)obj; button.LocalizedKey = button.LocalizedKey; button.SelectedKey = button.SelectedKey; button.DisabledKey = button.DisabledKey; button.HighlightedKey = button.HighlightedKey; }else if ([obj isKindOfClass:[UILabel class]]) { UILabel *label = (UILabel*)obj; label.LocalizedKey = label.LocalizedKey; }else if ([obj isKindOfClass:[UITextField class]]) { UITextField *textField = (UITextField*)obj; textField.LocalizedKey = textField.LocalizedKey; } }]; if (complete) complete(); }; [vc presentViewController:__vc animated:NO completion:nil]; } } }
简单使用如下,
[NSBundle kj_switchoverLanguage:^UIViewController * _Nonnull(KJLoadLanguageViewController * _Nonnull loadvc) { loadvc.view.backgroundColor = [UIColor.greenColor colorWithAlphaComponent:0.3]; return weakself; } complete:^{ [changebutton setTitle:NSLocalizedString(@"changeLanguage", nil) forState:UIControlStateNormal]; }];
内部处理
介绍完API,我再来说说实现吧,
国际化其实就是走该方法localizedStringForKey:value:table:
/// 国际化 - (NSString*)localizedStringForKey:(NSString*)key value:(NSString*)value table:(NSString*)tableName{ NSBundle *bundle = [NSBundle bundleWithPath:[[NSBundle mainBundle] pathForResource:NSBundle.currentLanguage ofType:@"lproj"]]; if (bundle) { return [bundle localizedStringForKey:key value:value table:tableName]; }else{ return [super localizedStringForKey:key value:value table:tableName]; } }
在load
方法中采用动态继创建子类KJLanguageBundle
调用国际化方法localizedStringForKey:value:table:
+ (void)load { static dispatch_once_t onceToken; dispatch_once(&onceToken, ^{ // 动态继承修改[NSBundle mainBundle]对象的isa指针使其指向子类,便可以调用子类的方法 // 在运行时创建新的子类,并添加新的方法 object_setClass([NSBundle mainBundle], [KJLanguageBundle class]); }); }
自定义strings文件,我采用类属性来设置,runtime关联实现
+ (NSString*)customStringsName{ return objc_getAssociatedObject(self, @selector(customStringsName)); } + (void)setCustomStringsName:(NSString*)customStringsName{ objc_setAssociatedObject(self, @selector(customStringsName), customStringsName, OBJC_ASSOCIATION_RETAIN_NONATOMIC); }
三、UIButton+KJLanguage
暂时我提供4种Api,IBInspectable
用来支持Xib快捷设置(偷懒偷的更彻底- -!)
LocalizedKey:Normal状态下的文字
SelectedKey:选中状态下的文字
DisabledKey:不可操作状态下的文字
HighlightedKey:高亮状态下的文字
- (NSString*)LocalizedKey{ return objc_getAssociatedObject(self, @selector(LocalizedKey));; } - (void)setLocalizedKey:(NSString*)LocalizedKey{ objc_setAssociatedObject(self, @selector(LocalizedKey), LocalizedKey, OBJC_ASSOCIATION_RETAIN_NONATOMIC); if (LocalizedKey == nil) return; if (NSBundle.customStringsName) { [self setTitle:NSLocalizedStringFromTable(LocalizedKey,NSBundle.customStringsName,nil) forState:UIControlStateNormal]; }else{ [self setTitle:NSLocalizedString(LocalizedKey, nil) forState:UIControlStateNormal]; } } - (NSString*)HighlightedKey{ return objc_getAssociatedObject(self, @selector(HighlightedKey));; } - (void)setHighlightedKey:(NSString*)HighlightedKey{ objc_setAssociatedObject(self, @selector(HighlightedKey), HighlightedKey, OBJC_ASSOCIATION_RETAIN_NONATOMIC); if (HighlightedKey == nil) return; if (NSBundle.customStringsName) { [self setTitle:NSLocalizedStringFromTable(HighlightedKey,NSBundle.customStringsName,nil) forState:UIControlStateHighlighted]; }else{ [self setTitle:NSLocalizedString(HighlightedKey, nil) forState:UIControlStateHighlighted]; } } - (NSString*)SelectedKey{ return objc_getAssociatedObject(self, @selector(SelectedKey));; } - (void)setSelectedKey:(NSString*)SelectedKey{ objc_setAssociatedObject(self, @selector(SelectedKey), SelectedKey, OBJC_ASSOCIATION_RETAIN_NONATOMIC); if (SelectedKey == nil) return; if (NSBundle.customStringsName) { [self setTitle:NSLocalizedStringFromTable(SelectedKey,NSBundle.customStringsName,nil) forState:UIControlStateSelected]; }else{ [self setTitle:NSLocalizedString(SelectedKey, nil) forState:UIControlStateSelected]; } } - (NSString*)DisabledKey{ return objc_getAssociatedObject(self, @selector(DisabledKey));; } - (void)setDisabledKey:(NSString*)DisabledKey{ objc_setAssociatedObject(self, @selector(DisabledKey), DisabledKey, OBJC_ASSOCIATION_RETAIN_NONATOMIC); if (DisabledKey == nil) return; if (NSBundle.customStringsName) { [self setTitle:NSLocalizedStringFromTable(DisabledKey,NSBundle.customStringsName,nil) forState:UIControlStateDisabled]; }else{ [self setTitle:NSLocalizedString(DisabledKey, nil) forState:UIControlStateDisabled]; } }
支持Xib快捷设置,右边为对应的Key
Demo对应的Key
"textLabel" = "当前语言为中文"; "textFieldPlaceholder" = "测试textField"; "textButtonDefault" = "按钮正常状态"; "textButtonSelect" = "按钮选中状态"; "textButtonHighliaght" = "按钮高亮状态"; "textButtonDisable" = "按钮不可操作状态"; "changeLanguage" = "切换语言";
四、UILabel+KJLanguage 和 UITextField+KJLanguage
这两其实差不多,UITextField设置placeholder
属性,UILabel设置text
属性
- (NSString*)LocalizedKey{ return objc_getAssociatedObject(self, @selector(LocalizedKey));; } - (void)setLocalizedKey:(NSString*)LocalizedKey{ objc_setAssociatedObject(self, @selector(LocalizedKey), LocalizedKey, OBJC_ASSOCIATION_RETAIN_NONATOMIC); if (LocalizedKey == nil) return; if (NSBundle.customStringsName) { self.placeholder = NSLocalizedStringFromTable(LocalizedKey,NSBundle.customStringsName,nil); }else{ self.placeholder = NSLocalizedString(LocalizedKey, nil); } }
使用示例
到此基本就介绍的差不多了,大致使用如下
#import "KJLanguageVC.h" #import "NSBundle+KJLanguage.h" @interface KJLanguageVC () @property (weak, nonatomic) IBOutlet UIButton *button; @end @implementation KJLanguageVC - (void)viewDidLoad { [super viewDidLoad]; // Do any additional setup after loading the view from its nib. _weakself; [self.button kj_addAction:^(UIButton * _Nonnull kButton) { kButton.selected = !kButton.selected; }]; __block UIButton *changebutton = [[UIButton alloc] initWithFrame:CGRectMake(0, kScreenH - 60, kScreenW-150, 40)]; [self.view addSubview:changebutton]; changebutton.centerX = kScreenW/2; changebutton.backgroundColor = UIColor.whiteColor; changebutton.layer.borderWidth = 1; changebutton.layer.borderColor = UIColor.blueColor.CGColor; changebutton.layer.masksToBounds = YES; changebutton.layer.cornerRadius = 5; changebutton.titleLabel.font = [UIFont systemFontOfSize:14]; [changebutton setTitle:NSLocalizedString(@"changeLanguage", nil) forState:UIControlStateNormal]; [changebutton setTitleColor:UIColor.blueColor forState:UIControlStateNormal]; [changebutton kj_addAction:^(UIButton * _Nonnull kButton) { NSString *language = NSBundle.currentLanguage; if ([language isEqualToString:@"en"]) { language = @"zh-Hans"; }else{ language = @"en"; } [NSBundle kj_setCurrentLanguage:language complete:nil]; [NSBundle kj_switchoverLanguage:^UIViewController * _Nonnull(KJLoadLanguageViewController * _Nonnull loadvc) { loadvc.view.backgroundColor = [UIColor.greenColor colorWithAlphaComponent:0.3]; return weakself; } complete:^{ [changebutton setTitle:NSLocalizedString(@"changeLanguage", nil) forState:UIControlStateNormal]; }]; }]; } /* #pragma mark - Navigation // In a storyboard-based application, you will often want to do a little preparation before navigation - (void)prepareForSegue:(UIStoryboardSegue *)segue sender:(id)sender { // Get the new view controller using [segue destinationViewController]. // Pass the selected object to the new view controller. } */ @end
End
到此就差不多了,粗略封装,望大神补充
该工具我也提交到Pod上,使用 pod 'KJEmitterView/Language' # 多语言模块