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

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