前言

一个应用若需要国际化,至少需要支持中文和英语这两种语言,而同时随着谷歌的系统的更新,安卓系统可以设置当前语言的首选语言。因此,本文立足于此,多语言的切换方案为: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. JAVA+HttpServletRequest文件上传

    public Result fileUp(HttpServletRequest request) { RowsVo vo = new RowsVo(); MultipartHttpServletReq ...

  2. AJ学IOS 之CoreLocation地理编码小Demo输入城市得到经纬度

    AJ分享,必须精品 一:效果 输入地名,可以得到相应的经纬度,知识为了学习写的小Demo 二:实现步骤 一 :首先获取用户输入的位置. 二 :创建地理编码对象. 三 :利用地理编码对象编码,根据传入的 ...

  3. webWMS开发过程记录(四)- 整体设计

    分层 View(Servlet/Action/JSP)--> Service(接口/实现类) --> Dao(接口/实现类) 所用技术 Struts2 Hibernate Spring J ...

  4. O - Navigation System CodeForces - 1321D

    题目大意:有一个导航系统,会根据你当前的位置,规划到目的地的最短路线,给你一个有向图,和一条行驶路径,问你导航重新规划路径的最大次数和最小次数. 读题的时候题意特别不理解,何为最大次数,何为最小次数? ...

  5. c++类初始化列表初探

    目录 1 初始化和赋值 1.1 结论 2 构造函数初始化列表 2.1 结论 3 必须使用初始化列表的情况 3.1 结论 4 成员初始化顺序 5 参考资料 1 初始化和赋值 初始化:创建一个对象并赋予一 ...

  6. 功能测试--聊天功能测试&微信聊天

    微信聊天功能测试 发送对象 普通用户.公众号.群.其他特殊主体 衍生功能 转发.语音转文字.删除等 消息发送 单聊.群聊.语音.文字.图片.表情.链接.字符及长度 消息管理 发布通知.接受通知.发文件 ...

  7. Centos8安装Docker提示:package docker-ce-3:19.03.8-3.el7.x86_64 requires containerd.io >= 1.2.2-3, but none of the providers can be installed

    Centos8安装Docker提示:package docker-ce-3:19.03.8-3.el7.x86_64 requires containerd.io >= 1.2.2-3, but ...

  8. CSS躬行记(7)——合成

    在图形编辑软件中,可以按特定地方式处理不同图层的合成,最新的CSS规范也引入了该功能,并提供了mix-blend-mode和background-blend-mode两个属性.混合模式(blendin ...

  9. PHP open_basedir配置未包含upload_tmp_dir 导致服务器不能上传文件

    在做一个上传图片的功能时候发现后台接收到的$_FILES['file']['error'] = 6,这个错误意思是找不到临时文件,或者是临时文件夹无权限,需要更改php.ini文件的 upload_t ...

  10. php token验证范例

    <?php $module = $_GET['module']; $action = $_GET['action']; $token = md5sum($module.date('Y-m-d', ...