Android实现app内的语言切换功能

我在目前所在的公司负责一个app项目的维护,最近需要对这个项目进行国际化,适配10多个国家的语言,在实现国际化过程中,遇到了很多问题,最麻烦的就是翻译了,得一个个将翻译从excel复制到资源文件中,还得保证key和value一一对应,稍不注意就容易出错,当然也有一些自动化的工具可以替代手工复制,但需要excel满足一定的规范,不然会出现一些差错。还有就是其他语言下的ui适配,有些文字翻译成其他语言,就会变得很长,设计的时候也没考虑这些,所有语言都使用同一套设计,导致很多文字显示不全,或者出现重叠的问题。另外一个就是app内的语言切换功能,其实这个功能实现很简单,系统有相应的api,但是需要注意这里面有几个坑,不要向我一样踩到了。

切换语言有两个方法可以实现,分别是

1、Resources
public void updateConfiguration(Configuration config, DisplayMetrics metrics)
2、Context 
Context createConfigurationContext(Configuration overrideConfiguration)
方法1属于Resources的,已经被弃用了。代码:
Resources resources = context.getResources();
Configuration config = resources.getConfiguration();
DisplayMetrics dm = resources.getDisplayMetrics();
Locale locale = new Locale("vi", "vn");
config.setLocale(locale);
resources.updateConfiguration(config, dm);

使用该方法,在不同手机上有不同的表现,
魅族手机在 application 的 onCreate 方法中设置即可生效,
但华为手机需要在 activity 的 onCreate 方法中设置才生效。
所以稳妥的方法是,

在Launcher activity 中判断如果有设置语言,使用该方法设置语言。
如果用户在设置中更改了语言,调用主 Activity 的 recreate 方法重建,不重建不会生效,因此还要在主 Activity 的 onCreate 判断 savedInstanceState 不为空时使用该方法切换语言。
若设置了语言,同时也要监听系统语言发生改变的广播,收到这个广播后,使用该方法切换语言。

既然这个被弃用了,那可能是有问题的。在测试过程中确实发现了不少问题:

问题1、Android 9 上失效:

在设置中更改语言后,回到主 Activity ,语言确实更改成功了,但是打开其他页面,语言还是上次设置的语言。关闭app重新打开,每个页面的语言又都是对的。解决方法是必须在每个页面都设置。

问题2、华为手机中失效:

在app某一页面切换了导航栏显示状态后,进入其他页面或返回页面时,因为配置(屏幕高度)改变了,会导致语言变成系统默认的语言。此时注册的配置改变的广播并不会收到广播,但会调用 MyApplication 中的onConfigurationCahnged 方法(会在Activity onCreate方法之前调用)。所以需要在导航栏显示状态发生改变后切换语言,但是不能直接在 Application 中来切换,这样切换对于 Activity 没有作用(Application 和Activity 的 Context 不一样)。也不能在 Application 中发送一个自定义的 Action 的广播来通知广播接收器修改,这样的修改对于 Activity 也是没有作用的(必须是自定义的 Action,如果使用系统的配置改变的 Action 会报错,只有系统权限才能发送该广播)。解决方法是在 Application 中注册 registerActivityLifecycleCallbacks,监听 Activity 的生命周期,当导航栏显示状态发生变化时,如果是进入新页面就在 onActivityCreated 里面使用该方法设置语言,如果是返回上一级页面,在 onActivityResumed 里面使用该方法设置语言。

基于上面的问题,我们应该使用方法二,代码:
override fun attachBaseContext(newBase: Context) {
    val configuration = newBase.resources.configuration
    configuration.setLocale(Locale.ENGLISH)
    val createContext = newBase.createConfigurationContext(configuration)
    super.attachBaseContext(createContext)
}
没错需要在 attachBaseContext 方法中修改,把修改后的Context 设置给 Activity 或 Appcalition 。
该方法需要在每个页面中都设置,所以可以写一个 BaseActivity ,在里面统一设置。
这样就完了吗?不可能的! 这两种方法都会遇到一个问题,若你的 app 加载了 WebView 你会发现语言又变回了系统默认的默认语言!!!

在 Android 7 之前WebView的渲染是通过Android System webView来实现的。但是在Android7之后WebView会被作为一个应用程序的方式服务于各个三方APP。由于WebView这里是作为一个单独的应用程序,所以他不会被绑定到你自己APP设置的Local上。不仅如此,WebView还会把语言变成设备的Local设置。然后相应的资源文件也会被变成设备语言下的资源文件这样就导致了只要打开了含有WebView的页面,应用内语言设置就失效的问题。

上面是网上搜到的解释。

所以在 WebView 加载后还需要设置一遍语言。
或者在 app 启动时就加载一次 WebView ,然后在设置语言,只要 WebView 第一次加载后修改了语言,后面再加载便不会重置为系统语言。
需要注意的地方:
1、部分手机需要给Local设置语言还有国家才成效,所以最好都设置国家或地区。
2、只在 Application 和 Activity 中的某一个修改了语言,它们的 Local 中的语言是不同的。
3、某些手机中,弹出Toast时如果使用的是getApplicationContext(),弹出的语言是系统默认的语言,所以最好都传 Activity 的 Context .

~~这下子就完美了。

  • 0
    点赞
  • 6
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值