Android實現多語言so easy

IT大飛說發表於2017-12-08

微信公眾號:CodingAndroid
CSDN:blog.csdn.net/xinpengfei5…
宣告:本文由CodingAndroid原創,未經授權,不可隨意轉載!

      最近,我們公司的業務已經擴充到了香港,我們都知道香港使用的是繁體中文,因此,我們的APP要可以設定繁體語言,這不我們要緊跟國際的步伐,實現多語言,產品定給我們的需求主要以實現簡體中文、繁體中文、英文三種語言切換即可,具體的業務邏輯是:當使用者第一次進入APP時,App的語言跟隨當前系統語言,當使用者設定了某種語言之後就切換為使用者設定的語言,不管系統之後設定成哪種語言,都不會影響使用者設定的語言,如果使用者一直沒有設定語言選項,只要系統語言改變時,APP的語言也要跟隨系統語言設定改變。

      說明:本文以實現簡體中文、繁體中文和英語為例進行簡要講解。

1.實現思路

      我們可以預先使用SharedPreference來儲存一個語言型別的值,當使用者第一次進入APP時,我們通過Key取出這個值,第一次肯定是取不到的,這時我們將App的語言設定為當前系統預設值即可;當使用者通設定多語言時,我們將這個語言對應的值通過SharedPreference儲存到本地即可,然後此時重啟APP,設定為使用者設定的語言即可,以後每次進入App時只需取出儲存使用者設定的語言設定即可,一般設定語言寫在程式的入口 ApplicationonCreate() 方法裡。

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”中提出
這裡寫圖片描述

相關文章