微信公眾號:CodingAndroid
CSDN:blog.csdn.net/xinpengfei5…
宣告:本文由CodingAndroid原創,未經授權,不可隨意轉載!
最近,我們公司的業務已經擴充到了香港,我們都知道香港使用的是繁體中文,因此,我們的APP要可以設定繁體語言,這不我們要緊跟國際的步伐,實現多語言,產品定給我們的需求主要以實現簡體中文、繁體中文、英文三種語言切換即可,具體的業務邏輯是:當使用者第一次進入APP時,App的語言跟隨當前系統語言,當使用者設定了某種語言之後就切換為使用者設定的語言,不管系統之後設定成哪種語言,都不會影響使用者設定的語言,如果使用者一直沒有設定語言選項,只要系統語言改變時,APP的語言也要跟隨系統語言設定改變。
說明:本文以實現簡體中文、繁體中文和英語為例進行簡要講解。
1.實現思路
我們可以預先使用SharedPreference來儲存一個語言型別的值,當使用者第一次進入APP時,我們通過Key取出這個值,第一次肯定是取不到的,這時我們將App的語言設定為當前系統預設值即可;當使用者通設定多語言時,我們將這個語言對應的值通過SharedPreference儲存到本地即可,然後此時重啟APP,設定為使用者設定的語言即可,以後每次進入App時只需取出儲存使用者設定的語言設定即可,一般設定語言寫在程式的入口 Application 的 onCreate() 方法裡。
2.自定義SharedPreference工具類
作用:用於儲存當前設定語言的型別,此文以SharedPreference儲存為例,當然使用資料庫或者其他儲存方式也是可以的。
/**
* Created by xpf on 2017/03/25 :)
* Function: sp儲存的工具類
*/
public class SpUtil {
private static final String APP_SP = "app_sp";
private static final String TAG = SpUtil.class.getSimpleName();
private SpUtil() {
}
private static SpUtil instance = new SpUtil();
private static SharedPreferences mSp = null;
public static SpUtil getInstance() {
if (mSp == null) {
mSp = MyApplication.getContext().getSharedPreferences(APP_SP, Context.MODE_PRIVATE);
}
return instance;
}
/**
* 儲存資料
*
* @param key 鍵
* @param value 值
*/
public void save(String key, Object value) {
if (value == null) {
Log.e(TAG, "value==null儲存失敗");
return;
}
if (value instanceof String) {
mSp.edit().putString(key, (String) value).commit();
} else if (value instanceof Boolean) {
mSp.edit().putBoolean(key, (Boolean) value).commit();
} else if (value instanceof Integer) {
mSp.edit().putInt(key, (Integer) value).commit();
}
}
/**
* 讀取String型別資料
*
* @param key
* @param defValue
* @return
*/
public String getString(String key, String defValue) {
return mSp.getString(key, defValue);
}
/**
* 讀取boolean型別資料
*
* @param key
* @param defValue
* @return
*/
public boolean getBoolean(String key, boolean defValue) {
return mSp.getBoolean(key, defValue);
}
/**
* 讀取boolean型別資料
*
* @param key
* @param defValue
* @return
*/
public int getInt(String key, int defValue) {
return mSp.getInt(key, defValue);
}
/**
* 清除所有儲存的資料(xxx.xml仍然存在,但是內部沒有資料)
*/
public void clearAll() {
mSp.edit().clear().commit();
}
}
複製程式碼
3.自定義LocaleUtil工具類
作用:用於設定儲存語言及獲取當前語言,重啟APP等操作
public class LocaleUtil {
/**
* 獲取使用者設定的Locale
*
* @return Locale
*/
public static Locale getUserLocale() {
int currentLanguage = SpUtil.getInstance().getInt("currentLanguage", 0);
Locale myLocale = Locale.SIMPLIFIED_CHINESE;
switch (currentLanguage) {
case 0:
myLocale = Locale.SIMPLIFIED_CHINESE;
break;
case 1:
myLocale = Locale.ENGLISH;
break;
case 2:
myLocale = Locale.TRADITIONAL_CHINESE;
break;
}
return myLocale;
}
/**
* 設定語言:如果之前有設定就遵循設定如果沒設定過就跟隨系統語言
*/
public static void changeAppLanguage(Context context) {
if (context == null) return;
Context appContext = context.getApplicationContext();
int currentLanguage = SpUtil.getInstance().getInt("currentLanguage", -1);
Locale myLocale;
// 0 簡體中文 1 繁體中文 2 English
switch (currentLanguage) {
case 0:
myLocale = Locale.SIMPLIFIED_CHINESE;
break;
case 1:
myLocale = Locale.TRADITIONAL_CHINESE;
break;
case 2:
myLocale = Locale.ENGLISH;
break;
default:
myLocale = appContext.getResources().getConfiguration().locale;
}
// 本地語言設定
if (needUpdateLocale(appContext, myLocale)) {
updateLocale(appContext, myLocale);
}
}
/**
* 儲存設定的語言
*
* @param currentLanguage index
*/
public static void changeAppLanguage(Context context, int currentLanguage) {
if (context == null) return;
Context appContext = context.getApplicationContext();
SpUtil.getInstance().save("currentLanguage", currentLanguage);
Locale myLocale = Locale.SIMPLIFIED_CHINESE;
// 0 簡體中文 1 繁體中文 2 English
switch (currentLanguage) {
case 0:
myLocale = Locale.SIMPLIFIED_CHINESE;
break;
case 1:
myLocale = Locale.TRADITIONAL_CHINESE;
break;
case 2:
myLocale = Locale.ENGLISH;
break;
}
// 本地語言設定
if (LocaleUtil.needUpdateLocale(appContext, myLocale)) {
LocaleUtil.updateLocale(appContext, myLocale);
}
Toast.makeText(appContext, appContext.getString(R.string.set_success), Toast.LENGTH_SHORT).show();
restartApp(appContext);
}
/**
* 重啟app生效
*
* @param context
*/
public static void restartApp(Context context) {
Intent intent = new Intent(context, MainActivity.class);
intent.setAction(Intent.ACTION_MAIN);
intent.addCategory(Intent.CATEGORY_LAUNCHER);
intent.setFlags(Intent.FLAG_ACTIVITY_CLEAR_TASK | Intent.FLAG_ACTIVITY_NEW_TASK);
context.startActivity(intent);
}
/**
* 獲取當前的Locale
*
* @param context Context
* @return Locale
*/
public static Locale getCurrentLocale(Context context) {
Locale locale;
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.N) { //7.0有多語言設定獲取頂部的語言
locale = context.getResources().getConfiguration().getLocales().get(0);
} else {
locale = context.getResources().getConfiguration().locale;
}
return locale;
}
/**
* 更新Locale
*
* @param context Context
* @param locale New User Locale
*/
public static void updateLocale(Context context, Locale locale) {
if (needUpdateLocale(context, locale)) {
Configuration configuration = context.getResources().getConfiguration();
if (Build.VERSION.SDK_INT >= 19) {
configuration.setLocale(locale);
} else {
configuration.locale = locale;
}
DisplayMetrics displayMetrics = context.getResources().getDisplayMetrics();
context.getResources().updateConfiguration(configuration, displayMetrics);
}
}
/**
* 判斷需不需要更新
*
* @param context Context
* @param locale New User Locale
* @return true / false
*/
public static boolean needUpdateLocale(Context context, Locale locale) {
return locale != null && !getCurrentLocale(context).equals(locale);
}
/**
* 當系統語言發生改變的時候還是繼續遵循使用者設定的語言
*
* @param context
* @param newConfig
*/
public static void setLanguage(Context context, Configuration newConfig) {
if (context == null) return;
Context appContext = context.getApplicationContext();
int currentLanguage = SpUtil.getInstance().getInt("currentLanguage", -1);
Locale locale;
// 0 簡體中文 1 繁體中文 2 English
switch (currentLanguage) {
case 0:
locale = Locale.SIMPLIFIED_CHINESE;
break;
case 1:
locale = Locale.TRADITIONAL_CHINESE;
break;
case 2:
locale = Locale.ENGLISH;
break;
default:
locale = appContext.getResources().getConfiguration().locale;
}
// 系統語言改變了應用保持之前設定的語言
if (locale != null) {
Locale.setDefault(locale);
Configuration configuration = new Configuration(newConfig);
if (Build.VERSION.SDK_INT >= 19) {
configuration.setLocale(locale);
} else {
configuration.locale = locale;
}
appContext.getResources().updateConfiguration(configuration, appContext.getResources().getDisplayMetrics());
}
}
}
複製程式碼
3.1Application中呼叫,用於初始化語言設定
@Override
public void onCreate() {
super.onCreate();
LocaleUtil.changeAppLanguage(this);
}
複製程式碼
3.2在Application中重寫如下方法:用於當系統設定語言變化時進行語言設定
@Override
public void onConfigurationChanged(Configuration newConfig) {
super.onConfigurationChanged(newConfig);
Log.e("TAG", "onConfigurationChanged");
LocaleUtil.setLanguage(mContext, newConfig);
}
複製程式碼
3.3在多語言設定介面設定APP語言
當使用者點選儲存時傳入當前語言對應的Index值即可,我這裡使用的是儲存一個Int型別的值,每一個Int型別的值對應一種語言的型別,當然你可以根據自己的實現儲存為String型別也是可以的。
LocaleUtil.changeAppLanguage(mContext, currentLanguage);
複製程式碼
4.多國語言資料夾命名對應表如下:
本文只以簡體中文、繁體中文和英語為例,要想實現更多語言設定,請參考下表:
國家 | Folder Name |
---|---|
中文(中國) | values-zh-rCN |
中文(臺灣) | values-zh-rTW |
中文(香港) | values-zh-rHK |
英語(美國) | 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 |
5.常見的一些坑
- 設定英文語言時在有些手機上不起作用
在開發過程中我們試過在Redmi Note 4手機上設定英語語言不起作用,這是由於有些手機廠商的預設英語設定的是英式英語,而我們只使用了美式英語的緣故,此時處理方式為:①設定兩種英語的設定選項,即美式英語和英式英語;②可將res的資料夾命名為values-en即可,不區分英式英語和美式英語即可; - 在Android Studio3.0之前,如果有些strings沒有對應到其他的語種,即有些欄位沒有翻譯過來,打包時會 報警告,可以打成包,而3.0之後是不可以的,會打包失敗,所以每個Strings必須對應一套完整的翻譯!
6.相關許可權
<uses-permission android:name="android.permission.CHANGE_CONFIGURATION"/>
複製程式碼
7.更多探討
在實現APP種切換語言時,試了試微信的多語言設定頁面是在4級頁面,當它設定完語言之後先是跳轉到我 介面(一級頁面),然後緊接著跳到設定介面(二級頁面),貌似微信沒有重啟App,它只是管理儲存了Activity任務棧,最後跳轉到設定介面,而我的例子只是重啟了App沒有跳轉回到設定介面,當然這要看具體的需求了,我個人感覺,設定完就沒有必要再跳轉回去了。
最後附上Demo:
github.com/xinpengfei5…
如果你覺得不錯可以幫我點個star,3Q~
若在使用過程中遇到什麼問題,或有好提議,歡迎在公眾號“CodingAndroid”中提出