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

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.06.28 19:24:52