Android原生多语言切换方案,兼容Android10
前言
一个应用若需要国际化,至少需要支持中文和英语这两种语言,而同时随着谷歌的系统的更新,安卓系统可以设置当前语言的首选语言。因此,本文立足于此,多语言的切换方案为: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的更多相关文章
- Android应用内语言切换实现(转)
使用Java反射机制 IActivityManager与ActivityManagerNative都是非公开类,使用Java反射去调用其中的方法. 第一步.使用Android开放的api更改Confi ...
- Android 应用内多语言切换
最近公司的 App 里需要用到多语言切换,简单来说,就是如果用户没有选择语言选项时,App 默认跟随系统语言,如果用户在 App 内进行了语言设置,那么就使用用户设置的语言.当然,你会发现,App 的 ...
- Android app应用多语言切换功能实现
最近在做一个多语言切换的功能,类似于微信的语言切换,搜了下资料基本上都是以下这种: 1. 实现的效果 和微信类似,在设置界面打开切换语言的界面,选择语言后重启 HomeActivity,语言切换完成, ...
- 【转】Android 语言切换过程分析
最近在看一个bug,系统切换语言后,本来退到后台的音乐,会在通知栏上显示通知.为了解决这个bug,我学习了下android的语言切换流程,也参考了大量其他人的资料.(主要参考了http://blog. ...
- android 语言切换过程分析
android 语言切换过程分析 2014-02-27 18:13 1207人阅读 评论(0) 收藏 举报 语言切换android语言切换android改变语言 最近在看一个bug,系统切换语言后,本 ...
- 【Android 多语言切换简单实例分享】
一.Android多语言切换 Android应用的开发不可能仅仅针对某一个国家或者区域使用,各国间语言文化各不同样,因此一个优秀的APP必须支持多种语言,为了实现这个特性,Android给出了一个解决 ...
- ASP.NET MVC5多语言切换快速实现方案
功能 实现动态切换语言,Demo做了三种语言库可以切换,包括资源文件的定义,实体对象属性设置,后台代码Controller,IAuthorizationFilter,HtmlHelper的实现,做法比 ...
- 史上最简单的springboot国际化多语言切换实现方案
每天学习一点点 编程PDF电子书.视频教程免费下载:http://www.shitanlife.com/code 前提: 在resources目录下建立 messages_en_US.properti ...
- web网页多语言的实现方案_前端实现多语言切换
实现的效果 需要在web中实现多语言的切换,当用户语言切换完成后下次重新打开网页,也是上次设置的语言进行显示. 资源网站搜索大全https://55wd.com 实现步骤 1.在用户点击切换语言后,把 ...
随机推荐
- 【Selenium05篇】python+selenium实现Web自动化:读取ini配置文件,元素封装,代码封装,异常处理,兼容多浏览器执行
一.前言 最近问我自动化的人确实有点多,个人突发奇想:想从0开始讲解python+selenium实现Web自动化测试,请关注博客持续更新! 这是python+selenium实现Web自动化第五篇博 ...
- 第十节:xml、re、logging模块
XML模块:(用到的时候再看)tree=xml.parse('xmltest.xml')root= tree.getroot()print(root.tag) 打印对象的标签root.attrib 获 ...
- 基于 HTML5 WebGL 的高炉炼铁厂可视化系统
前言 在当今 工业4.0 新时代的推动下,不仅迎来了 工业互联网 的发展,还开启了 5G 时代的新次元.而伴随着带宽的提升,网络信息飞速发展,能源管控上与实时预警在工业互联网中也占着举足轻 ...
- 5. iphone 的:active样式
如果给按钮定义 :hover 样式,在 iPhone 上按钮点击一次是 hover 态,再点击一次 hover 态才会消失,这不是我们想要的,继而想通过定义 :active 样式来实现按钮按下时的效果 ...
- NGINX 类漏洞 整理记录
简单介绍NGINX: Nginx是一款轻量级的Web 服务器/反向代理服务器及电子邮件(IMAP/POP3)代理服务器,在BSD-like 协议下发行. 其特点是占有内存少,并发能力强,nginx的并 ...
- python调用word2vec工具包安装和使用指南
python调用word2vec工具包安装和使用指南 word2vec python-toolkit installation and use tutorial 本文选译自英文版,代码注释均摘自本文, ...
- python函数-易错知识点
定义函数: def greet_users(names): #names是形参 """Print a simple greeting to each user in th ...
- 初探Redis-基础类型String
Redis存在五种基础类型:字符串(String).队列(List).哈希(Hash).集合(Set).有序集合(Sorted Set).String的出镜率算是最高的.本次列举出String的常用操 ...
- 类内部装饰器的使用:property、classmethod与staticmethod
1.property property是一种特殊的属性,可实现把函数名变为属性名使用.它可以在不改变类接口的前提下使用存取方法 (即读值和取值) 来修改数据的属性,property类有3个方法gett ...
- C#线程学习笔记
本笔记摘抄自:https://www.cnblogs.com/zhili/archive/2012/07/18/Thread.html,记录一下学习,方便后面资料查找 一.线程的介绍 进程(Proce ...