LoginSignup
19
24

More than 5 years have passed since last update.

Playframework の Lang でつらいところ

Last updated at Posted at 2014-09-10

基本的な使い方

Playframework で国際化するときには play.api.i18n.Messages() を使う。

val title = Messages("home.title")

でもって conf/messages, conf/messages.ja などに次のように書いておくと翻訳される。

home.title=ホーム

Messages("home.title")play.api.i18n.Messagesapply() メソッドを呼び出している。apply() メソッドは play.api.i18n.Lang 型 (以下 Lang)の implicit 引数を取る。

def apply(key: String, args: Any*)(implicit lang: Lang): String

Messages.apply() はテンプレートの中で使われることが多い。
公式ドキュメントでは twirl テンプレートに implicit で Lang を渡すように Note が書かれている。

@* テンプレートの引数宣言。implicit で Lang を渡す *@
@()(implicit lang: Lang)

<h1>@Messages("home.title")</h1>

テンプレート以外の場合でも同じように implicit で渡すことができる。

  // Scala コード中で implicit として渡す
  def title(implicit l: Lang) = Messages("home.title")

コントローラメソッドを Action で書くときは implicit な play.api.mvc.Request を取るようにして使う。

  def index = Action { implicit request =>
    Ok(views.html.index())
  }

問題

Lang implicit を渡し忘れてもコンパイルエラーにならない。

Lang companion object に implicit が定義されている。引数で渡し忘れるとそちらが使われる。

なお companion object の実装は、JVMが動作している環境のデフォルト言語となる。リクエストごとに言語を切り替えたいことが多いため、companion object の実装が使われると残念な思いをすることが多い。

よくある例1. テンプレートの引数で宣言し忘れる

@* (implicit lang: Lang) を付け忘れ *@
@()

<h1>@Messages("home.title")</h1>

よくある例2. 関数の引数で宣言し忘れる

  // (implicit l: Lang) を付け忘れ
  def title = Messages("home.title")

よくある例3. implicit request を付け忘れる

Request から Lang へは play.api.mvc.Controller#request2lang() の implicit 変換がなされるが、Request がなければ Lang へも変換されない。

  // implicit request => を付け忘れ
  def index = Action {
    Ok(views.html.index())
  }

よくはないけどはまった例

わかったよ。implicit で引き回すから忘れるんだろう。普通の引数にすればいいじゃないか。

  // Play 2.2 では companion object の Lang が使われてしまう
  def index = Action { implicit request =>
    // 暗黙的なものを取り出して、
    val lang = implicitly[Lang]
    // 以下 lang を明示的に渡して回る
    ...
  }

Play 2.2 では Request から Lang に変換する implicit def の名前が lang で、local 変数によって implicit が効かなくなる模様。(Scala のバグ?)
lang 以外の変数名(例えば _lang)を使えば期待したとおり動作する。

Play 2.3 では request2lang という名前に置き換わった。 val request2lang = ... とすれば同じような問題が発生しそう。

https://github.com/playframework/playframework/issues/2605
https://gist.github.com/tkawachi/8e4987441f775786d1d8

解決法

だれか良い解決法をください。

コメント欄に素敵な解決策が。

メモ

IntelliJ で Cmd+Shift+p を押すと、カーソルがある場所で使われている implicit がどこで定義されているかを参照することができる。便利。知らなかった。

Screen Shot 2014-09-10 at 14.17.35.png

19
24
3

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
19
24