鍋の底

雑多な記録

rails3とfast_gettextとgettext_i18n_rails

gettextのpoファイルを使用した国際化について、最近のrailsでの日本語の記事が見つけられなかったので、試しにやってみました。 *1

ベースになるアプリケーションは何でもよかったので、 http://railstutorial.jp/chapters/a-demo-app.html#top のデモアプリケーションを利用します。

今回はrails3系の最新(?)の3.2.14でやってみます。

チュートリアルのデモアプリを作成

ほぼチュートリアル通りに実行します。 異なったのは rails new の際にバージョンを指定したことぐらいです。 指定せずにrails4でやっても良かったかもしれません。

fast_gettext と gettext_i18n_rails のインストール

ここから、fast_gettextとそのrails I/F の gettext_i18n_rails を適用していきます。

その前に、ここで今回の適用方針を決めておきます。 といってもなるべくシンプルにしたいので、以下のような感じにします。

  • 翻訳はpoファイルのみで行う。moファイルは使用しない。
  • 翻訳のDB管理は今回対象外。
  • haml/slimファイルの翻訳は今回考えない。

https://github.com/grosser/gettext_i18n_rails によると、pluginとしてのインストールとgemとしてのインストールがあるようです。 ここではgemとしてインストールすることにします。

gemとしてインストールするにはGemfileに次の行を追加します。

gem 'gettext_i18n_rails'

bundle install すると、gettext_i18n_rails と fast_gettext がインストールされます。

アプリケーションへの組み込み

rails-i18n の成果の利用

gettext_i18n_railsrails標準(?)のi18nと、排他になるのではなく、共存できるようです。 https://github.com/svenfuchs/rails-i18n/tree/master/rails/locale/ の翻訳ファイルには、翻訳済みのエラーメッセージや曜日などが収められていて、これを利用したほうがよいでしょう。

i18nで使用するように、config/locales に ja.ymlを格納します。

fast_gettextの初期化

config/initializers/fast_gettext.rb を作成して、以下を追加します。

FastGettext.add_text_domain 'app', :path => 'locale', :type => :po
FastGettext.default_available_locales = ['en','ja']
FastGettext.default_text_domain = 'app'

上記:pathで指定したディレクトリを作成しておいてください

mkdir locale

アプリケーションへの組み込み

app/controllers/application_controller.rb の ApplicationController クラス宣言の中に次の行を追加してください。

before_filter :set_gettext_locale

翻訳準備

翻訳したい文字列リテラル 'foobar' を _('foobar') のように囲みます。 囲み終わったら、以下のrakeターゲットを実行してください。

$ rake gettext:find

これで、locale/app.pot が生成されます。 ファイル名は、環境変数TEXTDOMAINの値、FastGettext.default_text_domainの値の順に参照されます*2

potファイルから、各言語のpoファイルを作成するには、GNU gettext で配布されている msginit を用いて、次のようにします。作成先は locale/言語コード としてください。

$ msginit -i locale/app.pot -o locale/ja/app.po

または、次のように単純にコピーしてから、内容を編集しても構いません。

$ cp locale/app.pot locale/ja/app.po

エラーメッセージや、画面表示などは、モデルから文字列を取得しています。 モデルの属性を翻訳できるようにしたほうが都合がいいと思います。 次のrakeターゲットでモデルの文字列を locale/model_attributes.rb に抽出しておきます。

$ rake gettext:store_model_attributes

翻訳

GNU gettext のpoファイルの編集と同じように翻訳できますし、共通のツールを利用できます。

特に locale/model_attributes.rb 由来なのですが、msgidが「User|Email」のようになっているものがあります。 「|」で名前空間の表しますので、msgstrには「電子メール」のように訳してください。「User|」を訳出する必要はありません。

適用

アプリを起動し、翻訳が反映されていることを確認できました。 ここで一つ疑問が。localeを明示していないのに、なぜ反映されているのでしょうか?

実はapp/controllers/application_controller.rbに指定した、set_gettext_locale メソッドに理由がありました。

set_gettext_locale メソッドのソースを見ると、次の順番にlocaleを評価して決定します。

  1. リクエストパラメータのlocale
  2. セッション内のlocale
  3. cookie内のlocale
  4. HTTP_ACCEPT_LANGUAGE
  5. I18n.default_locale

このため、特に指定せずともブラウザの表示言語からlocaleを決定していました。 一度決定してしまうと、cookieに記憶したセッションに記録されてしまうため、リクエストパラメータにlocaleを指定したり、cookieを削除したりしないと、言語の変更ができないことになります。

実際に、言語切り替えのロジックを実装する際には、このあたりに留意したほうがいいでしょうね。

まとめと課題

今回は、ここまでにしましたが、いくつか課題があります。

  • 実行時にpoファイルをパースしていると思うのだけど、遅くないかな?
  • pluralizeはどう処理するべきでしょうね。
  • viewのhtml部分の文字列はどうしましょう? (haml/slimファイルの翻訳で扱うのか?)

次はviewについて調べてみます。

*1:あとから http://d.hatena.ne.jp/next49/20101016/p1 を見つけました

*2:自分の環境では、TEXTDOMAINが別途定義されていて、思ったファイル名にならなかったりしました。unsetすればOK