Android使用AndroidUtilCode实现多语言
作者:TimeFine 发布时间:2023-08-28 15:25:50
一、项目中配置多语言
多语言的实现是通过AndroidUtilCode实现的,表示感谢!
项目里面有4种语言:中文,英文,德文,俄文。文件夹如下:
配置多语言的思路是:
1、判断是否为国内版本,如果为国内版本则设置为简体中文
2、 如果为国外版本,获取用户之前设置的App语言,如果用户之前有设置App语言,则设置为之前用户设置的语言;如果用户之前没有设置App语言则获取手机系统的语言。
3、判断当前手机系统的语言是否App有做语言适配,如果有适配则设置成跟手机系统一样的语言,如果没有适配则设置为英文。
二、具体实现
1、初始化PropertiesUtil和MMKV,具体代码请参考上篇博客
2、在BaseApplication中设置语言
abstract class BaseApplication : Application() {
abstract fun init()
override fun onCreate() {
super.onCreate()
init()
PropertiesUtil.init(this)
MMKV.initialize(this)
MMKVUtil.setUserId(1000L)
//设置App语言
setAppLanguage()
}
/**
* 判断是否为国内版本,如果为国内版本则设置为简体中文
* 如果为国外版本,获取用户之前设置的App语言,
* 如果用户之前有设置App语言,则设置为之前用户设置的语言
* 如果用户之前没有设置App语言则获取手机系统的语言
* 判断手机系统的语言是否App有做语言适配,如果有适配则设置成跟手机系统一样的语言
* 如果App没有对当前系统语言做适配则设置为英文
*/
private fun setAppLanguage() {
if (PropertiesUtil.isCN()) { //国内版本
LanguageUtils.applyLanguage(Locale.SIMPLIFIED_CHINESE, false)
} else {
MMKVUtil.getLanguage().also {
if (it.isNotEmpty()) {
setLanguageAndBackCountry(it)
} else {
//获取系统语言
LanguageUtils.getSystemLanguage().country.also { country ->
setLanguageAndBackCountry(country).also { value ->
//保存设置的语言
MMKVUtil.setLanguage(value)
}
}
}
}
}
}
private fun setLanguageAndBackCountry(it: String): String {
return when (it) {
LanguageType.CN.name -> {
LanguageUtils.applyLanguage(Locale.SIMPLIFIED_CHINESE, false)
it
}
LanguageType.US.name -> {
LanguageUtils.applyLanguage(Locale.ENGLISH, false)
it
}
LanguageType.DE.name -> {
LanguageUtils.applyLanguage(Locale.GERMANY, false)
it
}
LanguageType.RU.name -> {
LanguageUtils.applyLanguage(Locale("ru"), false)
it
}
else -> {
LanguageUtils.applyLanguage(Locale.ENGLISH, false)
LanguageType.US.name
}
}
}
}
3、切换语言
比如设置为德文,按钮触发:
MMKVUtil.setLanguage(LanguageType.DE.name)
LanguageUtils.applyLanguage(Locale.GERMANY, false) //true:重启App false:不重启App
4、注意gradle配置resConfigs
不要限制为只有中文,比如:resConfigs "zh-rCN", "en"
三、AndroidX和多进程存在的问题
1、多进程读取Configuration
时发现其他进程与主进程获取的Configuration
值不一致,导致主进程切换语言后其他语言并没有切换成功。
2、AndroidX切换失败的问题,具体可以看下这篇博客【踩坑记录】多语言切换在Androidx失效
解决办法:重写Activity的attachBaseContext
方法,修改Context
/**
* 多语言的切换类, 解决多进程切换语言失败的问题以及AndroidX多语言切换失效的问题
* 解决由于 WebView 初始化会修改 Activity 语种配置,间接导致 Activity 语种会被还原,所以需要你手动重写 WebView 对这个问题进行修复
*/
object MultiLanguageUtil {
fun getAttachBaseContext(context: Context): Context {
return if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.N) {
configAppcompatLanguage(setAppLanguageApi24(context))
} else {
setAppLanguage(context)
configAppcompatLanguage(context)
}
}
/**
* 设置应用语言
*/
@Suppress("DEPRECATION")
private fun setAppLanguage(context: Context) {
val resources = context.resources
val displayMetrics = resources.displayMetrics
val configuration = resources.configuration
// 获取当前系统语言,默认设置跟随系统
val locale = getLocale()
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.JELLY_BEAN_MR1) {
configuration.setLocale(locale)
} else {
configuration.locale = locale
}
resources.updateConfiguration(configuration, displayMetrics)
}
/**
* 兼容 7.0 及以上
*/
@TargetApi(Build.VERSION_CODES.N)
fun setAppLanguageApi24(context: Context): Context {
val locale = getLocale()
val resource = context.resources
val configuration = resource.configuration
configuration.setLocale(locale)
configuration.setLocales(LocaleList(locale))
return context.createConfigurationContext(configuration)
}
private fun configAppcompatLanguage(context: Context): Context {
val configuration = context.resources.configuration
//兼容appcompat 1.2.0后切换语言失效问题
return object : ContextThemeWrapper(context, R.style.Base_Theme_AppCompat_Empty) {
override fun applyOverrideConfiguration(overrideConfiguration: Configuration?) {
overrideConfiguration?.setTo(configuration)
super.applyOverrideConfiguration(overrideConfiguration)
}
}
}
private fun getLocale(): Locale {
return when (CacheUtil.getInt(GlobalConstants.LANGUAGE_KEY, true)) {
0 -> {
Locale.SIMPLIFIED_CHINESE
}
1 -> {
Locale.ENGLISH
}
2 -> {
Locale.GERMANY
}
3 -> {
Locale("ru")
}
else -> Locale.ENGLISH
}
}
/**
* 解决WebView多语言失效的问题
*/
fun updateLanguage(context: Context) {
val resources = context.resources
val config = resources.configuration
val settingLanguage = getLocale().language
val systemLanguage = config.locales[0].language
if (settingLanguage != systemLanguage) {
setLocale(config, Locale(settingLanguage))
resources.updateConfiguration(config, resources.displayMetrics)
}
}
private fun setLocale(config: Configuration, locale: Locale?) {
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.JELLY_BEAN_MR1) {
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.N) {
val localeList = LocaleList(locale)
config.setLocales(localeList)
} else {
config.setLocale(locale)
}
} else {
config.locale = locale
}
}
}
获取appContext
lateinit var appContext: Application
//BaseApplication中调用方法获取Application的上下文
fun BaseApplication.getContext(application: BaseApplication) {
appContext = application
}
四、WebView导致的语言重置的问题
由于 WebView 初始化会修改 Activity 语种配置,间接导致 Activity 语种会被还原,所以需要你手动重写 WebView 对这个问题进行修复,如下:
/**
* 由于 WebView 初始化会修改 Activity 语种配置,间接导致 Activity 语种会被还原回去,所以需要你手动重写 WebView 对这个问题进行修复
*/
class LanguagesWebView(
context: Context,
@Nullable attrs: AttributeSet?,
defStyleAttr: Int
) : WebView(context, attrs, defStyleAttr) {
constructor(context: Context) : this(context, null) {}
constructor(context: Context, @Nullable attrs: AttributeSet?) : this(
context,
attrs,
0
)
init {
//修复 WebView 初始化时会修改Activity 语种配置的问题
MultiLanguageUtil.updateLanguage(context)
}
}
项目中用这个WebView即可。这个问题在华为手机鸿蒙系统上会出现。
五、枚举类的多语言实现
枚举类型是线程安全的,并且只会装载一次,这就导致下面的写法导致枚举的err
值在切换语言后不会发生变化。
enum class Error( var code: Int, var err: String) {
/**
* 未知错误
*/
UNKNOWN(1000,appContext.getString(R.string.error_1000)),
/**
* 解析错误
*/
PARSE_ERROR(1001, appContext.getString(R.string.error_1001)),
/**
* 网络错误
*/
NETWORK_ERROR(1002, appContext.getString(R.string.error_1002)),
/**
* 证书出错
*/
SSL_ERROR(1004, appContext.getString(R.string.error_1004)),
/**
* 连接超时
*/
TIMEOUT_ERROR(1006, appContext.getString(R.string.error_1002));
fun getValue(): String {
return err
}
fun getKey(): Int {
return code
}
}
那么如果做枚举类的多语言适配呢? 代码如下:
enum class Error(private val code: Int, private val err: Int) {
/**
* 未知错误
*/
UNKNOWN(1000, R.string.error_1000),
/**
* 解析错误
*/
PARSE_ERROR(1001, R.string.error_1001),
/**
* 网络错误
*/
NETWORK_ERROR(1002, R.string.error_1002),
/**
* 证书出错
*/
SSL_ERROR(1004, R.string.error_1004),
/**
* 连接超时
*/
TIMEOUT_ERROR(1006, R.string.error_1002);
fun getValue(): String {
return appContext.getString(err)
}
fun getKey(): Int {
return code
}
}
因为字符串的id是固定的不会发生变化,所以即使枚举类只会装载一次也不会有影响,通过getValue
就能取到正确语言的字符串。
参考
【踩坑记录】多语言切换在Androidx失效
MulituLanguage
MultiLanguages
来源:https://juejin.cn/post/7173211469029474335


猜你喜欢
- 前言最近接手了一个老项目,“愉悦的心情”自然无以言表,做开发的朋友都懂,这里就不多说了,都是泪...
- 一、RESTful 简介REST 是一种软件架构风格。REST:Representational State Transfer,表现层资源状
- 做了一个项目,首页是使用ResideMenu实现,通过菜单栏里的菜单项创建的Fragment;所以一个Activtiy里就包含多个Fragm
- 解决方法有以下3种1、在Edittext中加入以下属性android:cursorVisible="true"andro
- 前言Nacos 致力于帮助您发现、配置和管理微服务。Nacos 提供了一组简单易用的特性集,帮助您快速实现动态服务发现、服务配置、服务元数据
- 一、概念哈希算法(hash algorithm):是一种将任意内容的输入转换成相同长度输出的加密方式,其输出被称为哈希值。哈希表(hash
- 下面通过一段内容有文字说明有代码分析,并附有展示图供大家学习。要解析HTTP报文,需要实现以下操作:读取HTTP报头提供的各种属性分析属性值
- 本文章向大家讲解java中时间的获取和格式化, 一. 获取当前系统时间和日期并格式化输出:import java.util.Dat
- 只要是开发和手机通讯录有关的应用,总要学会获取联系人信息,每次都google很麻烦,怎么办?写一个工具类,获取到通讯录里所有的信息并分好类,
- Form1主窗体:public delegate void SetVisiableHandler();//定义委托类型private voi
- 前言对象关系映射(ORM)已经被使用了很长时间,以解决在编程过程中对象模型与数据模型在关系数据库中不匹配的问题。Dapper是由Stack
- 本文通过实例来介绍如何使用commons-fileupload.jar,Apache的commons-fileupload.jar可方便的实
- 1.与过滤器filter的区别2.springMVC中 * 的必须实现的三个方法:3. * 类的编写:package com.imooc.
- package com.wanmei.meishu;import java.io.FileInputStream;import java.i
- 【SpringBoot】通过Feign调用传递Header中参数如何通过Feign传递Header参数问题描述我们在SpringCloud中
- 本文实例讲述了C#使用timer实现的简单闹钟程序。分享给大家供大家参考。具体如下:当我在电脑上工作,我经常会被一些东西吸引,比如某宝,结果
- 目录断言对象、数组、集合ObjectUtilsStringUtilsCollectionUtils文件、资源、IO 流FileCopyUti
- 介绍线段树(又名区间树)也是一种二叉树,每个节点的值等于左右孩子节点值的和,线段树示例图如下以求和为例,根节点表示区间0-5的和,左孩子表示
- 本文实例讲述了C#使用linq查询大数据集的方法。分享给大家供大家参考。具体如下:using System;using System.Col
- init_output_stream() 是一个公共的函数,无论是音频,还是视频的输出流的初始化,都是通过它来完成的。init_o