资源 class 是如何被正确覆盖以实现动态翻译系统的?
How is the Resource class correctly overwritten to implement a dynamic translation system?
所有 Android 开发人员大家好,我需要澄清一个关于 Android 应用程序中动态资源管理的疑问。
我需要我的应用程序根据 phone 上配置的语言使用后端返回的翻译。
我想以一种优雅的方式在自定义 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 returns 我的自定义 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
问题是覆盖资源 class 的行为被认为是一种已弃用的策略。
如文档所述:
This constructor is deprecated. Resources should not be constructed by
apps. See 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)
}
}
有谁知道如何在不覆盖资源的情况下获得相同的功能class?
非常感谢您的帮助:)
我前段时间也在研究同样的事情,最后我们的团队决定使用 Lokalise SDK。
据我所知,覆盖资源是唯一的方法。即便如此,它仍然没有涵盖所有情况,就像 Lokalise 文档中提到的那样:
Some views are not supported when inflating from XML (Action bar, Menu
items, Android preferences, may be others), but you can still get the
latest translations via getString(), getText(), getQuantityString()
and other system methods, and set the content of these views
programmatically.
我在这个库中看到了类似的实现 https://github.com/hamidness/restring 尽管它不像 Lokalise 那样完整。如果你包含他们的库并在 Android Studio 中切换到 Project
视图,展开 External Libraries
并找到 com.lokalise.android
,你可以看到 Lokalise 是如何实现的,然后你可以看到反编译的 .class
个文件:
至于被弃用的构造函数 - 他们弃用它是为了在您需要它们用于不同的 Configuration
时重新创建 Resources
。但是 Context.createConfigurationContext
不允许您覆盖资源提供的字符串的来源,所以我看不到任何替代方法。
所有 Android 开发人员大家好,我需要澄清一个关于 Android 应用程序中动态资源管理的疑问。
我需要我的应用程序根据 phone 上配置的语言使用后端返回的翻译。
我想以一种优雅的方式在自定义 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 returns 我的自定义 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
问题是覆盖资源 class 的行为被认为是一种已弃用的策略。
如文档所述:
This constructor is deprecated. Resources should not be constructed by apps. See 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)
}
}
有谁知道如何在不覆盖资源的情况下获得相同的功能class?
非常感谢您的帮助:)
我前段时间也在研究同样的事情,最后我们的团队决定使用 Lokalise SDK。
据我所知,覆盖资源是唯一的方法。即便如此,它仍然没有涵盖所有情况,就像 Lokalise 文档中提到的那样:
Some views are not supported when inflating from XML (Action bar, Menu items, Android preferences, may be others), but you can still get the latest translations via getString(), getText(), getQuantityString() and other system methods, and set the content of these views programmatically.
我在这个库中看到了类似的实现 https://github.com/hamidness/restring 尽管它不像 Lokalise 那样完整。如果你包含他们的库并在 Android Studio 中切换到 Project
视图,展开 External Libraries
并找到 com.lokalise.android
,你可以看到 Lokalise 是如何实现的,然后你可以看到反编译的 .class
个文件:
至于被弃用的构造函数 - 他们弃用它是为了在您需要它们用于不同的 Configuration
时重新创建 Resources
。但是 Context.createConfigurationContext
不允许您覆盖资源提供的字符串的来源,所以我看不到任何替代方法。