Android国际化(多语言)实现,支持8.0+

前言

最近因为项目中使用了国际化,所以正好研究了下实现方法;
首先说下项目需求:

  • 可以随着系统切换语言而切换语言,不支持的语言显示默认
  • 用户可以选择语言,且不会随着系统切换语言或者应用重启而还原

虽然需求还是很简单的,但是实现起来还是遇到了不少的麻烦,首先看下效果图:


效果图

老规矩

项目源码

实现思路

  • 在application 的 attachBaseContext设置当前设置的语言Local
  • 在application 的onConfigurationChanged(改变系统语言时会调用到)设置当前的语言Local
  • 在 Activity 的attachBaseContext设置当前设置的语言Local,所以一般这里是创建BaseActivity来方便统一改变
  • 在 service 的attachBaseContext设置当前设置的语言Local

实现代码

有了思路实现起来就很清晰了,

  • 第一步肯定是创建对应语言的string.xml,在demo中我只实现了:中文简体,中文繁体,和英文三个语言


    image.png
  • 因为这个我们要保存用户的选择语言,所以这里创建个 SharedPreferences的单例:
public class SPUtil {

    private final String SP_NAME = "language_setting";
    private final String TAG_LANGUAGE = "language_select";
    private static volatile SPUtil instance;

    private final SharedPreferences mSharedPreferences;

    public SPUtil(Context context) {
        mSharedPreferences = context.getSharedPreferences(SP_NAME, Context.MODE_PRIVATE);
    }


    public void saveLanguage(int select) {
        SharedPreferences.Editor edit = mSharedPreferences.edit();
        edit.putInt(TAG_LANGUAGE, select);
        edit.commit();
    }

    public int getSelectLanguage() {
        return mSharedPreferences.getInt(TAG_LANGUAGE, 0);
    }

    public static SPUtil getInstance(Context context) {
        if (instance == null) {
            synchronized (SPUtil.class) {
                if (instance == null) {
                    instance = new SPUtil(context);
                }
            }
        }
        return instance;
    }
}

创建管理语言的Util

  • 创建根据用户设置获取对应的 Local方法:
/**
     * 获取选择的语言设置
     *
     * @param context
     * @return
     */
    public static Locale getSetLanguageLocale(Context context) {

        switch (SPUtil.getInstance(context).getSelectLanguage()) {
            case 0:
                return getSystemLocale(context);
            case 1:
                return Locale.CHINA;
            case 2:
                return Locale.TAIWAN;
            case 3:
            default:
                return Locale.ENGLISH;
        }
    }

 /**
     * 获取系统的locale
     *
     * @return Locale对象
     */
    public static Locale getSystemLocale(Context context) {
        Locale locale;
        if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.N) {
            locale = LocaleList.getDefault().get(0);
        } else {
            locale = Locale.getDefault();
        }
        return locale;
    }
  • 创建改变Local方法
public static Context setLocal(Context context) {
        return updateResources(context, getSetLanguageLocale(context));
    }

    private static Context updateResources(Context context, Locale locale) {
        Locale.setDefault(locale);

        Resources res = context.getResources();
        Configuration config = new Configuration(res.getConfiguration());
        if (Build.VERSION.SDK_INT >= 17) {
            config.setLocale(locale);
            context = context.createConfigurationContext(config);
        } else {
            config.locale = locale;
            res.updateConfiguration(config, res.getDisplayMetrics());
        }
        return context;
    }
  • 在相应地方调用
#Application
 @Override
    protected void attachBaseContext(Context base) {
       super.attachBaseContext(LocalManageUtil.setLocal(base));
    }

@Override
    public void onConfigurationChanged(Configuration newConfig) {
        super.onConfigurationChanged(newConfig);
        LocalManageUtil.setLocal(context);
    }
#BaseActivity
@Override
    protected void attachBaseContext(Context newBase) {
        super.attachBaseContext(LocalManageUtil.setLocal(newBase));
    }
#service
@Override
    protected void attachBaseContext(Context base) {
        super.attachBaseContext(LocalManageUtil.setLocal(base));
    }
  • 切换语言
private void selectLanguage(int select) {
        LocalManageUtil.saveSelectLanguage(this, select);
        //重启APP到主页面
        MainActivity.reStart(this);
    }

搞定,


image.png

没错就是这么简单。


image.png

但是总有你想不到的事

我们都会在代码中调用context.getResource().getString()这句代码看起来没什么问题,但是你这个context要是用的是applicationContext那么问题就来了。你会发现当你切换语言后用这样方式设置的string没有改变,所以我们需要改动我们的代码。
解决方法就是,在切换语言后把application的updateConfiguration也要更新了,方法如下:

 /**
     * 设置语言类型
     */
    public static void setApplicationLanguage(Context context) {
        Resources resources = context.getApplicationContext().getResources();
        DisplayMetrics dm = resources.getDisplayMetrics();
        Configuration config = resources.getConfiguration();
        Locale locale = getSetLanguageLocale(context);
        config.locale = locale;
        if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.N) {
            LocaleList localeList = new LocaleList(locale);
            LocaleList.setDefault(localeList);
            config.setLocales(localeList);
            context.getApplicationContext().createConfigurationContext(config);
            Locale.setDefault(locale);
        }
        resources.updateConfiguration(config, dm);
    }
  • 但是当你调用这个代码后你获取到的系统选择语言就是你设置的语言,这不准确呀,那怎么办呢?很简单,我们把真实的系统语言保存下来就行了。
  • 我们在SharedPreferences单例中添加系统Local变量:
    /**
     * 用来保存系统语言
     */
    private Locale systemCurrentLocal = Locale.ENGLISH;

public int getSelectLanguage() {
        return mSharedPreferences.getInt(TAG_LANGUAGE, 0);
    }


    public Locale getSystemCurrentLocal() {
        return systemCurrentLocal;
    }
  • 然后在 application的attachBaseContextonConfigurationChanged获取真实的系统Local并保存

  • 最后改变下我们原来获取系统Local的方法:

    /**
     * 获取系统的locale
     *
     * @return Locale对象
     */
    public static Locale getSystemLocale(Context context) {
        return SPUtil.getInstance(context).getSystemCurrentLocal();
    }

这样就真的完成了,具体的代码可见项目源码这里,
若您觉得对您有帮助,您的赞是我最大的动力

最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
平台声明:文章内容(如有图片或视频亦包括在内)由作者上传并发布,文章内容仅代表作者本人观点,简书系信息发布平台,仅提供信息存储服务。

推荐阅读更多精彩内容

  • Spring Cloud为开发人员提供了快速构建分布式系统中一些常见模式的工具(例如配置管理,服务发现,断路器,智...
    卡卡罗2017阅读 134,969评论 19 139
  • 《ilua》速成开发手册3.0 官方用户交流:iApp开发交流(1) 239547050iApp开发交流(2) 1...
    叶染柒丶阅读 10,996评论 0 11
  • Android 自定义View的各种姿势1 Activity的显示之ViewRootImpl详解 Activity...
    passiontim阅读 173,436评论 25 708
  • ¥开启¥ 【iAPP实现进入界面执行逐一显】 〖2017-08-25 15:22:14〗 《//首先开一个线程,因...
    小菜c阅读 6,536评论 0 17
  • 正月十五,往年都在家的日子,我,想你了。 我已经很久都没有想你了,但是今晚却抵挡不住回忆的翻涌,思念十年前你的笑脸...
    不魚的猫阅读 301评论 1 0