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