i18n-active_record 0.0.1

Sign up to get free protection for your applications and to get access to all the features.
@@ -0,0 +1,3 @@
1
+ require 'i18n'
2
+ require 'i18n/backend/active_record'
3
+
@@ -0,0 +1,6 @@
1
+ module I18n
2
+ module ActiveRecord
3
+ VERSION = "0.0.1"
4
+ end
5
+ end
6
+
@@ -0,0 +1,62 @@
1
+ require 'i18n/backend/base'
2
+ require 'i18n/backend/active_record/translation'
3
+
4
+ module I18n
5
+ module Backend
6
+ class ActiveRecord
7
+ autoload :Missing, 'i18n/backend/active_record/missing'
8
+ autoload :StoreProcs, 'i18n/backend/active_record/store_procs'
9
+ autoload :Translation, 'i18n/backend/active_record/translation'
10
+
11
+ module Implementation
12
+ include Base, Flatten
13
+
14
+ def available_locales
15
+ begin
16
+ Translation.available_locales
17
+ rescue ::ActiveRecord::StatementInvalid
18
+ []
19
+ end
20
+ end
21
+
22
+ def store_translations(locale, data, options = {})
23
+ escape = options.fetch(:escape, true)
24
+ flatten_translations(locale, data, escape, false).each do |key, value|
25
+ Translation.locale(locale).lookup(expand_keys(key)).delete_all
26
+ Translation.create(:locale => locale.to_s, :key => key.to_s, :value => value)
27
+ end
28
+ end
29
+
30
+ protected
31
+
32
+ def lookup(locale, key, scope = [], options = {})
33
+ key = normalize_flat_keys(locale, key, scope, options[:separator])
34
+ result = Translation.locale(locale).lookup(key).all
35
+
36
+ if result.empty?
37
+ nil
38
+ elsif result.first.key == key
39
+ result.first.value
40
+ else
41
+ chop_range = (key.size + FLATTEN_SEPARATOR.size)..-1
42
+ result = result.inject({}) do |hash, r|
43
+ hash[r.key.slice(chop_range)] = r.value
44
+ hash
45
+ end
46
+ result.deep_symbolize_keys
47
+ end
48
+ end
49
+
50
+ # For a key :'foo.bar.baz' return ['foo', 'foo.bar', 'foo.bar.baz']
51
+ def expand_keys(key)
52
+ key.to_s.split(FLATTEN_SEPARATOR).inject([]) do |keys, key|
53
+ keys << [keys.last, key].compact.join(FLATTEN_SEPARATOR)
54
+ end
55
+ end
56
+ end
57
+
58
+ include Implementation
59
+ end
60
+ end
61
+ end
62
+
@@ -0,0 +1,66 @@
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 - Base::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
+ super
58
+ rescue I18n::MissingTranslationData => e
59
+ self.store_default_translations(locale, key, options)
60
+ raise e
61
+ end
62
+ end
63
+ end
64
+ end
65
+ end
66
+
@@ -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,111 @@
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
+ set_table_name 'translations'
53
+ attr_protected :is_proc, :interpolations
54
+
55
+ serialize :value
56
+ serialize :interpolations, Array
57
+
58
+ class << self
59
+ def locale(locale)
60
+ scoped(:conditions => { :locale => locale.to_s })
61
+ end
62
+
63
+ def lookup(keys, *separator)
64
+ column_name = connection.quote_column_name('key')
65
+ keys = Array(keys).map! { |key| key.to_s }
66
+
67
+ unless separator.empty?
68
+ warn "[DEPRECATION] Giving a separator to Translation.lookup is deprecated. " <<
69
+ "You can change the internal separator by overwriting FLATTEN_SEPARATOR."
70
+ end
71
+
72
+ namespace = "#{keys.last}#{I18n::Backend::Flatten::FLATTEN_SEPARATOR}%"
73
+ scoped(:conditions => ["#{column_name} IN (?) OR #{column_name} LIKE ?", keys, namespace])
74
+ end
75
+
76
+ def available_locales
77
+ Translation.find(:all, :select => 'DISTINCT locale').map { |t| t.locale.to_sym }
78
+ end
79
+ end
80
+
81
+ def interpolates?(key)
82
+ self.interpolations.include?(key) if self.interpolations
83
+ end
84
+
85
+ def value
86
+ value = read_attribute(:value)
87
+ if is_proc
88
+ Kernel.eval(value)
89
+ elsif value == FALSY_CHAR
90
+ false
91
+ elsif value == TRUTHY_CHAR
92
+ true
93
+ else
94
+ value
95
+ end
96
+ end
97
+
98
+ def value=(value)
99
+ if value === false
100
+ value = FALSY_CHAR
101
+ elsif value === true
102
+ value = TRUTHY_CHAR
103
+ end
104
+
105
+ write_attribute(:value, value)
106
+ end
107
+ end
108
+ end
109
+ end
110
+ end
111
+
metadata ADDED
@@ -0,0 +1,72 @@
1
+ --- !ruby/object:Gem::Specification
2
+ name: i18n-active_record
3
+ version: !ruby/object:Gem::Version
4
+ hash: 29
5
+ prerelease: false
6
+ segments:
7
+ - 0
8
+ - 0
9
+ - 1
10
+ version: 0.0.1
11
+ platform: ruby
12
+ authors:
13
+ - Sven Fuchs
14
+ autorequire:
15
+ bindir: bin
16
+ cert_chain: []
17
+
18
+ date: 2010-12-07 00:00:00 +08:00
19
+ default_executable:
20
+ dependencies: []
21
+
22
+ description: "[description]"
23
+ email: svenfuchs@artweb-design.de
24
+ executables: []
25
+
26
+ extensions: []
27
+
28
+ extra_rdoc_files: []
29
+
30
+ files:
31
+ - lib/i18n/active_record.rb
32
+ - lib/i18n/active_record/version.rb
33
+ - lib/i18n/backend/active_record.rb
34
+ - lib/i18n/backend/active_record/missing.rb
35
+ - lib/i18n/backend/active_record/store_procs.rb
36
+ - lib/i18n/backend/active_record/translation.rb
37
+ has_rdoc: true
38
+ homepage: http://github.com/svenfuchs/i18n-active_record
39
+ licenses: []
40
+
41
+ post_install_message:
42
+ rdoc_options: []
43
+
44
+ require_paths:
45
+ - lib
46
+ required_ruby_version: !ruby/object:Gem::Requirement
47
+ none: false
48
+ requirements:
49
+ - - ">="
50
+ - !ruby/object:Gem::Version
51
+ hash: 3
52
+ segments:
53
+ - 0
54
+ version: "0"
55
+ required_rubygems_version: !ruby/object:Gem::Requirement
56
+ none: false
57
+ requirements:
58
+ - - ">="
59
+ - !ruby/object:Gem::Version
60
+ hash: 3
61
+ segments:
62
+ - 0
63
+ version: "0"
64
+ requirements: []
65
+
66
+ rubyforge_project: "[none]"
67
+ rubygems_version: 1.3.7
68
+ signing_key:
69
+ specification_version: 3
70
+ summary: "[summary]"
71
+ test_files: []
72
+