Android支持国际化多语言那点事(支持8.0+)

时间:2021-05-20

起因

我们在开发app可能会拓展国外市场,那么对包含英语在内的其它语言支持就很有必要了。

效果


思路

一:添加相关资源文件,并引用。
二:设置configuration,configuration里面指定语言类型。
三:在需要时候更换configuration即可。

实现

在res的values文件夹下新建相关语言类型的资源文件

右键新建资源文件,选择Locale,点击 >> 按钮

选择Language,以及地区(any region)即可


最后 文件名字和其他语言文件名字一样,strings即可。

在MyApplication里面的onCreate和onConfigurationChanged方法里面添加语言相关处理(onConfigurationChanged是为了处理横竖屏切换问题),给应用上下文对象添加configuration,configuration里面指定了当前语言。

public class MyApplication extends Application {@Overridepublic void onCreate() { super.onCreate(); languageWork();}@Overridepublic void onConfigurationChanged(Configuration newConfig) { super.onConfigurationChanged(newConfig); languageWork();}private void languageWork() { //自己写的工具包(如下) Locale locale = LanguageUtil.getLocale(this); LanguageUtil.updateLocale(this, locale);}}

LanguageUtil如下(没整理过的小伙伴直接用即可),为了保证语言从A切换到B,在之后启动应用依旧使用B语言,我们需要将B语言存入本地。下次启动应用,设置即可。

public class LanguageUtil {/** * 中文 */public static final Locale LOCALE_CHINESE = Locale.CHINESE;/** * 英文 */public static final Locale LOCALE_ENGLISH = Locale.ENGLISH;/** * 俄文 */public static final Locale LOCALE_RUSSIAN = new Locale("ru");private static final String LOCALE_SP = "LOCALE_SP";private static final String LOCALE_SP_KEY = "LOCALE_SP_KEY"; public static Locale getLocale(Context context) { SharedPreferences spLocale = context.getSharedPreferences(LOCALE_SP, Context.MODE_PRIVATE); String localeJson = spLocale.getString(LOCALE_SP_KEY, ""); Gson gson = new Gson(); return gson.fromJson(localeJson, Locale.class);}pivate static void setLocale(Context pContext, Locale pUserLocale) { SharedPreferences spLocal = pContext.getSharedPreferences(LOCALE_SP, Context.MODE_PRIVATE); SharedPreferences.Editor edit = spLocal.edit(); String json = new Gson().toJson(pUserLocale); edit.putString(LOCALE_SP_KEY, json); edit.apply();}public static boolean updateLocale(Context context, Locale locale) { if (needUpdateLocale(context, locale)) { Configuration configuration = context.getResources().getConfiguration(); if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.JELLY_BEAN_MR1) { configuration.setLocale(locale); } else { configuration.locale = locale; } DisplayMetrics displayMetrics = context.getResources().getDisplayMetrics(); context.getResources().updateConfiguration(configuration, displayMetrics); setLocale(context, locale); return true; } return false;}public static boolean needUpdateLocale(Context pContext, Locale newUserLocale) { return newUserLocale != null && !getCurrentLocale(pContext).equals(newUserLocale);}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;}}

进行切换,主要触发动作是activity的recreate()(切换使用新的configuration)。所有的activity在activityManager里面进行管理。只需将其他(除了当前语言选择activity)的所有activity进行recreate(),即可。languageUtil同时进行了是否需要切换语言的判定。如果当前语言和要选择的一致,则无需再做处理)

public void onClick(View view) { boolean need = false; switch (view.getId()) { case R.id.chinese: need = LanguageUtil.updateLocale(this, LanguageUtil.LOCALE_CHINESE); if (need) { //自己写的常用activity管理工具 ActivityManager.getInstance().recreateAllOtherActivity(this); Toast.makeText(this, "change to chinese", Toast.LENGTH_SHORT).show(); } else { Toast.makeText(this, "no need", Toast.LENGTH_SHORT).show(); } break; case R.id.english: need = LanguageUtil.updateLocale(this, LanguageUtil.LOCALE_ENGLISH); if (need) { ActivityManager.getInstance().recreateAllOtherActivity(this); Toast.makeText(this, "change to english", Toast.LENGTH_SHORT).show(); } else { Toast.makeText(this, "no need", Toast.LENGTH_SHORT).show(); } break; case R.id.russian: need = LanguageUtil.updateLocale(this, LanguageUtil.LOCALE_RUSSIAN); if (need) { ActivityManager.getInstance().recreateAllOtherActivity(this); Toast.makeText(this, "change to russian", Toast.LENGTH_SHORT).show(); } else { Toast.makeText(this, "no need", Toast.LENGTH_SHORT).show(); } break; }}

ActivityManager如下

public class ActivityManager {private static final Stack<Activity> sActivityStack = new Stack<>();private static ActivityManager sActivityManager;private ActivityManager() {}public Stack<Activity> getActivityStack() { return sActivityStack;}/** * 单一实例 */public static ActivityManager getInstance() { if (sActivityManager == null) { synchronized (ActivityManager.class) { sActivityManager = new ActivityManager(); } } return sActivityManager;}/** * 添加Activity到堆栈 */public void addActivity(Activity activity) { sActivityStack.add(activity);}/** * 删除堆栈中的Activity */public void removeActivity(Activity activity) { if (sActivityStack.isEmpty()) { return; } sActivityStack.remove(activity);}/** * 获取当前Activity(堆栈中最后一个压入的) */public Activity currentActivity() { Activity activity = sActivityStack.lastElement(); return activity;}/** * 结束当前Activity(堆栈中最后一个压入的) */public void finishActivity() { Activity activity = sActivityStack.lastElement(); finishActivity(activity);}/** * 结束指定的Activity */public void finishActivity(Activity activity) { if (activity != null) { sActivityStack.remove(activity); activity.finish(); }}/** * 结束指定类名的Activity */public void finishActivity(Class<?> cls) { for (Activity activity : sActivityStack) { if (activity.getClass().equals(cls)) { finishActivity(activity); return; } }}//获取指定类名的Activitypublic Activity getActivity(Class<?> cls) { for (Activity activity : sActivityStack) { if (activity.getClass().equals(cls)) { return activity; } } return null;}/** * 结束所有Activity */public void finishAllActivity() { for (int i = 0, size = sActivityStack.size(); i < size; i++) { if (null != sActivityStack.get(i)) { sActivityStack.get(i).finish(); } } sActivityStack.clear();}public void finishAllOtherActivity(Activity activity) { for (int i = 0, size = sActivityStack.size(); i < size; i++) { if (null != sActivityStack.get(i) && sActivityStack.get(i) != activity) { sActivityStack.get(i).finish(); } } sActivityStack.clear();}public void recreateAllOtherActivity(Activity activity) { for (int i = 0, size = sActivityStack.size(); i < size; i++) { if (null != sActivityStack.get(i) && sActivityStack.get(i) != activity) { sActivityStack.get(i).recreate(); } }}/** * 退出应用程序 */public void AppExit() { try { finishAllActivity(); System.exit(0); } catch (Exception e) { } } }

将app的所有acitivity进行添加和移除,可以在BaseActivity里面进行。

@Overrideprotected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); ActivityManager.getInstance().addActivity(this);}@Overrideprotected void onDestroy() { super.onDestroy(); ActivityManager.getInstance().removeActivity(this);}

以上步骤,我们的语言切换算是完成了。但是,在API 26+以上版本,我们需要额外添加如下代码做兼容,没啥说的,SDK变动而已,跟着SDK走咯~(在activity或者BaseActivity添加)

@Overrideprotected void attachBaseContext(Context newBase) { Context context = languageWork(newBase); super.attachBaseContext(context); }private Context languageWork(Context context) { // 8.0及以上使用createConfigurationContext设置configuration if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) { return updateResources(context); } else { return context; } }@RequiresApi(api = Build.VERSION_CODES.O)private Context updateResources(Context context) { Resources resources = context.getResources(); Locale locale = LanguageUtil.getLocale(context); if (locale==null) { return context; } Configuration configuration = resources.getConfiguration(); configuration.setLocale(locale); configuration.setLocales(new LocaleList(locale)); return context.createConfigurationContext(configuration); }

完工~

地址:https://github.com/HoldMyOwn/MultiLanguage

以上就是本文的全部内容,希望对大家的学习有所帮助,也希望大家多多支持。

声明:本页内容来源网络,仅供用户参考;我单位不保证亦不表示资料全面及准确无误,也不保证亦不表示这些资料为最新信息,如因任何原因,本网内容或者用户因倚赖本网内容造成任何损失或损害,我单位将不会负任何法律责任。如涉及版权问题,请提交至online#300.cn邮箱联系删除。

相关文章