动态加载旋转模板

时间:2014-07-04 16:16:05

标签: scala template-engine twirl

在我的Scala项目中,我使用Twirl模板引擎。模板文件结构与俄语和英语语言重复,例如我有以下两条路径:en.Send.txt.MonoEnsureru.Send.txt.MonoEnsure

在我的代码中,我希望能够动态加载enru模板,如下所示:

def render(lang: String) = lang.Send.txt.MonoEnsure("hi")
render("en") // does not work, just to illustrate my point

我怎样才能做到这一点?

2 个答案:

答案 0 :(得分:3)

这不是您问题的直接答案,而是解决问题的不同解决方案。另一个答案解决了如何在技术上实现你想要的东西,但使用反射进行一些国际化是不必要的脆弱,绝对不推荐。

正如评论中所提到的,当您在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的默认属性文件格式,但事实证明它使用了不支持西里尔字符的Latin-1编码,因此很难与俄语一起使用。因此,我更新了我的答案,而不是使用(不幸的是更详细)属性XML格式,它使用UTF-8编码,因此支持西里尔字符。

答案 1 :(得分:3)

我认为这是应该实现的代码:

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?

中反射的更多信息