RailsでのRuby i18n
i18n、便利ですよね。
ビュー内でこうやって、
= t "hoge.fuga.title"
あるいはこうやって、
I18n.t :title, scope: [:hoge, :moge]
こんなYAMLを用意すれば
en:
hoge:
fuga:
title: "TITLE"
ja:
hoge:
fuga:
title: "タイトル"
ばっちり置き換えてくれます。
多言語対応だけでなく、
単純にテキストとサイト構成を疎結合にする為に使っても良いです。
ネストした要素の参照
上で例示しましたが、ネストした要素を参照するには2通りの方法があります。
1つは、
I18n.t "hoge.fuga.title"
のように1つの文字列にしてドットで区切るやり方で、もう1つが、
I18n.t :title, scope: [:hoge, :fuga]
と、scope
と要素名の配列とを使った方法です。
ちなみに、これらは混ぜて使う事もでき、
またシンボルでも文字列でも引数に取ります。
I18n.t :"hoge.fuga.title"
I18n.t "title", scope: [:"hoge.fuga"]
I18n.t :title, scope: %w(hoge fuga)
I18n.t "fuga.title", scope: [:hoge]
I18n.t :"fuga.title", :scope => ["hoge"]
ドットで区切られた単語を階層として扱っているんですね。
キー名にドットを使いたい
さて、本題です。
次のコードはYAMLのどの箇所の要素を参照するでしょうか?
name = "Mr.Smith"
render json: { name: I18n.t("hoge.fuga.#{name}") }
これは式展開されて"hoge.fuga.Mr.Smith"
という文字列になりますので当然、
hoge:
fuga:
Mr:
Smith: "..."
という要素を参照しに行きます。
……多分求めているものと違いますね。
おそらく実際のYAMLは、
hoge:
fuga:
Mr.Smith: "スミスさん"
こんな感じでしょう。
YAMLのキー名にドットが入っている場合、そのキー名を引数に含めても、
I18n.t
メソッドがそれを区切りとして判断してしまうので、
意図したものと違う場所を参照してしまうという事ですね。
そこでこういう希望が出てきます。
Ruby i18nのyamlでキー名にドットを使いたい
separatorを変えよう
いきなり結論ですが、これが手っ取り早そうです。
separatorをデフォルトのドットから変えてしまえば良いのです。
name = "Mr.Smith"
render json: { name: I18n.t(name.intern, scope: [:hoge, :fuga], separator: "\001") }
これで、ドットは区切りとして扱われなくなる為、
Mr.Smithも分割されません。良かった。
"\001"
というのはCtrl-Aで入力できる区切り文字の一種だそうです。
正確に述べると、所謂ASCIIの制御文字で、「ヘッディング開始」を表します。
「ここから読み取り始めるよ」というくらいの意味でしょうか。
キー名に使われている可能性は(少なくともドットよりは)低いでしょう。
ちなみにこの\001
も勿論そのまま区切り文字として使えます。
I18n.t "hoge\001fuga\001Mr.Smith", separator: "\001"
区切り文字は何にしても良いので、
I18n.t "hoge*fuga*Mr.Smith", separator: "*"
とかでも良いわけです。キー名にアスタリスクが入り込んで来なければ。
また、こんなこともできます。
I18n.t "hoge fuga Mr.Smith", separator: " "
特段理由が無ければデフォルトのままで使い、必要ならば、
見やすくて、バグを起こし難いものを選ぶのがいいでしょう。
と、無難にまとめておきます。
勿論デフォルトの区切り文字も変えられます。
I18n::Config.default_separator = "\001"