Android_国际开发_语言切换

Android_语言切换

效果:

这里写图片描述

如果关于基本概念不是很清楚 这里有谷歌官方的介绍:https://developer.android.google.cn/guide/topics/resources/localization

一、首先新建备用资源文件/文件夹

Android 如果需要进行多语言开发,实现语言切换 如果仅仅是文字显示之类的 则在res文件夹下新建你需要的语言资源 如下所示

MyProject/
res/
   values/(默认)
       strings.xml
   values-es/
       strings.xml
   values-fr/
       strings.xml 

如果需要显示多语言的图片 则需要新建你需要的语言的drawable 文件夹

MyProject/
res/
   drawable/(默认)
   drawable-mdpi/
   drawable-en/
   drawable-en-mdpi/
   drawable-fr/

关于详细的官方备用资源介绍:https://developer.android.google.cn/guide/topics/resources/providing-resources#AlternativeResources

二、在不同的资源文件中建立名称相同的资源

例如在String文件中

/values-en/strings.xml:(英语)

    <?xml version="1.0" encoding="utf-8"?>
<resources>
    <string name="title">My Application</string>
    <string name="hello_world">Hello World!</string>
</resources>

/values/strings.xml:(默认)

    <?xml version="1.0" encoding="utf-8"?>
<resources>
    <string name="title">Mi Aplicación</string>
    <string name="hello_world">你好</string>
</resources>


drawable/girl.jpg      (默认)
drawable-en/girl.jpg   (英语)

三、代码中实现语言切换

代码中语言切换有两种情形

1,自己在App中自主的切换语言环境
2,app自动的随用户切换系统的语言环境的时候切换环境

关于语言切换自己写了个工具类如下:

    /**
 * Created by WangKunKun on 2018/9/5
 * 注解:语言切换帮助类
 * <p>
 * 假设语言有很多
 **/
public class ChangeLanguageUtil {

    private static Context mContext;
    private static Resources mResources;
    private static Context configurationContext;

    /**
     * 初始化一般只要初始化一次就可以了 这里的作用主要是获取context 为下面的getString(int id)方法做准备
     * @param context
     */
    public static void init(Context context) {
        mContext = context.getApplicationContext();
        mResources = mContext.getResources();
    }

    /**
     * 切换语言
     * @param language 这个string 是语言代码如 中文 zh 英语 en 等等
     */
    public static void changeLanguage(String language) {
        if (mContext == null) {
            throw new RuntimeException("没有调用 init() 方法进行初始化");
        }
        Locale changeLocale;
        Configuration configuration = mResources.getConfiguration();
        DisplayMetrics displayMetrics = mResources.getDisplayMetrics();
        switch (language) {
            case Constants.LANGUAGE_CH:
                changeLocale = Locale.CHINA;
                SpUtil.setCurrentLanguage(Constants.LANGUAGE_CH, mContext);
                break;
            case Constants.LANGUAGE_EN:
                changeLocale = Locale.ENGLISH;
                SpUtil.setCurrentLanguage(Constants.LANGUAGE_EN, mContext);
                break;
            default:
                configuration.locale = Locale.CHINA;
                changeLocale = Locale.CHINA;
                SpUtil.setCurrentLanguage(Constants.LANGUAGE_CH, mContext);
        }
        if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.N) {
            configuration.setLocale(changeLocale);
            configuration.setLocales(new LocaleList(changeLocale));
            configurationContext = mContext.createConfigurationContext(configuration);
        } else {
            configuration.locale = changeLocale;
            mResources.updateConfiguration(configuration, displayMetrics);
        }
    }


    /**
     * 获取系统当前默认的语言,并根据系统的语言设置app的语言 ,
     * 如果 系统语言在当前app中包含了 并且与当前app中设置的app的语言不相同时 返回true 并更改配置 否则返回false
     *
     * @return
     */
    public static boolean setSystemDefaultLanguage() {
        Locale defaultLanguage;
        if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.N) {
            defaultLanguage = LocaleList.getDefault().get(0);
        } else {
            defaultLanguage = Locale.getDefault();
        }
        String language = defaultLanguage.getLanguage();
        if (TextUtils.equals(language, Constants.LANGUAGE_CH) || TextUtils.equals(language, "en")) {
            SpUtil.setCurrentLanguage(language, mContext);
        } else {
            return false;
        }
        if (TextUtils.equals(language, SpUtil.getCurrentLanguage(mContext))) {
            return false;
        }
        Configuration configuration = mResources.getConfiguration();
        DisplayMetrics displayMetrics = mResources.getDisplayMetrics();
        configuration.locale = defaultLanguage;
        mResources.updateConfiguration(configuration, displayMetrics);
        return true;
    }

    /**
     * 获取Value资源下String文件中定义好的文字
     * 特别需要注意的是 在程序需要进行国际化开发的时候 这个string 一定要是通过 Resources.getString()的方式获取
     * 否则获取的字段仅仅是默认语言下的String字段,无法实现语言切换
     * @param id String中字段的id
     * @return String中的字段
     */
    public static String getString(int id) {
        return mResources.getString(id);
    }

    public static Context getConfigurationContext() {
        return configurationContext;
    }
}

在Android7.0以下 设置语言环境是设置一个,但是Android7.0以及以上可以设置多个语言所以 在开发上有点微小的区别:

切换环境

  7.0以下
    Configuration configuration = mResources.getConfiguration();
    DisplayMetrics displayMetrics = mResources.getDisplayMetrics();
    configuration.locale = changeLocale;
    mResources.updateConfiguration(configuration, displayMetrics);
 7.0以及以上
    Configuration configuration = mResources.getConfiguration();
    configuration.setLocale(changeLocale);
    configuration.setLocales(new LocaleList(changeLocale));
    configurationContext = mContext.createConfigurationContext(configuration);
    //createConfigurationContext方法是7.0才出的方法,而且如果要采用 createConfigurationContext方法还必须要在Activity的attachBaseContext方法重新设置context
        @Override
    protected void attachBaseContext(Context newBase) {
        if (ChangeLanguageUtil.getConfigurationContext() == null) {
            super.attachBaseContext(newBase);
        } else {
            super.attachBaseContext(ChangeLanguageUtil.getConfigurationContext());
        }
    }

上述还有个问题是 Android7.0以下和以上在语言切换后的刷新方式不同
Android7.0以下只需要重新 initView()就好(重新走下oncreate()中的内容 但是不能调用super.onCreate(savedInstanceState);方法)
但是Android7.0开始需要 Activity.recreate();才可以

但是Android7.0以上 其实不采用configurationContext = mContext.createConfigurationContext(configuration);方式而是继续使用Android7.0以下的方式切换环境也是可以的,代码如下
Configuration configuration = mResources.getConfiguration();
DisplayMetrics displayMetrics = mResources.getDisplayMetrics();
configuration.setLocale(changeLocale);
configuration.setLocales(new LocaleList(changeLocale));
mResources.updateConfiguration(configuration, displayMetrics);
此时就不需要在attachBaseContext方法中重新设置context了,但是切换语言后 刷新Activity的方式还是调用recreate()方法
比如上面工具类中 changeLanguage()方法我使用按照7.0以上的方法,但是setSystemDefaultLanguage()方法我使用则是按照7.0以下的方法

获取系统当前的语言

在7.0以下获取方式是

defaultLanguage = Locale.getDefault();

从7.0开始获取方式是:

defaultLanguage = LocaleList.getDefault().get(0);
//因为7.0开始系统是设置多个默认语言的所以我们需要获取语言列表中的第一个语言

监控系统语言切换

监控系统语言切换有2种 一个是配置configuration 一个是设置广播监听 这里采用设置广播监听
    /**
 * Created by WangKunKun on 2018/9/5
 * 注解:系统配置改变监听类 用来系统语言改变时
 **/
public class LanguageChangeReceiver extends BroadcastReceiver {
    @Override
    public void onReceive(Context context, Intent intent) {
        //当切用户更改换了系统的语言时 更改当前app的语言
        String systemLanguage = Locale.getDefault().getLanguage();
        if (!TextUtils.equals(SpUtil.getCurrentLanguage(context),systemLanguage)&&(TextUtils.equals(systemLanguage, Constants.LANGUAGE_CH)||TextUtils.equals(systemLanguage,Constants.LANGUAGE_EN))){
            //此时更新所有activity的 View
        }
    }
}

上面我没有写更新Activity的方法(主要是嫌弃麻烦),但是思路还是说下 这个更新有2方式 
一种是采用广播/Eventbus 给每一个activity发出通知让他们更新View
另一种是 在项目中我们一般会用一个集合存储所有的还存活的Activity 这时我们可以遍历每一个Activity 让他刷新 刷新方式可以是 Activity.recreate()  
记住我没说Android7.0以下刷新不能用这个方法,实际上只有api大于等于11就可以用的

好了这里我们基本上已经说完了所有的知识 这里粘贴下项目代码

MainActivity

    public class MainActivity extends AppCompatActivity implements View.OnClickListener {

    private Button btChange;
    private Button btAuto;

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        ChangeLanguageUtil.init(this);
        // ChangeLanguageUtil.setSystemDefaultLanguage();
        initView();
    }

    @Override
    public void onClick(View view) {
        switch (view.getId()) {
            case R.id.bt_change_language:
                Toast.makeText(this,ChangeLanguageUtil.getString(R.string.change_language),Toast.LENGTH_SHORT).show();
                if (TextUtils.equals(SpUtil.getCurrentLanguage(this), Constants.LANGUAGE_ERROR) || TextUtils.equals(SpUtil.getCurrentLanguage(this), Constants.LANGUAGE_CH)) {
                    ChangeLanguageUtil.changeLanguage(Constants.LANGUAGE_EN);
                } else {
                    ChangeLanguageUtil.changeLanguage(Constants.LANGUAGE_CH);
                }
                if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.N) {
                    recreate();
                } else {
                    initView();
                }
                break;
            case R.id.bt_auto:
                break;
        }
    }

    private void initView() {
        setContentView(R.layout.activity_main);
        btChange = findViewById(R.id.bt_change_language);
        btChange.setOnClickListener(this);
        btAuto = findViewById(R.id.bt_auto);
        btAuto.setOnClickListener(this);
    }

    @Override
    protected void attachBaseContext(Context newBase) {
        if (ChangeLanguageUtil.getConfigurationContext() == null) {
            super.attachBaseContext(newBase);
        } else {
            super.attachBaseContext(ChangeLanguageUtil.getConfigurationContext());
        }
    }
}

Constants

     /**
 * Created by WangKunKun on 2018/9/5
 * 注解:
 **/
public interface Constants {
    //sp的文件名称
    String SP_NAME = "language";
    //sp中语言的key名称
    String SP_LANGUAGE_NAME = "language_name";
    //ISO 639语言代码
    //中文
    String LANGUAGE_CH = "zh";
    //英文
    String LANGUAGE_EN = "en";
    //错误的语言
    String LANGUAGE_ERROR ="error";
    //设置系统默认的语言
    //设置当前app设计默认的语言
    String LANGUAGE_DEFAULT = LANGUAGE_CH;
}

SpUtil

    public class SpUtil {

    private static SharedPreferences sharedPreferences;

    public static void setCurrentLanguage(String language, Context context){
        getInstances(context).edit().putString(Constants.SP_LANGUAGE_NAME,language).apply();
    }

    public static String getCurrentLanguage(Context context){
        return getInstances(context).getString(Constants.SP_LANGUAGE_NAME,Constants.LANGUAGE_ERROR);
    }

    private static  SharedPreferences getInstances(Context context){
        if (sharedPreferences==null){
            return  sharedPreferences = context.getSharedPreferences(Constants.SP_NAME, Context.MODE_PRIVATE);
        }
       return sharedPreferences;
    }

}

关于语言切换的几个需要注意的点:

1,在获取String类字段的时候需要Resources.getString().get()的方式 
2,bean要实现序列化 否则在切换语言的时候将失效,因为Android中配置改变时候 会有一个 序列化->反序列化 的过程

常用的语言代码表:https://blog.csdn.net/wkk_ly/article/details/82428891
源码:https://download.csdn.net/download/wkk_ly/10649046

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章