You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

Android应用内语言切换失效:未添加系统语言时无法切换

Android应用内语言切换失效问题

我用以下代码实现Android应用内语言切换:当系统「添加语言」列表包含英语(en)和法语(fr)时,切换正常;但把对应语言从系统列表移除后,切换就失效了。按网上示例,无需系统添加语言也能实现应用内切换,请问哪里错了?怎么实现无需系统添加语言的应用内切换?


现有实现代码

LocalUtil.kt

object LocalUtil {

    fun applyLanguageContext(context: Context, locale: Locale?): Context {

        if (locale == null) return context
        if (locale == getLocale(context.resources.configuration)) return context
        return try {
            setupLocale(locale)
            val resources = context.resources
            val configuration = getOverridingConfig(locale, resources)
            updateResources(context, resources, configuration)
            context.createConfigurationContext(configuration)
        } catch (e: Exception) {
            e.printStackTrace()
            context
        }
    }

    private fun updateResources(
        context: Context,
        resources: Resources,
        config: Configuration
    ) {
        if (context.applicationContext !== context) {
            resources.updateConfiguration(config, resources.displayMetrics)
        }
    }

    private fun setupLocale(locale: Locale) {
        Locale.setDefault(locale)
        LocaleList.setDefault(LocaleList(locale))
    }

    private fun getOverridingConfig(locale: Locale, resources: Resources): Configuration {
        val configuration = resources.configuration
        configuration.setLocales(LocaleList(locale))
        return configuration
    }

    private fun getLocale(configuration: Configuration): Locale {
        return configuration.locales.get(0)
    }
}

MyApp.kt

class MyApp: Application() {

    override fun getApplicationContext(): Context {
        val context = super.getApplicationContext()
        return LocalUtil.applyLanguageContext(context, Locale(LANGUAGE))
    }

    override fun attachBaseContext(newBase: Context) {
        super.attachBaseContext(LocalUtil.applyLanguageContext(newBase, Locale(LANGUAGE)))
    }

    companion object {
        var LANGUAGE = "en"
    }
}

MainActivity.kt

class MainActivity : AppCompatActivity() {
    override fun onCreate(savedInstanceState: Bundle?) {
        super.onCreate(savedInstanceState)
        setContentView(R.layout.activity_main)
    }

    fun setChangeLangBtn(view: View) {
        val changeLangBtn: Button = findViewById(R.id.change_lang_btn)
        changeLangBtn.setOnClickListener {
            if (MyApp.LANGUAGE == "en") MyApp.LANGUAGE = "fr" else MyApp.LANGUAGE = "en"
            reloadActivity()
        }
    }

    fun reloadActivity() {
         val intent = Intent(this, javaClass).apply {
             addFlags(Intent.FLAG_ACTIVITY_CLEAR_TOP)
             addFlags(Intent.FLAG_ACTIVITY_NO_ANIMATION)
         }

         startActivity(intent)
         recreate()
    }

    override fun getBaseContext(): Context {
        return LocalUtil.applyLanguageContext(super.getBaseContext(), Locale(MyApp.LANGUAGE))
    }

    override fun getApplicationContext(): Context {
        val context = super.getApplicationContext()
        return LocalUtil.applyLanguageContext(context, Locale(MyApp.LANGUAGE))
    }

    override fun attachBaseContext(newBase: Context) {
        super.attachBaseContext(LocalUtil.applyLanguageContext(newBase, Locale(MyApp.LANGUAGE)))
    }
}

问题原因

  1. 系统语言过滤机制:Android 7.0+ 会自动过滤系统未安装的语言资源,导致应用无法加载对应语言的strings.xml文件。
  2. 废弃API使用:resources.updateConfiguration已被废弃,且仅修改非ApplicationContext的资源不彻底。
  3. Context处理冗余:重复重写getApplicationContext、getBaseContext会导致上下文混乱,反而影响语言切换生效。
  4. Activity重启逻辑冗余:同时调用startActivity和recreate会导致不必要的页面重建,甚至冲突。

修正方案

1. 重构LocalUtil,绕过系统语言过滤

核心是通过createConfigurationContext创建独立的上下文,强制加载指定语言资源:

object LocalUtil {
    fun applyLanguageContext(context: Context, locale: Locale?): Context {
        if (locale == null) return context
        val currentLocale = getLocale(context.resources.configuration)
        if (locale == currentLocale) return context

        return try {
            // 强制设置默认Locale
            Locale.setDefault(locale)
            // 创建包含指定Locale的配置
            val config = Configuration(context.resources.configuration).apply {
                setLocales(LocaleList(locale))
            }
            // 返回包装后的上下文,绕过系统资源过滤
            context.createConfigurationContext(config)
        } catch (e: Exception) {
            e.printStackTrace()
            context
        }
    }

    // 兼容高低版本的Locale获取
    private fun getLocale(configuration: Configuration): Locale {
        return if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.N) {
            configuration.locales[0]
        } else {
            @Suppress("DEPRECATION")
            configuration.locale
        }
    }
}

2. 简化Application和Activity的Context处理

只需要在attachBaseContext中处理语言切换,无需重写其他Context获取方法:

MyApp.kt 修改

class MyApp : Application() {
    companion object {
        var LANGUAGE = "en"
    }

    override fun attachBaseContext(newBase: Context) {
        val targetLocale = Locale(LANGUAGE)
        super.attachBaseContext(LocalUtil.applyLanguageContext(newBase, targetLocale))
    }
}

MainActivity.kt 修改

class MainActivity : AppCompatActivity() {
    override fun onCreate(savedInstanceState: Bundle?) {
        super.onCreate(savedInstanceState)
        setContentView(R.layout.activity_main)
    }

    fun setChangeLangBtn(view: View) {
        findViewById<Button>(R.id.change_lang_btn).setOnClickListener {
            MyApp.LANGUAGE = if (MyApp.LANGUAGE == "en") "fr" else "en"
            // 仅调用recreate即可完成页面重建
            recreate()
        }
    }

    override fun attachBaseContext(newBase: Context) {
        val targetLocale = Locale(MyApp.LANGUAGE)
        super.attachBaseContext(LocalUtil.applyLanguageContext(newBase, targetLocale))
    }
}

3. 确保资源文件存在

在res目录下创建对应语言的资源文件夹,确保包含对应语言的字符串:

  • values-en/strings.xml(英语资源)
  • values-fr/strings.xml(法语资源)

关键说明

  • Android 7.0+ 系统的语言过滤机制会忽略系统未安装的语言,通过createConfigurationContext创建的上下文可以绕过此限制,直接加载应用内的语言资源。
  • 不要使用废弃的resources.updateConfiguration方法,改用createConfigurationContext是官方推荐的正确方式。
  • 仅在attachBaseContext中处理语言切换即可,避免重写其他Context方法导致的上下文不一致问题。

内容的提问来源于stack exchange,提问作者PhilBlais

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.08.18 20:20:18