背景:项目已经基于模块化的方式上线,原项目由于之前赶进度等原因,部分代码中直接插入中文,现需要国际化。
国际化所需要做的事情:
- 用户系统(国内外手机号的注册)
- 语言切换
用户系统
这个客户端需要实现的就是注册的支持,
- 从服务端拉取‘国家’与‘区号码’,经用户选择,获取验证码,提交服务端处理,问题不大。
- 测试验证的话,有开源平台支持国外验证码的获取,可Google。
字符串翻译
重点说下语言切换的思路以及需要注意的点:
- 将代码中的中文转移到String文件中,AS快捷键
option + enter
自动将代码中的字符串转成String资源。
2.创建一个String_module的library模块,将所有strings.xml文件中的资源copy到String_module中,经脚本去重后,进行翻译。
所有需要翻译字符串的所在模块均添加对String_module的依赖。
对于Activity/Fragment直接引用String_module的string.xml文件的资源。
在接口内,我们在实现中传递给接口一个context即可。
class或常量中,我们在String_module中定义一个基于applicationContext的弱引用的context全部变量,添加getString()方法。
internal var globalSharedResourceContext: WeakReference<Context>? = null
fun initGlobalShareResourceContext(context: Application){
globalSharedResourceContext = WeakReference(context.applicationContext)
}
至此,所有翻译的工作已全部完成。
语言切换
语言切换首先需要明确是否跟随系统。其次本地需要维护App的系统语言的环境变量,可以用SP存储,服务端肯定也要保存一份。
Android系统的语言切换是通过去更新resources
的configuration
来实现的(对于Activity最终是会触发onConfigurationChanged
方法),那么我们肯定需要去获取resources
对象,然后生成一个新的configuration去更新就好了。代码如下:
fun updateResourceLocale(context:Context, locale:Locale){
val newConfig = context.resources.configuration
if (locale != newConfig.locale){
newConfig.locale = locale
context.resources.updateConfiguration(newConfig, resources.displayMetrics)
}
}
我们知道,获取resource一般通过context去获取,而一个App的context数量是:activity数量 + service数量 + 1(applicationContext),一个context对应获取一个Resource对象(实际是以弱引用的方式管理resource的对象),要修改我们只需要对每个有context对象的Activity/Service/Application去重新修改一些configration就可以。
我们可以将实现封装在BaseActivity中。在基础模块中维护一个模块的全局变量,记录当前App的语言,然后维护该变量修改App的语言以达到我们想要的需求。
最后,有一个AS自动化插件AndroidLocalizationer,有兴趣可以了解一下。