Android应用内语言切换与问题解决策略

Android应用内语言切换与问题解决策略

最近在做App内切换语言的功能,不光需要切换成指定的语言,还提供跟随系统选项,并且app内全局生效,踩了很多坑,于是做了今天的总结;

参考:

https://juliensalvi.medium.com/demystifying-locale-on-android-95450adf5aec

android实现多语言填坑之路 - 简书

场景:

假设需要实现app内切换语言需求, 当前我们app内已经内置了三种语言, 中文(zh),英文(en),阿拉伯(ar); 设置页面有切换语言选项, 选择有 中文,英文,阿拉伯文,跟随系统;

踩过的坑:

1. 打开WebView后回到主界面,会造成部分不生效

2. 设置App语言之后,部分不生效,比如动态代码中生效,xml中定义的字符串不生效

3. 三方sdk中的activity不生效

4. 切换系统语言后,会影响app的部分语言显示

最终实现方案:

1. 实现点击切换语言逻辑

/**

* 点击切换语言

* languageCode = en/zh/ar

* SAVED_BASE_LANGUAGE 为定义的SharePreference的key

**/

btn_change?.setOnClickListener{

//保存当前设置的语言标识

PrefUtils.putString(SAVED_BASE_LANGUAGE, languageCode)

//切换app内语言

LanguageManager.changeLanguageGlobal()

//业务调整, 这里是可选,里面可以做一些语言切换后的逻辑,比如某些接口要重新刷新等等;

onLanguageChanged()

//重启app

restartApp()

}

//切换app内语言

fun changeLanguageGlobal() {

//获取app内所有activity,service,Application

var contextList = arrayListOf().apply {

addAll(AppUtil.activeActivitys)

addAll(AppUtil.activeServices)

add(AppUtil.getAppContext())

}

if (contextList.isEmpty())) return

//重置WebView语言设置

WebView(contextList[0]).destroy()

//设置语言

val language = PrefUtils.getString(SAVED_BASE_LANGUAGE)

val locale = if (!language.isStrictEmpty()) Locale(language) else getSystemLocale()

list.forEach {

if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.N) {

val resource = context.resources

val configuration = resource.configuration

configuration.setLocale(local)

configuration.setLocales(LocaleList(local))

val displayMetrics = resource.displayMetrics

resource.updateConfiguration(configuration,displayMetrics)

context.createConfigurationContext(configuration)

} else {

Locale.setDefault(local)

val resources = context.resources

val displayMetrics = resources.displayMetrics

val configuration = resources.configuration

// 获取当前系统语言,默认设置跟随系统

configuration.setLocale(local)

resources.updateConfiguration(configuration, displayMetrics)

}

}

}

/**

* 获取系统当前设置的语言

*/

fun getSystemLocale(): Locale {

var currentLocale = if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.N) {

val locales = Resources.getSystem().configuration.locales

if (locales.isEmpty) {

Locale.getDefault()

} else {

locales[0]

}

} else {

Resources.getSystem().configuration.locale

}

return currentLocale

}

AppUtil这里保存了所有的activity和service以及application的context,都可以在对应的生命周期onCreate中添加到列表,并在onDestroy时移除

//重启App

fun restartApp() {

activity?.let {

val intent = Intent(context, it.javaClass)

intent.flags = Intent.FLAG_ACTIVITY_NEW_TASK or Intent.FLAG_ACTIVITY_CLEAR_TASK

startActivity(intent)

}

此种重启activity方式会回到主界面, 如果不想跳页面可以使用 ActivityCompat.recreate(requireActivity()), 但是部分场景不生效

2. App重启后设置

Application启动

override fun onCreate() {

LanguageManager.changeLanguageGlobal()

}

//这里必须,因为如果设置了跟随系统, 当系统语言改变,但未重启app时,这里就会起作用

override fun onConfigurationChanged(newConfig: Configuration) {

super.onConfigurationChanged(newConfig)

LanguageManager.changeLanguageGlobal()

}

Activity启动

override fun onCreate() {

super.onCreate()

LanguageManager.changeLanguageGlobal()

}

override fun onResume() {

super.onResume()

LanguageManager.changeLanguageGlobal()

}

通过实践,基本可实现全部场景的语言切换功能

风雨相关