§使用消息进行国际化
§指定您的应用程序支持的语言
您可以使用语言标签为您的应用程序指定语言,语言标签是专门格式化的字符串,用于标识特定语言。语言标签可以指定简单的语言,例如“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.fr
或 conf/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
由于通常需要在不提供参数的情况下使用消息,因此您可以将给定的 Lang
与 MessagesApi
结合起来以创建 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
您可以通过扩展 MessagesAbstractController
或 MessagesBaseController
为您的请求添加 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
添加了以下方法。
request.messages
使用隐式MessagesApi
返回Messages
的实例。request.lang
使用隐式MessagesApi
返回首选的Lang
。
首选语言是从 Accept-Language
标头(以及可选的语言 cookie)中提取的,并使用 messagesApi.preferred
与 MessagesApi
支持的语言之一匹配。
§语言 Cookie 支持
I18nSupport
还为 Result
添加了两个方便的方法。
result.withLang(lang: Lang)
用于使用 Play 的语言 cookie 设置语言。result.withoutLang
用于清除语言 cookie。
例如
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
。
下一步:依赖注入
发现此文档中的错误?此页面的源代码可以在 此处 找到。阅读完 文档指南 后,请随时贡献拉取请求。有疑问或建议要分享?前往 我们的社区论坛 与社区开始对话。