控制器中的 Play Framework Lang 未发生隐式转换

Implicit conversion not taking place for Play Framework Lang in controller

我有一个视图接受 Play 的 Messages 对象所需的隐式 Lang。此视图的签名是:

@()(implicit lang: Lang)

然后我有一个需要创建视图的控制器:

def createView = Action { request =>
  Ok(views.html.showView())
}

然后我有一个隐式方法,我想调用它来创建视图需要的 Lang

implicit def getLangFromRequest(request: RequestHeader): Lang = {
  request.cookies.get("lang") match {
    case Some(cookie) => Lang(cookie.value)
    case None => Lang("en") // Default
  }
}

换句话说,如果可以的话,该方法应该从 cookie 中获取语言,否则使用默认值(我已经删除了这个问题的错误处理)。

但是,此隐式转换并未发生。我知道它能够隐式转换,因为通过在控制器中创建一个隐式变量可以工作:

def createView = Action { request =>
  implicit val lang: Lang = request
  Ok(views.html.showView())
}

但我宁愿不必在任何地方都添加这条样板行。大概我必须显式调用该方法,因为在隐式转换之前使用了一些全局 Lang 对象。

我有什么选择可以避免在每个控制器中重复此 implicit val lang: Lang = request

根据 Play 文档

If you have an implicit Request in the scope, it will provide an implicit Lang value corresponding to the preferred language extracted from the Accept-Language header and matching one of the application supported languages.

因此您需要将操作更改为

def createView = Action { implicit request =>
  Ok(views.html.showView())
}

它应该可以工作。

必须为每个控制器调用 implicit val lang: Lang = request 似乎需要做很多工作,但当您考虑它时,实际上并非如此,您已经调用了 Action 方法(它接受一个 Request => Result 函数)每当你创建一个新的动作。

编写一个 trait 来执行查找语言的所有繁重逻辑,将其混合到所有控制器中,而不是使用 Action 方法,而是使用您在该特征中编写的方法,接受一个 Request => Lang => Result 函数,执行语言逻辑,然后将函数参数应用于范围内的请求。像这样:

trait Internationalization { subj: Controller =>

  def withLanguage(f: => Request[AnyContent] => Lang => Result) = Action { implicit request =>
    val lang = request.cookies.get("lang") match {
      case Some(cookie) => Lang(cookie.value)
      case None => Lang("en") // Default
    }
    f(request)(lang)
  }

}

然后,而不是 def action = Action { ... },只需混合特征并使用:

def action = withLanguage { request => implicit lang => 
   Ok(views.html.showView())
}