Android 入門——App國際化之動態切換多語言小結
#引言
如果你的App是面向國際的或者是做手機ROM的,那麼對於Android國際化適配應該不會陌生,今天就好好地總結下。
一、Locale和Configuration 概述
Locale物件是用於表示特定的地理,政治或文化區域。 需要Locale執行其任務的操作稱為區域設定敏感,並使用Locale為使用者定製資訊。 例如顯示數字是區域設定敏感操作 - 應根據使用者原生國家,地區或文化的習慣和慣例格式化數字,再比如阿拉伯國家是從右往左佈局的,這些配置資訊都是由Locale決定的,當然也可以從Locale中獲取對應的配置資訊。而Configuration 封裝了影響應用程式檢索的資源的所有裝置配置資訊
二、動態切換語言
如果你檢視過原始碼你會發現Application的第一個生命週期方法是attachBaseContext而不是onCreate方法,同樣的Activity從一定程度上來說也是先呼叫attachBaseContext方法拿到ContextWrapper上下文封裝類物件,然後根據對應的ContextWrapper進行初始化的,所以只要我們替換成我們自己的ContextWrapper就可以實現替換資源了,其實還有另另一種思路,全部使用程式碼進行動態設定。
##1、建立對應資原始檔夾
在res資料夾上右鍵
2、自定義用於資源適配的ContextWrapper
package com.crazymo.changelanguage;
import android.content.Context;
import android.content.ContextWrapper;
import android.content.SharedPreferences;
import android.content.res.Configuration;
import android.content.res.Resources;
import android.os.Build;
import android.os.LocaleList;
import android.text.TextUtils;
import java.util.Locale;
/**
* Auther: Crazy.Mo on 2018/4/18 14:58
* Summary:
*/
public class LanContextWrapper extends ContextWrapper {
public static final String LANG_HK = "hk";
public static final String LANG_CN = "cn";
public static final String LANG_EN = "en";
public LanContextWrapper(Context ctx) {
super(ctx);
}
public static ContextWrapper wrap(Context context) {
Locale newLocale;
SharedPreferences sharedPreferences=context.getSharedPreferences(MainActivity.SP_NAME, MODE_PRIVATE);
String lanTag=sharedPreferences.getString(MainActivity.LANGUAGE, "def");
switch (lanTag) {
case "def"://沒有手東設定過對應的語言則預設讀取手機系統的語言
String locale = Locale.getDefault().getLanguage();
String langFlag="";
if (TextUtils.isEmpty(locale)) {
langFlag=LANG_CN;
newLocale = Locale.CHINESE;
} else if (locale.contains("en")) {
langFlag=LANG_EN;
newLocale = Locale.ENGLISH;
}else if (locale.startsWith("zh")) {
String region=Locale.getDefault().getDisplayCountry();
if(region.equals("香港特別行政區")||region.equals("臺灣")){
langFlag=LANG_HK;
newLocale=Locale.TRADITIONAL_CHINESE;
}else{
langFlag=LANG_CN;
newLocale=Locale.SIMPLIFIED_CHINESE;
}
}
else {
newLocale = Locale.CHINESE;
}
sharedPreferences.edit().putString(MainActivity.LANGUAGE, langFlag).apply();
break;
case LANG_EN://設定為英語
newLocale = Locale.ENGLISH;
break;
case LANG_HK://設定為繁體
newLocale = Locale.TRADITIONAL_CHINESE;
break;
case LANG_CN:
newLocale=Locale.SIMPLIFIED_CHINESE;
break;
default://預設為漢語
newLocale = Locale.SIMPLIFIED_CHINESE;
break;
}
context = getLanContext(context, newLocale);
return new ContextWrapper(context);
}
/**
* 初始化Context
* @param context
* @param pNewLocale
* @return
*/
private static Context getLanContext(Context context, Locale pNewLocale) {
Resources res = context.getApplicationContext().getResources();//1、獲取Resources
Configuration configuration = res.getConfiguration();//2、獲取Configuration
//3、設定Locale並初始化Context
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.N) {
configuration.setLocale(pNewLocale);
LocaleList localeList = new LocaleList(pNewLocale);
LocaleList.setDefault(localeList);
configuration.setLocales(localeList);
context = context.createConfigurationContext(configuration);
} else if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.KITKAT) {
configuration.setLocale(pNewLocale);
context = context.createConfigurationContext(configuration);
}
return context;
}
/**
* 獲取手機設定的語言國家
* @param context
* @return
*/
public static String getCountry(Context context) {
String country;
Resources resources = context.getApplicationContext().getResources();
//在7.0以上和7.0一下獲取國家的方式有點不一樣
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.N) {
country = resources.getConfiguration().getLocales().get(0).getCountry();
} else {
country = resources.getConfiguration().locale.getCountry();
}
return country;
}
}
3、在Activity中進行動態切換
package com.crazymo.changelanguage;
import android.app.Activity;
import android.content.Context;
import android.content.Intent;
import android.content.SharedPreferences;
import android.os.Build;
import android.os.Bundle;
import android.view.View;
public class MainActivity extends Activity {
public static final String SP_NAME = "name";
public static final String LANGUAGE = "language";
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
}
/**
* 設定修改語言
*
* @param newBase
*/
@Override
protected void attachBaseContext(Context newBase) {
Context context = LanContextWrapper.wrap(newBase);
super.attachBaseContext(context);
}
public void changeChinese(View view) {
SharedPreferences sharedPreferences=getSharedPreferences(MainActivity.SP_NAME, MODE_PRIVATE);
sharedPreferences.edit().putString(MainActivity.LANGUAGE, LanContextWrapper.LANG_CN).apply();
rebot();
}
public void changeEnglish(View view) {
SharedPreferences sharedPreferences=getSharedPreferences(MainActivity.SP_NAME, MODE_PRIVATE);
sharedPreferences.edit().putString(MainActivity.LANGUAGE, LanContextWrapper.LANG_EN).apply();
rebot();
}
public void changeRChinese(View view) {
SharedPreferences sharedPreferences=getSharedPreferences(MainActivity.SP_NAME, MODE_PRIVATE);
sharedPreferences.edit().putString(MainActivity.LANGUAGE, LanContextWrapper.LANG_HK).apply();
rebot();
}
private void rebot() {
if(Build.VERSION.SDK_INT>=Build.VERSION_CODES.N) {
Intent intent = new Intent(this, MainActivity.class);
intent.setFlags(Intent.FLAG_ACTIVITY_CLEAR_TASK | Intent.FLAG_ACTIVITY_NEW_TASK);
startActivity(intent);
overridePendingTransition(R.anim.anim_change_lang_enter, R.anim.anim_change_lang_exit);
finish();
}else{
recreate();
}
}
public void toOther(View view) {
String country=LanContextWrapper.getCountry(this);
startActivity(new Intent(this,Main2Activity.class));
}
}
#附錄、國際化資源表示形式
Android 應用資源國際化的知識。對於資原始檔的國際化,我們一般是在 Android src/main/res/ 目錄下,建立對應語言資料夾,格式一般為:values-語言代號-地區代號,預設的資源是不包含語言代號和地區代號的。一般情況下,應用資源是沒有做任何適配的,所以不管如何切換語言和地區設定,應用顯示的資源都不會發生任何改變。配置選項包括語言代號和地區代號。表示中文和中國的配置選項是 zh-rCN(zh表示中文,CN表示中國)。表示英文和美國的配置選項是 en-rUS(en表示英文,US表示美國)。同一語言代號可以有多個地區代號,用 r 表示區分。
國家/區域 | 對應values資料夾 |
---|---|
中文(中國) | values-zh-rCN |
中文(臺灣) | values-zh-rTW |
中文(香港) | values-zh-rHK |
維吾爾文(中國) | values-ug-rCN |
英語(美國) | values-en-rUS |
英語(英國) | values-en-rGB |
英文(澳大利亞) | values-en-rAU |
英文(加拿大) | values-en-rCA |
英文(愛爾蘭) | values-en-rIE |
英文(印度) | values-en-rIN |
英文(紐西蘭) | values-en-rNZ |
英文(新加坡) | values-en-rSG |
英文(南非) | values-en-rZA |
阿拉伯文(埃及) | values-ar-rEG |
阿拉伯文(以色列) | values-ar-rIL |
保加利亞文: values-bg-rBG | |
加泰羅尼亞文 | values-ca-rES |
捷克文 | values-cs-rCZ |
丹麥文 | values-da-rDK |
德文(奧地利) | values-de-rAT |
德文(瑞士) | values-de-rCH |
德文(德國) | values-de-rDE |
德文(列支敦斯登) | values-de-rLI |
希臘文 | values-el-rGR |
西班牙文(西班牙) | values-es-rES |
西班牙文(美國) | values-es-rUS |
芬蘭文(芬蘭) | values-fi-rFI |
法文(比利時) | values-fr-rBE |
法文(加拿大) | values-fr-rCA |
法文(瑞士) | values-fr-rCH |
法文(法國) | values-fr-rFR |
希伯來文 | values-iw-rIL |
印地文 | values-hi-rIN |
克羅里亞文 | values-hr-rHR |
匈牙利文 | values-hu-rHU |
印度尼西亞文 | values-in-rID |
義大利文(瑞士) | values-it-rCH |
義大利文(義大利) | values-it-rIT |
日文 | values-ja-rJP |
韓文 | values-ko-rKR |
立陶宛文 | valueslt-rLT |
拉脫維亞文 | values-lv-rLV |
挪威博克馬爾文 | values-nb-rNO |
荷蘭文(比利時) | values-nl-BE |
荷蘭文(荷蘭) | values-nl-rNL |
波蘭文 | values-pl-rPL |
葡萄牙文(巴西) | values-pt-rBR |
葡萄牙文(葡萄牙) | values-pt-rPT |
羅馬尼亞文 | values-ro-rRO |
俄文 | values-ru-rRU |
斯洛伐克文 | values-sk-rSK |
斯洛維尼亞文 | values-sl-rSI |
塞爾維亞文 | values-sr-rRS |
瑞典文 | values-sv-rSE |
泰文 | values-th-rTH |
塔加洛語 | values-tl-rPH |
土耳其文 | values–r-rTR |
烏克蘭文 | values-uk-rUA |
越南文 | values-vi-rVN |