前置操作
1. 在res文件下添加对应的values
values-xx-xx, 通用格式为values-<语言代号>-r<国家/地区代号>, 自己按需要查找添加。
2. 添加对应的locale-config文件
1. 手动添加
在res/xml下添加locales_config.xml,将涉及到的tag加入
<locale-config xmlns:android="http://schemas.android.com/apk/res/android" android:defaultLocale="en">
<locale android:name="en"/>
<locale android:name="cs"/>
<locale android:name="da"/>
<locale android:name="de"/>
<locale android:name="es"/>
<locale android:name="fr"/>
<locale android:name="it"/>
<locale android:name="ko"/>
<locale android:name="nl"/>
<locale android:name="pl"/>
<locale android:name="pt-PT"/>
<locale android:name="ru"/>
<locale android:name="th"/>
<locale android:name="uk"/>
<locale android:name="vi"/>
<locale android:name="zh-CN"/>
</locale-config>
接着在minifest.xml中应用该文件,可能会出现33+才能使用的提示,可以不管
<application
android:localeConfig="@xml/locales_config"
/>
2. 通过gradle添加
在app模块下的build.gradle中添加
android {
androidResources {
generateLocaleConfig = true
}
}
点击编译后,gradle会根据项目的res文件夹,在build/generated/res中生成对应的localeConfig文件,并且在manifest.xml文件中也会进行对应的android:localeConfig设置。
切换语言方法
官方推荐
1. 具体操作
导入谷歌appcompact的依赖。
implementation 'androidx.appcompat:appcompat:1.7.1'
调用AppCompatDelegate的方法即可
AppCompatDelegate.setApplicationLocales(LocaleListCompat.forLanguageTags(languageTag));
2. 注意点(低于API33版本)
谷歌的方法虽然兼容了33以前的版本,但是需要添加一个服务在manifest.xml中
<application
...
<service
android:name="androidx.appcompat.app.AppLocalesMetadataHolderService"
android:enabled="false"
android:exported="false">
<meta-data
android:name="autoStoreLocales"
android:value="true" />
</service>
...
</application>
但是要注意,AppCompatDelegate.setApplicationLocales()的方法虽然做了兼容处理,但是对于API33以前的版本所做的操作,还是基于缓存,在Activity的attachContext方法中,替换Configuration的Locale。这个Service就是用来进行混存操作的,其中autoStoreLocales参数就是用来开启这个缓存的开关。
Tip,我在集成Compose时遇到的问题
切换语言后,Activity会自动重建,来进行语言的切换
可以在manifest.xml中添加以下代码,防止Activity重建。
android:configChanges="locale|layoutDirection"
API33+,没有问题,语言正常进行了切换。
但是 !!在API33之前的,没有办法切换。为啥??
因为在API33之前,AppCompatDelegate.setApplicationLocales(),只是进行了缓存的切换,具体应用的逻辑是在attchContext里面,当Activity没有重建的时候,就没有办法进行语言切换。当然了,下次启动APP,语言就换成了新的,但是显然这不是我们想要的。
好在我们是Compose,数据驱动UI的方式,很适合页面刷新。
本质上stringResource()的方法,也是通过context获取resource,然后获取对应的string。因此我们可以跟谷歌操作一样,对getResource方法进行修改。
private class LocalizedContextWrapper(
base: Context,
private val language: String
) : ContextWrapper(base) {
private val localizedResources: Resources by lazy {
val config = Configuration(baseContext.resources.configuration)
config.setLocale(Locale.forLanguageTag(language))
baseContext.createConfigurationContext(config).resources
}
override fun getResources(): Resources {
return localizedResources
}
}
@Composable
fun AppLanguage(
language: String,
content: @Composable () -> Unit
) {
var context = LocalContext.current
context = remember(context, language) {
LocalizedContextWrapper(context, language)
}
CompositionLocalProvider(
LocalContext provides context,
content = content
)
}
依旧是我们自己本地缓存当前的语言,然后将context进行修改。由于是Compose,所以当我们切换语言后,页面会自动重构。
引用:
- 官方文档:developer.android.com/guide/topic…
- GSY的Compose项目 github.com/CarGuo/GSYG…