目次
この記事はアピリッツの技術ブログ「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アクセスが走るのでキャッシュを使用する方法も次回記述します。
次回の記事