ドキュメントを読み込むのは大事、ということでRailsガイドを頭から読んでいく取り組みをしています。 各章ごとに、(Railsガイドにちゃんと書いてあるのに)知らなかった機能を雑にまとめていきます。
今回は、Rails 国際化(I18n)APIの章です。
railsguides.jp
パラメータでロケールを管理する際の工夫されたURL設計
リンクはこちら
ルーティングを以下のように書くことで、https://xxx.com/yyy?locale=ja
などではなく、https://xxx.com/en/yyy
にアクセスした際にparams
でlocale
を受け取ることができます。
※あくまでparams
のlocale
で値を受け取れるだけで、ロケールが変更されるというわけではないです。
scope "/:locale" do
resources :books
end
Railsガイド中の、以下の記載もなるほどなーと思いました。
アプリケーションの設計面から見れば、ロケールはアプリケーションドメインの他の部分よりも構造上の上位に位置するのだから、ロケール情報もURLの上位に置くべきという考え方もあります。
アプリによっては、基本は日本が対象であれば、Railsガイドにも紹介されている以下のように省略(デフォルト)できるようにするのが良さそうです。
さらに以下では言語も絞っていて、enかja以外だとRoutingErrorになります。
scope "(:locale)", locale: /en|ja/ do
resources :books
end
リンクはこちら
ロケールはURLの一部にするべきであるということが書いてあります。
URLを共有した相手が同じページを見れる「RESTful」であることを守るためということです。
リンクはこちら
つい先日会社の勉強会でも話題になったのですが、YAMLのクセについてです。
いくつか特定のキーはエスケープしないと訳文が見つからないエラーになってしまいます。
true
とかfalse
とかはなんとなくわかりますが、yes
, no
, on
, off
あたりもエスケープしないといけないのは個人的に驚きがある仕様です。
知らないと地味にハマりポイントになりそうです。
sample:
on: 'Sample On!'
dummy:
'on': 'Dummy On!'
I18n.t('sample.on')
I18n.t('dummy.on')
index.en.html.erb
でテンプレートファイルごと区別する
リンクはこちら
たとえば3つ上のところで設定したようなルーティング(英語と日本語のロケールがあるもの)のとき、index.en.html.erb
などとすることでロケールによってテンプレートファイルを分けることができます。
1つのファイルで表現するのは難しいとか、内容が大きく異なるときなどはこちらを使うのが良さそうです。
ただ、試したところ、たとえばデフォルトロケールが日本語の状態で、index.ja.html.erb
とindex.html.erb
だけ用意して英語のロケールでアクセスすると、index.ja.html.erb
が使われました。
なんとなくindex.html.erb
が使われるのかな?と思っていたのでこの優先度は意外でした。
translateメソッドの参照
リンクはこちら
scope
sample:
parent:
child1:
child2: 'Child2!'
上記は以下で呼び出せます。文字列の形で.
で繋ぐ方法しか使ってこなかったので知りませんでした。
I18n.t(:child2, scope: [:sample, :parent, :child1])
default
訳文が見つけられなかったときに表示するものを指定できます。
dummy: '見つけられなかったらこれ'
I18n.t('no_exist', default: :dummy)
I18n.t('no_exist', default: [:no_exist1, :no_exist2, :dummy])
=> "見つけられなかったらこれ"
ハッシュで複数取得
parent:
child1: 1つ目
child2: 2つ目
child3: 3つ目
配列で複数取得したり、親要素を指定してハッシュで取得したりもできます。
I18n.t(['parent.child1', 'parent.child2'])
I18n.t('parent')
deep_interpolation: trueで変数を使う
まとめて取得する際に変数に値を入れたい場合はdeep_interpolation: true
を使う必要があります。
parent:
child1: 1つ目
child2: 2つ目 %{foo}
I18n.t('parent', deep_interpolation: true, foo: 'フー')
i18n.plural.rule
で固有の複数形化のルールを設定できるというものです。
I18n::Backend::Simple.include(I18n::Backend::Pluralization)
を使うことで柔軟な複数形の対応ができるようになります。
apples:
one: 0もしくは1
other: 1より大きい
I18n.t :apples, count: 0, locale: :ja
I18n::Backend::Simple.include(I18n::Backend::Pluralization)
I18n.backend.store_translations :ja, i18n: { plural: { rule: lambda { |n| [0, 1].include?(n) ? :one : :other } } }
I18n.t :apples, count: 0, locale: :ja
バックエンドを切り替える
リンクはこちら
I18n.backend=
でバックエンドを切り替えることができます。
Redisを読みに行くようにするなどをすることがあるみたいですね。
たとえば以下のように適当にバックエンドを指定してあげると、.ymlファイルでは翻訳ができなくなりました。
hello: こんにちは
config.i18n.backend = I18n::Backend::KeyValue.new(String.new)
I18n.t('hello')
訳文が見つからなかった時に例外を発生させる
リンクはこちら
config.i18n.raise_on_missing_translations = true
にすることで訳文が見つからなかった場合に例外が発生します。
viewでtranslateメソッドを使った場合には訳文が見つからないとkey名をそのまま返すため、訳文の実装を忘れていても意外と気づきにくいです。
Railsガイドで書いてあるようにtest環境(もしかしたらdevelopment環境も?)をtrueにするのはアリだなと思いました。