App内切换语言最全方案

最近在做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<Context>().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()    
}

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

  • 5
    点赞
  • 7
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

龍林1102

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值