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

Jetpack Compose切换语言后stringResource()未加载当前locale字符串

问题说明

更新

我在Application类中注入了ChangeLanguageRepository,每次应用启动时会调用changeLanguage方法设置应用语言,实现代码如下:

class ChangeLanguageRepository @Inject constructor(@ApplicationContext private val context: Context) {

    fun changeLanguage(languageLocale: String) {
        val locale = Locale(languageLocale)
        Locale.setDefault(locale)
        val config = Configuration()
        config.locale = locale
        context.resources.updateConfiguration(config, context.resources.displayMetrics)
    }
}

我基于Jetpack Compose开发支持应用内切换语言的应用时,遇到如下问题:切换语言后,即便重启Activity甚至重启应用,所有通过stringResource()加载的字符串资源都不会更新为当前语言环境的对应内容。

应用内有一个页面通过Dagger Hilt在Repository中注入ApplicationContext来加载字符串,实现代码如下:

class HelplineRepository @Inject constructor(@ApplicationContext private val context: Context) {

    fun getHelplines(): List<Helpline> {
        val ambulance = Helpline(
            Icons.Rounded.Emergency,
            context.getString(R.string.helpline_text_ambulance),
            context.getString(R.string.helpline_text_ambulance_number)
        )

        val fireStation = Helpline(
            Icons.Rounded.LocalFireDepartment,
            context.getString(R.string.helpline_text_fire_station),
            context.getString(R.string.helpline_text_fire_station_number)
        )

        return listOf(ambulance, fireStation, policeControlRoom, womenHelpLine)
    }
}

该页面在切换语言后可以正常显示本地化字符串,但其余在Composable中通过stringResource()加载字符串的页面,都无法正确更新为当前语言环境的内容。

说明:我已经尝试过重启Activity、重启应用,也确认用户切换语言后locale确实已经被正确修改。我还在Google问题追踪平台找到了一个提及类似问题的帖子,但没有找到可行的解决方案。


问题根因

出现这个问题的核心原因有两点:

  • 你使用的context.resources.updateConfiguration()是API 25就已废弃的方法,该方法只会修改当前调用对象的Resources配置,不会同步更新应用全局所有Context的配置
  • Jetpack Compose中stringResource()依赖的LocalContext取自当前承载Compose视图的Activity,而非Application实例。你仅修改了ApplicationContext的配置,Activity层级的Context始终持有旧的Locale配置,自然无法加载对应语言的字符串。

注入ApplicationContext的Repository能正常加载新语言字符串,就是因为你之前的代码确实修改了ApplicationContext的Resources配置,和Activity层级的配置互不影响。


修复方案

1. 修正Locale设置逻辑

废弃直接修改Resources配置的写法,通过createConfigurationContext生成绑定了新Locale的Context实例,同时持久化保存用户选中的语言,保证应用重启后配置不丢失:

class ChangeLanguageRepository @Inject constructor(@ApplicationContext private val context: Context) {
    private val prefs = context.getSharedPreferences("app_config", Context.MODE_PRIVATE)

    // 获取已保存的语言配置
    fun getCurrentLocaleTag(): String {
        return prefs.getString("selected_locale", Locale.getDefault().toLanguageTag()) ?: Locale.getDefault().toLanguageTag()
    }

    // 切换语言并持久化
    fun changeLanguage(localeTag: String) {
        prefs.edit().putString("selected_locale", localeTag).apply()
        val locale = Locale.forLanguageTag(localeTag)
        Locale.setDefault(locale)
    }

    // 给基础Context绑定正确的Locale配置
    fun applyLocaleToContext(base: Context): Context {
        val locale = Locale.forLanguageTag(getCurrentLocaleTag())
        Locale.setDefault(locale)

        val config = Configuration(base.resources.configuration)
        config.setLocale(locale)
        return when {
            Build.VERSION.SDK_INT >= Build.VERSION_CODES.N -> {
                config.setLayoutDirection(locale)
                base.createConfigurationContext(config)
            }
            else -> {
                @Suppress("DEPRECATION")
                base.resources.updateConfiguration(config, base.resources.displayMetrics)
                base
            }
        }
    }
}

2. 全局注入Locale配置

需要在Application和所有Activity的attachBaseContext生命周期中,将绑定了正确Locale的Context作为baseContext传入,保证所有层级的Context都持有正确的配置:

  • 自定义Application类中重写方法:
@HiltAndroidApp
class App : Application() {
    @Inject
    lateinit var languageRepository: ChangeLanguageRepository

    override fun attachBaseContext(base: Context) {
        super.attachBaseContext(languageRepository.applyLocaleToContext(base))
    }
}
  • 抽离BaseActivity统一处理,所有承载Compose视图的Activity都继承该类:
open class BaseActivity : ComponentActivity() {
    @Inject
    lateinit var languageRepository: ChangeLanguageRepository

    override fun attachBaseContext(newBase: Context) {
        super.attachBaseContext(languageRepository.applyLocaleToContext(newBase))
    }
}

3. 运行时切换语言生效方式

用户在应用内切换语言后,直接调用当前Activity的recreate()方法重建页面即可,不需要重启应用。重建过程中attachBaseContext会自动绑定新的Locale配置,所有通过stringResource()加载的字符串都会自动更新为对应语言内容。


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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.09.03 04:18:31