前言

一个应用若需要国际化,至少需要支持中文和英语这两种语言,而同时随着谷歌的系统的更新,安卓系统可以设置当前语言的首选语言。因此,本文立足于此,多语言的切换方案为:App固定的文字内容,跟随系统,中文,英文,三种切换,选择后重启应用生效;

本文代码参考链接,感觉原作者~不过直接使用链接文章中的工具类可能会在系统兼容上会有一点点问题,我在项目实践过程改进了,分享出来

特别说明:工具类由Java编写,项目中的页面及相关的Application类使用了kotlin编写,请谅解

具体步骤

一、切换语言的代码逻辑

1、Application的onCreate中初始化,根据本地保存的多语言选项(用户所选)来确定app中显示哪种语言

2、在设置语言界面选择对应语言,然后把语言选项持久化后中,重启应用(返回第一个Activity)

其中获取系统首选语言,设置语言信息,注册Activity生命周期监听回调,修改应用内语言设置等操作可以放在一个工具类内进行使用;

下面是多语言切换工具类的具体代码:其中SPUtils为项目中一个操作SharedPreferences的一个工具类

public class MultiLanguageUtils {

    /**
* 修改应用内语言设置
* @param language 语言
* @param area 地区
*/
public static void changeLanguage(Context context,String language, String area) {
if (TextUtils.isEmpty(language) && TextUtils.isEmpty(area)) {
//如果语言和地区都是空,那么跟随系统
SPUtils.getInstance().put(Constants.SP_LANGUAGE,"");
SPUtils.getInstance().put(Constants.SP_LANGUAGE,"");
} else {
//不为空,修改app语言,持久化语言选项信息
Locale newLocale = new Locale(language, area);
setAppLanguage(context,newLocale);
saveLanguageSetting(context, newLocale);
}
} /**
* 更新应用语言(核心)
* @param context
* @param locale
*/
private static void setAppLanguage(Context context, Locale locale) {
Resources resources = context.getResources();
DisplayMetrics metrics = resources.getDisplayMetrics();
Configuration configuration = resources.getConfiguration();
//Android 7.0以上的方法
if (Build.VERSION.SDK_INT >= 24) {
configuration.setLocale(locale);
configuration.setLocales(new LocaleList(locale));
context.createConfigurationContext(configuration);
//实测,updateConfiguration这个方法虽然很多博主说是版本不适用
//但是我的生产环境androidX+Android Q环境下,必须加上这一句,才可以通过重启App来切换语言
resources.updateConfiguration(configuration,metrics); } else if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.JELLY_BEAN_MR1) {
//Android 4.1 以上方法
configuration.setLocale(locale);
resources.updateConfiguration(configuration,metrics);
} else {
configuration.locale = locale;
resources.updateConfiguration(configuration,metrics);
}
} /**
* 跟随系统语言
*/
public static Context attachBaseContext(Context context) {
String spLanguage = SPUtils.getInstance().getString(Constants.SP_LANGUAGE , "");
String spCountry = SPUtils.getInstance().getString(Constants.SP_COUNTRY,"");
if(!TextUtils.isEmpty(spLanguage)&&!TextUtils.isEmpty(spCountry)){
Locale locale = new Locale(spLanguage, spCountry);
setAppLanguage(context, locale);
}
return context;
} /**
* 判断SharedPrefences中存储和app中的多语言信息是否相同
*/
public static boolean isSameWithSetting(Context context) {
Locale locale = getAppLocale(context);
String language = locale.getLanguage();
String country = locale.getCountry();
String sp_language = SPUtils.getInstance().getString(Constants.SP_LANGUAGE , "");
String sp_country = SPUtils.getInstance().getString(Constants.SP_COUNTRY,"");
if (language.equals(sp_language) && country.equals(sp_country)) {
return true;
} else {
return false;
}
} /**
* 保存多语言信息到sp中
*/
public static void saveLanguageSetting(Context context, Locale locale) {
SPUtils.getInstance().put(Constants.SP_LANGUAGE , locale.getLanguage());
SPUtils.getInstance().put(Constants.SP_COUNTRY , locale.getCountry());
} /**
* 获取应用语言
*/
public static Locale getAppLocale(Context context){
Locale local;
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.N) {
local =context.getResources().getConfiguration().getLocales().get(0);
} else {
local =context.getResources().getConfiguration().locale;
}
return local;
} /**
* 获取系统语言
*/
public static LocaleListCompat getSystemLanguage(){
Configuration configuration = Resources.getSystem().getConfiguration();
LocaleListCompat locales = ConfigurationCompat.getLocales(configuration);
return locales;
} //在Application实现类注册Activity生命周期监听回调,有些版本不加的话多语言切换不回来
//registerActivityLifecycleCallbacks(callbacks);
public static Application.ActivityLifecycleCallbacks callbacks = new Application.ActivityLifecycleCallbacks() {
@Override
public void onActivityCreated(Activity activity, Bundle savedInstanceState) {
String language = SPUtils.getInstance().getString(Constants.SP_LANGUAGE , "");
String country = SPUtils.getInstance().getString(Constants.SP_COUNTRY ,"");
if (!TextUtils.isEmpty(language) && !TextUtils.isEmpty(country)) {
//强制修改应用语言
if (!isSameWithSetting(activity)) {
Locale locale = new Locale(language, country);
setAppLanguage(activity,locale);
} }
} @Override
public void onActivityStarted(Activity activity) { } @Override
public void onActivityResumed(Activity activity) { } @Override
public void onActivityPaused(Activity activity) { } @Override
public void onActivityStopped(Activity activity) { } @Override
public void onActivitySaveInstanceState(Activity activity, Bundle outState) { } @Override
public void onActivityDestroyed(Activity activity) { }
}; /**
* 设置语言信息
*
* 说明:
* 该方法建议在attachBaseContext和onConfigurationChange中调用,attachBaseContext可以保证页面加载时修改语言信息,
* 而onConfigurationChange则是为了对应横竖屏切换时系统更新Resource的问题
*
* @param context application context
*/
public static void setConfiguration(Context context) {
if (context == null) {
return;
}
/*
* 为防止传入非ApplicationContext,这里做一次强制转化,目的是避免onConfigurationChange可能导致的问题,
* 因为onConfigurationChange被触发时系统会更新ApplicationContext中的Resource,如果页面包含Runtime资源
* (运行时动态加载的资源)时,有可能语言显示不一致。
*/
Context appContext = context.getApplicationContext();
Locale preferredLocale = getSysPreferredLocale();
Configuration configuration = appContext.getResources().getConfiguration();
if (Build.VERSION.SDK_INT >= 17) {
configuration.setLocale(preferredLocale);
} else {
configuration.locale = preferredLocale;
}
// 更新context中的语言设置
Resources resources = appContext.getResources();
DisplayMetrics dm = resources.getDisplayMetrics();
resources.updateConfiguration(configuration, dm);
} /**
* 获取系统首选语言
*
* 注意:该方法获取的是用户实际设置的不经API调整的系统首选语言
*
* @return
*/
public static Locale getSysPreferredLocale() {
Locale locale;
//7.0以下直接获取系统默认语言
if (Build.VERSION.SDK_INT < 24) {
// 等同于context.getResources().getConfiguration().locale;
locale = Locale.getDefault();
// 7.0以上获取系统首选语言
} else {
/*
* 以下两种方法等价,都是获取经API调整过的系统语言列表(可能与用户实际设置的不同)
* 1.context.getResources().getConfiguration().getLocales()
* 2.LocaleList.getAdjustedDefault()
*/
// 获取用户实际设置的语言列表
locale = LocaleList.getDefault().get(0);
}
return locale;
} }

下面是语言设置的页面中具体调用的方法(核心过程),有详细注释

ActivityUtils 是一个项目内关于Activity操作的工具类,此处我用来关闭当前所有Activity并显示首页Activity以达到重启的效果,您可以选择其他方式实现

class MultiLanguageFragment : BaseFragment() {
//枚举类,判断用户具体的选项
enum class MultiLanguage{
FOLLOW_SYSTEM,
SIMPLIFY_CHINESE,
ENGLISH
}
private var flag = -1 override fun initViews() {
tbChangeLanguage.addRightTextButton(getString(R.string.save), Constants.BUTTON_SAVE_MULTI_LANGUAGE )
.setOnClickListener {
//记录选择了哪种语言,执行切换语言
when(flag){
MultiLanguage.FOLLOW_SYSTEM.ordinal -> {
//获取手机系统的首要语言
//此处可以有逻辑,如系统第一语言APP不提供,则顺次判断系统语言是否符合APP提供语言
val locale: Locale = MultiLanguageUtils.getSystemLanguage()[0]
val language: String = locale.language
val country: String = locale.country
//将APP内语言切换成手机系统语言
MultiLanguageUtils.changeLanguage(activity, language, country)
//清空SP数据 ,用于当系统切换语言时 应用可以同步保持切换
//例:系统转换成英文 则应用语言也会变成英文
MultiLanguageUtils.changeLanguage(activity, null, null)
//重启APP,到第一个Activity
ActivityUtils.finishAllActivities()
ActivityUtils.startActivity(this.requireActivity()::class.java)
} //选择简体中文
MultiLanguage.SIMPLIFY_CHINESE.ordinal -> {
MultiLanguageUtils.changeLanguage(this.requireActivity(), "zh", "ZH")
ActivityUtils.finishAllActivities()
ActivityUtils.startActivity(this.requireActivity()::class.java)
}
//选择English
MultiLanguage.ENGLISH.ordinal -> {
MultiLanguageUtils.changeLanguage(_mActivity, "en", "US")
ActivityUtils.finishAllActivities()
ActivityUtils.startActivity(this.requireActivity()::class.java)
} else -> {
ToastUtils.showLong(getString(R.string.none_chosen_language))
}
}
}
}
}

App中application的实现类,对每个Activity设置切换语言的回调,确保重启后可以重启应用

class App : Application() {

    override fun onCreate() {
super.onCreate()
//多语言设置
registerActivityLifecycleCallbacks(MultiLanguageUtils.callbacks)
context = applicationContext
}

二、切换语言需要准备的内容

这语言内容其实就是指,建立提供的多语言切换准备的资源文件夹,最基础的就是定义多语言所需的字符串内容

values-zh、values-en、…………

下面是新建的方法:在res文件夹右键new Android Resource File中,在第一个竖框内选择Locale,然后点击 >> 按钮,在第二个框中点击 Locale(?) ,在第三个框中选择对应语言,在第四个框选择语言的地区

如下面的图所示

Android原生多语言切换方案,兼容Android10的更多相关文章

  1. Android应用内语言切换实现(转)

    使用Java反射机制 IActivityManager与ActivityManagerNative都是非公开类,使用Java反射去调用其中的方法. 第一步.使用Android开放的api更改Confi ...

  2. Android 应用内多语言切换

    最近公司的 App 里需要用到多语言切换,简单来说,就是如果用户没有选择语言选项时,App 默认跟随系统语言,如果用户在 App 内进行了语言设置,那么就使用用户设置的语言.当然,你会发现,App 的 ...

  3. Android app应用多语言切换功能实现

    最近在做一个多语言切换的功能,类似于微信的语言切换,搜了下资料基本上都是以下这种: 1. 实现的效果 和微信类似,在设置界面打开切换语言的界面,选择语言后重启 HomeActivity,语言切换完成, ...

  4. 【转】Android 语言切换过程分析

    最近在看一个bug,系统切换语言后,本来退到后台的音乐,会在通知栏上显示通知.为了解决这个bug,我学习了下android的语言切换流程,也参考了大量其他人的资料.(主要参考了http://blog. ...

  5. android 语言切换过程分析

    android 语言切换过程分析 2014-02-27 18:13 1207人阅读 评论(0) 收藏 举报 语言切换android语言切换android改变语言 最近在看一个bug,系统切换语言后,本 ...

  6. 【Android 多语言切换简单实例分享】

    一.Android多语言切换 Android应用的开发不可能仅仅针对某一个国家或者区域使用,各国间语言文化各不同样,因此一个优秀的APP必须支持多种语言,为了实现这个特性,Android给出了一个解决 ...

  7. ASP.NET MVC5多语言切换快速实现方案

    功能 实现动态切换语言,Demo做了三种语言库可以切换,包括资源文件的定义,实体对象属性设置,后台代码Controller,IAuthorizationFilter,HtmlHelper的实现,做法比 ...

  8. 史上最简单的springboot国际化多语言切换实现方案

    每天学习一点点 编程PDF电子书.视频教程免费下载:http://www.shitanlife.com/code 前提: 在resources目录下建立 messages_en_US.properti ...

  9. web网页多语言的实现方案_前端实现多语言切换

    实现的效果 需要在web中实现多语言的切换,当用户语言切换完成后下次重新打开网页,也是上次设置的语言进行显示. 资源网站搜索大全https://55wd.com 实现步骤 1.在用户点击切换语言后,把 ...

随机推荐

  1. Python Requests-学习笔记(11)-请求与响应对象

    任何时候调用requests.*()你都在做两件主要的事情.其一,你在构建一个 Request 对象, 该对象将被发送到某个服务器请求或查询一些资源.其二,一旦 requests 得到一个从 服务器返 ...

  2. 小程序以及H5页面上IphoneX底部安全区域小黑条适配问题

    背景 公司项目开发中,发现iPhoneX上吸底元素存在被小黑条遮挡的问题 原因 在苹果 iPhoneX .iPhone XR等机型上,物理Home键被取消,改为底部小黑条替代home键功能,从而导致吸 ...

  3. bootstrapTable随机改变列颜色

    { title: '运单编号', field: 'waybillNumber', align: 'center', valign: 'middle', cellStyle: function (val ...

  4. (转) 关于Windows CE和Windows Mobile

    转发自http://www.cnblogs.com/chump/articles/1281955.aspx 一.Windows CE Windows CE是微软的嵌入式操作系统主要的一种,面世于199 ...

  5. 简单网络编程如何用python来实现

    对于网络编程,通信模式是后台必备技能,先用最基础代码实现,理解一些 API 的含义,在深入学习. 总是有读者问过我关于 Python 后台开发相关,如果想走 Python 后台方向,对于 Python ...

  6. SDL-开篇明义

    SDL只是方法论,忌为SDL而SDL 1.sdl是什么 sdl是安全研发生命周期 ,一个方法论, 理念是安全左移, 通过各种方法.工具.流程设计和交付更安全的软件,以期望降低安全成本,最终还是为了保护 ...

  7. How Many Answers Are Wrong HDU - 3038 (经典带权并查集)

    题目大意:有一个区间,长度为n,然后跟着m个子区间,每个字区间的格式为x,y,z表示[x,y]的和为z.如果当前区间和与前面的区间和发生冲突,当前区间和会被判错,问:有多少个区间和会被判错. 题解:x ...

  8. 如何将你的 Vue.js 项目部署在云开发静态托管之上

    云开发静态托管是云开发提供的静态网站托管的能力,静态资源(HTML.CSS.JavaScript.字体等)的分发由腾讯云对象存储 COS 和拥有多个边缘网点的腾讯云 CDN 提供支持. 在云开发静态托 ...

  9. vue2.x学习笔记(十四)

    接着前面的内容:https://www.cnblogs.com/yanggb/p/12602256.html. 组件的Prop Prop是组件之间通信的一个重要途径,了解其知识十分重要. Prop的大 ...

  10. SQLyog-证书密钥

    * 用户名: + 随意填写 * 秘钥: + b70d7f66-dac2-4462-bf51-c4e9347da763 + ccbfc13e-c31d-42ce-8939-3c7e63ed5417 + ...