日本免费高清视频-国产福利视频导航-黄色在线播放国产-天天操天天操天天操天天操|www.shdianci.com

學無先后,達者為師

網站首頁 編程語言 正文

Android使用AndroidUtilCode實現多語言_Android

作者:TimeFine ? 更新時間: 2023-03-01 編程語言

一、項目中配置多語言

多語言的實現是通過AndroidUtilCode實現的,表示感謝!

項目里面有4種語言:中文,英文,德文,俄文。文件夾如下:

配置多語言的思路是:

1、判斷是否為國內版本,如果為國內版本則設置為簡體中文

2、 如果為國外版本,獲取用戶之前設置的App語言,如果用戶之前有設置App語言,則設置為之前用戶設置的語言;如果用戶之前沒有設置App語言則獲取手機系統的語言。

3、判斷當前手機系統的語言是否App有做語言適配,如果有適配則設置成跟手機系統一樣的語言,如果沒有適配則設置為英文。

二、具體實現

1、初始化PropertiesUtil和MMKV,具體代碼請參考上篇博客

2、在BaseApplication中設置語言

abstract class BaseApplication : Application() {
    abstract fun init()
    override fun onCreate() {
        super.onCreate()
        init()
        PropertiesUtil.init(this)
        MMKV.initialize(this)
        MMKVUtil.setUserId(1000L)
        //設置App語言
        setAppLanguage()
    }
    /**
     * 判斷是否為國內版本,如果為國內版本則設置為簡體中文
     * 如果為國外版本,獲取用戶之前設置的App語言,
     * 如果用戶之前有設置App語言,則設置為之前用戶設置的語言
     * 如果用戶之前沒有設置App語言則獲取手機系統的語言
     * 判斷手機系統的語言是否App有做語言適配,如果有適配則設置成跟手機系統一樣的語言
     * 如果App沒有對當前系統語言做適配則設置為英文
     */
    private fun setAppLanguage() {
        if (PropertiesUtil.isCN()) {   //國內版本
            LanguageUtils.applyLanguage(Locale.SIMPLIFIED_CHINESE, false)
        } else {
            MMKVUtil.getLanguage().also {
                if (it.isNotEmpty()) {
                    setLanguageAndBackCountry(it)
                } else {
                    //獲取系統語言
                    LanguageUtils.getSystemLanguage().country.also { country ->
                        setLanguageAndBackCountry(country).also { value ->
                            //保存設置的語言
                            MMKVUtil.setLanguage(value)
                        }
                    }
                }
            }
        }
    }
    private fun setLanguageAndBackCountry(it: String): String {
        return when (it) {
            LanguageType.CN.name -> {
                LanguageUtils.applyLanguage(Locale.SIMPLIFIED_CHINESE, false)
                it
            }
            LanguageType.US.name -> {
                LanguageUtils.applyLanguage(Locale.ENGLISH, false)
                it
            }
            LanguageType.DE.name -> {
                LanguageUtils.applyLanguage(Locale.GERMANY, false)
                it
            }
            LanguageType.RU.name -> {
                LanguageUtils.applyLanguage(Locale("ru"), false)
                it
            }
            else -> {
                LanguageUtils.applyLanguage(Locale.ENGLISH, false)
                LanguageType.US.name
            }
        }
    }
}

3、切換語言

比如設置為德文,按鈕觸發:

MMKVUtil.setLanguage(LanguageType.DE.name)
LanguageUtils.applyLanguage(Locale.GERMANY, false)  //true:重啟App false:不重啟App

4、注意gradle配置resConfigs不要限制為只有中文,比如:resConfigs "zh-rCN", "en"

三、AndroidX和多進程存在的問題

1、多進程讀取Configuration時發現其他進程與主進程獲取的Configuration值不一致,導致主進程切換語言后其他語言并沒有切換成功。

2、AndroidX切換失敗的問題,具體可以看下這篇博客【踩坑記錄】多語言切換在Androidx失效

解決辦法:重寫Activity的attachBaseContext方法,修改Context

/**
 * 多語言的切換類, 解決多進程切換語言失敗的問題以及AndroidX多語言切換失效的問題
 * 解決由于 WebView 初始化會修改 Activity 語種配置,間接導致 Activity 語種會被還原,所以需要你手動重寫 WebView 對這個問題進行修復
 */
object MultiLanguageUtil {
    fun getAttachBaseContext(context: Context): Context {
        return if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.N) {
            configAppcompatLanguage(setAppLanguageApi24(context))
        } else {
            setAppLanguage(context)
            configAppcompatLanguage(context)
        }
    }
    /**
     * 設置應用語言
     */
    @Suppress("DEPRECATION")
    private fun setAppLanguage(context: Context) {
        val resources = context.resources
        val displayMetrics = resources.displayMetrics
        val configuration = resources.configuration
        // 獲取當前系統語言,默認設置跟隨系統
        val locale = getLocale()
        if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.JELLY_BEAN_MR1) {
            configuration.setLocale(locale)
        } else {
            configuration.locale = locale
        }
        resources.updateConfiguration(configuration, displayMetrics)
    }
    /**
     * 兼容 7.0 及以上
     */
    @TargetApi(Build.VERSION_CODES.N)
    fun setAppLanguageApi24(context: Context): Context {
        val locale = getLocale()
        val resource = context.resources
        val configuration = resource.configuration
        configuration.setLocale(locale)
        configuration.setLocales(LocaleList(locale))
        return context.createConfigurationContext(configuration)
    }
    private fun configAppcompatLanguage(context: Context): Context {
        val configuration = context.resources.configuration
        //兼容appcompat 1.2.0后切換語言失效問題
        return object : ContextThemeWrapper(context, R.style.Base_Theme_AppCompat_Empty) {
            override fun applyOverrideConfiguration(overrideConfiguration: Configuration?) {
                overrideConfiguration?.setTo(configuration)
                super.applyOverrideConfiguration(overrideConfiguration)
            }
        }
    }
    private fun getLocale(): Locale {
        return when (CacheUtil.getInt(GlobalConstants.LANGUAGE_KEY, true)) {
            0 -> {
                Locale.SIMPLIFIED_CHINESE
            }
            1 -> {
                Locale.ENGLISH
            }
            2 -> {
                Locale.GERMANY
            }
            3 -> {
                Locale("ru")
            }
            else -> Locale.ENGLISH
        }
    }
    /**
     * 解決WebView多語言失效的問題
     */
    fun updateLanguage(context: Context) {
        val resources = context.resources
        val config = resources.configuration
        val settingLanguage = getLocale().language
        val systemLanguage = config.locales[0].language
        if (settingLanguage != systemLanguage) {
            setLocale(config, Locale(settingLanguage))
            resources.updateConfiguration(config, resources.displayMetrics)
        }
    }
    private fun setLocale(config: Configuration, locale: Locale?) {
        if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.JELLY_BEAN_MR1) {
            if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.N) {
                val localeList = LocaleList(locale)
                config.setLocales(localeList)
            } else {
                config.setLocale(locale)
            }
        } else {
            config.locale = locale
        }
    }
}

獲取appContext

lateinit var appContext: Application
//BaseApplication中調用方法獲取Application的上下文
fun BaseApplication.getContext(application: BaseApplication) {
    appContext = application
}

四、WebView導致的語言重置的問題

由于 WebView 初始化會修改 Activity 語種配置,間接導致 Activity 語種會被還原,所以需要你手動重寫 WebView 對這個問題進行修復,如下:

/**
 * 由于 WebView 初始化會修改 Activity 語種配置,間接導致 Activity 語種會被還原回去,所以需要你手動重寫 WebView 對這個問題進行修復
 */
class LanguagesWebView(
    context: Context,
    @Nullable attrs: AttributeSet?,
    defStyleAttr: Int
) : WebView(context, attrs, defStyleAttr) {
    constructor(context: Context) : this(context, null) {}
    constructor(context: Context, @Nullable attrs: AttributeSet?) : this(
        context,
        attrs,
        0
    )
    init {
        //修復 WebView 初始化時會修改Activity 語種配置的問題
        MultiLanguageUtil.updateLanguage(context)
    }
}

項目中用這個WebView即可。這個問題在華為手機鴻蒙系統上會出現。

五、枚舉類的多語言實現

枚舉類型是線程安全的,并且只會裝載一次,這就導致下面的寫法導致枚舉的err值在切換語言后不會發生變化。

enum class Error( var code: Int,  var err: String) {
    /**
     * 未知錯誤
     */
    UNKNOWN(1000,appContext.getString(R.string.error_1000)),
    /**
     * 解析錯誤
     */
    PARSE_ERROR(1001, appContext.getString(R.string.error_1001)),
    /**
     * 網絡錯誤
     */
    NETWORK_ERROR(1002, appContext.getString(R.string.error_1002)),
    /**
     * 證書出錯
     */
    SSL_ERROR(1004, appContext.getString(R.string.error_1004)),
    /**
     * 連接超時
     */
    TIMEOUT_ERROR(1006, appContext.getString(R.string.error_1002));
    fun getValue(): String {
        return err
    }
    fun getKey(): Int {
        return code
    }
}

那么如果做枚舉類的多語言適配呢? 代碼如下:

enum class Error(private val code: Int, private val err: Int) {
    /**
     * 未知錯誤
     */
    UNKNOWN(1000, R.string.error_1000),
    /**
     * 解析錯誤
     */
    PARSE_ERROR(1001, R.string.error_1001),
    /**
     * 網絡錯誤
     */
    NETWORK_ERROR(1002, R.string.error_1002),
    /**
     * 證書出錯
     */
    SSL_ERROR(1004, R.string.error_1004),
    /**
     * 連接超時
     */
    TIMEOUT_ERROR(1006, R.string.error_1002);
    fun getValue(): String {
        return appContext.getString(err)
    }
    fun getKey(): Int {
        return code
    }
}

因為字符串的id是固定的不會發生變化,所以即使枚舉類只會裝載一次也不會有影響,通過getValue就能取到正確語言的字符串。

參考

【踩坑記錄】多語言切換在Androidx失效

MulituLanguage

MultiLanguages

原文鏈接:https://juejin.cn/post/7173211469029474335

欄目分類
最近更新