k4200’s notes and thoughts

Programmer side of k4200

Play! framework 2.0でのi18n関連

Scala Advent Calendar 2012の2日目、のはずだったけど、諸事情によりこちらの 12/5 の記事になりました。

Play! framework 2.0のアプリを国際化する方法についてちょっと書きます。基本はここに書いてある通りだけど、補足とか書いていない事とかハマりポイントとか。

前提・環境

  • Play 2.0.4
  • 英語・日本語の2か国語に対応
  • 英語がデフォルトの言語

メッセージカタログにメッセージを外出し

基本

以下の3ファイルを用意

  • conf/messages.en → 英語のメッセージ
  • conf/messages.ja → 日本語のメッセージ
  • conf/messages → デフォルトのメッセージ

最初の2つは説明不要だと思うので、最後のに関して説明。

デフォルトのメッセージファイル

例えばviewの中で以下のような記述があり、

@Messages("index.welcome", user.name)

ユーザーの言語(これがどうやって定まるかは後述)が"ja"だとすると、messages.ja の以下の行が使われる。

#messages.ja
index.welcome={0}さん、ようこそ

仮に、この行がないと、messages の中の対応する行が使われる。

#messages
index.welcome=Welcome {0}!
実際の開発での流れ

ということで、自分なりの結論。

  • messages にはデフォルトの言語の内容を入れておく(この場合は英語)
  • messages.en はそれのコピーとかシンボリックリンクにしておく
  • サブの言語(この場合、日本語)用のファイルは、messages の内容を翻訳

ちなみに、規模が大きくなって翻訳者とかが複数人絡むようになってくると、メッセージファイルをテキストのままで単純に管理するのは辛くなってくるので、翻訳者用のシステムとDBを用意して、そのDBからテキストファイルを出力するようにしたほうが良さそう。(Play じゃないけど、別プロジェクトではそうした)

画像

ファイルの配置

メッセージだけ多言語対応すればi18nが完了すると思っちゃだめで、画像内のテキストとかも対応する必要がある。

画像は以下の様な感じでフォルダ分けしておく。

  • public/images/common → 言語関係なく使う画像(字のないアイコン、線、背景等)
  • public/images/en → 英語用の画像
  • public/images/ja → 日本語用の画像
viewからの参照

画像を表示する場合は、基本は後述するCSS(LESS)で対応した方が簡単だけど、view 内で直接 img タグを書きたい場合には以下のようにする。

@(param: some.Type)(implicit lang: Lang)
<!-- ↑先頭で implicit parameter として lang を受け取る -->

<img src="images/@lang.language/foo.png" />

CSS

プロジェクトの設定

Build.scala は以下のように。

    // どの less ファイルをコンパイルするか、みたいな設定
    def customLessEntryPoints(base: File): PathFinder = (
      (base / "app" / "assets" / "stylesheets" * ("*.less" -- "_*.less"))
    )

    // project 設定に、lessEntryPoints を追加。
    val main = PlayProject(appName, appVersion, appDependencies, mainLang = SCALA).settings(
      // Add your own project settings here
        lessEntryPoints <<= baseDirectory(customLessEntryPoints),
    )

これで準備完了。

LESS

LESS便利だね。lessファイルの配置に関して説明。

まずはapp/assets/stylesheets というディレクトリを作成し、その配下に以下のようにファイルを作成。

  • en.less
  • ja.less
  • _common.less (サブディレクトリに入れてもよし)

en.less はこんな感じ。ja.lessも同様に作る。

@lang: en;
@import "_common.less";

_common.less はこんな感じ。

.logo {
	background: url("/images/@{lang}/logo.png");
}

これで、en.css は以下のように生成される。

.logo {
  background: url("/images/en/logo.png");
}

LESS便利だね。

LESSのハマりポイント

とにかくエラーメッセージが分かりにくい。

LESSの行末のセミコロンがなかったり(Scalaプログラマーがよくやる間違い)、urlのダブルクォートがなかったりすると意味不明のメッセージが出る。そのメッセージでググると、Play自体のバグだとか、ライブラリのバグだとか色々情報が出てくるけど、実際は簡単なミスだったりする。

ということで、いきなりがっつり書かず、まずは簡単なLESSファイルを書いてある程度仕組みに慣れてから、徐々にやってくと良さそう。

ちなみに、出たエラーはこんなの。

EcmaError: TypeError: Cannot call method "charAt" of undefined (less-1.3.0.js#352)

まとめ

Play 2.0の多言語対応は、基本的な機能は揃っているので、どんどん海外対応のアプリ・サービスを作るといいのでは。