并非所有后端都符合相同的接口(在我看来这非常可怕),但是您可以通过猴子补丁或创建自己的基于内置的后端之一来完成您需要做的事情I18n 后端。
例如,我想拥有一个回退到默认 rails I18n 后端的 redis 后端,并且我需要它与 i18n-js gem 一起工作。由于 KeyValue 后端允许您查找整个子树的翻译,因此只要您将所有内容存储在顶级键下,就可以模拟“翻译”方法。就这么简单:backend.translate(:en, 'top-level-key')"
# config/initializers/custom_i18n.js
module CustomI18n
def self.backend
Backend::Chain.new
end
module Backend
class Chain < I18n::Backend::Chain
def initialize
super(RedisStore.new, I18n::Backend::Simple.new)
end
def initialized?
backends.all? do |backend|
!backend.respond_to?(:initialized?) || backend.initialized?
end
end
protected
def translations
backends.each_with_object({}) do |backend, hash|
backend.instance_eval do
if respond_to?(:translations, true)
hash.deep_merge! translations
else
available_locales.each do |locale|
translations = translate(locale, RedisStore::SCOPE, :scope => nil) rescue ArgumentError
hash.deep_merge!({ locale => translations }) if translations
end
end
end
end
end
end
class RedisStore < I18n::Backend::KeyValue
SCOPE = 'redis'
def initialize(*args)
super(Redis.new)
end
def translate(*args)
args << {} unless args.last.is_a?(Hash)
args.last[:scope] = SCOPE unless args.last.has_key?(:scope)
super
end
def store_translations(locale, data, options = {})
super(locale, { SCOPE => data }, options)
end
end
end
end
I18n.backend = CustomI18n.backend
因此,使用这种方法,您可以执行以下操作:
redis_backend = I18n.backend.backends.find { |backend| backend.is_a?(CustomI18n::Backend::RedisStore) }
redis_backend.store_translations(:en, {:foo => { :bar => { :baz => 'qux' } } })
并且它会自动存储在“redis”的顶级键下,但您可以通过各种不同的方式正常访问它:
> I18n.backend.send(:translations)[:en][:foo]
=> {:bar=>{:baz=>"qux"}}
> I18n.t('foo')
I18N keys: [:en, :foo]
=> {:bar=>{:baz=>"qux"}}
但是如果你真的看一下redis,你会发现它存储在顶级键下:
> Redis.new.get('en.redis')
=> "{\"foo\":{\"bar\":{\"baz\":\"qux\"}}}"