Skip to content

HTTPS clone URL

Subversion checkout URL

You can clone with HTTPS or Subversion.

Download ZIP
Browse files

Add an ActiveRecordMissing extension that stores empty records for mi…

…ssing

translations to the ActiveRecord backend. This is useful when you e.g. have
a web-based translation tool and want the database to be populated with
empty (missing) translation records as the application is being used.
Translators can then go through these records and add actual translations.
  • Loading branch information...
commit 10c8a26fef279be227dc8cd7bdb49d11c4a03f6a 1 parent ddc0820
@m4ssive m4ssive authored committed
View
21 README.textile
@@ -26,6 +26,22 @@ h2. Install
gem install i18n
+h3. Install on Rails 2.3.4 (deprecated)
+
+Rails 2.3.4 will not accept i18n gems > 0.1.3. There is an unpacked gem inside of active_support/lib/vendor which gets loaded unless gem 'i18n', '~> 0.1.3'. This requirement is relaxed in http://github.com/rails/rails/commit/6da036538334fd459156ab2789c9fae5512be5d2
+
+The following is needed to get the new i18n gem inside vendor/plugins loaded properly.
+
+ def reload_i18n!
+ raise "Move to i18n version 0.2.0 or greater" if Rails.version > "2.3.4"
+
+ $:.grep(/i18n/).each { |path| $:.delete(path) }
+ I18n::Backend.send :remove_const, "Simple"
+ $: << Rails.root.join('vendor', 'plugins', 'i18n', 'lib').to_s
+ end
+
+Then you can `reload_i18n!` inside an i18n initializer.
+
h2. Authors
* "Sven Fuchs":http://www.artweb-design.de
@@ -36,7 +52,4 @@ h2. Authors
h2. License
-MIT License. See the included MIT-LICENCE file.
-
-
-
+MIT License. See the included MIT-LICENCE file.
View
1  init.rb
@@ -0,0 +1 @@
+require File.dirname(__FILE__) + '/lib/i18n'
View
10 lib/i18n/backend/active_record.rb
@@ -1,3 +1,13 @@
+require 'i18n/backend/base'
+require 'i18n/backend/active_record/translation'
+
+#
+# This backend reads translations from a Translations table in environment database. Note that the database
+# will not automatically be prepopulated with missing keys. You can achieve this effect with the ActiveRecordMissing backend,
+# as the following example shows:
+#
+# I18n.backend = I18n::Backend::Chain.new(I18n::Backend::ActiveRecord.new, I18.backend, I18n::Backend::ActiveRecordMissing.new)
+#
module I18n
module Backend
class ActiveRecord
View
10 lib/i18n/backend/active_record/translation.rb
@@ -46,14 +46,16 @@ module Backend
class ActiveRecord
class Translation < ::ActiveRecord::Base
set_table_name 'translations'
- attr_protected :is_proc
+ attr_protected :is_proc, :interpolations
+
serialize :value
+ serialize :interpolations, Array
named_scope :locale, lambda { |locale|
{ :conditions => { :locale => locale.to_s } }
}
- named_scope :lookup, lambda { |keys, separator|
+ named_scope :lookup, lambda { |keys, *separator|
keys = Array(keys).map! { |key| key.to_s }
separator ||= I18n.default_separator
{ :conditions => ["`key` IN (?) OR `key` LIKE '#{keys.last}#{separator}%'", keys] }
@@ -62,6 +64,10 @@ class Translation < ::ActiveRecord::Base
def self.available_locales
Translation.find(:all, :select => 'DISTINCT locale').map { |t| t.locale }
end
+
+ def interpolates?(key)
+ self.interpolations.include?(key) if self.interpolations
+ end
def value
if is_proc
View
55 lib/i18n/backend/active_record_missing.rb
@@ -0,0 +1,55 @@
+#
+# This extension stores untranslated keys as translation stubs in the database. This is useful if you have a web based
+# translation tool. It will populate with untranslated keys as the application is being used. A translator can then go
+# through these. Example usage:
+#
+# I18n::Backend::Chain.send(:include, I18n::Backend::ActiveRecordMissing)
+# I18n.backend = I18nChainBackend.new(I18n::Backend::ActiveRecord.new, I18n::Backend::Simple.new)
+#
+# Stubs for pluralizations will also be created for each key defined in i18n.plural_keys. Eg:
+#
+# en:
+# i18n:
+# plural_keys: [:zero, :one, :other]
+#
+# pl:
+# i18n:
+# plural_keys: [:zero, :one, :few, :other]
+#
+# This extension can also persist interpolation keys in Translation#interpolations. This is useful for translators
+# who cannot infer possible interpolations from the keys, as they can with other solutions such as gettext or globalize.
+#
+module I18n
+ module Backend
+ module ActiveRecordMissing
+
+ def store_default_translations(locale, key, options = {})
+ count, scope, default, separator = options.values_at(:count, *Base::RESERVED_KEYS)
+ separator ||= I18n.default_separator
+ keys = I18n.send(:normalize_translation_keys, locale, key, scope, separator)[1..-1]
+ key = keys.join(separator || I18n.default_separator)
+
+ unless ActiveRecord::Translation.locale(locale).lookup(key, separator).exists?
+ interpolations = options.reject { |name, value| Base::RESERVED_KEYS.include?(name) }.keys
+ keys = count ? I18n.t('i18n.plural_keys', :locale => locale).map { |k| [key, k].join(separator) } : [key]
+ keys.each { |key| store_default_translation(locale, key, interpolations) }
+ end
+ end
+
+ def store_default_translation(locale, key, interpolations)
+ translation = ActiveRecord::Translation.new :locale => locale.to_s, :key => key
+ translation.interpolations = interpolations
+ translation.save
+ end
+
+ def translate(locale, key, options = {})
+ super
+
+ rescue I18n::MissingTranslationData => e
+ self.store_default_translations(locale, key, options)
+
+ raise e
+ end
+ end
+ end
+end
View
1  test/backend/active_record/setup.rb
@@ -13,6 +13,7 @@
t.string :locale
t.string :key
t.string :value
+ t.string :interpolations
t.boolean :is_proc, :default => false
end
end
View
63 test/backend/active_record_missing/active_record_missing_test.rb
@@ -0,0 +1,63 @@
+# encoding: utf-8
+require File.expand_path(File.dirname(__FILE__) + '/../../test_helper')
+require 'i18n/backend/chain'
+require 'i18n/backend/active_record'
+require 'i18n/backend/active_record_missing'
+
+class I18nActiveRecordMissingTest < Test::Unit::TestCase
+ include Tests::Backend::ActiveRecord::Setup::Base
+
+ def setup
+ I18n.backend.store_translations(:en, :i18n => { :plural_keys => [:zero, :one, :other] })
+
+ I18n.backend = I18n::Backend::Chain.new(I18n.backend)
+ I18n.backend.meta_class.send(:include, I18n::Backend::ActiveRecordMissing)
+
+ I18n::Backend::ActiveRecord::Translation.delete_all
+ end
+
+ def test_can_persist_interpolations
+ translation = I18n::Backend::ActiveRecord::Translation.new \
+ :key => 'foo',
+ :value => 'bar',
+ :locale => :en
+
+ translation.interpolations = %w{ count name }
+ translation.save
+
+ assert translation.valid?
+ end
+
+ def test_lookup_persists_key
+ I18n.t('foo.bar.baz')
+
+ assert_equal 1, I18n::Backend::ActiveRecord::Translation.count
+ end
+
+ def test_lookup_does_not_persist_key_twice
+ 2.times { I18n.t('foo.bar.baz') }
+
+ assert_equal 1, I18n::Backend::ActiveRecord::Translation.count
+ end
+
+ def test_persists_interpolation_keys_when_looked_up_directly
+ I18n.t('foo.bar.baz', :cow => "lucy" ) # creates stub translation.
+
+ translation_stub = I18n::Backend::ActiveRecord::Translation.locale(:en).lookup('foo.bar.baz').first
+ assert translation_stub.interpolates?(:cow)
+ end
+
+ def test_creates_one_stub_per_pluralization
+ I18n.t('foo', :count => 999)
+
+ translations = I18n::Backend::ActiveRecord::Translation.locale(:en).find_all_by_key %w{ foo.zero foo.one foo.other }
+ assert_equal 3, translations.length
+ end
+
+ def test_creates_no_stub_for_base_key_in_pluralization
+ I18n.t('foo', :count => 999)
+
+ translations = I18n::Backend::ActiveRecord::Translation.locale(:en).find_by_key %w{ foo.zero foo.one foo.other }
+ assert !I18n::Backend::ActiveRecord::Translation.locale(:en).find_by_key("foo")
+ end
+end
Please sign in to comment.
Something went wrong with that request. Please try again.