Android应用多语言切换异常:布局方向变但未加载对应语言字符串
Android多语言切换:布局方向生效但字符串未加载目标语言资源
我使用GitHub上的LocaleHelper工具(代码如下)配合自定义代码实现Android应用多语言切换,已重建Activity。当前系统Locale与布局方向已成功切换,但应用字符串仍取自默认的string.xml,未加载目标语言的资源文件,期望正常显示所选语言的文本。
package com.zeugmasolutions.localehelper import android.annotation.SuppressLint import android.app.Application import android.content.Context import android.content.SharedPreferences import android.os.Build import java.util.Locale object LocaleHelper { private const val SELECTED_LANGUAGE = "Locale.Helper.Selected.Language" private const val SELECTED_COUNTRY = "Locale.Helper.Selected.Country" private var initialized = false /** * Returns the system [Locale] */ @SuppressLint("ConstantLocale") val systemLocale: Locale = Locale.getDefault() /** * Attach the selected or default [Locale] to the [context] */ fun onAttach(context: Context): Context { if (!initialized) { Locale.setDefault(load(context)) initialized = true } return updateContextResources(context, Locale.getDefault()) } /** * Gets the currently saved [Locale] from [SharedPreferences] or returns [Locale.getDefault] */ fun getLocale(context: Context): Locale = load(context) /** * Sets [locale] for [context] and persist the selection in [SharedPreferences] */ fun setLocale(context: Context, locale: Locale): Context { persist(context, locale) Locale.setDefault(locale) return updateContextResources(context, locale) } /** * Returns if the given [locale] is a Right-To-Left language */ fun isRTL(locale: Locale): Boolean = Locales.RTL.contains(locale.language) private fun getPreferences(context: Context): SharedPreferences = context.getSharedPreferences(LocaleHelper::class.java.name, Context.MODE_PRIVATE) private fun persist(context: Context, locale: Locale?) { if (locale == null) return getPreferences(context).edit() .putString(SELECTED_LANGUAGE, locale.language) .putString(SELECTED_COUNTRY, locale.country) .apply() } private fun load(context: Context): Locale { val preferences = getPreferences(context) val default = Locale.getDefault() val language = preferences.getString(SELECTED_LANGUAGE, default.language) ?: return default val country = preferences.getString(SELECTED_COUNTRY, default.country) ?: return default return Locale(language, country) } private fun updateContextResources(context: Context, locale: Locale): Context { if (context.currentLocale == locale && context is Application) { return context } val resources = context.resources val configuration = resources.configuration configuration.setCurrentLocale(locale) if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.JELLY_BEAN_MR1) { configuration.setLayoutDirection(locale) } return if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.N) { context.createConfigurationContext(configuration) } else { @Suppress("DEPRECATION") resources.updateConfiguration(configuration, resources.displayMetrics) context } } }
问题排查与解决方案
1. 检查资源文件命名规范
确认目标语言的资源文件夹命名完全符合Android要求:
- 简体中文:
values-zh-rCN - 英文:
values-en - 日文:
values-ja-rJP
不要出现拼写错误(比如values-zh_CN或values-zh),否则系统无法识别并加载对应资源。
2. 确保Activity正确覆盖attachBaseContext
在所有需要切换语言的Activity中,必须重写attachBaseContext方法,使用LocaleHelper处理后的Context:
override fun attachBaseContext(newBase: Context?) { super.attachBaseContext(LocaleHelper.onAttach(newBase ?: return)) }
这一步是确保Activity的资源加载使用正确Locale的核心。
3. 补全setCurrentLocale扩展函数的正确实现
LocaleHelper中调用的configuration.setCurrentLocale(locale)是自定义扩展函数,需确认其实现是否正确(Android SDK无此原生方法),正确实现如下:
import android.content.res.Configuration import android.os.Build import java.util.Locale fun Configuration.setCurrentLocale(locale: Locale) { if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.N) { this.setLocale(locale) this.locales = LocaleList(locale) } else { @Suppress("DEPRECATION") this.setLocale(locale) } }
如果该函数实现缺失或错误,会导致Locale无法被正确注入到Configuration中,资源加载仍使用默认Locale。
4. 处理Application级别的Context
自定义Application类时,同样需要重写attachBaseContext,确保全局Context的Locale正确:
class MyApplication : Application() { override fun attachBaseContext(base: Context?) { super.attachBaseContext(LocaleHelper.onAttach(base ?: return)) } }
5. 切换语言后的重启逻辑
切换语言时,需确保调用setLocale后正确重启Activity,且不使用缓存的Context:
// 示例:切换到简体中文 val targetLocale = Locale("zh", "CN") LocaleHelper.setLocale(this, targetLocale) // 重启当前Activity val intent = Intent(this, javaClass) intent.addFlags(Intent.FLAG_ACTIVITY_CLEAR_TOP or Intent.FLAG_ACTIVITY_NEW_TASK) startActivity(intent) finish()
6. 禁用Instant Run测试
Instant Run会缓存资源文件,导致新语言资源无法及时加载。测试时需关闭Instant Run,或完全卸载应用后重新安装调试。
内容的提问来源于stack exchange,提问作者Hamza Bhatti
相关产品推荐
相关产品推荐

