iOS_国际化


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;
}

注:NSUserDefaultsAppleLanguages 值一旦修改就无法复原,取到的永远会带设置的值


获取到的系统语言举例:
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

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

小莫同学~

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值