文档

§使用消息进行国际化

§指定您的应用程序支持的语言

您可以使用语言标签为您的应用程序指定语言,语言标签是专门格式化的字符串,用于标识特定语言。语言标签可以指定简单的语言,例如“en”表示英语,特定语言的区域方言(例如“en-AU”表示澳大利亚使用的英语),语言和脚本(例如“az-Latn”表示用拉丁字母书写的阿塞拜疆语),或这些的组合(例如“zh-cmn-Hans-CN”表示中国使用的汉语普通话简体字)。

首先,您需要在 conf/application.conf 文件中指定您的应用程序支持的语言

play.i18n.langs = [ "en", "en-US", "fr" ]

这些语言标签将用于创建 play.api.i18n.Lang 实例。要访问您的应用程序支持的语言,您可以将 play.api.i18n.Langs 组件注入到您的类中

import javax.inject.Inject

import play.api.i18n.Lang
import play.api.i18n.Langs
import play.api.mvc.Action
import play.api.mvc.AnyContent
import play.api.mvc.BaseController
import play.api.mvc.ControllerComponents

class ScalaI18nService @Inject() (langs: Langs) {
  val availableLangs: Seq[Lang] = langs.availables
}

单个 play.api.i18n.Lang 可以使用 lang.toLocale 转换为 java.util.Locale 对象

val locale: java.util.Locale = lang.toLocale

§外部化消息

您可以在 conf/messages.xxx 文件中外部化消息。

默认的 conf/messages 文件匹配所有语言。此外,您可以指定特定于语言的消息文件,例如 conf/messages.frconf/messages.en-US

消息可通过 MessagesApi 实例获得,该实例可以通过注入添加。然后,您可以使用 play.api.i18n.MessagesApi 对象检索消息

import play.api.i18n.MessagesApi

class MyService @Inject() (langs: Langs, messagesApi: MessagesApi) {
  val lang: Lang = langs.availables.head

  val title: String = messagesApi("home.title")(lang)
}

您也可以使语言隐式,而不是声明它

class MyOtherService @Inject() (langs: Langs, messagesApi: MessagesApi) {
  implicit val lang: Lang = langs.availables.head

  lazy val title: String = messagesApi("home.title")
}

Play 提供了用于表单验证的预定义消息。您可以使用默认消息文件或任何特定于语言的消息文件覆盖这些消息。您可以在下面看到可以覆盖哪些消息

# Copyright (C) from 2022 The Play Framework Contributors <https://github.com/playframework>, 2011-2021 Lightbend Inc. <https://www.lightbend.com>

# Default messages

# --- Constraints
constraint.required=Required
constraint.min=Minimum value: {0}
constraint.max=Maximum value: {0}
constraint.minLength=Minimum length: {0}
constraint.maxLength=Maximum length: {0}
constraint.email=Email
constraint.pattern=Required pattern: {0}

# --- Formats
format.date=Date (''{0}'')
format.numeric=Numeric
format.real=Real
format.uuid=UUID

# --- Patterns for Formats
formats.date=yyyy-MM-dd

# --- Errors
error.invalid=Invalid value
error.invalid.java.util.Date=Invalid date value
error.required=This field is required
error.number=Numeric value expected
error.real=Real number value expected
error.real.precision=Real number value with no more than {0} digit(s) including {1} decimal(s) expected
error.min=Must be greater or equal to {0}
error.min.strict=Must be strictly greater than {0}
error.max=Must be less or equal to {0}
error.max.strict=Must be strictly less than {0}
error.minLength=Minimum length is {0}
error.maxLength=Maximum length is {0}
error.email=Valid email required
error.pattern=Must satisfy {0}
error.date=Valid date required
error.uuid=Valid UUID required

error.expected.date=Date value expected
error.expected.date.isoformat=Iso date value expected
error.expected.time=Time value expected
error.expected.jsarray=Array value expected
error.expected.jsboolean=Boolean value expected
error.expected.jsnumber=Number value expected
error.expected.jsobject=Object value expected
error.expected.jsstring=String value expected
error.expected.jsnumberorjsstring=String or number expected
error.expected.keypathnode=Node value expected
error.expected.uuid=UUID value expected
error.expected.validenumvalue=Valid enumeration value expected
error.expected.enumstring=String value expected

error.path.empty=Empty path
error.path.missing=Missing path
error.path.result.multiple=Multiple results for the given path

§使用 Messages 和 MessagesProvider

由于通常需要在不提供参数的情况下使用消息,因此您可以将给定的 LangMessagesApi 结合起来以创建 play.api.i18n.Messages 实例。如果要直接创建一个,play.api.i18n.MessagesImpl 案例类实现了 Messages 特性

val messages: Messages = MessagesImpl(lang, messagesApi)
val title: String      = messages("home.title")

您也可以使用单例对象方法,并使用隐式 play.api.i18n.MessagesProvider

implicit val messagesProvider: MessagesProvider = {
  MessagesImpl(lang, messagesApi)
}
// uses implicit messages
val title2 = Messages("home.title")

一个 play.api.i18n.MessagesProvider 是一个特质,可以按需提供 Messages 对象。一个 Messages 实例扩展了 MessagesProvider 并返回自身。

MessagesProvider 最适合在不是 Messages 的情况下扩展。

implicit val customMessagesProvider: MessagesProvider = new MessagesProvider {
  // resolve messages at runtime
  override def messages: Messages = { ... }
}
// uses implicit messages
val title3: String = Messages("home.title")

§在控制器中使用 Messages

您可以通过扩展 MessagesAbstractControllerMessagesBaseController 为您的请求添加 Messages 支持。

import javax.inject.Inject

import play.api.i18n._

class MyMessagesController @Inject() (mcc: MessagesControllerComponents) extends MessagesAbstractController(mcc) {
  def index = Action { implicit request: MessagesRequest[AnyContent] =>
    val messages: Messages = request.messages
    val message: String    = messages("info.error")
    Ok(message)
  }

  def messages2 = Action { implicit request: MessagesRequest[AnyContent] =>
    val lang: Lang      = request.messages.lang
    val message: String = messagesApi("info.error")(lang)
    Ok(message)
  }

  def messages4 = Action { implicit request: MessagesRequest[AnyContent] =>
    // MessagesRequest is an implicit MessagesProvider
    Ok(views.html.formpage())
  }
}

或者,将 play.api.i18n.I18nSupport 特质添加到您的控制器,并确保 MessagesApi 的实例在范围内,这将使用隐式将请求进行转换。

import javax.inject.Inject

import play.api.i18n._

class MySupportController @Inject() (val controllerComponents: ControllerComponents)
    extends BaseController
    with I18nSupport {
  def index: Action[AnyContent] = Action { implicit request =>
    // type enrichment through I18nSupport
    val messages: Messages = request.messages
    val message: String    = messages("info.error")
    Ok(message)
  }

  def messages2: Action[AnyContent] = Action { implicit request =>
    // type enrichment through I18nSupport
    val lang: Lang      = request.lang
    val message: String = messagesApi("info.error")(lang)
    Ok(message)
  }

  def messages3: Action[AnyContent] = Action { request =>
    // direct access with no implicits required
    val messages: Messages = messagesApi.preferred(request)
    val lang               = messages.lang
    val message: String    = messages("info.error")
    Ok(message)
  }

  def messages4: Action[AnyContent] = Action { implicit request =>
    // takes implicit Messages, converted using request2messages
    // template defined with @()(implicit messages: Messages)
    Ok(views.html.formpage())
  }
}

Twirl 模板中的所有表单助手都接受 MessagesProvider,并且假设在处理表单时,将 MessagesProvider 作为隐式参数传递到模板中。

@(form: Form[Foo])(implicit messages: MessagesProvider)

@helper.inputText(field = form("name")) @* <- takes MessagesProvider *@

§从 HTTP 请求中检索支持的语言

您可以检索特定 HTTP 请求支持的语言。

def index: Action[AnyContent] = Action { request =>
  Ok("Languages: " + request.acceptLanguages.map(_.code).mkString(", "))
}

§请求类型

I18nSupport 特质为 Request 添加了以下方法。

首选语言是从 Accept-Language 标头(以及可选的语言 cookie)中提取的,并使用 messagesApi.preferredMessagesApi 支持的语言之一匹配。

I18nSupport 还为 Result 添加了两个方便的方法。

例如

def homePageInFrench: Action[AnyContent] = Action {
  Redirect("/user/home").withLang(Lang("fr"))
}

def homePageWithDefaultLang: Action[AnyContent] = Action {
  Redirect("/user/home").withoutLang
}

withLang 方法为将来的请求设置名为 PLAY_LANG 的 cookie,而 withoutLang 会丢弃 cookie,Play 将根据客户端的 Accept-Language 标头选择语言。

可以通过更改配置参数 play.i18n.langCookieName 来更改 cookie 名称。

§隐式 Lang 转换

可以在控制器上声明 LangImplicits 特性,以在给定隐式 Lang 实例的情况下将请求隐式转换为 Messages

import play.api.i18n.LangImplicits

class MyClass @Inject() (val messagesApi: MessagesApi) extends LangImplicits {
  def convertToMessage: Unit = {
    implicit val lang: Lang = Lang("en")
    val messages: Messages  = lang2Messages // implicit conversion
  }
}

§消息格式

消息使用 java.text.MessageFormat 库进行格式化。例如,假设您定义了以下消息

files.summary=The disk {1} contains {0} file(s).

然后可以指定参数为

Messages("files.summary", d.files.length, d.name)

§关于撇号的说明

由于 Messages 使用 java.text.MessageFormat,请注意单引号用作转义参数替换的元字符。

例如,如果您定义了以下消息

info.error=You aren''t logged in!
example.formatting=When using MessageFormat, '''{0}''' is replaced with the first parameter.

您应该期望以下结果

messagesApi("info.error") == "You aren't logged in!"
messagesApi("example.formatting") == "When using MessageFormat, '{0}' is replaced with the first parameter."

§显式 MessagesApi

MessagesApi 的默认实现是 DefaultMessagesApi。您可以在文档的测试部分看到 单元测试功能测试 示例。

您也可以在测试中使用 Helpers.stubMessagesApi() 来提供预制的空 MessagesApi

下一步:依赖注入


发现此文档中的错误?此页面的源代码可以在 此处 找到。阅读完 文档指南 后,请随时贡献拉取请求。有疑问或建议要分享?前往 我们的社区论坛 与社区开始对话。