前言
最近因為項目中使用了國際化卒蘸,所以正好研究了下實現(xiàn)方法雌隅;
首先說下項目需求:
- 可以隨著系統(tǒng)切換語言而切換語言,不支持的語言顯示默認(rèn)
- 用戶可以選擇語言缸沃,且不會隨著系統(tǒng)切換語言或者應(yīng)用重啟而還原
雖然需求還是很簡單的恰起,但是實現(xiàn)起來還是遇到了不少的麻煩,首先看下效果圖:
效果圖
老規(guī)矩
實現(xiàn)思路
- 在application 的
attachBaseContext
設(shè)置當(dāng)前設(shè)置的語言Local
- 在application 的
onConfigurationChanged
(改變系統(tǒng)語言時會調(diào)用到)設(shè)置當(dāng)前的語言Local
- 在 Activity 的
attachBaseContext
設(shè)置當(dāng)前設(shè)置的語言Local
趾牧,所以一般這里是創(chuàng)建BaseActivity
來方便統(tǒng)一改變 - 在 service 的
attachBaseContext
設(shè)置當(dāng)前設(shè)置的語言Local
實現(xiàn)代碼
有了思路實現(xiàn)起來就很清晰了检盼,
-
第一步肯定是創(chuàng)建對應(yīng)語言的string.xml,在demo中我只實現(xiàn)了:中文簡體,中文繁體翘单,和英文三個語言
image.png
- 因為這個我們要保存用戶的選擇語言吨枉,所以這里創(chuàng)建個
SharedPreferences
的單例:
public class SPUtil {
private final String SP_NAME = "language_setting";
private final String TAG_LANGUAGE = "language_select";
private static volatile SPUtil instance;
private final SharedPreferences mSharedPreferences;
public SPUtil(Context context) {
mSharedPreferences = context.getSharedPreferences(SP_NAME, Context.MODE_PRIVATE);
}
public void saveLanguage(int select) {
SharedPreferences.Editor edit = mSharedPreferences.edit();
edit.putInt(TAG_LANGUAGE, select);
edit.commit();
}
public int getSelectLanguage() {
return mSharedPreferences.getInt(TAG_LANGUAGE, 0);
}
public static SPUtil getInstance(Context context) {
if (instance == null) {
synchronized (SPUtil.class) {
if (instance == null) {
instance = new SPUtil(context);
}
}
}
return instance;
}
}
創(chuàng)建管理語言的Util
- 創(chuàng)建根據(jù)用戶設(shè)置獲取對應(yīng)的
Local
方法:
/**
* 獲取選擇的語言設(shè)置
*
* @param context
* @return
*/
public static Locale getSetLanguageLocale(Context context) {
switch (SPUtil.getInstance(context).getSelectLanguage()) {
case 0:
return getSystemLocale(context);
case 1:
return Locale.CHINA;
case 2:
return Locale.TAIWAN;
case 3:
default:
return Locale.ENGLISH;
}
}
/**
* 獲取系統(tǒng)的locale
*
* @return Locale對象
*/
public static Locale getSystemLocale(Context context) {
Locale locale;
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.N) {
locale = LocaleList.getDefault().get(0);
} else {
locale = Locale.getDefault();
}
return locale;
}
- 創(chuàng)建改變
Local
方法
public static Context setLocal(Context context) {
return updateResources(context, getSetLanguageLocale(context));
}
private static Context updateResources(Context context, Locale locale) {
Locale.setDefault(locale);
Resources res = context.getResources();
Configuration config = new Configuration(res.getConfiguration());
if (Build.VERSION.SDK_INT >= 17) {
config.setLocale(locale);
context = context.createConfigurationContext(config);
} else {
config.locale = locale;
res.updateConfiguration(config, res.getDisplayMetrics());
}
return context;
}
- 在相應(yīng)地方調(diào)用
#Application
@Override
protected void attachBaseContext(Context base) {
super.attachBaseContext(LocalManageUtil.setLocal(base));
}
@Override
public void onConfigurationChanged(Configuration newConfig) {
super.onConfigurationChanged(newConfig);
LocalManageUtil.setLocal(context);
}
#BaseActivity
@Override
protected void attachBaseContext(Context newBase) {
super.attachBaseContext(LocalManageUtil.setLocal(newBase));
}
#service
@Override
protected void attachBaseContext(Context base) {
super.attachBaseContext(LocalManageUtil.setLocal(base));
}
- 切換語言
private void selectLanguage(int select) {
LocalManageUtil.saveSelectLanguage(this, select);
//重啟APP到主頁面
MainActivity.reStart(this);
}
搞定,
image.png
沒錯就是這么簡單哄芜。
image.png
但是總有你想不到的事
我們都會在代碼中調(diào)用context.getResource().getString()
這句代碼看起來沒什么問題貌亭,但是你這個context
要是用的是applicationContext
那么問題就來了。你會發(fā)現(xiàn)當(dāng)你切換語言后用這樣方式設(shè)置的string沒有改變属提,所以我們需要改動我們的代碼。
解決方法就是美尸,在切換語言后把application的updateConfiguration也要更新了冤议,方法如下:
/**
* 設(shè)置語言類型
*/
public static void setApplicationLanguage(Context context) {
Resources resources = context.getApplicationContext().getResources();
DisplayMetrics dm = resources.getDisplayMetrics();
Configuration config = resources.getConfiguration();
Locale locale = getSetLanguageLocale(context);
config.locale = locale;
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.N) {
LocaleList localeList = new LocaleList(locale);
LocaleList.setDefault(localeList);
config.setLocales(localeList);
context.getApplicationContext().createConfigurationContext(config);
Locale.setDefault(locale);
}
resources.updateConfiguration(config, dm);
}
- 但是當(dāng)你調(diào)用這個代碼后你獲取到的系統(tǒng)選擇語言就是你設(shè)置的語言,這不準(zhǔn)確呀师坎,那怎么辦呢恕酸?很簡單,我們把真實的系統(tǒng)語言保存下來就行了胯陋。
- 我們在
SharedPreferences
單例中添加系統(tǒng)Local變量:
/**
* 用來保存系統(tǒng)語言
*/
private Locale systemCurrentLocal = Locale.ENGLISH;
public int getSelectLanguage() {
return mSharedPreferences.getInt(TAG_LANGUAGE, 0);
}
public Locale getSystemCurrentLocal() {
return systemCurrentLocal;
}
然后在 application的
attachBaseContext
和onConfigurationChanged
獲取真實的系統(tǒng)Local
并保存最后改變下我們原來獲取系統(tǒng)
Local
的方法:
/**
* 獲取系統(tǒng)的locale
*
* @return Locale對象
*/
public static Locale getSystemLocale(Context context) {
return SPUtil.getInstance(context).getSystemCurrentLocal();
}
這樣就真的完成了蕊温,具體的代碼可見項目源碼這里袱箱,
若您覺得對您有幫助,您的贊是我最大的動力