乐趣区

关于android:Android-国际化之多语言适配小记

害, 乱哄哄, 总要去梳理.

面对未知的所有, 陌生感突突的.

甲方要求实现 App 国际化多语言, 正好抽个工夫弄了下, 害, 被本人蠢到死, 特意记录下.

如有不对, 欢送斧正, 一起交换~

成果演示

视频录制的不是太好, 整体的成果进去了, 大家见谅~

版本为别为: 6.0、8.0 以及 10.0

搞起来

简略说下须要留神的:

  • 国际化, 多语言目录创立, 资源配置;
  • Locale 资源获取以及本地缓存, 缓存的目标是为了下次从新关上 App 仍然是上次抉择的语言;
  • Android 零碎间不同的差别, 例如 7.0 后不再是惟一默认语言, 而是多种语言配置, 具体差异如下所示:

好啦, 间接上码~

网上看到大家再探讨这个 androidx 包下 appcompat 问题, 这里也把我应用的版本贴出来:

  • implementation ‘androidx.appcompat:appcompat:1.2.0’

一、创立对应的资源文件

形式有两种. 如下:

  • 形式一:

右键「res」, 抉择「New」,「Android Resource File」:

按如下图进行抉择配置语言表:

  • 形式二:

Android Studio 左侧抉择「Resource Manager」, 随后抉择小地图 + 的标记, 最初在列表中抉择对应兼容的国家即可.

随后会为咱们创立抉择的国家的 values 目录以及 strings 文件, 如下所示:

好了, 到当初, 根本的语言目录以及文件都曾经创立好了, 剩下的就是会有专人负责提供对应的翻译词.

当然, 我司一贯的准则是, 本人入手, 饥寒交迫.

提供了局部罕用的、不错的在线翻译地址, 如下:

  • https://www.deepl.com/translator
  • https://translate.google.cn/

二、贴心附上过程中应用的 MMKV Utils

记得去援用 MMKV 依赖以及初始化, 地址如下:

  • https://github.com/Tencent/MMKV

集体应用的版本如下:

  • implementation ‘com.tencent:mmkv:1.0.17’
/**
 * @author:HLQ_Struggle
 * @date:2020/4/13
 * @desc:根底数据缓存
 */

class MMKVPro<T>(
    private val mmkv: MMKV,
    private val key: String,
    private val defValue: T
) {operator fun getValue(thisRef: Any?, property: KProperty<*>): T {
        // 本地加密存储并反对多过程拜访
        return mmkv.run {when (defValue) {is String -> getString(key, defValue)
                is Boolean -> getBoolean(key, defValue)
                is Long -> getLong(key, defValue)
                is Int -> getInt(key, defValue)
                is Float -> getFloat(key, defValue)
                else -> Unit
            }
        } as T
    }

    operator fun setValue(thisRef: Any?, property: KProperty<*>, value: T) {
        return mmkv.run {when (value) {is String -> putString(key, value)
                is Boolean -> putBoolean(key, value)
                is Long -> putLong(key, value)
                is Int -> putInt(key, value)
                is Float -> putFloat(key, value)
                else -> Unit
            }
        }
    }

}

/**
 * 移除 key
 */
fun removeKey(key: String) {MMKV.mmkvWithID(F_APP_CACHE, MMKV.MULTI_PROCESS_MODE, K_ENCRYPT).run {remove(key)
    }
}

三、筹备多语言 utils

/**
 * @author HLQ_Struggle
 * @date 2021/02/26
 * @desc
 */

/**
 * Activity 更新语言资源
 */
fun getAttachBaseContext(context: Context): Context {if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.N) {return setAppLanguageApi24(context)
    } else {setAppLanguage(context)
    }
    return context
}

/**
 * 设置利用语言
 */
@Suppress("DEPRECATION")
fun setAppLanguage(context: Context) {
    val resources = context.resources
    val displayMetrics = resources.displayMetrics
    val configuration = resources.configuration
    // 获取以后零碎语言,默认设置追随零碎
    val locale = getAppLocale()
    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)
private fun setAppLanguageApi24(context: Context): Context {val locale = getAppLocale()
    val resource = context.resources
    val configuration = resource.configuration
    configuration.setLocale(locale)
    configuration.setLocales(LocaleList(locale))
    return context.createConfigurationContext(configuration)
}

/**
 * 获取 App 以后语言
 */
private fun getAppLocale() = when (LocalDataStorage().multilingual) {
    0 -> { // 追随零碎
        getSystemLocale()}
    1 -> { // 中文
        Locale.CHINA
    }
    2 -> { // 英文
        Locale.ENGLISH
    }
    else -> Locale.ENGLISH
}

/**
 * 获取以后零碎语言,如未蕴含则默认英文
 */
private fun getSystemLocale(): Locale {val systemLocale = if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.N) {LocaleList.getDefault()[0]
    } else {Locale.getDefault()
    }
    return when (systemLocale.language) {
        Locale.CHINA.language -> {Locale.CHINA}
        Locale.ENGLISH.language -> {Locale.ENGLISH}
        else -> {Locale.ENGLISH}
    }
}

四、在抉择多语言页面进行解决

当然这里我的思路是, 本地缓存语言列表索引, 而后后续依据 id 间接获取对应的语言即可.

点击确认时, 进行缓存以后抉择的

override fun onClick(v: View?) {when (v?.id) {
        R.id.tvDone -> {
            // 更新抉择状态
            LocalDataStorage().multilingual = mAfterPosition
            setAppLanguage(this)
            reStartActivity()}
    }
}

private fun reStartActivity() {val intent = Intent(mSelfActivity, MainActivity::class.java)
    intent.flags = FLAG_ACTIVITY_NEW_TASK or Intent.FLAG_ACTIVITY_CLEAR_TASK
    startActivity(intent)
    // 勾销其专场动画
    overridePendingTransition(0, 0)
}

五、Application 中 Configuration 解决

override fun onConfigurationChanged(newConfig: Configuration?) {super.onConfigurationChanged(newConfig)
    // ...
    setAppLanguage(this)
}

六、BaseActivity 解决

因为须要重建 Activity 去解决对应资源, 所以这里集体是把它放在 BaseActivity 中去解决:

override fun attachBaseContext(newBase: Context?) {super.attachBaseContext(newBase?.let { getAttachBaseContext(it) })
}

七、优化项, 资源文件更新

大家千万记得更新这个, 如果做过 Apk 大小优化, 八成都会限度 resConfigs 内容, 防止打包时多处一些无用内容减少 Apk 大小.
大家千万记得更新这个, 如果做过 Apk 大小优化, 八成都会限度 resConfigs 内容, 防止打包时多处一些无用内容减少 Apk 大小.
大家千万记得更新这个, 如果做过 Apk 大小优化, 八成都会限度 resConfigs 内容, 防止打包时多处一些无用内容减少 Apk 大小.

我就是写完之后, 怎么也不出成果, 起初一看, 好家伙, 限度只有中文. 过后的难堪、无奈 …

resConfigs "zh-rCN", "en"

好了, 到此结束, 当然,Android 不得不面对的多机型适配 …

这里后续遇到在更新把~

多语言遇到的一些问题

1. 布局问题

这个确实让人蛮头疼的, 尤其对于咱们基建不残缺的状况, 能做的只能说是保障大部分的成果, 尽量应用短称英文或者非中文.

同时这个也揭示我, 如何在开发的过程中尽可能兼容后续呢?

可能也是教训把, 缓缓致力.

2.TabLayout 英文模式下大写

切换后成果如下:

目前应用的 TabLayout 版本如下:

  • implementation ‘com.google.android.material:material:1.2.1’

喏, 设置个款式就好:

<style name="TabLayoutTextStyle" parent="TextAppearance.Design.Tab">
    <item name="android:textSize">@dimen/sp_18</item>
    <item name="textAllCaps">false</item>
</style>

后续遇到再补充吧.

参考资料

  • 本地化您的利用
  • Unicode 和国际化反对
  • 语言和语言区域解析概览
  • Android(国际化)多语言的实现和切换
  • Android 多语言切换(兼容安卓 9、10)
退出移动版