前言
拿来主义而已, 也很感谢创作者的分享精神,开源有益,共同进步才能走得更远,
旧版
旧版本仅适配API28以下版本
高版本环境 AS会提示 Deprecated
/*
* 过时 App中维护
* 注释:
* @author maqi
* created at 2021/12/15 11:39
* */
@Deprecated("")
private fun switchLanguage() {
val language = xxx//SP获取
//设置应用语言类型
val resources = resources
val config = resources.configuration
val dm = resources.displayMetrics
if (0 == language) {
config.locale = Locale.CHINESE
} else if (1 == language) {
config.locale = Locale.ENGLISH
} else /*第一次进入 取系统环境 */ {
config.locale = Locale.getDefault()
}
resources.updateConfiguration(config, dm)
}
新版工具类
仔细看了下区别并不大,主要是作者的思路很完整,加之工具封装,故笔者稍作修改,并给出使用方法,以及需要注意的其他地方,这里会给出笔者踩过的坑,看大家是不是也会遇到。
public final class LocaleUtils {
private static final String FILE_NAME = "key_language_file";
private static final String KEY_LANGUAGE = "key_language";
private static final String KEY_COUNTRY = "key_country";
/**
* 获取手机系统的Locale
*
* @return
*/
public static Locale getSystemLocale() {
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.N) {
return LocaleList.getDefault().get(0);
}
return Locale.getDefault();
}
/**
* 设置 App 的Locale
*
* @param context
* @param loc
* @return
*/
public static void setAppLocale(Context context, Locale loc) {
if (loc != null) {
setUserSetLocale(context, loc);
Resources rs = context.getResources();
Configuration config = rs.getConfiguration();
DisplayMetrics dm = rs.getDisplayMetrics();
if (Build.VERSION.SDK_INT >= 17) {
config.setLocale(loc);
} else {
config.locale = loc;
}
context.getResources().updateConfiguration(config, dm);
}
}
/**
* 在activity 的 onResume or onConfigChange中调用此方法
* http://www.jianshu.com/p/47bbd34d2af8
*
* @param context
* @param loc
*/
public static void setLocaleWhenConfigChange(Context context, Locale loc) {
if (loc != null) {
Resources rs = context.getResources();
Configuration config = rs.getConfiguration();
DisplayMetrics dm = rs.getDisplayMetrics();
if (Build.VERSION.SDK_INT >= 17) {
config.setLocale(loc);
} else {
config.locale = loc;
}
context.getResources().updateConfiguration(config, dm);
}
}
/**
* 获取App Locale
*
* @param context
* @return
*/
public static Locale getAppLocale(Context context) {
Configuration config = context.getResources().getConfiguration();
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.N)
return config.getLocales().get(0);
else
return config.locale;
}
/**
* 获取用户设置的Locale
*
* @param context
* @return
*/
public static Locale getUserSetLocale(Context context) {
SharedPreferences sp = context.getSharedPreferences(FILE_NAME, Context.MODE_PRIVATE);
String lang = sp.getString(KEY_LANGUAGE, "");
String country = sp.getString(KEY_COUNTRY, "");
Log.d("language", "getUserSetLocale " + "lang " + lang + " country " + country);
if (!TextUtils.isEmpty(lang) /*&& !TextUtils.isEmpty(country)*/) {
return new Locale(lang, country);
} else {
return null;
}
}
/**
* 返回 en_US 格式
*
* @param context
* @return
*/
public static String getUserSetLocaleStr(Context context) {
SharedPreferences sp = context.getSharedPreferences(FILE_NAME, Context.MODE_PRIVATE);
String lang = sp.getString(KEY_LANGUAGE, "");
String country = sp.getString(KEY_COUNTRY, "");
if (!TextUtils.isEmpty(lang) && !TextUtils.isEmpty(country)) {
return String.format("%s_%s", lang, country);
}
return "";
}
/**
* 清空设置,跟随系统
*
* @param context
*/
public static void removeLocaleSet(Context context) {
SharedPreferences sp = context.getSharedPreferences(FILE_NAME, Context.MODE_PRIVATE);
final SharedPreferences.Editor edit = sp.edit();
edit.putString(KEY_LANGUAGE, "");
edit.putString(KEY_COUNTRY, "");
edit.apply();
}
/**
* 用户设置的Locale
*/
public static void setUserSetLocale(Context context, Locale locale) {
if (locale != null) {
try {
SharedPreferences sp = context.getSharedPreferences(FILE_NAME, Context.MODE_PRIVATE);
final SharedPreferences.Editor edit = sp.edit();
edit.putString(KEY_LANGUAGE, locale.getLanguage());
edit.putString(KEY_COUNTRY, locale.getCountry());
edit.apply();
} catch (Exception e) {
}
}
}
}
使用方式
- 在Application的oncreat中先设置好
/*设置系统语言*/
val isFirstOpenComplete = SharePreferenceUtil.getFirstOpenComplete(MainApp.getContext()!!)
if (isFirstOpenComplete) {
val sysLocale = LocaleUtils.getSystemLocale()
val appLocale = LocaleUtils.getAppLocale(this)
val userLocale = LocaleUtils.getUserSetLocale(this)
Log.d(TAG, "sysLocale " + sysLocale)
Log.d(TAG, "appLocale " + appLocale)
Log.d(TAG, "userLocale " + userLocale)
} else {
val userSet = LocaleUtils.getSystemLocale()
val language = userSet?.language ?: ""
val country = userSet?.country ?: ""
Log.d("language", "language $language country $country")
if (language == Locale.CHINESE.language) {
LocaleUtils.setAppLocale(this, Locale.CHINESE)
} else {
LocaleUtils.setAppLocale(this, Locale.ENGLISH)
}
}
- 在BaseActivity的oncreate中使用,不要在Application中的registerActivityLifecycleCallbacks中使用,试过了不行.
requireActivity().finish()
重建或者requireActivity().recreate()
都是能生效的,与启动模式launchMode无关
/*
* API>29后 新版语言切换
* 注释:
* @author maqi
* created at 2021/12/15 16:41
* */
private fun changeLanguage() {
val userSetLocale = LocaleUtils.getUserSetLocale(this)
val language = userSetLocale?.language?:""
val country = userSetLocale?.country?:""
Log.d("language", "reset $language country $country userSetLocale $userSetLocale")
LocaleUtils.setAppLocale(this, userSetLocale)
}
- 语言切换以用户设置为主
代码同上 - 恢复出厂设置以系统设置为主,
Locale userSet = LocaleUtils.getSystemLocale();
String language = userSet.getLanguage();
String country = userSet.getCountry();
Log.d("language", "language " + language + " country " + country + " userSet " + userSet.toString());
LocaleUtils.setUserSetLocale(this, userSet)
- 大多数情况,getAppLocale是不用的,因为在setAppLocale后如果恢复出厂设置调用getAppLocale的话会获取到上次设置的语言
注意事项
- 获取固定语言
该函数乍一看很简洁方便,其实配合之前的 LocaleUtils.setAppLocale 会出现语言混乱的情况
public String getStringInDefaultLocale(Locale local, int resId) {
Resources currentResources = mContext.getResources();
AssetManager assets = currentResources.getAssets();
DisplayMetrics metrics = currentResources.getDisplayMetrics();
Configuration config = new Configuration(currentResources.getConfiguration());
config.locale = local;
Resources defaultLocaleResources = new Resources(assets, metrics, config);
String string = defaultLocaleResources.getString(resId);
return string;
}
//使用
/*目的:维持原语言*/
String english = getStringInDefaultLocale(Locale.ENGLISH, R.string.language_english);
String china = getStringInDefaultLocale(Locale.CHINESE, R.string.language_china);
解决:直接在strings-zh或者strings-en中写同样的翻译,正常使用setText(resID)
<string name="language_china_other">简体中文</string>
- Locale.CHINESE & Locale.CHINA,Locale.ENGLISH与Locale.US
在setUserSetLocale和getUserSetLocale时需要注意country为空的判断后使用
其他
- 获取语言失败现象,始终为
en
,如下反射
和键盘流
获取最稳,LocaleList.getDefault().get(0)
概率性出错 - 如图:
- 解决:
/**
* 获取手机系统的Locale
*
* @return
*/
public static Locale getSystemLocale() {
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.N) {
String displayLanguage = Locale.getDefault().getDisplayLanguage();
PackageManager packageManager = MainApp.Companion.getContext().getPackageManager();
Resources resources = null;
try {
resources = packageManager.getResourcesForApplication("android");
} catch (PackageManager.NameNotFoundException e) {
}
Locale Syslocale = resources.getConfiguration().getLocales().get(0);
String packageManagerLanguage = Syslocale.getLanguage();
InputMethodManager imm = (InputMethodManager) MainApp.Companion.getContext().getSystemService(Context.INPUT_METHOD_SERVICE);
InputMethodSubtype ims = imm.getCurrentInputMethodSubtype();
String immlocale = ims.getLocale();
//displayLanguage English packageManagerLanguage zh immlocale zh_CN
LocaleList aDefault = LocaleList.getDefault();
Log.d("language", "--------------------xxx-----"
+ " displayLanguage " + displayLanguage
+ " packageManagerLanguage " + packageManagerLanguage
+ " immlocale " + immlocale);
for (int i = 0; i < aDefault.size(); i++) {
Locale locale = aDefault.get(i);
Log.d("language", "getSystemLocale " + i + " " + locale.getLanguage()
+ " country " + locale.getCountry()
);
}
// return LocaleList.getDefault().get(0);
return Syslocale;
}
return Locale.getDefault();
}