- 在从来没有调用过
MultiLanguages.setAppLanguage
的情况下,又不想让应用跟随系统的语种,而是想指定某个语种该怎么做?具体写法示例如下:
public final class XxxApplication extends Application {
static {
// 设置默认的语种(越早设置越好)
MultiLanguages.setDefaultLanguage(LocaleContract.getEnglishLocale());
}
}
- 当然你如果想判断当前的系统语种类型,然后再设置默认的语种,可以这样写:
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
文件进行配置,具体用法可以参考官方文档
android {
......
bundle {
......
language {
enableSplit = false
}
......
}
}
- 其他情况:如果不是以上原因造成的,请提一个 issue 给到我处理。
- 在 Application 的 onCreate 方法中加入以下代码
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());
}
});
- 在 Application 的 onCreate 方法中加入以下代码
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 初始化会修改 Activity 语种配置,间接导致 Activity 语种会被还原回去,所以需要你手动重写 WebView 对这个问题进行修复
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);
}
}
- 将
webView.loadUrl(@NonNull String url)
替换成webView.loadUrl(@NonNull String url, @NonNull Map<String, String> additionalHttpHeaders)
,并添加Accept-Language
请求头即可,具体的示例代码如下:
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 层不用动,但是数据层还是要重新请求)。