【问题标题】:How is the Resource class correctly overwritten to implement a dynamic translation system?如何正确覆盖 Resource 类以实现动态翻译系统?
【发布时间】:2019-07-04 18:22:29
【问题描述】:

各位 Android 开发者您好,我需要澄清一个关于 Android 应用程序中动态资源管理的疑问。

我需要我的应用程序根据手机上配置的语言使用后端返回的翻译。

我想以优雅的方式在自定义 LayoutInflater 上实现它,该自定义 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 已经实现,它返回我的自定义 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 类的情况下获得相同的功能?

非常感谢您的帮助:)

【问题讨论】:

  • 为什么不让您的ViewModel 为您的活动/片段提供正确的字符串,就像您使用任何其他动态数据一样填充它们?鉴于涉及服务器,无论如何您都需要考虑网络+磁盘 I/O 和线程,这与您对服务器的任何其他操作没有什么不同。
  • 感谢您的回答,这个策略在我看来更加自动化,并且被封装在膨胀视图的过程中,我不希望在我的功能的所有视图模型中看到翻译的逻辑。我将翻译加载到内存中的 LRU 缓存中,可以立即访问。
  • 我不确定如何使用 ViewModel 执行此操作,在我加载翻译之前,屏幕可能没有文字显示

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


【解决方案1】:

前段时间我也在研究同样的事情,最后我们的团队决定选择Lokalise SDK

据我所知,覆盖资源是唯一的方法。即便如此,它仍然不能涵盖所有情况,就像 Lokalise 文档中提到的那样:

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

我在这个库https://github.com/hamidness/restring 中看到了类似的实现,尽管它不像 Lokalise 那样完整。你可以看到 Lokalise 是如何实现的,如果你包含他们的库并在 Android Studio 中切换到Project 视图,展开External Libraries 并找到com.lokalise.android,然后你可以看到反编译的.class 文件:

至于被弃用的构造函数 - 他们弃用它是为了在您需要它们用于不同的Configuration 时重新创建Resources。但是Context.createConfigurationContext 不允许你覆盖资源提供的字符串的来源,所以我看不到任何替代方案。

【讨论】:

  • 感谢@arekolek,您的回答对我帮助很大。我没有看到 Lokalise 库的源代码。在来自 github 的存储库中,我只能下载“.aar”文件。
  • 如果您在build.gradle 中包含implementation "com.lokalise.android:ota-sdk:1.3.14",那么您可以在Android Studio 中看到反编译的代码(请参阅更新的答案)
  • 您提到使用 Lokalise 很有趣。我试过了,但不幸的是,它不适用于 androidx lib v1.2.0 和 Lokalise SDK v1.3.15。
  • @soshial 我们遇到了一个问题,即在将com.google.android.material:material 升级到1.1.0 后它停止工作。我们将 Lokalise 升级到 2.0.0 beta 并且可以正常工作
  • @arekolek 在我的情况下是androidx.appcompat:appcompat:1.2.0 破坏了 Lokalise。必须改用 1.1.0。感谢您的提示,以便我注意到并查看 androidx.appcompat:appcompatcom.google.android.material:material
猜你喜欢
  • 1970-01-01
  • 2015-09-03
  • 2022-01-01
  • 1970-01-01
  • 2012-03-16
  • 2016-10-23
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多