美文网首页
一种应用内国际化方案

一种应用内国际化方案

作者: 山有木枝壮 | 来源:发表于2019-07-30 11:29 被阅读0次

    cvI18n

    一种应用内国际化方案
    https://github.com/ssrrxx111/cvI18n

    iOS对应用国际化做了原生的支持,一般获取系统的地区设置,然后根据设置读取设置的语言文件。iOS主要使用不同地区的Localizable.strings文件,然后使用NSLocalizedString方法进行国际化数据的获取。

    NSLocalizedString(<#key#>, <#comment#>)
    NSLocalizedStringWithDefaultValue(<#key#>, <#tbl#>, <#bundle#>, <#val#>, <#comment#>)
    

    对于带参数的字符串,可以使用如下NSString...format的方法,将上面的国际化数据进行参数处理

    "cvte.text.test" = "english %2$@ test %1$@ ";
    
    [[NSString alloc] initWithFormat:<#(nonnull NSString *)#> arguments:<#(struct __va_list_tag *)#>]
    

    使用系统切换地区的方式进行国际化处理,有一些不太适合的场景。

    1、测试人员再做国际化文案测试的时候需要来回切换系统语言,有些语言,这样会使系统的主体语言也发生变化,当切换到类似阿拉伯语的时候,有可能系统使用起来都太方便,并且每次切换需要重启系统。

    2、对于销售人员,需要给国外客户做演示的时候,也需要切换系统为英文环境,使用不便


    demo.gif

    基于上述原因,可以做一些改进方案

    1、应用内切换语言,重启应用,然后根据语言设置获取语言文件,进行国际化显示

    2、如果切换系统语言,与上次系统语言对比,如果改变了,将当前语言切换为系统语言

    iOS应用内切换语言重启应用对用户体验比较差,我们可以尝试采用下面的方式进行应用内动态语言切换

    基本原理

    1、使用runtime为每个需要需要国际化的控件新增一个对象属性,对象属性中包含了控件本身和执行国际化的block
    2、切换语言的时候发出通知,控件新增的对象中监听通知,执行国际化block

    相关文件如下所示:


    国际化.jpg

    注意事项

    1、国际化文件要通过bundle方式获取

    NSLocalizedStringWithDefaultValue(<#key#>, <#tbl#>, <#bundle#>, <#val#>, <#comment#>)
    

    2、需要注意国际化处理中强引用问题,以免引起循环引用

    3、可变参数的处理,可以做到类似NSLog可变参数的传递

    相关代码如下

    1、国际化语言切换和处理单例I18nManager。I18nManager中维护了所有支持的语言,以及当前选中的语言和index,切换方式目前根据index切换,当然也可以增加通过地区code切换

    // 根据对应的国际化数组进行切换
    - (void) changeIndex: (NSInteger)index
    
    // 支持可变参数传递
    - (NSString *)localized: (NSString *)identifier, ... {
        self.currentLanguage = self.languageDic.allKeys[self.index];
        
        NSBundle *bundle = [NSBundle bundleWithPath:[[NSBundle mainBundle] pathForResource:self.currentLanguage ofType:@"lproj"]];
        
        if (!bundle) {
            bundle = [NSBundle mainBundle];
        }
        
        NSString *localized_str = NSLocalizedStringFromTableInBundle(identifier, nil, bundle, @"");
        va_list paramList;
        va_start(paramList, identifier);
        NSString *result = [[NSString alloc] initWithFormat:localized_str arguments: paramList];
        va_end(paramList);
        
        NSLog(@"key: %@, value为: %@ 结果为: %@", identifier, localized_str, result);
        
        return result;
    }
    

    2、为NSObject新增处理国际化的方法,主要使用runtime为当前对象新增属性

    - (void)handleLanguage: (void(^)(id))callback {
        callback(self);
        
        HandleModel *model = [[HandleModel alloc] initWithBlock:callback onObject:self];
        objc_setAssociatedObject(self, languageAssoKey, model, OBJC_ASSOCIATION_RETAIN_NONATOMIC);
    }
    

    因为国际化通常是对控件处理的,这里也可以只对UIView进行扩展

    3、控件新增的对象主要包含控件本身和国际化block

    - (instancetype)initWithBlock: (void(^)(id))block onObject: (id)obj {
        self = [super init];
        if (self) {
            self.handleBlock = block;
            self.handleObj = obj;
            [[NSNotificationCenter defaultCenter] addObserver:self selector:@selector(dealNotification) name:@"cvte.setting.language" object:nil];
        }
        return self;
    }
    

    4、为了兼容目前已经存在的国际化处理,可以使用下面的宏定义

    #define L(Languagekey, ...) [[I18nManager shareInstance] localized:Languagekey, ##__VA_ARGS__]
    

    需要改进

    1、项目中目前的需求是根据系统语言进行app语言的切换,因此可以考虑这部分内容加入到后门中,如果后门没有打开语言切换,那么功能与现在一样。如果后门打开语言切换,那么项目根据切换的语言动态处理。


    语言切换

    更多

    1、通过这种获取自身的方式,在做自动布局或者设置界面属性的时候,可以使用统一的标识,如:

    [self.tipsLabel customize:^(UILabel label) {
     label.text = @"";
     label.textColor= UIColor.red;
     label...
    }];
    

    之后在编码处理的时候,对于相同的ui设置,可以直接复制粘贴。

    2、同样的,对于界面主题的切换,界面字体大小的切换,都可以采用这种方式处理

    Demo地址

    https://github.com/ssrrxx111/cvI18n

    相关文章

      网友评论

          本文标题:一种应用内国际化方案

          本文链接:https://www.haomeiwen.com/subject/ndmgrctx.html