ホーム DoRuby 【Rails】I18nの言語データをDBから取得【i18n/i18n-active_record】
【Rails】I18nの言語データをDBから取得【i18n/i18n-active_record】
 

【Rails】I18nの言語データをDBから取得【i18n/i18n-active_record】

この記事はアピリッツの技術ブログ「DoRuby」から移行した記事です。情報が古い可能性がありますのでご注意ください。

I18nの言語データをymlではなくDBから取得する方法を記述します。

準備

1.Gemfileに追記してbundle install

Gemfile

gem 'i18n-active_record', :require => 'i18n/active_record'

2.migrateファイル作成

$ bundle exec rails g migrations CreateTranslations locale:string key:string value:text interpolations:text is_proc:boolean
class CreateTranslations < ActiveRecord::Migration
  def self.up
    create_table :translations do |t|
      t.string :locale
      t.string :key
      t.text   :value
      t.text   :interpolations
      t.boolean :is_proc, :default => false

      t.timestamps
    end
  end
end

3.config/initializers/i18n_active_record.rbの作成

require 'i18n/backend/active_record'

Translation = I18n::Backend::ActiveRecord::Translation

if Translation.table_exists?
  I18n.backend = I18n::Backend::ActiveRecord.new

  I18n::Backend::ActiveRecord.send(:include, I18n::Backend::Flatten)
  I18n::Backend::Simple.send(:include, I18n::Backend::Pluralization)

  # 一度呼んだkey,valueをインスタンス変数に保存する場合に使用。
  # 毎回SQLを実行しなくて済むがI18n.reload!しないとDBの値が書き換わっても前回の値が表示される
  # マルチテナント非対応
  # I18n::Backend::ActiveRecord.send(:include, I18n::Backend::Memoize)
  # I18n::Backend::Simple.send(:include, I18n::Backend::Memoize)

  I18n.backend = I18n::Backend::Chain.new(I18n.backend, I18n::Backend::Simple.new)

  # I18n.t()でDBでもファイルでも言語がヒットしなかった場合、その時のkeyやoptions等の情報ををDBに保存したい時に使用
  # 後でレコードやlocaleファイルを追加・更新する時に便利になるが毎度saveが走るためパフォーマンス低下の恐れあり
  # I18n::Backend::Chain.send(:include, I18n::Backend::ActiveRecord::Missing)
  # I18n.backend = I18n::Backend::Chain.new(I18n::Backend::ActiveRecord.new, I18n::Backend::Simple.new)
end

使い方

1. 通常

config/locales/ja.yml

ja:
  user:
    name: ymlのユーザー名
$ bundle exec rails c

[1] pry(main)> I18n.t('user.name')
=> 'ymlのユーザー名'

[2] pry(main)> Translation.create(locale: :ja, key: 'user.name', value: 'DBのユーザー名')
=> #<I18n::Backend::ActiveRecord::Translation...........

[3] pry(main)> I18n.t('user.name')
=> 'DBのユーザー名'

2. proc

$ bundle exec rails c

[1] pry(main)> Translation.create(locale: :ja, key: 'test.proc', value: '1+2', is_proc: true)
=> #<I18n::Backend::ActiveRecord::Translation...........

[2] pry(main)> I18n.t('test.proc')
=> 3

Kernel.eval(value)してるだけみたい。ソース

3. I18n::Backend::ActiveRecord::Missingの使用時

config/initializers/i18n_active_record.rb

# I18n::Backend::Chain.send(:include, I18n::Backend::ActiveRecord::Missing)
# I18n.backend = I18n::Backend::Chain.new(I18n::Backend::ActiveRecord.new, I18n::Backend::Simple.new)

↓コメントアウトを外す

I18n::Backend::Chain.send(:include, I18n::Backend::ActiveRecord::Missing)
I18n.backend = I18n::Backend::Chain.new(I18n::Backend::ActiveRecord.new, I18n::Backend::Simple.new)
$ bundle exec rails c

[1] pry(main)>  I18n.t('user.name', name: 'なまえ', append: 'です')
=> "translation missing: ja.user.name"

[2] pry(main)> Translation.last
=> #<...Translation... id: 1, locale: :ja, key: 'user.name', value: nil, interpolations: [:name, :append], ....

DBに入っていないものを参照したときにレコードが自動的に作られる。
interpolationsカラムにその時の引数の名前が入る。

注意事項

このままではI18n.tを呼ぶたびに毎回DBアクセスが走るのでキャッシュを使用する方法も次回記述します。
次回の記事

記事を共有

最近人気な記事