i18n-active_record-backend 0.1.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -0,0 +1,22 @@
1
+ Copyright (c) 2010 Sven Fuchs <svenfuchs@artweb-design.de>
2
+ Copyright (c) 2013 Endika Gutiérrez <me@endika.net>
3
+
4
+ Permission is hereby granted, free of charge, to any person obtaining
5
+ a copy of this software and associated documentation files (the
6
+ "Software"), to deal in the Software without restriction, including
7
+ without limitation the rights to use, copy, modify, merge, publish,
8
+ distribute, sublicense, and/or sell copies of the Software, and to
9
+ permit persons to whom the Software is furnished to do so, subject to
10
+ the following conditions:
11
+
12
+ The above copyright notice and this permission notice shall be
13
+ included in all copies or substantial portions of the Software.
14
+
15
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
16
+ EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
17
+ MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
18
+ NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
19
+ LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
20
+ OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
21
+ WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
22
+
@@ -0,0 +1,61 @@
1
+ h1. I18n::Backend::ActiveRecord
2
+
3
+ This repository contains the I18n ActiveRecord backend and support code that has been extracted from the "I18n gem":http://github.com/svenfuchs/i18n.
4
+
5
+ h2. Installation
6
+
7
+ For Bundler put the following in your Gemfile:
8
+
9
+ <pre>
10
+ gem 'i18n-active_record',
11
+ :git => 'git://github.com/svenfuchs/i18n-active_record.git',
12
+ :branch => 'rails-3.2',
13
+ :require => 'i18n/active_record'
14
+ </pre>
15
+
16
+ This gem can generate a migration to create a database table named @translations@, which will store the localized strings.
17
+
18
+ <pre>
19
+ rails g i18n:active_record:install
20
+ rake db:migrate
21
+ </pre>
22
+
23
+ To load @I18n::Backend::ActiveRecord@ into your Rails application, create a new file in *config/initializers* named *locale.rb*.
24
+
25
+ A simple configuration for your locale.rb could look like this:
26
+
27
+ <pre>
28
+ require 'i18n/backend/active_record'
29
+ I18n.backend = I18n::Backend::ActiveRecord.new
30
+ </pre>
31
+
32
+ A more advanced example (thanks, Moritz), which uses YAML files and ActiveRecord for lookups:
33
+
34
+ <pre>
35
+ require 'i18n/backend/active_record'
36
+ I18n.backend = I18n::Backend::ActiveRecord.new
37
+
38
+ I18n::Backend::ActiveRecord.send(:include, I18n::Backend::Memoize)
39
+ I18n::Backend::ActiveRecord.send(:include, I18n::Backend::Flatten)
40
+ I18n::Backend::Simple.send(:include, I18n::Backend::Memoize)
41
+ I18n::Backend::Simple.send(:include, I18n::Backend::Pluralization)
42
+
43
+ I18n.backend = I18n::Backend::Chain.new(I18n::Backend::Simple.new, I18n.backend)
44
+ </pre>
45
+
46
+ h2. Usage
47
+
48
+ You can now use @I18n.t('Your String')@ to lookup translations in the database.
49
+
50
+ h2. Contributing
51
+
52
+ <pre>
53
+ bundle install --gemfile=ci/Gemfile.rails-3.2
54
+ rake
55
+ </pre>
56
+
57
+ h2. Maintainers
58
+
59
+ * "Sven Fuchs":http://github.com/svenfuchs
60
+ * "Jeremy Weiskotten":http://github.com/jeremyw
61
+
@@ -0,0 +1,11 @@
1
+ require 'rake'
2
+ require 'rake/testtask'
3
+
4
+ Rake::TestTask.new do |t|
5
+ t.libs << 'lib' << 'test'
6
+ t.pattern = 'test/**/*_test.rb'
7
+ t.verbose = false
8
+ t.warning = false
9
+ end
10
+
11
+ task :default => :test
@@ -0,0 +1,8 @@
1
+ source :rubygems
2
+
3
+ gem 'i18n', '~> 0.6.0'
4
+ gem 'activerecord', '~> 3.2.0'
5
+ gem 'activesupport', '~> 3.2.0'
6
+
7
+ gem 'sqlite3'
8
+ gem 'mocha'
@@ -0,0 +1,33 @@
1
+ GEM
2
+ remote: http://rubygems.org/
3
+ specs:
4
+ activemodel (3.2.3)
5
+ activesupport (= 3.2.3)
6
+ builder (~> 3.0.0)
7
+ activerecord (3.2.3)
8
+ activemodel (= 3.2.3)
9
+ activesupport (= 3.2.3)
10
+ arel (~> 3.0.2)
11
+ tzinfo (~> 0.3.29)
12
+ activesupport (3.2.3)
13
+ i18n (~> 0.6)
14
+ multi_json (~> 1.0)
15
+ arel (3.0.2)
16
+ builder (3.0.0)
17
+ i18n (0.6.0)
18
+ metaclass (0.0.1)
19
+ mocha (0.10.5)
20
+ metaclass (~> 0.0.1)
21
+ multi_json (1.2.0)
22
+ sqlite3 (1.3.5)
23
+ tzinfo (0.3.32)
24
+
25
+ PLATFORMS
26
+ ruby
27
+
28
+ DEPENDENCIES
29
+ activerecord (~> 3.2.0)
30
+ activesupport (~> 3.2.0)
31
+ i18n (~> 0.6.0)
32
+ mocha
33
+ sqlite3
@@ -0,0 +1,25 @@
1
+ require 'rails/generators'
2
+ require 'rails/generators/migration'
3
+
4
+ module I18n
5
+ module ActiveRecord
6
+ class InstallGenerator < Rails::Generators::Base
7
+ include Rails::Generators::Migration
8
+
9
+ def self.next_migration_number(path)
10
+ unless @prev_migration_nr
11
+ @prev_migration_nr = Time.now.utc.strftime("%Y%m%d%H%M%S").to_i
12
+ else
13
+ @prev_migration_nr += 1
14
+ end
15
+ @prev_migration_nr.to_s
16
+ end
17
+
18
+ source_root File.expand_path('../templates', __FILE__)
19
+
20
+ def copy_migrations
21
+ migration_template "migration.rb", "db/migrate/create_translations.rb"
22
+ end
23
+ end
24
+ end
25
+ end
@@ -0,0 +1,15 @@
1
+ class CreateTranslations < ActiveRecord::Migration
2
+ def change
3
+ create_table :translations do |t|
4
+ t.string :locale
5
+ t.string :key
6
+ t.text :value
7
+ t.text :interpolations
8
+ t.boolean :is_proc, :default => false
9
+
10
+ t.timestamps
11
+ end
12
+
13
+ add_index :translations, [:locale, :key], :unique => true
14
+ end
15
+ end
@@ -0,0 +1 @@
1
+ require 'i18n'
@@ -0,0 +1,6 @@
1
+ module I18n
2
+ module ActiveRecord
3
+ VERSION = "0.1.0"
4
+ end
5
+ end
6
+
@@ -0,0 +1,63 @@
1
+ require 'i18n/backend/base'
2
+
3
+ module I18n
4
+ module Backend
5
+ class ActiveRecord
6
+ autoload :Missing, 'i18n/backend/active_record/missing'
7
+ autoload :StoreProcs, 'i18n/backend/active_record/store_procs'
8
+ autoload :Translation, 'i18n/backend/active_record/translation'
9
+
10
+ module Implementation
11
+ include Base, Flatten
12
+
13
+ def available_locales
14
+ Translation.available_locales
15
+ rescue ::ActiveRecord::StatementInvalid
16
+ []
17
+ end
18
+
19
+ def store_translations(locale, data, options = {})
20
+ escape = options.fetch(:escape, true)
21
+ flatten_translations(locale, data, escape, false).each do |key, value|
22
+ Translation.locale(locale).lookup(expand_keys(key)).delete_all
23
+ Translation.create(:locale => locale.to_s, :key => key.to_s, :value => value)
24
+ end
25
+ end
26
+
27
+ protected
28
+
29
+ def lookup(locale, key, scope = [], options = {})
30
+ key = normalize_flat_keys(locale, key, scope, options[:separator])
31
+ result = Translation.locale(locale).lookup(key).all
32
+
33
+ if result.empty?
34
+ nil
35
+ elsif result.first.key == key
36
+ result.first.value
37
+ else
38
+ chop_range = (key.size + FLATTEN_SEPARATOR.size)..-1
39
+ result = result.inject({}) do |hash, r|
40
+ hash[r.key.slice(chop_range)] = r.value
41
+ hash
42
+ end
43
+ result.deep_symbolize_keys
44
+ end
45
+
46
+ rescue ::ActiveRecord::StatementInvalid
47
+ # is the translations table missing?
48
+ nil
49
+ end
50
+
51
+ # For a key :'foo.bar.baz' return ['foo', 'foo.bar', 'foo.bar.baz']
52
+ def expand_keys(key)
53
+ key.to_s.split(FLATTEN_SEPARATOR).inject([]) do |keys, key|
54
+ keys << [keys.last, key].compact.join(FLATTEN_SEPARATOR)
55
+ end
56
+ end
57
+ end
58
+
59
+ include Implementation
60
+ end
61
+ end
62
+ end
63
+
@@ -0,0 +1,74 @@
1
+ # This extension stores translation stub records for missing translations to
2
+ # the database.
3
+ #
4
+ # This is useful if you have a web based translation tool. It will populate
5
+ # the database with untranslated keys as the application is being used. A
6
+ # translator can then go through these and add missing translations.
7
+ #
8
+ # Example usage:
9
+ #
10
+ # I18n::Backend::Chain.send(:include, I18n::Backend::ActiveRecord::Missing)
11
+ # I18n.backend = I18n::Backend::Chain.new(I18n::Backend::ActiveRecord.new, I18n::Backend::Simple.new)
12
+ #
13
+ # Stub records for pluralizations will also be created for each key defined
14
+ # in i18n.plural.keys.
15
+ #
16
+ # For example:
17
+ #
18
+ # # en.yml
19
+ # en:
20
+ # i18n:
21
+ # plural:
22
+ # keys: [:zero, :one, :other]
23
+ #
24
+ # # pl.yml
25
+ # pl:
26
+ # i18n:
27
+ # plural:
28
+ # keys: [:zero, :one, :few, :other]
29
+ #
30
+ # It will also persist interpolation keys in Translation#interpolations so
31
+ # translators will be able to review and use them.
32
+ module I18n
33
+ module Backend
34
+ class ActiveRecord
35
+ module Missing
36
+ include Flatten
37
+
38
+ def store_default_translations(locale, key, options = {})
39
+ count, scope, default, separator = options.values_at(:count, :scope, :default, :separator)
40
+ separator ||= I18n.default_separator
41
+ key = normalize_flat_keys(locale, key, scope, separator)
42
+
43
+ unless ActiveRecord::Translation.locale(locale).lookup(key).exists?
44
+ interpolations = options.keys - I18n::RESERVED_KEYS
45
+ keys = count ? I18n.t('i18n.plural.keys', :locale => locale).map { |k| [key, k].join(FLATTEN_SEPARATOR) } : [key]
46
+ keys.each { |key| store_default_translation(locale, key, interpolations) }
47
+ end
48
+ end
49
+
50
+ def store_default_translation(locale, key, interpolations)
51
+ translation = ActiveRecord::Translation.new :locale => locale.to_s, :key => key
52
+ translation.interpolations = interpolations
53
+ translation.save
54
+ end
55
+
56
+ def translate(locale, key, options = {})
57
+ # Support throw/catch for MissingTranslation (i18n 0.6.0)
58
+ result = catch(:exception) do
59
+ super
60
+ end
61
+ if result.is_a?(I18n::MissingTranslation)
62
+ self.store_default_translations(locale, key, options)
63
+ throw(:exception, result)
64
+ end
65
+ result
66
+ rescue I18n::MissingTranslationData => e
67
+ self.store_default_translations(locale, key, options)
68
+ raise e
69
+ end
70
+ end
71
+ end
72
+ end
73
+ end
74
+
@@ -0,0 +1,39 @@
1
+ # This module is intended to be mixed into the ActiveRecord backend to allow
2
+ # storing Ruby Procs as translation values in the database.
3
+ #
4
+ # I18n.backend = I18n::Backend::ActiveRecord.new
5
+ # I18n::Backend::ActiveRecord::Translation.send(:include, I18n::Backend::ActiveRecord::StoreProcs)
6
+ #
7
+ # The StoreProcs module requires the ParseTree and ruby2ruby gems and therefor
8
+ # was extracted from the original backend.
9
+ #
10
+ # ParseTree is not compatible with Ruby 1.9.
11
+
12
+ begin
13
+ require 'ruby2ruby'
14
+ require 'parse_tree'
15
+ require 'parse_tree_extensions'
16
+ rescue LoadError => e
17
+ puts "can't use StoreProcs because: #{e.message}"
18
+ end
19
+
20
+ module I18n
21
+ module Backend
22
+ class ActiveRecord
23
+ module StoreProcs
24
+ def value=(v)
25
+ case v
26
+ when Proc
27
+ write_attribute(:value, v.to_ruby)
28
+ write_attribute(:is_proc, true)
29
+ else
30
+ write_attribute(:value, v)
31
+ end
32
+ end
33
+
34
+ Translation.send(:include, self) if method(:to_s).respond_to?(:to_ruby)
35
+ end
36
+ end
37
+ end
38
+ end
39
+
@@ -0,0 +1,104 @@
1
+ require 'active_record'
2
+
3
+ module I18n
4
+ module Backend
5
+ # ActiveRecord model used to store actual translations to the database.
6
+ #
7
+ # This model expects a table like the following to be already set up in
8
+ # your the database:
9
+ #
10
+ # create_table :translations do |t|
11
+ # t.string :locale
12
+ # t.string :key
13
+ # t.text :value
14
+ # t.text :interpolations
15
+ # t.boolean :is_proc, :default => false
16
+ # end
17
+ #
18
+ # This model supports to named scopes :locale and :lookup. The :locale
19
+ # scope simply adds a condition for a given locale:
20
+ #
21
+ # I18n::Backend::ActiveRecord::Translation.locale(:en).all
22
+ # # => all translation records that belong to the :en locale
23
+ #
24
+ # The :lookup scope adds a condition for looking up all translations
25
+ # that either start with the given keys (joined by an optionally given
26
+ # separator or I18n.default_separator) or that exactly have this key.
27
+ #
28
+ # # with translations present for :"foo.bar" and :"foo.baz"
29
+ # I18n::Backend::ActiveRecord::Translation.lookup(:foo)
30
+ # # => an array with both translation records :"foo.bar" and :"foo.baz"
31
+ #
32
+ # I18n::Backend::ActiveRecord::Translation.lookup([:foo, :bar])
33
+ # I18n::Backend::ActiveRecord::Translation.lookup(:"foo.bar")
34
+ # # => an array with the translation record :"foo.bar"
35
+ #
36
+ # When the StoreProcs module was mixed into this model then Procs will
37
+ # be stored to the database as Ruby code and evaluated when :value is
38
+ # called.
39
+ #
40
+ # Translation = I18n::Backend::ActiveRecord::Translation
41
+ # Translation.create \
42
+ # :locale => 'en'
43
+ # :key => 'foo'
44
+ # :value => lambda { |key, options| 'FOO' }
45
+ # Translation.find_by_locale_and_key('en', 'foo').value
46
+ # # => 'FOO'
47
+ class ActiveRecord
48
+ class Translation < ::ActiveRecord::Base
49
+ TRUTHY_CHAR = "\001"
50
+ FALSY_CHAR = "\002"
51
+
52
+ self.table_name = 'translations'
53
+ self.logger = nil
54
+ attr_accessible :locale, :key, :value
55
+
56
+ serialize :value
57
+ serialize :interpolations, Array
58
+
59
+ class << self
60
+ def locale(locale)
61
+ scoped conditions: { locale: locale.to_s }
62
+ end
63
+
64
+ def lookup(keys, *separator)
65
+ column_name = connection.quote_column_name('key')
66
+ keys = Array(keys).map(&:to_s)
67
+
68
+ unless separator.empty?
69
+ warn "[DEPRECATION] Giving a separator to Translation.lookup is deprecated. " <<
70
+ "You can change the internal separator by overwriting FLATTEN_SEPARATOR."
71
+ end
72
+
73
+ namespace = "#{keys.last}#{I18n::Backend::Flatten::FLATTEN_SEPARATOR}%"
74
+ scoped conditions: ["#{column_name} IN (?) OR #{column_name} LIKE ?", keys, namespace]
75
+ end
76
+
77
+ def available_locales
78
+ Translation.pluck('DISTINCT locale').map(&:to_sym)
79
+ end
80
+ end
81
+
82
+ def interpolates?(key)
83
+ self.interpolations.include?(key) if self.interpolations
84
+ end
85
+
86
+ def value
87
+ value = read_attribute(:value)
88
+ return Kernel.eval(value) if is_proc?
89
+ return false if value == FALSY_CHAR
90
+ return true if value == TRUTHY_CHAR
91
+ value
92
+ end
93
+
94
+ def value=(value)
95
+ value = FALSY_CHAR if value === false
96
+ value = TRUTHY_CHAR if value === true
97
+
98
+ write_attribute(:value, value)
99
+ end
100
+ end
101
+ end
102
+ end
103
+ end
104
+
@@ -0,0 +1,54 @@
1
+ require 'test_helper'
2
+
3
+ class I18nBackendActiveRecordTest < Test::Unit::TestCase
4
+ def setup
5
+ I18n.backend = I18n::Backend::ActiveRecord.new
6
+ store_translations(:en, :foo => { :bar => 'bar', :baz => 'baz' })
7
+ end
8
+
9
+ def teardown
10
+ I18n::Backend::ActiveRecord::Translation.destroy_all
11
+ super
12
+ end
13
+
14
+ test "store_translations does not allow ambiguous keys (1)" do
15
+ I18n::Backend::ActiveRecord::Translation.delete_all
16
+ I18n.backend.store_translations(:en, :foo => 'foo')
17
+ I18n.backend.store_translations(:en, :foo => { :bar => 'bar' })
18
+ I18n.backend.store_translations(:en, :foo => { :baz => 'baz' })
19
+
20
+ translations = I18n::Backend::ActiveRecord::Translation.locale(:en).lookup('foo').all
21
+ assert_equal %w(bar baz), translations.map(&:value)
22
+
23
+ assert_equal({ :bar => 'bar', :baz => 'baz' }, I18n.t(:foo))
24
+ end
25
+
26
+ test "store_translations does not allow ambiguous keys (2)" do
27
+ I18n::Backend::ActiveRecord::Translation.delete_all
28
+ I18n.backend.store_translations(:en, :foo => { :bar => 'bar' })
29
+ I18n.backend.store_translations(:en, :foo => { :baz => 'baz' })
30
+ I18n.backend.store_translations(:en, :foo => 'foo')
31
+
32
+ translations = I18n::Backend::ActiveRecord::Translation.locale(:en).lookup('foo').all
33
+ assert_equal %w(foo), translations.map(&:value)
34
+
35
+ assert_equal 'foo', I18n.t(:foo)
36
+ end
37
+
38
+ test "can store translations with keys that are translations containing special chars" do
39
+ I18n.backend.store_translations(:es, :"Pagina's" => "Pagina's" )
40
+ assert_equal "Pagina's", I18n.t(:"Pagina's", :locale => :es)
41
+ end
42
+
43
+ with_mocha do
44
+ test "missing translations table does not cause an error in #available_locales" do
45
+ I18n::Backend::ActiveRecord::Translation.expects(:available_locales).raises(::ActiveRecord::StatementInvalid)
46
+ assert_equal [], I18n.backend.available_locales
47
+ end
48
+ end
49
+
50
+ def test_expand_keys
51
+ assert_equal %w(foo foo.bar foo.bar.baz), I18n.backend.send(:expand_keys, :'foo.bar.baz')
52
+ end
53
+ end if defined?(ActiveRecord)
54
+
@@ -0,0 +1,30 @@
1
+ require 'test_helper'
2
+
3
+ class I18nActiveRecordApiTest < Test::Unit::TestCase
4
+ def setup
5
+ I18n.backend = I18n::Backend::ActiveRecord.new
6
+ super
7
+ end
8
+
9
+ # def self.can_store_procs?
10
+ # I18n::Backend::ActiveRecord.included_modules.include?(I18n::Backend::ActiveRecord::StoreProcs)
11
+ # end
12
+ #
13
+ # include I18n::Tests::Basics
14
+ # include I18n::Tests::Defaults
15
+ # include I18n::Tests::Interpolation
16
+ # include I18n::Tests::Link
17
+ # include I18n::Tests::Lookup
18
+ # include I18n::Tests::Pluralization
19
+ # include I18n::Tests::Procs if can_store_procs?
20
+ #
21
+ # include I18n::Tests::Localization::Date
22
+ # include I18n::Tests::Localization::DateTime
23
+ # include I18n::Tests::Localization::Time
24
+ # include I18n::Tests::Localization::Procs if can_store_procs?
25
+
26
+ test "make sure we use an ActiveRecord backend" do
27
+ assert_equal I18n::Backend::ActiveRecord, I18n.backend.class
28
+ end
29
+ end if defined?(ActiveRecord)
30
+
@@ -0,0 +1,71 @@
1
+ require 'test_helper'
2
+
3
+ class I18nActiveRecordMissingTest < Test::Unit::TestCase
4
+ class Backend < I18n::Backend::ActiveRecord
5
+ include I18n::Backend::ActiveRecord::Missing
6
+ end
7
+
8
+ def setup
9
+ I18n.backend.store_translations(:en, :bar => 'Bar', :i18n => { :plural => { :keys => [:zero, :one, :other] } })
10
+ I18n.backend = I18n::Backend::Chain.new(Backend.new, I18n.backend)
11
+ I18n::Backend::ActiveRecord::Translation.delete_all
12
+ end
13
+
14
+ test "can persist interpolations" do
15
+ translation = I18n::Backend::ActiveRecord::Translation.new(:key => 'foo', :value => 'bar', :locale => :en)
16
+ translation.interpolations = %w(count name)
17
+ translation.save
18
+ assert translation.valid?
19
+ end
20
+
21
+ test "lookup persists the key" do
22
+ I18n.t('foo.bar.baz')
23
+ assert_equal 1, I18n::Backend::ActiveRecord::Translation.count
24
+ assert I18n::Backend::ActiveRecord::Translation.locale(:en).find_by_key('foo.bar.baz')
25
+ end
26
+
27
+ test "lookup does not persist the key twice" do
28
+ 2.times { I18n.t('foo.bar.baz') }
29
+ assert_equal 1, I18n::Backend::ActiveRecord::Translation.count
30
+ assert I18n::Backend::ActiveRecord::Translation.locale(:en).find_by_key('foo.bar.baz')
31
+ end
32
+
33
+ test "lookup persists interpolation keys when looked up directly" do
34
+ I18n.t('foo.bar.baz', :cow => "lucy" ) # creates stub translation.
35
+ translation_stub = I18n::Backend::ActiveRecord::Translation.locale(:en).lookup('foo.bar.baz').first
36
+ assert translation_stub.interpolates?(:cow)
37
+ end
38
+
39
+ test "creates one stub per pluralization" do
40
+ I18n.t('foo', :count => 999)
41
+ translations = I18n::Backend::ActiveRecord::Translation.locale(:en).find_all_by_key %w{ foo.zero foo.one foo.other }
42
+ assert_equal 3, translations.length
43
+ end
44
+
45
+ test "creates no stub for base key in pluralization" do
46
+ I18n.t('foo', :count => 999)
47
+ assert_equal 3, I18n::Backend::ActiveRecord::Translation.locale(:en).lookup("foo").count
48
+ assert !I18n::Backend::ActiveRecord::Translation.locale(:en).find_by_key("foo")
49
+ end
50
+
51
+ test "creates a stub when a custom separator is used" do
52
+ I18n.t('foo|baz', :separator => '|')
53
+ I18n::Backend::ActiveRecord::Translation.locale(:en).lookup("foo.baz").first.update_attributes!(:value => 'baz!')
54
+ assert_equal 'baz!', I18n.t('foo|baz', :separator => '|')
55
+ end
56
+
57
+ test "creates a stub per pluralization when a custom separator is used" do
58
+ I18n.t('foo|bar', :count => 999, :separator => '|')
59
+ translations = I18n::Backend::ActiveRecord::Translation.locale(:en).find_all_by_key %w{ foo.bar.zero foo.bar.one foo.bar.other }
60
+ assert_equal 3, translations.length
61
+ end
62
+
63
+ test "creates a stub when a custom separator is used and the key contains the flatten separator (a dot character)" do
64
+ key = 'foo|baz.zab'
65
+ I18n.t(key, :separator => '|')
66
+ I18n::Backend::ActiveRecord::Translation.locale(:en).lookup("foo.baz\001zab").first.update_attributes!(:value => 'baz!')
67
+ assert_equal 'baz!', I18n.t(key, :separator => '|')
68
+ end
69
+
70
+ end if defined?(ActiveRecord)
71
+
@@ -0,0 +1,71 @@
1
+ $KCODE = 'u' if RUBY_VERSION <= '1.9'
2
+
3
+ require 'rubygems'
4
+ require 'test/unit'
5
+ require 'test_setup'
6
+
7
+ # Do not load the i18n gem from libraries like active_support.
8
+ #
9
+ # This is required for testing against Rails 2.3 because active_support/vendor.rb#24 tries
10
+ # to load I18n using the gem method. Instead, we want to test the local library of course.
11
+ alias :gem_for_ruby_19 :gem # for 1.9. gives a super ugly seg fault otherwise
12
+ def gem(gem_name, *version_requirements)
13
+ puts("skipping loading the i18n gem ...") and return if gem_name == 'i18n'
14
+ super(gem_name, *version_requirements)
15
+ end
16
+
17
+
18
+ I18n::Tests.parse_options!
19
+
20
+ require 'bundler/setup'
21
+ require 'i18n/active_record'
22
+ require 'i18n/tests'
23
+ require 'mocha'
24
+ I18n::Tests.setup_active_record
25
+
26
+ class Test::Unit::TestCase
27
+ def self.test(name, &block)
28
+ test_name = "test_#{name.gsub(/\s+/,'_')}".to_sym
29
+ defined = instance_method(test_name) rescue false
30
+ raise "#{test_name} is already defined in #{self}" if defined
31
+ if block_given?
32
+ define_method(test_name, &block)
33
+ else
34
+ define_method(test_name) do
35
+ flunk "No implementation provided for #{name}"
36
+ end
37
+ end
38
+ end
39
+
40
+ def self.with_mocha
41
+ yield if Object.respond_to?(:expects)
42
+ end
43
+
44
+ def teardown
45
+ I18n.locale = nil
46
+ I18n.default_locale = :en
47
+ I18n.load_path = []
48
+ I18n.available_locales = nil
49
+ I18n.backend = nil
50
+ end
51
+
52
+ def translations
53
+ I18n.backend.instance_variable_get(:@translations)
54
+ end
55
+
56
+ def store_translations(*args)
57
+ data = args.pop
58
+ locale = args.pop || :en
59
+ I18n.backend.store_translations(locale, data)
60
+ end
61
+
62
+ def locales_dir
63
+ File.dirname(__FILE__) + '/test_data/locales'
64
+ end
65
+ end
66
+
67
+ Object.class_eval do
68
+ def meta_class
69
+ class << self; self; end
70
+ end
71
+ end unless Object.method_defined?(:meta_class)
@@ -0,0 +1,72 @@
1
+ require 'optparse'
2
+
3
+ module I18n
4
+ module Tests
5
+ class << self
6
+ def options
7
+ @options ||= { :with => [], :adapter => 'sqlite3' }
8
+ end
9
+
10
+ def parse_options!
11
+ OptionParser.new do |o|
12
+ o.on('-w', '--with DEPENDENCIES', 'Define dependencies') do |dep|
13
+ options[:with] = dep.split(',').map { |group| group.to_sym }
14
+ end
15
+ end.parse!
16
+
17
+ options[:with].each do |dep|
18
+ case dep
19
+ when :sqlite3, :mysql, :postgres
20
+ @options[:adapter] = dep
21
+ end
22
+ end
23
+
24
+ ENV['BUNDLE_GEMFILE'] ||= 'ci/Gemfile.rails-3.2'
25
+ end
26
+
27
+ def setup_active_record
28
+ begin
29
+ require 'active_record'
30
+ ActiveRecord::Base.connection
31
+ true
32
+ rescue LoadError => e
33
+ puts "can't use ActiveRecord backend because: #{e.message}"
34
+ rescue ActiveRecord::ConnectionNotEstablished
35
+ require 'i18n/backend/active_record'
36
+ require 'i18n/backend/active_record/store_procs'
37
+ connect_active_record
38
+ true
39
+ end
40
+ end
41
+
42
+ def connect_active_record
43
+ connect_adapter
44
+ ActiveRecord::Migration.verbose = false
45
+ ActiveRecord::Schema.define(:version => 1) do
46
+ create_table :translations, :force => true do |t|
47
+ t.string :locale
48
+ t.string :key
49
+ t.text :value
50
+ t.text :interpolations
51
+ t.boolean :is_proc, :default => false
52
+ end
53
+ add_index :translations, [:locale, :key], :unique => true
54
+ end
55
+ end
56
+
57
+ def connect_adapter
58
+ case options[:adapter].to_sym
59
+ when :sqlite3
60
+ ActiveRecord::Base.establish_connection(:adapter => "sqlite3", :database => ":memory:")
61
+ when :mysql
62
+ # CREATE DATABASE i18n_unittest;
63
+ # CREATE USER 'i18n'@'localhost' IDENTIFIED BY '';
64
+ # GRANT ALL PRIVILEGES ON i18n_unittest.* to 'i18n'@'localhost';
65
+ ActiveRecord::Base.establish_connection(:adapter => "mysql", :database => "i18n_unittest", :username => "i18n", :password => "", :host => "localhost")
66
+ end
67
+ end
68
+ end
69
+ end
70
+ end
71
+
72
+
metadata ADDED
@@ -0,0 +1,80 @@
1
+ --- !ruby/object:Gem::Specification
2
+ name: i18n-active_record-backend
3
+ version: !ruby/object:Gem::Version
4
+ version: 0.1.0
5
+ prerelease:
6
+ platform: ruby
7
+ authors:
8
+ - Sven Fuchs
9
+ - Endika Gutiérrez
10
+ autorequire:
11
+ bindir: bin
12
+ cert_chain: []
13
+ date: 2013-02-04 00:00:00.000000000 Z
14
+ dependencies:
15
+ - !ruby/object:Gem::Dependency
16
+ name: i18n
17
+ requirement: !ruby/object:Gem::Requirement
18
+ none: false
19
+ requirements:
20
+ - - ! '>='
21
+ - !ruby/object:Gem::Version
22
+ version: 0.6.0
23
+ type: :runtime
24
+ prerelease: false
25
+ version_requirements: !ruby/object:Gem::Requirement
26
+ none: false
27
+ requirements:
28
+ - - ! '>='
29
+ - !ruby/object:Gem::Version
30
+ version: 0.6.0
31
+ description: I18n ActiveRecord backend. Allows to store translations in a database
32
+ using ActiveRecord, e.g. for providing a web-interface for managing translations.
33
+ email: me@endika.net
34
+ executables: []
35
+ extensions: []
36
+ extra_rdoc_files: []
37
+ files:
38
+ - ci/Gemfile.rails-3.2
39
+ - ci/Gemfile.rails-3.2.lock
40
+ - lib/generators/i18n/active_record/install/install_generator.rb
41
+ - lib/generators/i18n/active_record/install/templates/migration.rb
42
+ - lib/i18n/active_record/version.rb
43
+ - lib/i18n/active_record.rb
44
+ - lib/i18n/backend/active_record/missing.rb
45
+ - lib/i18n/backend/active_record/store_procs.rb
46
+ - lib/i18n/backend/active_record/translation.rb
47
+ - lib/i18n/backend/active_record.rb
48
+ - test/active_record_test.rb
49
+ - test/api_test.rb
50
+ - test/missing_test.rb
51
+ - test/test_helper.rb
52
+ - test/test_setup.rb
53
+ - MIT-LICENSE
54
+ - README.textile
55
+ - Rakefile
56
+ homepage: https://github.com/endSly/i18n-active_record-backend
57
+ licenses: []
58
+ post_install_message:
59
+ rdoc_options: []
60
+ require_paths:
61
+ - lib
62
+ required_ruby_version: !ruby/object:Gem::Requirement
63
+ none: false
64
+ requirements:
65
+ - - ! '>='
66
+ - !ruby/object:Gem::Version
67
+ version: '0'
68
+ required_rubygems_version: !ruby/object:Gem::Requirement
69
+ none: false
70
+ requirements:
71
+ - - ! '>='
72
+ - !ruby/object:Gem::Version
73
+ version: '0'
74
+ requirements: []
75
+ rubyforge_project: ! '[none]'
76
+ rubygems_version: 1.8.24
77
+ signing_key:
78
+ specification_version: 3
79
+ summary: I18n ActiveRecord backend
80
+ test_files: []