国際化対応として言葉を各言語の翻訳して表示したりするためにRailsではI18n.tを使う。
1.言語ごとの辞書ファイルを作成
翻訳したい言語の数だけ辞書ファイルを用意する(ja.yml、en.yml…)
2.ロケールに応じて辞書ファイルを参照
I18n.tを使って作成しておいた辞書ファイルを参照する。ロケールはHTTPヘッダ等で適当に判断する。
■早速Railsで使ってみる
application.rb
1 2 3 4 5 |
# デフォルトのロケールを設定 config.i18n.default_locale = :ja # 読み込む辞書ファイルのパスを設定 config.i18n.load_path += Dir[Rails.root.join('config', 'locales', '**', '*.{rb,yml}').to_s] |
デフォルトロケールを:jaに設定したので
config/locals/ja.ymlを作成する
1 2 |
ja: test: "テストです" |
I18n.tメソッドを実行
1 2 |
[1] pry(main)> I18n.t("test") => "テストです" |
ja以下の定義を参照できることがわかる。
次に、デフォルトロケールを変更してみる
application.rbを以下のように修正
1 |
config.i18n.default_locale = :en |
1 2 |
[1] pry(main)> I18n.t("test") => "translation missing: en.test" |
なるほど。デフォルトに:enを指定すると、en.ymlを探しに行く模様。
まだ:en用の定義ファイルは作成していないので、エラーとなっている。
(例外等にエラーは吐かず、”translation missing: en.test”文字列を返す)
config/locales/en.ymlを作成して、再度I18n.t(“test”)を実行してみる。
1 2 |
en: test: "it is test" |
1 2 |
[1] pry(main)> I18n.t("test") => "it is test" |
現状のロケールを取得
現状のロケール設定はI18n.localeで取得できる
1 2 |
[4] pry(main)> I18n.locale => :en |
デフォルトで設定している:enになっている。
変更するには
1 2 |
[5] pry(main)> I18n.locale = :ja => :ja |
とすると切り替わる
1 2 |
[8] pry(main)> I18n.locale => :ja |
testにアクセスするとjaの定義にアクセスできる。
1 2 |
[6] pry(main)> I18n.t("test") => "テストです" |
あらかじめymlの形式で翻訳したい言語用のマスタを作成しておいて、リクエストに応じて(ロケールに応じて)、参照先を変更すれば良さそう。
まとめると、
・辞書ファイルを用意しておく
・リクエストよりロケールを取得し、I18n.locale=()でロケール設定することでロケールごとにアプリ内の文言等を出し分けることができる
番外編
■もう少し、I18n.tメソッドを見ていく
変数を埋め込むこともできるようだ
1 2 |
ja: test: "テストです%{arg}" |
1 2 |
[25] pry(main)> I18n.t('test', arg: "よー") => "テストですよー" |
ネストして定義する場合
1 2 3 4 |
ja: data: detail: test: テストです |
1 2 |
[97] pry(main)> I18n.t("data.detail.test") => "テストです" |
“.”でつなげてアクセスできる。
1 2 |
[104] pry(main)> I18n.t("test", scope: "data.detail") => "テストです" |
このようにscopeを使って参照することもできる
ネストの途中を指定すると、ハッシュでの取得となる
1 2 3 4 5 6 |
ja: data: detail: test: テストです error: test: テストです |
1 2 |
[122] pry(main)> I18n.t("data") => {:detail=>{:test=>"テストです"}, :error=>{:test=>"テストです"}} |
■Railsのモデルで使ってみる
この仕組はモデルの翻訳でもよく使用される。
Planモデルがあるとして
Planモデルを翻訳する場合
1 2 3 4 5 6 7 8 9 10 |
ja: activerecord: models: plan: プラン attributes: plan: id: ID name: プラン名 start_date: 開始日 end_date: 終了日 |
こうすると、今まで見てきたような以下のアクセス方法に加えて
1 2 3 4 |
[134] pry(main)> I18n.t("id", scope: "activerecord.attributes.plan") => "ID" [135] pry(main)> I18n.t("name", scope: "activerecord.attributes.plan") => "プラン名" |
human_attribute_nameメソッドでもアクセスすることも可能になる。
1 2 3 4 |
[137] pry(main)> Plan.human_attribute_name("id") => "ID" [138] pry(main)> Plan.human_attribute_name("name") => "プラン名" |
モデルを翻訳する場合はこちらを使ったほうがわかりやすそう。
■バリデーションのエラーメッセージを翻訳する
モデルのバリデーションエラー時に生成されるエラーメッセージも翻訳できる。
以下のようなモデルがあるとする
1 2 3 |
class Plan < ActiveRecord::Base validates :name, presence: true end |
presenceは必須チェックを行い、エラーが発生した場合のキーはデフォルトで:blankとなる。
属性名やキーを予め以下のように定義しておくと、:name は「プラン名」、blankは「は必須です」と翻訳してくれる。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 |
ja: activerecord: models: plan: プラン attributes: plan: id: ID name: プラン名 start_date: 開始日 end_date: 終了日 errors: models: plan: attributes: name: blank: は必須です |
1 2 |
[196] pry(main)> Plan.new.save! ActiveRecord::RecordInvalid: バリデーションに失敗しました: プラン名 は必須です |
キーについては、以下の優先順位に従って定義を探していき、最初に見つかった値を取得する。
上の定義は、一番上の定義なので、優先順位は一番強いということになる。
activerecord.errors.models.user.attributes.name.blank
activerecord.errors.models.user.blank
activerecord.errors.messages.blank
errors.attributes.name.blank
errors.messages.blank