在我的Scala项目中,我使用了Twirl模板引擎。俄语和英语的模板文件结构是重复的,例如,我有以下两个路径:en.Send.txt.MonoEnsure和ru.Send.txt.MonoEnsure
在我的代码中,我希望能够动态加载en或ru模板,如下所示:
def render(lang: String) = lang.Send.txt.MonoEnsure("hi")
render("en") // does not work, just to illustrate my point我如何才能做到这一点?
发布于 2014-07-09 18:51:57
这不是对你的问题的直接回答,而是解决你的问题的不同解决方案。另一个答案是如何在技术上实现你想要的东西,但是使用反射来做一些国际化是不必要的脆弱的,并且绝对不被推荐。
正如评论中提到的,当您在Play应用程序的上下文中使用Twirl时,Play为您提供了自己的国际化方式。因为你没有在你的应用程序中使用Play,所以你不能使用它。但是你不需要使用Play的特定方式来进行国际化。您可以轻松地构建自己的基本国际化构造,而无需引入额外的依赖项,我将在本答案中说明这一点。
首先也是最重要的,这种方法应该更加干练。其次,它将您的布局与您碰巧使用的语言解耦。最后,它是完全类型安全的,并且不使用反射。
首先,创建一个表示一种语言的类,包装一个Properties对象。
// Language.scala
class Language(filename: String) {
val properties = new java.util.Properties()
properties.loadFromXML(new FileInputStream(filename))
def apply(key: String) = properties.getProperty(key, s"Key $key not found.")
}
object Language {
val English = new Language("path/to/english.xml")
val Russian = new Language("path/to/russian.xml")
}还可以使用Properties XML format定义一些转换
<!-- path/to/english.xml -->
<?xml version="1.0" encoding="UTF-8" standalone="no"?>
<!DOCTYPE properties SYSTEM "http://java.sun.com/dtd/properties.dtd">
<properties>
<entry key="hello.world">Hello World</entry>
</properties>
<!-- path/to/russian.xml -->
<?xml version="1.0" encoding="UTF-8" standalone="no"?>
<!DOCTYPE properties SYSTEM "http://java.sun.com/dtd/properties.dtd">
<properties>
<entry key="hello.world">привет мир</entry>
</properties>然后,在渲染时,您可以将正在使用的语言隐式地放在作用域上:
implicit val language: Language = determineLanguage() // Your logic for determining the language you want to use
// Do other things here..
// Render template
Send.txt.MonoEnsure("hi")然后,在您的模板中,使用如下语言:
@(arg1: Any, arg2: Any)(implicit lang: Language)
<html>
<body>
<p>@lang("hello.world")</p>
</body
</html>它将输出一个显示"Hello World“或”приветмир“的页面,具体取决于所选择的语言。
Java:我的第一个建议是使用的默认属性文件格式,但事实证明它使用的是拉丁-1编码,不支持西里尔字符,这使得它很难与俄语一起使用。因此,我更新了我的答案,改为使用Properties XML格式(不幸的是更冗长),该格式使用UTF-8编码,因此支持西里尔字符。
发布于 2014-07-10 00:34:29
我认为这是应该实现这一点的代码:
import play.twirl.api.Template1
def getTemplate[T](name : String)(implicit man: Manifest[T]) : T =
Class.forName(name + "$").getField("MODULE$").get(man.erasure).asInstanceOf[T]
def render(lang: String) =
getTemplate[Template1[String,String]](s"$lang.Send.txt.MonoEnsure").render("hi")
render("en")模板被编译成BaseScalaTemplate,因此您可以使用反射来调用它。您只需要知道模板的参数数量,这样您就可以将其作为特征play.api.twirl.TemplateX的实例加载。在本例中为Template1[String, String] (第一个字符串用于参数,第二个字符串用于呈现响应的类型)。
有关scala How do I call a Scala Object method using reflection?中的反射的更多信息,请查看此线程
https://stackoverflow.com/questions/24578073
复制相似问题