Ошибка i18n: контроллер и шаблоны используют разные неявные языки

Контроллер:

def test = Action { implicit request =>
    import play.api.i18n._
    val msg = Messages("error.invalid")
    implicit val langInController = lang(request)
    Ok(views.html.test(langInController, msg))
}

Вид:

@(langInController: play.api.i18n.Lang, msg:String)(implicit request: Request[_])
<div>Lang from controller: @langInController, Message: @msg</div>
<div>Message from view: @play.api.i18n.Messages("error.required")</div>

Ресурс сообщений, conf/messages.zh-CN:

error.required=该字段必填

Попытка

  • Использует английский Firefox, который отправляет заголовок запроса Accept-Language:en-us,en;q=0.5 для посещения действия test. Результат:

    Language from controller: Lang(en,), Message: This field is required
    Message in view: 该字段必填
    
  • Использует китайский Google Chrome, который отправляет заголовок запроса Accept-Language:zh-CN,zh;q=0.8 для его просмотра. Результат:

    Language: Lang(zh,CN), Message: 该字段必填
    Message in view: 该字段必填
    

Из тестов мы знаем, что:

  • Неявный язык в контроллере из заголовка запроса Accept-Language
  • Неявный язык, используемый в шаблоне, определяется ОС

Окружающая среда:

  • Play 2 - последний play2.1-SNAPSHOT от GitHub (2012-03-16)
  • Моя ОС - Windows 7 x64 китайская версия

Я думаю, что Play 2 должен использовать тот же неявный язык для контроллеров и представлений. Я могу исправить это, добавив что-то в Build.sbt:

val main = PlayProject(...) (
    templatesImport ++= Seq("utilis.TemplateMixin._")
)

Где TemplateMixin справедливо:

object TemplateMixin extends play.api.mvc.Controller

(Он расширяет Controller и только для повторного использования некоторых методов, таких как implicit def lang(request).)

Но я думаю, что это должно быть сделано с помощью платформы Play.

Ответ 1

Функция play.api.i18n.Messages(key) принимает дополнительный неявный параметр типа Lang. Поэтому, когда вы пишете Messages("foo"), он расширяется до Messages("foo")(l), где l - это значение типа Lang, взятое из текущей неявной области.

Всегда есть доступный default implicit lang (который имеет низкий приоритет), используя ваш стандарт jvm default.

Но когда вы находитесь внутри Controller, неявное значение с более высоким приоритетом может быть найдено, если есть неявный запрос. Это значение отображается в заголовке Accept-Language запроса.

Когда вы находитесь внутри шаблона, подразумеваемый lang по умолчанию будет использоваться, если ваш шаблон не импортирует другой неявный язык.

Вот почему в вашем примере сообщения, вычисленные с помощью контроллера, используют заголовок запроса Accept-Language и сообщения, вычисленные из представления, в соответствии с вашим стандартом jvm default.

Если вы добавите в шаблон неявный параметр типа Lang, этот параметр будет иметь более высокий приоритет, чем lang по умолчанию, и будет использоваться для вычисления сообщений:

@(langInController: Lang, msg:String)(implicit request: RequestHeader, lang: Lang)

<div>Lang from controller: @langInController, Message: @msg</div>
<div>Message from view: @Messages("error.required")</div>

Когда вы вызываете шаблон из действия Controller, его неявный lang будет передан, поэтому тот же lang будет использоваться как вашими представлениями, так и вашими контроллерами.