Files
coco 7846a45f2c a
2026-07-03 15:47:27 +08:00

224 lines
9.4 KiB
Markdown

#### 目录
* [如何设置 App 默认的语种](#如何设置-app-默认的语种)
* [切换语种后没有任何效果该怎么办](#切换语种后没有任何效果该怎么办)
* [怎么在切换语种后应用到所有 Activity 上](#怎么在切换语种后应用到所有-activity-上)
* [怎么在用户切换系统语种的时候重启 App](#怎么在用户切换系统语种的时候重启-app)
* [WebView 导致语种失效的解决方案](#webview-导致语种失效的解决方案)
* [Android 13 WebView 语种失效怎么办](#android-13-webview-语种失效怎么办)
* [上架 aab 包后语种切换失败了怎么处理](#上架-aab-包后语种切换失败了怎么处理)
* [有没有一种不用通过重启的方式来切换语种](#有没有一种不用通过重启的方式来切换语种)
#### 如何设置 App 默认的语种
* 在从来没有调用过 `MultiLanguages.setAppLanguage` 的情况下,又不想让应用跟随系统的语种,而是想指定某个语种该怎么做?具体写法示例如下:
```java
public final class XxxApplication extends Application {
static {
// 设置默认的语种(越早设置越好)
MultiLanguages.setDefaultLanguage(LocaleContract.getEnglishLocale());
}
}
```
* 当然你如果想判断当前的系统语种类型,然后再设置默认的语种,可以这样写:
```java
public final class XxxApplication extends Application {
@Override
protected void attachBaseContext(Context newBase) {
if (newBase != null) {
Locale systemLanguage = MultiLanguages.getSystemLanguage(newBase);
// 如果当前语种既不是中文(包含简体和繁体)和英语(包含美式英式等),就默认设置成英文的,避免跟随系统语种
if (!MultiLanguages.equalsLanguage(systemLanguage, LocaleContract.getChineseLocale()) &&
!MultiLanguages.equalsLanguage(systemLanguage, LocaleContract.getEnglishLocale())) {
MultiLanguages.setDefaultLanguage(LocaleContract.getEnglishLocale());
}
}
// 绑定语种
super.attachBaseContext(MultiLanguages.attach(newBase));
}
}
```
#### 切换语种后没有任何效果该怎么办
* 情况一:可以检查一下是否在 `build.gradle` 文件中配置了仅保留某个国家的语种资源,例如 `resConfigs 'zh'` 就代表只保留和中文相关的语种资源,而其他国家的语种资源就不会被打包进 apk 包中,这样就会导致在切换语种的时候始终都是中文的尴尬局面。
* 情况二:如果是 Fragment 里面的语种切换之后没有变化,请检查 Fragment 在 Activity 重启之后是否被复用了,一般情况下是调用了 `fragment.setRetainInstance(true)` 导致的。
* 情况三:如果是上架 GooglePlay 或者华为的 aab 包后,上架成功后再下载发现切换不了 App 语种,那是因为在分包的时候导致多语言资源缺失了,这时候需要对主模块的 `build.gradle` 文件进行配置,具体用法可以参考[官方文档](https://developer.android.google.cn/guide/app-bundle/configure-base?hl=zh-cn)
```groovy
android {
......
bundle {
......
language {
enableSplit = false
}
......
}
}
```
* 其他情况:如果不是以上原因造成的,请提一个 [issue](https://github.com/getActivity/MultiLanguages/issues) 给到我处理。
#### 怎么在切换语种后应用到所有 Activity 上
* 在 Application 的 onCreate 方法中加入以下代码
```java
MultiLanguages.setOnLanguageListener(new OnLanguageListener() {
@Override
public void onAppLocaleChange(Locale oldLocale, Locale newLocale) {
Log.i("MultiLanguages", "监听到应用切换了语种,旧语种:" + oldLocale + ",新语种:" + newLocale);
// 如需在系统切换语种后应用也要随之变化的,可以在这里获取所有的 Activity 并调用它的 recreate 方法
// getAllActivity 只是演示代码,需要自行替换成项目已实现的方法,若项目中没有,请自行封装
List<Activity> activityList = getAllActivity();
for (Activity activity : activityList) {
activity.recreate();
}
}
@Override
public void onSystemLocaleChange(Locale oldLocale, Locale newLocale) {
Log.i("MultiLanguages", "监听到系统切换了语种,旧语种:" + oldLocale + ",新语种:" + newLocale +
",是否跟随系统:" + MultiLanguages.isSystemLanguage());
}
});
```
#### 怎么在用户切换系统语种的时候重启 App
* 在 Application 的 onCreate 方法中加入以下代码
```java
MultiLanguages.setOnLanguageListener(new OnLanguageListener() {
@Override
public void onAppLocaleChange(Locale oldLocale, Locale newLocale) {
Log.i("MultiLanguages", "监听到应用切换了语种,旧语种:" + oldLocale + ",新语种:" + newLocale);
}
@Override
public void onSystemLocaleChange(Locale oldLocale, Locale newLocale) {
Log.i("MultiLanguages", "监听到系统切换了语种,旧语种:" + oldLocale + ",新语种:" + newLocale +
",是否跟随系统:" + MultiLanguages.isSystemLanguage());
// 如需在系统切换语种后应用也要随之变化的,可以在这里获取所有的 Activity 并调用它的 recreate 方法
// getAllActivity 只是演示代码,需要自行替换成项目已实现的方法,若项目中没有,请自行封装
List<Activity> activityList = getAllActivity();
for (Activity activity : activityList) {
activity.recreate();
}
}
});
```
#### WebView 导致语种失效的解决方案
* 由于 WebView 初始化会修改 Activity 语种配置,间接导致 Activity 语种会被还原回去,所以需要你手动重写 WebView 对这个问题进行修复
```java
public final class LanguagesWebView extends WebView {
public LanguagesWebView(@NonNull Context context) {
this(context, null);
}
public LanguagesWebView(@NonNull Context context, @Nullable AttributeSet attrs) {
this(context, attrs, android.R.attr.webViewStyle);
}
public LanguagesWebView(@NonNull Context context, @Nullable AttributeSet attrs, int defStyleAttr) {
super(context, attrs, defStyleAttr);
// 修复 WebView 初始化时会修改 Activity 语种配置的问题
MultiLanguages.updateAppLanguage(context);
}
}
```
#### Android 13 WebView 语种失效怎么办
*`webView.loadUrl(@NonNull String url)` 替换成 `webView.loadUrl(@NonNull String url, @NonNull Map<String, String> additionalHttpHeaders)`,并添加 `Accept-Language` 请求头即可,具体的示例代码如下:
```java
public final class MainActivity extends Activity {
private WebView mWebView;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
mWebView = findViewById(R.id.wv_main_web);
mWebView.setWebViewClient(new LanguagesViewClient());
mWebView.setWebChromeClient(new WebChromeClient());
mWebView.loadUrl("https://developer.android.google.cn/kotlin", generateLanguageRequestHeader(this));
}
public static class LanguagesViewClient extends WebViewClient {
@TargetApi(Build.VERSION_CODES.N)
@Override
public boolean shouldOverrideUrlLoading(WebView view, WebResourceRequest request) {
return shouldOverrideUrlLoading(view, request.getUrl().toString());
}
@Override
public boolean shouldOverrideUrlLoading(WebView view, String url) {
String scheme = Uri.parse(url).getScheme();
if (scheme == null) {
return false;
}
switch (scheme) {
// 如果这是跳链接操作
case "http":
case "https":
view.loadUrl(url, generateLanguageRequestHeader(view.getContext()));
break;
default:
break;
}
return true;
}
}
/**
* 给 WebView 请求头添加语种环境
*/
@NonNull
public static Map<String, String> generateLanguageRequestHeader(Context context) {
Map<String, String> map = new HashMap<>(1);
// Android 13 上面语种失效的问题解决方案
// https://developer.android.google.cn/about/versions/13/features/app-languages?hl=zh-cn#consider-header
map.put("Accept-Language", String.valueOf(MultiLanguages.getAppLanguage(context)));
return map;
}
}
```
#### 有没有一种不用通过重启的方式来切换语种
* 我先问大家一个问题,生米煮成熟饭了,怎么从熟饭变成生米?这显然是不现实的,退一万步讲,假设框架能做到,文字和图片都能自动跟随语种的变化而变化,那么通过接口请求的数据又怎么切换语种?是不是得重新请求?如果是列表数据是不是得从第 1 页开始请求?再问大家一个问题,还有语种切换是一个常用动作吗?我相信大家此时心里已经有了答案。
* 所以并不是做不到不用重启的效果,而是没有那个必要(切语种不是常用动作),并且存在一定的硬伤(虽然 UI 层不用动,但是数据层还是要重新请求)。