§メッセージによる国際化
§アプリケーションでサポートされる言語の指定
アプリケーションの言語は、言語タグを使用して指定します。言語タグは、特定の言語を識別する特別な形式の文字列です。言語タグでは、英語の場合は「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
§メッセージと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")
§コントローラーでのメッセージの使用
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
ヘッダー(およびオプションで言語クッキー)から抽出され、messagesApi.preferred
を使用してMessagesApi
でサポートされている言語のいずれかと照合されます。
§言語クッキのサポート
I18nSupport
は、Result
に2つの便利なメソッドも追加します。
result.withLang(lang: Lang)
は、Playの言語クッキーを使用して言語を設定するために使用されます。result.withoutLang
は、言語クッキーをクリアするために使用されます。
例えば、
def homePageInFrench: Action[AnyContent] = Action {
Redirect("/user/home").withLang(Lang("fr"))
}
def homePageWithDefaultLang: Action[AnyContent] = Action {
Redirect("/user/home").withoutLang
}
withLang
メソッドは、将来のリクエストのためにPLAY_LANG
という名前のクッキーを設定しますが、withoutLangはクッキーを破棄し、PlayはクライアントのAccept-Languageヘッダーに基づいて言語を選択します。
クッキー名は、設定パラメーター:play.i18n.langCookieName
を変更することで変更できます。
§暗黙的な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)
§アポストロフィに関する注意事項
メッセージは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
を提供することもできます。
次へ:依存性注入
このドキュメントに誤りを見つけましたか?このページのソースコードはこちらにあります。ドキュメントガイドラインをお読みいただいた後、プルリクエストをお送りください。質問やアドバイスはありますか?コミュニティフォーラムにアクセスして、コミュニティとの会話を始めましょう。