害,乱哄哄,总要去梳理.
面对未知的所有,陌生感突突的.
甲方要求实现 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 文件,如下所示:
好了,到当初,根本的语言目录以及文件都曾经创立好了,剩下的就是会有专人负责提供对应的翻译词.
当然,我司一贯的准则是,本人入手,饥寒交迫.
提供了局部罕用的、不错的在线翻译地址,如下:
二、贴心附上过程中应用的 MMKV Utils
记得去援用 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)