最近因为项目中使用了国际化,所以正好研究了下实现方法;
首先说下项目需求:
虽然需求还是很简单的,但是实现起来还是遇到了不少的麻烦,首先看下效果图:
项目源码
attachBaseContext
设置当前设置的语言Local
onConfigurationChanged
(改变系统语言时会调用到)设置当前的语言Local
attachBaseContext
设置当前设置的语言Local
,所以一般这里是创建BaseActivity
来方便统一改变attachBaseContext
设置当前设置的语言Local
有了思路实现起来就很清晰了,
因为这个我们要保存用户的选择语言,所以这里创建个 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;
}
}
Local
方法:/**
* 获取选择的语言设置
*
* @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;
}
}
/**
* 获取系统的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;
}
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;
}
#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);
}
我们都会在代码中调用context.getResource().getString()
这句代码看起来没什么问题,但是你这个context
要是用的是applicationContext
那么问题就来了。你会发现当你切换语言后用这样方式设置的string没有改变,所以我们需要改动我们的代码。
解决方法就是,在切换语言后把application的updateConfiguration也要更新了,方法如下:
/**
* 设置语言类型
*/
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);
}
但是当你调用这个代码后你获取到的系统选择语言就是你设置的语言,这不准确呀,那怎么办呢?很简单,我们把真实的系统语言保存下来就行了。
我们在SharedPreferences
单例中添加系统Local变量:
/**
* 用来保存系统语言
*/
private Locale systemCurrentLocal = Locale.ENGLISH;
public int getSelectLanguage() {
return mSharedPreferences.getInt(TAG_LANGUAGE, 0);
}
public Locale getSystemCurrentLocal() {
return systemCurrentLocal;
}
然后在 application的attachBaseContext
和onConfigurationChanged
获取真实的系统Local
并保存
最后改变下我们原来获取系统Local
的方法:
/**
* 获取系统的locale
*
* @return Locale对象
*/
public static Locale getSystemLocale(Context context) {
return SPUtil.getInstance(context).getSystemCurrentLocal();
}
这样就真的完成了,具体的代码可见项目源码这里,
若您觉得对您有帮助,欢迎点个start