Android多语言以及APP内切换语言的实现

时间:2022-07-24 15:49:41

Android多语言的适配以及APP内语言切换的实现

最近项目需要发布一个海外版,因此需要适配英文版以及在APP内部加入切换语言的功能。琢磨了一段时间,发现并不是之前了解的添加一个EN文件就可以的,因此写个博,希望能够帮到他人。这是第一次写,如果有什么错误,还望见谅。


多语言的适配

简单的语言适配

因为需要多种语言,因此需要在项目中声明所需要的语言资源文件。
在工程的res目录下,新建values-en的文件夹(后缀表示的是语言,比如-en表示英文,-fr表示法语,-es表示西班牙语,等等不赘述了,想知道的同学网上随便搜一下就知道了),在这个文件夹目录下,新建字符串资源xml文件strings.xml。

Android多语言以及APP内切换语言的实现

文件创建完成后,就可以简单的输入一些中英文对应的字符串资源了。举例说明,“完成”这个字符资源,我们首先在values目录下的strings.xml中存入该中文字符串资源,并赋予id:done
Android多语言以及APP内切换语言的实现

再在values-en目录下的strings.xml中存入对应id的英文字符串资源
Android多语言以及APP内切换语言的实现

到这里准备工作就结束了。当需要使用“完成”资源时,使用R.string.done即可使用该字符串资源。当切换系统语言环境的时候,会自动调用values-en目录下的strings.xml内,id为done的资源。到这里,我们就已经实现了简单的英文适配。
这种方式同样适用于图片资源的多语言适配,和values文件夹一样,我们只需要新建drawable-en,drawable-en-hdpi,drawable-en-xhdpi的文件夹一样,对应的中英文资源命名一致,即可完成图片资源的语言适配。

通过工具类获取其他语言资源

上面的方法,仅适用于像TextView,EditText这种可以通过setText(R.string.done)方法直接获取字符并显示的地方。而这种用处相对来说,在项目中仅仅占极小一部分,大多数string,都需要对其进行一些处理,比如dialog,Toast等等。因此需要建立一个工具类用于获取到当前语言环境的对应资源。
新建工具类ChangeLanguageHelper。类的初始化尽量放在Application中进行。先上代码:


/** * Created by Yif on 2017/8/16. */

public class ChangeLanguageHelper {
    private static Context mContext = null;
    private static String country = null;

    public static final int CHANGE_LANGUAGE_CHINA = 1;
    public static final int CHANGE_LANGUAGE_ENGLISH = 2;
    public static final int CHANGE_LANGUAGE_DEFAULT = 0;
    private static String mLanguage = "";

    private static Resources mResources;
    private static Locale mDefaultLocale;

    public static void init(Context context) {
        mResources = context.getResources();
        country = context.getResources().getConfiguration().locale.getCountry();

        mContext = context;
        int appLanguage = Configure.getAppLanguage();
        changeLanguage(appLanguage);
    }

    /** * 获取当前字符串资源的内容 * * @param id * @return */
    public static String getStringById(int id) {
        String string ;
        if (mLanguage != null && !"".equals(mLanguage)){
            string = mResources.getString(id,mLanguage);
        }else {
            string = mResources.getString(id,"");
        }

        if (string != null && string.length() > 0) {
            return string;
        }
        return "";
    }

    public static void changeLanguage(int language) {

        Configuration config = mResources.getConfiguration();     // 获得设置对象
        DisplayMetrics dm = mResources.getDisplayMetrics();      
        switch (language) {
            case CHANGE_LANGUAGE_CHINA:
                config.locale = Locale.SIMPLIFIED_CHINESE;     // 中文
                config.setLayoutDirection(Locale.SIMPLIFIED_CHINESE);
                mLanguage = "zh-CN";
                country = "CN";
                Configure.setAppLanguage(CHANGE_LANGUAGE_CHINA);
                break;
            case CHANGE_LANGUAGE_ENGLISH:
                config.locale = Locale.ENGLISH;   // 英文
                config.setLayoutDirection(Locale.ENGLISH);
                mLanguage = "en";
                country = "US";
                Configure.setAppLanguage(CHANGE_LANGUAGE_ENGLISH);
                break;
            case CHANGE_LANGUAGE_DEFAULT:

                country = Locale.getDefault().getCountry();

                if ("CN".equals(country)){
                    mDefaultLocale = Locale.SIMPLIFIED_CHINESE;
                }else {
                    mDefaultLocale =  Locale.ENGLISH;
                }

                config.locale = mDefaultLocale;         // 系统默认语言
                config.setLayoutDirection(mDefaultLocale);
                Configure.setAppLanguage(CHANGE_LANGUAGE_DEFAULT);
                break;
        }
        mResources.updateConfiguration(config, dm);
        EventBus.getDefault().post(new AppEvent.ChangeLanguage());

    }

    public static boolean getDefaultLanguage() {
        return ("CN".equals(country));
    }

}

Configure.getAppLanguage为通过sharepreference记录后获取的app语言环境(后面实现app内切换语言需要用到,大家可以自行处理)。
通过此工具类的getStringById()的方法,即可获取到所需语言对应的资源。

APP内切换语言的实现

上述代码中changeLanguage()方法,即可实现。(在某些UI页面切换语言后,无法自动刷新语言时,需要使用到EventBus处理,具体使用方法就不说了,自行百度-.-)。

功能自此已经实现了,那么来讲讲过程中遇到的坑吧。其实最主要的坑,就在于app内的语言环境,与app外系统语言环境的相互切换问题。

1.在app内切换语言为“自动”时,此时app内的语言为跟随手机系统的语言环境。因此,我们需要获取到当前手机系统的语言环境,我们可以通过获取当前城市来进行判断。

        country = Locale.getDefault().getCountry();
        if ("CN".equals(country)){
           mDefaultLocale = Locale.SIMPLIFIED_CHINESE;
        }else {
           mDefaultLocale =  Locale.ENGLISH;
        }

2.当app运行时,使用home键进入后台,进入设置,切换当前手机语言环境后,再次进入app时,我们看到的是app重新运行的UI。因此,下意识的认为,又走了一遍Application中ChangeLanguageHelper的初始化方法。其实并不是这样的,application并没有被销毁,只是所有的UI均重新渲染了,这是一个坑。

3.设置语言环境时,看到很多文章都说要这么写:

        config.locale = Locale.ENGLISH;   // 英文
        Locale.setDefault(Locale.ENGLISH);
        config.setLayoutDirection(Locale.ENGLISH);

从我的工具类可以看出来区别在于,我减少了Locale.setDefault(Locale.ENGLISH);这一句代码。这句的代码的意思是,以后所有需要Locale.getDefault()的地方,获取到的值,都不会跟随手机系统的语言环境,而是这里设置的值。这样的写法会导致一个问题,在我在app内切换中文后继续切换为自动时,当前app语言环境为中文,但是当我继续切换为英文再继续切换为自动后,这时确变成了英文,这显然是不符合逻辑的。因此,我把这一句去掉了,逻辑就正确了。

最后上一张效果图:
Android多语言以及APP内切换语言的实现