Ошибка 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 будет использоваться как вашими представлениями, так и вашими контроллерами.