やりたいこと
https://github.com/svenfuchs/rails-i18n/blob/v6.0.0/rails/locale/ja.yml の翻訳ファイルを i18n を使って読み込むと、以下のような hash を取得できます。
require 'i18n'
I18n.load_path << 'rails/locale/ja.yml'
I18n.locale = :ja
I18n.t('.')
#=>
# {:activerecord=>{:errors=>{:messages=>{:record_invalid=>"バリデーションに失敗しました: %{errors}", :restrict_dependent_destroy=>{:has_one=>"%{record}が存在しているので削除できません", :has_many=>"%{record}が存在しているので削除できません"}}}},
# :date=>
# {:abbr_day_names=>["日", "月", "火", "水", "木", "金", "土"],
# :abbr_month_names=>[nil, "1月", "2月", "3月", "4月", "5月", "6月", "7月", "8月", "9月", "10月", "11月", "12月"],
# (省略)
# :datetime=>
# {:distance_in_words=>
# {:about_x_hours=>{:one=>"約1時間", :other=>"約%{count}時間"},
# :about_x_months=>{:one=>"約1ヶ月", :other=>"約%{count}ヶ月"},
# (省略)
# :prompts=>{:second=>"秒", :minute=>"分", :hour=>"時", :day=>"日", :month=>"月", :year=>"年"}},
# :errors=>
# {:format=>"%{attribute}%{message}",
# :messages=>
# {:accepted=>"を受諾してください",
# :blank=>"を入力してください",
# (省略)
これを以下のようなフラットな hash に変換したいです。
{
"activerecord.errors.messages.record_invalid" => "バリデーションに失敗しました: %{errors}",
"activerecord.errors.messages.restrict_dependent_destroy.has_one" => "%{record}が存在しているので削除できません",
"activerecord.errors.messages.restrict_dependent_destroy.has_many" => "%{record}が存在しているので削除できません",
"date.abbr_day_names"=>["日", "月", "火", "水", "木", "金", "土"],
"date.abbr_month_names"=>[nil, "1月", "2月", "3月", "4月", "5月", "6月", "7月", "8月", "9月", "10月", "11月", "12月"],
# 省略
"datetime.distance_in_words.about_x_hours.one" => "約1時間",
"datetime.distance_in_words.about_x_hours.other" => "約%{count}時間",
"datetime.distance_in_words.about_x_months.one" => "約1ヶ月",
"datetime.distance_in_words.about_x_months.other" => "約%{count}ヶ月",
# 省略
"datetime.prompts.second" => "秒",
"datetime.prompts.minute" => "分",
"datetime.prompts.hour" => "時",
"datetime.prompts.day" => "日",
"datetime.prompts.month" => "月",
"datetime.prompts.year" => "年",
"errors.format" => "%{attribute}%{message}",
"errors.messages.accepted" => "を受諾してください",
"errors.messages.blank" => "を入力してください",
# 省略
}
例えば言語ファイル (YAML) を複数に分割している場合に、すべての翻訳データを列挙するためにこのようなフラットな hash を取得したいです。
方法
ネストした hash を再帰的に処理してフラットな hash に変換するためのメソッドを用意します。
def flatten_nested_hash(hash, previous_key: nil, flat_hash: {})
hash.each do |key, value|
current_key = [previous_key, key.to_s].compact.join('.')
if value.is_a?(Hash)
flatten_nested_hash(value, previous_key: current_key, flat_hash: flat_hash)
next
end
flat_hash[current_key] = value
end
flat_hash
end
flat_hash = flatten_nested_hash(I18n.t('.'))
flat_hash['datetime.distance_in_words.about_x_hours.other']
#=> "約%{count}時間"
I18n.t('datetime.distance_in_words.about_x_hours.other')
#=> "約%{count}時間"