Harm, mess, always sort out.
Facing the unknown, the sense of strangeness was sudden.
Party A requested the realization of App internationalization and multilingualism, and it took a time to get it.
If there is something wrong, please correct me and communicate together~
Effect demonstration
The video recording is not very good, the overall effect is out, everyone forgive me~
The version is: 6.0, 8.0 and 10.0
Get it up
Simply talk about the things that need to be noted:
- Internationalization, multilingual catalog creation, resource configuration;
- Locale resource acquisition and local caching, the purpose of caching is to reopen the App next time and still be the last selected language;
- The differences between Android systems, for example, after 7.0, it is no longer the only default language, but multiple language configurations. The specific differences are as follows:
Okay, just upload the code~
I saw on the Internet that everyone discusses the appcompat issue under the androidx package. Here I also post the version I use:
- implementation 'androidx.appcompat:appcompat:1.2.0'
One, create the corresponding resource file
There are two ways. As follows:
- method one:
Right-click ``res'', select ``New'', ``Android Resource File'':
Select the configuration language table as shown below:
- Way two:
Select ``Resource Manager'' on the left side of Android Studio, then select the small map + logo, and finally select the corresponding compatible country in the list.
Then the values directory and strings file of the selected country will be created for us, as shown below:
Well, up to now, the basic language directory and files have been created, and the rest is that someone will be responsible for providing the corresponding translation words.
Of course, our company's consistent principle is to do it yourself and get enough food and clothing.
Some commonly used and good online translation addresses are provided, as follows:
2. Intimately attach the MMKV Utils used in the process
Remember to refer to MMKV dependencies and initialization, the address is as follows:
The personal version is as follows:
- 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)
}
}
Three, prepare multilingual 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
}
}
}
Four, select the multi-language page for processing
Of course, my idea here is to cache the language list index locally, and then directly obtain the corresponding language according to the id.
When you click confirm, cache the currently selected
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)
}
Five, Configuration processing in Application
override fun onConfigurationChanged(newConfig: Configuration?) {
super.onConfigurationChanged(newConfig)
// ...
setAppLanguage(this)
}
Six, BaseActivity processing
Since the Activity needs to be rebuilt to process the corresponding resources, I personally put it in BaseActivity to handle it:
override fun attachBaseContext(newBase: Context?) {
super.attachBaseContext(newBase?.let { getAttachBaseContext(it) })
}
Seven, optimization items, resource file update
Everyone, please remember to update this. If you have done Apk size optimization, 80% will limit the content of resConfigs, avoiding multiple useless content during packaging to increase the Apk size.
Everyone, please remember to update this. If you have done Apk size optimization, 80% will limit the content of resConfigs, avoiding multiple useless content during packaging to increase the Apk size.
Everyone, please remember to update this. If you have done Apk size optimization, 80% will limit the content of resConfigs, avoiding multiple useless content during packaging to increase the Apk size.
After I finished writing, it didn't work. Later, I saw, good guy, only Chinese was restricted. At that time, I was embarrassed and helpless...
resConfigs "zh-rCN", "en"
Well, that's the end, of course, Android has to face the multi-model adaptation...
The follow-up encounter here is in the update~
Some problems encountered in multiple languages
1. Layout issues
This is really a headache, especially for our incomplete infrastructure. What we can do is to ensure most of the effects, and try to use short English or non-Chinese.
At the same time, this also reminds me, how to be as compatible as possible in the development process?
It may also be experience, and work slowly.
2.TabLayout uppercase in English mode
The effect after switching is as follows:
The currently used TabLayout version is as follows:
- implementation 'com.google.android.material:material:1.2.1'
Here, just set a style:
<style name="TabLayoutTextStyle" parent="TextAppearance.Design.Tab">
<item name="android:textSize">@dimen/sp_18</item>
<item name="textAllCaps">false</item>
</style>
Add it later when you encounter it.
**粗体** _斜体_ [链接](http://example.com) `代码` - 列表 > 引用
。你还可以使用@
来通知其他用户。