如何正确覆盖Resource类以实现动态翻译系统?

时间:2019-07-04 18:22:29

标签: android android-layout android-view android-resources layout-inflater

向所有Android开发人员问好,我需要澄清有关Android应用程序中动态资源管理的疑问。

我需要我的应用程序使用我的后端返回的翻译,具体取决于手机上配置的语言。

我想以优雅的方式在自定义 LayoutInflater 上实现它,该自定义 ViewTransformer 取决于图形组件的类型。

每个ViewTransformer只会收集标识符(例如@ id / landing_welcome_text)并进行下一个调用:

 val value = attrs.getAttributeValue(index)
 if (value != null && value.startsWith("@")) {
      val text = view.context.resources.getString(attrs.getAttributeResourceValue(index, 0))
     setTextForView(view, text)
 }

已实现ContextWrapper,该ContextWrapper返回我的自定义LayoutInflater和Resource实现

override fun getSystemService(name: String): Any {
   return if (Context.LAYOUT_INFLATER_SERVICE == name)
      CustomLayoutInflater(
          LayoutInflater.from(baseContext),
                this,
                viewTransformerManager
            )
      else
            super.getSystemService(name)
}

override fun getResources(): Resources = customResources

问题在于,覆盖Resources类的行为被视为不建议使用的策略。

如文档所述:

  

不建议使用此构造函数。资源不应由   应用。请参阅Context.createConfigurationContext(Configuration)。

class CustomResourcesWrapper constructor(
    res: Resources,
    private val languageStringRepo: ILanguageStringRepo
): Resources(res.assets, res.displayMetrics, res.configuration) {


    @Throws(Resources.NotFoundException::class)
    override fun getString(id: Int): String {
        val value = getStringFromRepository(id)
        return value ?: super.getString(id)
    }

}

有人知道我如何在不覆盖Resources类的情况下获得相同的功能吗?

非常感谢您的帮助:)

1 个答案:

答案 0 :(得分:1)

前段时间我一直在研究同一件事,最终我们的团队决定选择Lokalise SDK

从我发现的结果来看,覆盖资源是唯一的方法。即便如此,它仍然不能涵盖所有情况,如Lokalise文档中所述:

  

从XML扩展时不支持某些视图(操作栏,菜单   项,Android偏好设置,可能是其他),但您仍然可以   通过getString(),getText(),getQuantityString()的最新翻译   和其他系统方法,并设置这些视图的内容   以编程方式。

我在该库https://github.com/hamidness/restring中看到了类似的实现,尽管它不如Lokalise完整。如果您包括Lokalise的库并切换至Android Studio中的Project视图,展开External Libraries并找到com.lokalise.android,则可以看到Lokalise的实现方式,然后可以看到反编译的.class文件:

Decompiled sources

关于不赞成使用的构造函数-为了在需要其他Resources时重新创建Configuration的目的,他们不赞成使用它。但是Context.createConfigurationContext不允许您覆盖资源提供的字符串的来源,因此我看不到任何替代方法。