iOS应用内语言切换功能

作者: FarmGuo | 来源:发表于2016-01-27 15:36 被阅读18610次

    当我们的应用仅仅面向国内用户群,一般仅支持一种语言--中文就可以了。当面向国外用户时就需要进行国际化了,不仅仅是语言的转变,也可能包括设计风格,页面布局、交互效果的转变,如微信,微博,QQ这类应用都有着切换语言的功能。

    iOS确定应用的语言

    1.iOS首先搜索用户的语言偏好设置(设置-通用-语言与地区)
    2.检测你的应用是否支持用户的语言,先用偏好设置的第一个语言,检测应用是否包含该语言对应的文件夹(后缀是.lproj,文件名部分,英语为en,中文简体为zh-Hans,日语为ja)如果存在,那就是该语言,否则用偏好设置第二个语言来匹配。重复该过程。
    3.一旦系统为应用确定了语言,对应的.lproj文件夹就会用作本地化资源。

    iOS常用的国际化流程

    1.建立strings文件。2.在Localization勾选支持的语言,在不同的后缀的同文件名的strings中设置标题。3.使用NSLocalizedStringFromTable(key, tbl, comment) 这个宏取出key对应的value。
    这样的做法方便快捷,但有一些缺点。1.完全是根据手机系统设置的语言来进行国际化的。2.手机系统语言更改后,需将App Kill后,重新进入才有改变。可以看出给用户带来很大的不便,一些用户根本不知道如何设置语言,而且还去跳出应用,再Kill应用。我们需要的是应用内切换语言,所见即所得。

    应用内切换语言

    先看下微信的做法

    111.gif

    可以看出选择新语言,保存后就直接切换了。这样的用户体验就比较好了。

    关键

    1.NSBundle

    An NSBundle object represents a location in the file system that groups code and resources that can be used in a program.NSBundle objects locate program resources, dynamically load and unload executable code, and assist in localization. You build a bundle in Xcode using one of these project types: Application, Framework, plug-ins.

    2.宏 NSLocalizedStringFromTableInBundle

    它的定义
    #define NSLocalizedStringFromTableInBundle(key, tbl, bundle, comment) [bundle localizedStringForKey:(key) value:@"" table:(tbl)]
    Returns a localized version of a string.The key for a string in the specified table.从指定的bundle里的table中返回对应key的值。
    上面两点就是应用内切换的关键
    先浏览下Demo架构

    structure.png

    使用storyboard方式,常见的TabBar+Navigation形式,第一个页面的按钮来切换语言,第二个来显示当前语言。

    建立FGLanguageTool类来管理语言的切换,因为许多地方都要用到,将其设计为单例。并定义一个宏来加载设定的语言。

    #define FGGetStringWithKeyFromTable(key, tbl) 
    [[FGLanguageTool sharedInstance] getStringForKey:key withTable:tbl]
    
    #import <Foundation/Foundation.h>
    
    @interface FGLanguageTool : NSObject
    
    +(id)sharedInstance;
    
    /**
     *  返回table中指定的key的值
     *
     *  @param key   key
     *  @param table table
     *
     *  @return 返回table中指定的key的值
     */
    -(NSString *)getStringForKey:(NSString *)key withTable:(NSString *)table;
    
    /**
     *  改变当前语言
     */
    -(void)changeNowLanguage;
    
    /**
     *  设置新的语言
     *
     *  @param language 新语言
     */
    -(void)setNewLanguage:(NSString*)language;
    
    @end
    

    对应的.m文件

    #define CNS @"zh-Hans"
    #define EN @"en"
    #define LANGUAGE_SET @"langeuageset"
    
    #import "AppDelegate.h"
    #import "FGLanguageTool.h"
    
    static FGLanguageTool *sharedModel;
    
    @interface FGLanguageTool()
    
    @property(nonatomic,strong)NSBundle *bundle;
    @property(nonatomic,copy)NSString *language;
    
    @end
    
    @implementation FGLanguageTool
    
    +(id)sharedInstance
    {
        if (!sharedModel)
        {
            sharedModel = [[FGLanguageTool alloc]init];
        }
        
        return sharedModel;
    }
    
    -(instancetype)init
    {
        self = [super init];
        if (self)
        {
            [self initLanguage];
        }
        
        return self;
    }
    
    -(void)initLanguage
    {
        NSString *tmp = [[NSUserDefaults standardUserDefaults]objectForKey:LANGUAGE_SET];
        NSString *path;
        //默认是中文
        if (!tmp)
        {
            tmp = CNS;
        }
        else
        {
            tmp = EN;
        }
        
        self.language = tmp;
        path = [[NSBundle mainBundle]pathForResource:self.language ofType:@"lproj"];
        self.bundle = [NSBundle bundleWithPath:path];
    }
    
    -(NSString *)getStringForKey:(NSString *)key withTable:(NSString *)table
    {
        if (self.bundle)
        {
            return NSLocalizedStringFromTableInBundle(key, table, self.bundle, @"");
        }
        
        return NSLocalizedStringFromTable(key, table, @"");
    }
    
    -(void)changeNowLanguage
    {
        if ([self.language isEqualToString:EN])
        {
           [self setNewLanguage:CNS];
        }
        else
        {
            [self setNewLanguage:EN];
        }
    }
    
    -(void)setNewLanguage:(NSString *)language
    {
        if ([language isEqualToString:self.language])
        {
            return;
        }
        
        if ([language isEqualToString:EN] || [language isEqualToString:CNS])
        {
            NSString *path = [[NSBundle mainBundle]pathForResource:language ofType:@"lproj"];
            self.bundle = [NSBundle bundleWithPath:path];
        }
        
        self.language = language;
        [[NSUserDefaults standardUserDefaults]setObject:language forKey:LANGUAGE_SET];
        [[NSUserDefaults standardUserDefaults]synchronize];
        [self resetRootViewController];
    }
    
    //重新设置
    -(void)resetRootViewController
    {
        AppDelegate *appDelegate =
        (AppDelegate *)[[UIApplication sharedApplication] delegate];
        UIStoryboard *storyBoard = [UIStoryboard storyboardWithName:@"Main" bundle:nil];
        UINavigationController *rootNav = [storyBoard instantiateViewControllerWithIdentifier:@"rootnav"];
        UINavigationController *personNav = [storyBoard instantiateViewControllerWithIdentifier:@"personnav"];
        UITabBarController *tabVC = (UITabBarController*)appDelegate.window.rootViewController;
        tabVC.viewControllers = @[rootNav,personNav];
    }
    @end
    

    在ViewController里使用下面类似的方式进行赋值

    self.navigationItem.title = FGGetStringWithKeyFromTable(@"RootTitle", @"Main");
    self.languageLabel.text = FGGetStringWithKeyFromTable(@"NowLanguage", @"Person");
    

    "Main","Person"就是strings文件的名字。"RootTitle"和"NowLanguage"就是key。


    setting.png

    这些就是我们的代码部分,还有一些资源文件要进行配置,就是我们的多语言文件。
    1,添加支持的语言,选择工程。


    add.png
    点击Localizations区域的+号,添加新的语言,我们这里示例就选择简体中文。
    2,建立strings文件

    方法1.选择一个storyboard,这里我们使用工程默认的Main.storyboard,在File Inspecter。在Localization栏中勾选支持的语言。系统就会生成对应的文件。方法2.我们直接新建strings资源文件。在该文件的File Inspecter的Localization栏中勾选支持的语言。


    strings.png
    图中的Main是用方法1创建的,Person是用方法2创建的。这些同名的文件仅仅依靠后缀来区分,对应相应的资源。在这些文件中添加对应的key和value,如
    Person.strings(English)文件中内容

    "NowLanguage"="English";
    "PersonTitle"="Person";

    Person.strings(Chinese(Simplified))文件中内容

    "NowLanguage"="中文";
    "PersonTitle"="个人";

    即在不同的相同文件名不同后缀名文件中设置不同的value。

    几个关键点

    1,当我们设置支持多语言后创建多语言文件后,工程文件结构中多了一些文件夹,Base是工程默认的,而后面的两个就是我们设置多语言后自动生成的,对应相应的英文和简体中文。分别以en和zh-Hans开头,所以FGLanguageTool中将中文和英文定义为en和zh-Hans来加载对应的bundle。


    directory.png

    里面存放的就是对应的strings文件


    stings.png

    2.NSLocalizedStringFromTableInBundle,从指定的bundle中去指定table的key的值。
    3.更改语言后,重新设置rootViewController,使得可以重新加载语言。

    最终效果

    change.gif

    参考:How iOS Determines the Language For Your App

    相关文章

      网友评论

      • 莫须有恋:问个问题,相机权限这些提示,应用内切换应该怎么做
      • 来自外太空:楼主代码是否验证过了,单词都能拼错,大家不要粘贴复制
      • Stroman:你怎么让刷新那些字符串呢?这是最关键的。
      • 蒋昉霖:应用内切语言,行为方向不重启不生效有没有思路,阿语的方向是相反的
      • 我的珊妮:求demo
      • 哇哇卡:因为APP需要调用系统相册,所以请教一下怎么实现APP内设置语言对系统相册的文本多语言也有效果?
        一月筠:在你项目的PROJECT->info中,选中Localization,点击"+"号,添加对应的语言即可。
      • 等这姑娘老在我心里:那你的TAB 上的标题有什么办法也一起翻译吗
      • 码农斯密达:你好 代码能发一下吗?
        360172788@qq.com
      • CoderJackieYip:楼主这个实现的思路很好!但是,把NSLoclizedStringFromTable方法封装在一个类里,就无法使用genstrings导出的所有代码UI文本的strings文件了。按楼主的思路,这些strings文件的文本,请问楼主有什么方法可以自动导出吗?
      • JohnHow:楼主的单例是不是写的有问题
        FarmGuo:@JohnHow 不严谨
      • 9c517c119692:楼主,求demo ,和联系方式
      • 9c517c119692:楼主,为什么要切换根视图
      • CoderAO:您好,我采用了类似的方法,但是对于xib创建的view好像不好使,请问您有遇到过这样的问题吗?
        9c517c119692:@CoderAO 能否 给我说下你是怎么做的,求一个联系方式
        FarmGuo:@CoderAO 没有遇到,我采用的就是storyBoard.
      • e03f590b7408:楼主好文章!思维真的比较巧妙
        9c517c119692:@e03f590b7408 你做完了吗?能不能给我说下,你的 扣扣号多少,我加你
      • _YZG_:您好, 我想问下重新设置rootViewcontroller这种方法和微信的一样吗?效率怎么样, 性能?
      • SAW_:请问如何做到像微信或者微博那种切换语言之后,微信是切换了页面刷新,微博是当页刷新,这种思路?
        SAW_:@FarmGuo 重新设置根控制器很简单,但是实现效果体验很生硬,你看看微信微博这种体验就好多了
        FarmGuo:@SAW 比如重新设置了下rootViewController都可以。
      • dispath_once:其实切换语言到很好做,我个人感觉切换语言之后立即刷新程序 不好做
        鄙人Joe:@Wheatping 請問像支付寶這樣的你實現了嗎
        灬安然:@FarmGuo 微信那种好做,支付宝那种就没明白了
        FarmGuo:@dispath_once 比如重新设置了下rootViewController都可以。
      • Mc小陈:能不能把这个demo发一下啊。谢谢
        9435e52a4db1:@Mc小陈 你好,在简书中看到 您也在做 iOS应用内语言切换功能 想向您请教一下

      本文标题:iOS应用内语言切换功能

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