【问题标题】:Load twirl template dynamically动态加载旋转模板
【发布时间】:2014-07-04 16:16:04
【问题描述】:

在我的 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

我怎样才能做到这一点?

【问题讨论】:

  • 你为什么不用 i18n 代替呢?一个模板,多个消息文件:playframework.com/documentation/2.3.x/ScalaI18N
  • @LimbSoup 我将 Twirl 与 Play 框架分开使用,并且我的项目不是 Web 应用程序。我不确定是否可以在此设置中使用 application.conf。

标签: scala template-engine twirl


【解决方案1】:

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

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,因此您可以使用反射调用它。您只需要知道模板的参数数量,以便您可以将其作为 trait play.api.twirl.TemplateX 的实例加载。在这种情况下,Template1[String, String](第一个字符串用于参数,第二个字符串用于呈现响应的类型)。

查看此线程以获取有关 scala How do I call a Scala Object method using reflection? 中反射的更多信息

【讨论】:

    【解决方案2】:

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

    正如 cmets 中所述,当您在 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 编码,因此很难与俄语一起使用。因此,我更新了我的答案,改为使用(不幸的是更冗长的)Properties XML 格式,它使用 UTF-8 编码,因此支持西里尔字符。

    【讨论】:

      猜你喜欢
      • 2016-03-29
      • 2011-05-03
      • 1970-01-01
      • 2013-12-14
      • 2013-05-19
      • 2012-10-09
      • 2014-02-22
      • 1970-01-01
      • 2012-09-03
      相关资源
      最近更新 更多