概要
以前GlobalSettingの撲滅に関してブログを書きましたが、言語対応に関して書いていなかったので、続編ということでブログにまとめました。
yuutookun.hatenablog.com
前提
Play2.4移行の対応を以下スライドを参考に実施。
http://sssslide.com/speakerdeck.com/tsuyoshizawa/play-2-dot-3-kara-2-dot-4-heatupudetositahua
import play.api.play.current
import play.api.i18n.Messages.Implicits._
言語対応に関しては、上記のようにimportを追加して一旦対応していました。
コンパイルは通っていましたが、このままではCookieに対応される言語に変換
これでは翻訳が実行されていませんでした。
根本対応
以下の5ステップで対応を進めました。
1.コントローラーをInjectionの形に移行
変更前
object Account extends Controller
変更後
import javax.inject.Inject
class Account @Inject() () extends Controller
このようにInjectionの形に修正
同時にroutesの設定を以下に変更
GET /accounts controllers.Accounts.index
GET /accounts @controllers.Accounts.index
2.DefaultMessageApiを継承した自前のmessageApiを作成
MeMessageApiを作ります。
package models
import javax.inject.{ Inject, Singleton }
import consts.AppConfig
import play.api.i18n.{ DefaultMessagesApi, Lang, Langs, Messages }
import play.api.mvc.RequestHeader
import play.api.{ Configuration, Environment }
@Singleton
class MyMessageApi @Inject() (
environment: Environment,
configuration: Configuration,
langs: Langs) extends DefaultMessagesApi(environment, configuration, langs) {
private lazy val cookieName = AppConfig.play.modules.i18n.langCookieName.toString
override def preferred(request: RequestHeader) = {
val langOp = request.cookies.get(cookieName).map(_.value)
langOp.fold(super.preferred(request))(lang => new Messages(Lang(lang), this))
}
}
3.MessageModuleを作成
作成したMyMessageApiをbindします。
package modules
import models.MyMessageApi
import play.api.i18n.{ DefaultLangs, Langs, MessagesApi }
import play.api.{ Configuration, Environment }
import play.api.inject.Module
class MyMessageModule extends Module {
def bindings(environment: Environment, configuration: Configuration) = {
Seq(
bind[Langs].to[DefaultLangs],
bind[MessagesApi].to[MyMessageApi]
)
}
}
4,confにそのmoduleを使う旨を記述
application.confなどに書きます。
play.modules.enabled += "modules.MyMessageModule"
play.modules.disabled += “play.api.i18n.I18nModule"
5,各controllerが継承している親クラスに対してI18nSupportを継承させ、messageApiをInjectさせる
import play.api.i18n.{ I18nSupport, Lang, Messages }
trait BaseController extends I18nSupport { }
class Account @Inject() (val messageApi: MessageApi) extends Controller extends BaseController
元々BaseControllerを継承させていたので、そのControllerにI18nSupportを継承させれば、全部動くので、この方式を取りました。
MessageApiを使うControllerが少ないのであれば、個別に継承させたほうがいいですね。
ここのMessageApiは型を変えなくてもconfでmodule指定をしているので、
自動でMyMessageModuleがDIされてきます。
以上が、i18nの対応です。
まとめ
Controllerが多いと改修範囲が大きいですが、
moduleの形で実装すればロジック的な改修範囲は最低限に抑えられるので、ぜひ挑戦してみてください。
参考URL
play2-i18n-patterns