文章目录
1、前置
Project
-> Info
-> Localizations
添加所需的语言(Apple 的语言也可以详细区分地区,如繁体分香港和台湾等)
Use Base Internationalization
: 是否使用 Base 语言。
如果取消勾选,可以指定某一语言为 Default 的就行。
2、文案
创建 Localizable.strings
文件,点击右边导航栏的 Localization
按钮,添加上所需语言。
key 命名规范:功能+描述+UI元素:
- 功能 Function:所属功能/模块/页面
- 描述 Description: 描述词条是什么/做什么/什么结果
- UI元素 UI Element: 词条所在的页面元素
例如: chatInputPressSpeakBtn (输入框-长按说话-按钮)
3、图片
步骤一:在左侧文件导航栏拖入图片,选中图片后在右侧导航栏点击 Localization
,添加上所需的语言。
步骤二:将各个语言对应的图片替换为正确的(默认用的是步骤一加的图片)
这样修改手机系统为支持的语言,App 里的文案和图片都可以跟随使用对应的语言了。
4、单独设置 App 语言
4.1、获取系统语言:
/// 获取系统当前语言
+ (NSString *)systemResourceName {
NSArray *systemResourceNames = [self systemResourceNames];
if (systemResourceNames.count == 0) {
return @"";
}
return systemResourceNames.firstObject;
}
/// 获取系统支持语言
+ (NSArray<NSString *> * _Nullable)systemResourceNames {
id languages = [[NSUserDefaults standardUserDefaults] objectForKey:@"AppleLanguages"];
if ([languages isKindOfClass:[NSString class]]) {
return @[languages];
}
if (![languages isKindOfClass:[NSArray class]]) {
return nil;
}
NSArray *languageArray = (NSArray *)languages;
if (languageArray.count == 0) {
return nil;
}
return languageArray;
}
注:NSUserDefaults
的 AppleLanguages
值一旦修改就无法复原,取到的永远会带设置的值
获取到的系统语言举例:
zh: 中文
zh-Hans: 简体
zh-Hant: 繁体
zh-Hans-HK: 香港简体
zh-Hant-TW: 台湾繁体
等等
总结就是:语言-体-地区
跟随系统时,在仅支持 简体、繁体、英文 的情况下,无需区分地区,所以判断系统语言是否包含相关前缀就行。
NSArray<NSString *> *supportResourceNames = @[@"zh-Hans", @"zh-Hant", @"en"];
__block NSString *resourceName = @"zh-Hans";
[supportResourceNames enumerateObjectsUsingBlock:^(NSString * _Nonnull obj, NSUInteger idx, BOOL * _Nonnull stop) {
if ([systemResourceName hasPrefix:obj]) {
resourceName = obj;
*stop = YES;
}
}];
4.2、获取指定语言的 bundle:
NSString *bundlePath = [[NSBundle mainBundle] pathForResource:resourceName ofType:@"lproj"];
self.currentBundle = [NSBundle bundleWithPath:bundlePath];
获取文案:
[self.currentBundle localizedStringForKey:key value:@"" table:@"Localizable"]
获取图片:
[UIImage imageNamed:name inBundle:self.currentBundle withConfiguration:nil]
4.3、修改语言后假重启:
销毁 rootVC 后重新创建并模拟重启动画
UIWindow *window = [UIApplication sharedApplication].delegate.window;
[UIView animateWithDuration:0.2 animations:^{
window.rootViewController.view.alpha = 0.0;
window.rootViewController.view.transform = CGAffineTransformMakeScale(0.1, 0.1);
} completion:^(BOOL finished) {
window.rootViewController.view.alpha = 1.0;
window.rootViewController.view.transform = CGAffineTransformMakeScale(1.0, 1.0);
MOBaseNavigationController *rootVC = [[MOBaseNavigationController alloc] initWithRootViewController:[[MORootContainerController alloc] init]];
window.rootViewController = rootVC;
window.rootViewController.view.alpha = 0.0;
[UIView animateWithDuration:0.2 animations:^{
window.rootViewController.view.alpha = 1.0;
}];
}];
5、App 语言和权限弹窗文案
这部分内容没法指定语言,只能跟随系统语言。需要新建 InfoPlist.strings
文件,并点右侧导航栏的 Localization
按钮,添加上所需语言。
"CFBundleDisplayName" = "App 名称";
"NSCameraUsageDescription" = "请授权APP使用相机功能";
"NSPhotoLibraryAddUsageDescription" = "请允许APP访问你的相册,以保存照片或视频";
"NSPhotoLibraryUsageDescription" = "请允许APP访问你的相册";
"NSLocationWhenInUseUsageDescription" = "开启精准定位,以便为您提供地点查询和路径规划服务。你可以随时关闭。";
"NSLocationAlwaysAndWhenInUseUsageDescription" = "开启精准定位,以便为您提供地点查询和路径规划服务。你可以随时关闭。";
"NSMicrophoneUsageDescription" = "请授权设备麦克风。以使用语音消息、语音通话、音色克隆功能";
需要在 Info.plist 文件里设置 Bundle display name 为默认展示语言,否则当系统切换到不支持的语言时会显示 Project Name。
6、热切换方案:
切换语言后发出通知:
/// 语言已修改通知
FOUNDATION_EXTERN NSString *const MOOLanguageDidChangeNotification;
NSString *const MOOLanguageDidChangeNotification = @"LanguageDidChangeNotification";
[[NSNotificationCenter defaultCenter] postNotificationName:MOOLanguageDidChangeNotification object:self];
6.1、Label
实现热切换:
// UILabel+MOOLocalizable.h
@interface UILabel (MOOLocalizable)
@property (nonatomic, copy) NSString *textLocalizableKey;
@end
// UILabel+MOOLocalizable.m
#import <objc/runtime.h>
@implementation UILabel (MOOLocalizable)
- (void)setTextLocalizableKey:(NSString * _Nonnull)textLocalizableKey {
objc_setAssociatedObject(self, @selector(textLocalizableKey), textLocalizableKey, OBJC_ASSOCIATION_COPY);
[[NSNotificationCenter defaultCenter] removeObserver:self name:MOOLanguageDidChangeNotification object:nil];
if (textLocalizableKey.length == 0) {
self.text = nil;
return;
}
__weak typeof(self) weakSelf = self;
[[NSNotificationCenter defaultCenter] addObserverForName:MOOLanguageDidChangeNotification
object:nil
queue:nil
usingBlock:^(NSNotification * _Nonnull notification) {
weakSelf.text = MOOLocalizableString(textLocalizableKey);
}];
self.text = MOOLocalizableString(textLocalizableKey);
}
- (NSString *)textLocalizableKey {
return objc_getAssociatedObject(self, _cmd);
}
@end
6.2、UIButton
实现热切换:
// UIButton+MOOLocalizable.h
@interface UIButton (MOOLocalizable)
/// {@(UIControlState): titleLocalizableKey}
@property (nonatomic, strong, readonly) NSDictionary<NSNumber *, NSString *> *titleLocalizableKeys;
- (void)setTitleLocalizableKey:(NSString *)localizableKey
forState:(UIControlState)state;
@end
// UIButton+MOOLocalizable.m
#import <objc/runtime.h>
@implementation UIButton (MOOLocalizable)
- (void)setTitleLocalizableKey:(NSString *)localizableKey
forState:(UIControlState)state {
NSMutableDictionary<NSNumber *,NSString *> *titleLocalizableKeys = [self.titleLocalizableKeys mutableCopy];
if (!titleLocalizableKeys) {
titleLocalizableKeys = [NSMutableDictionary dictionary];
}
if (localizableKey.length == 0) {
[titleLocalizableKeys removeObjectForKey:@(state)];
} else {
[titleLocalizableKeys setObject:localizableKey forKey:@(state)];
[self setTitle:MOOLocalizableString(localizableKey) forState:state];
}
self.titleLocalizableKeys = [titleLocalizableKeys copy];
[[NSNotificationCenter defaultCenter] removeObserver:self name:MOOLanguageDidChangeNotification object:nil];
if (self.titleLocalizableKeys.count == 0) {
return;
}
__weak typeof(self) weakSelf = self;
[[NSNotificationCenter defaultCenter] addObserverForName:MOOLanguageDidChangeNotification
object:nil
queue:nil
usingBlock:^(NSNotification * _Nonnull notification) {
[weakSelf updateLocalizableLanguage];
}];
}
#pragma mark - Private Methods
- (void)updateLocalizableLanguage {
[self.titleLocalizableKeys enumerateKeysAndObjectsUsingBlock:^(NSNumber * _Nonnull key,
NSString * _Nonnull obj,
BOOL * _Nonnull stop) {
[self setTitle:MOOLocalizableString(obj) forState:[key unsignedIntegerValue]];
}];
}
- (void)setTitleLocalizableKeys:(NSDictionary<NSNumber *,NSString *> *)titleLocalizableKeys {
objc_setAssociatedObject(self, @selector(titleLocalizableKeys), titleLocalizableKeys, OBJC_ASSOCIATION_RETAIN_NONATOMIC);
}
- (NSDictionary<NSNumber *,NSString *> *)titleLocalizableKeys {
return objc_getAssociatedObject(self, _cmd);
}
@end