i18n-active_record 0.2.2 → 1.4.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.
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
- SHA1:
3
- metadata.gz: 6b1b7eba888729976d370e18c88c1710d818e8d4
4
- data.tar.gz: cc0b86a33d8742fc2cf6a2db0bf3891681bc7b1c
2
+ SHA256:
3
+ metadata.gz: a6895e3f4b2c615221ac6a44bba495f6a6557e76fe5815fe604005e3e9d455d0
4
+ data.tar.gz: febd2054212ebeec7624de340aebc0c9f86ae4ec509f55751f97459adef82bf9
5
5
  SHA512:
6
- metadata.gz: 532cadaf5a7b6a349a4d84f5658be0c914521ec931e1c03089bd02d4e217279f080924568c8461c140ba3dd3d265eb5b3a017f817ec1723b91b6c6c4ca20aabd
7
- data.tar.gz: c74ac31d2b20876ba61042b46de889f49f678f9fa23cf5d4173db7fc0d8ec4a878f779f03e53c76f563a051f99b2774fbcd7d28f3a7d9fe644cbf37b3880c184
6
+ metadata.gz: 3fbd83d43d6158a23eb0573a598c87c23986912403496761d60b9e72950d06ff0897e6e911bb2f3d1073ab0066e17d7aa02c0f288e6b2f43bacad3f306f31625
7
+ data.tar.gz: b51858da9da92d578fe190a185e45df9779e34dfb07c5b8daf097059edf18394c83fbbb1f2add6ac72b59e8ff19342f1ba3190bb72bee322a4430e25decce5ae
data/README.md ADDED
@@ -0,0 +1,165 @@
1
+ # I18n::Backend::ActiveRecord [![Ruby Style Guide](https://img.shields.io/badge/code_style-rubocop-brightgreen.svg)](https://github.com/rubocop/rubocop) [![Tests Status](https://github.com/svenfuchs/i18n-active_record/actions/workflows/test.yml/badge.svg)](https://github.com/svenfuchs/i18n-active_record/actions) [![Linter Status](https://github.com/svenfuchs/i18n-active_record/actions/workflows/linter.yml/badge.svg)](https://github.com/svenfuchs/i18n-active_record/actions)
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
+ It is fully compatible with Rails 4+.
5
+
6
+ ## Installation
7
+
8
+ For Bundler put the following in your Gemfile:
9
+
10
+ ```ruby
11
+ gem 'i18n-active_record', require: 'i18n/active_record'
12
+ ```
13
+
14
+ After updating your bundle, run the installer
15
+
16
+ $ rails g i18n:active_record:install
17
+
18
+ It creates a migration:
19
+
20
+ ```ruby
21
+ class CreateTranslations < ActiveRecord::Migration
22
+ def change
23
+ create_table :translations do |t|
24
+ t.string :locale
25
+ t.string :key
26
+ t.text :value
27
+ t.text :interpolations
28
+ t.boolean :is_proc, default: false
29
+
30
+ t.timestamps
31
+ end
32
+ end
33
+ end
34
+ ```
35
+
36
+ To specify table name use:
37
+
38
+ $ rails g i18n:active_record:install MyTranslation
39
+
40
+ With the translation model you will be able to manage your translation, and add new translations or languages through
41
+ it.
42
+
43
+ By default the installer creates a new file in `config/initializers` named `i18n_active_record.rb` with the following content.
44
+
45
+ ```ruby
46
+ require 'i18n/backend/active_record'
47
+
48
+ Translation = I18n::Backend::ActiveRecord::Translation
49
+
50
+ if Translation.table_exists?
51
+ I18n.backend = I18n::Backend::ActiveRecord.new
52
+
53
+ I18n::Backend::ActiveRecord.send(:include, I18n::Backend::Memoize)
54
+ I18n::Backend::Simple.send(:include, I18n::Backend::Memoize)
55
+ I18n::Backend::Simple.send(:include, I18n::Backend::Pluralization)
56
+
57
+ I18n.backend = I18n::Backend::Chain.new(I18n::Backend::Simple.new, I18n.backend)
58
+ end
59
+ ```
60
+
61
+ To perform a simpler installation use:
62
+
63
+ $ rails g i18n:active_record:install --simple
64
+
65
+ It generates:
66
+
67
+ ```ruby
68
+ require 'i18n/backend/active_record'
69
+ I18n.backend = I18n::Backend::ActiveRecord.new
70
+ ```
71
+
72
+ You may also configure whether the ActiveRecord backend should use `destroy` or `delete` when cleaning up internally.
73
+
74
+ ```ruby
75
+ I18n::Backend::ActiveRecord.configure do |config|
76
+ config.cleanup_with_destroy = true # defaults to false
77
+ end
78
+ ```
79
+
80
+ To configure the ActiveRecord backend to cache translations(might be useful in production) use:
81
+
82
+ ```ruby
83
+ I18n::Backend::ActiveRecord.configure do |config|
84
+ config.cache_translations = true # defaults to false
85
+ end
86
+ ```
87
+
88
+ The ActiveRecord backend can be configured to use a `scope` to isolate sets of translations. That way, two applications
89
+ using the backend with the same database table can use translation data independently of one another.
90
+ If configured with a scope, all data used will be limited to records with that particular scope identifier:
91
+
92
+ ```ruby
93
+ I18n::Backend::ActiveRecord.configure do |config|
94
+ config.scope = 'app1' # defaults to nil, disabling scope
95
+ end
96
+ ```
97
+
98
+ ## Usage
99
+
100
+ You can now use `I18n.t('Your String')` to lookup translations in the database.
101
+
102
+ ## Custom translation model
103
+
104
+ By default, the gem relies on [the built-in translation model](https://github.com/svenfuchs/i18n-active_record/blob/master/lib/i18n/backend/active_record/translation.rb).
105
+ However, to extend the default functionality, the translation model can be customized:
106
+
107
+ ```ruby
108
+ class MyTranslation < I18n::Backend::ActiveRecord::Translation
109
+ def value=(val)
110
+ super("custom #{val}")
111
+ end
112
+ end
113
+
114
+ I18n::Backend::ActiveRecord.configure do |config|
115
+ config.translation_model = MyTranslation
116
+ end
117
+ ```
118
+
119
+ ## Missing Translations
120
+
121
+ To make the `I18n::Backend::ActiveRecord::Missing` module working correctly pluralization rules should be configured properly.
122
+ The `i18n.plural.keys` translation key should be present in any of the backends.
123
+ See https://github.com/svenfuchs/i18n-active_record/blob/master/lib/i18n/backend/active_record/missing.rb for more information.
124
+
125
+ ```yaml
126
+ en:
127
+ i18n:
128
+ plural:
129
+ keys:
130
+ - :zero
131
+ - :one
132
+ - :other
133
+ ```
134
+
135
+ ### Interpolations
136
+
137
+ The `interpolations` field in the `translations` table is used by `I18n::Backend::ActiveRecord::Missing` to store the interpolations seen the first time this Translation was requested. This will help translators understand what interpolations to expect, and thus to include when providing the translations.
138
+
139
+ The `interpolations` field is otherwise unused since the "value" in `Translation#value` is actually used for interpolation during actual translations.
140
+
141
+ ## Examples
142
+
143
+ * http://collectiveidea.com/blog/archives/2016/05/31/beyond-yml-files-dynamic-translations/ ([use `before_action`](https://github.com/svenfuchs/i18n-active_record/issues/138) for Rails 5.1+)
144
+
145
+ ## Contributing
146
+
147
+ ### Test suite
148
+
149
+ The test suite can be run with:
150
+
151
+ bundle exec rake
152
+
153
+ By default it runs the tests for SQLite database, to specify a database the `DB` env variable can be used:
154
+
155
+ DB=postgres bundle exec rake
156
+ DB=mysql bundle exec rake
157
+
158
+ To run tests for a specific rails version see [Appraisal](https://github.com/thoughtbot/appraisal):
159
+
160
+ bundle exec appraisal rails-4 rake test
161
+
162
+ ## Maintainers
163
+
164
+ * Sven Fuchs
165
+ * Tim Masliuchenko
data/Rakefile CHANGED
@@ -1,61 +1,12 @@
1
- require 'rake'
1
+ # frozen_string_literal: true
2
+
2
3
  require 'rake/testtask'
3
4
  require 'bundler/gem_tasks'
4
5
 
5
- def execute(command)
6
- puts command
7
- system command
8
- end
9
-
10
- def bundle_options
11
- opt = ''
12
- opt += "--gemfile #{ENV['BUNDLE_GEMFILE']}" if ENV['BUNDLE_GEMFILE']
13
- end
14
-
15
- def each_database(&block)
16
- ['sqlite', 'postgres', 'mysql'].each &block
17
- end
18
-
19
- namespace :bundle do
20
- task :env do
21
- ar = ENV['AR'].to_s
22
-
23
- next if ar.empty?
24
-
25
- gemfile = "gemfiles/Gemfile.rails_#{ar}"
26
- raise "Cannot find gemfile at #{gemfile}" unless File.exist?(gemfile)
27
-
28
- ENV['BUNDLE_GEMFILE'] = gemfile
29
- puts "Using gemfile: #{gemfile}"
30
- end
31
-
32
- task install: :env do
33
- execute "bundle install #{bundle_options}"
34
- end
35
-
36
- task :install_all do
37
- [nil, '3', '4', '5', 'master'].each do |ar|
38
- opt = ar && "AR=#{ar}"
39
- execute "rake bundle:install #{opt}"
40
- end
41
- end
42
- end
43
-
44
- task :test do
45
- each_database { |db| execute "rake #{db}:test" }
46
- end
47
-
48
- Rake::TestTask.new :_test do |t|
6
+ Rake::TestTask.new :test do |t|
49
7
  t.libs << 'test'
50
8
  t.pattern = 'test/**/*_test.rb'
51
9
  t.verbose = false
52
10
  end
53
11
 
54
- each_database do |db|
55
- namespace db do
56
- task(:env) { ENV['DB'] = db }
57
- task test: ['env', 'bundle:env', '_test']
58
- end
59
- end
60
-
61
12
  task default: :test
@@ -0,0 +1,29 @@
1
+ # frozen_string_literal: true
2
+
3
+ require 'rails/generators/active_record'
4
+
5
+ module I18n
6
+ module ActiveRecord
7
+ module Generators
8
+ class InstallGenerator < ::ActiveRecord::Generators::Base
9
+ desc 'Installs i18n-active_record and generates the necessary migrations'
10
+
11
+ argument :name, type: :string, default: 'Translation'
12
+
13
+ class_option :simple, type: :boolean, default: false, desc: 'Perform the simple setup'
14
+
15
+ source_root File.expand_path('templates', __dir__)
16
+
17
+ def copy_initializer
18
+ tpl = "#{options[:simple] ? 'simple' : 'advanced'}_initializer.rb.erb"
19
+
20
+ template tpl, 'config/initializers/i18n_active_record.rb'
21
+ end
22
+
23
+ def create_migrations
24
+ migration_template 'migration.rb.erb', "db/migrate/create_#{table_name}.rb"
25
+ end
26
+ end
27
+ end
28
+ end
29
+ end
@@ -0,0 +1,19 @@
1
+ require 'i18n/backend/active_record'
2
+
3
+ Translation = I18n::Backend::ActiveRecord::Translation
4
+
5
+ if Translation.table_exists?
6
+ I18n.backend = I18n::Backend::ActiveRecord.new
7
+
8
+ I18n::Backend::ActiveRecord.send(:include, I18n::Backend::Memoize)
9
+ I18n::Backend::Simple.send(:include, I18n::Backend::Memoize)
10
+ I18n::Backend::Simple.send(:include, I18n::Backend::Pluralization)
11
+
12
+ I18n.backend = I18n::Backend::Chain.new(I18n::Backend::Simple.new, I18n.backend)
13
+ end
14
+
15
+ I18n::Backend::ActiveRecord.configure do |config|
16
+ # config.cache_translations = true # defaults to false
17
+ # config.cleanup_with_destroy = true # defaults to false
18
+ # config.scope = 'app_scope' # defaults to nil, won't be used
19
+ end
@@ -0,0 +1,14 @@
1
+ class <%= migration_class_name %> < ActiveRecord::Migration[<%= ActiveRecord::Migration.current_version %>]
2
+ def change
3
+ create_table :<%= table_name %> do |t|
4
+ t.string :scope
5
+ t.string :locale
6
+ t.string :key
7
+ t.text :value
8
+ t.text :interpolations
9
+ t.boolean :is_proc, default: false
10
+
11
+ t.timestamps
12
+ end
13
+ end
14
+ end
@@ -0,0 +1,8 @@
1
+ require 'i18n/backend/active_record'
2
+ I18n.backend = I18n::Backend::ActiveRecord.new
3
+
4
+ I18n::Backend::ActiveRecord.configure do |config|
5
+ # config.cache_translations = true # defaults to false
6
+ # config.cleanup_with_destroy = true # defaults to false
7
+ # config.scope = 'app_scope' # defaults to nil, won't be used
8
+ end
@@ -1,5 +1,7 @@
1
+ # frozen_string_literal: true
2
+
1
3
  module I18n
2
4
  module ActiveRecord
3
- VERSION = '0.2.2'
5
+ VERSION = '1.4.0'
4
6
  end
5
7
  end
@@ -1 +1,3 @@
1
+ # frozen_string_literal: true
2
+
1
3
  require 'i18n'
@@ -1,11 +1,16 @@
1
+ # frozen_string_literal: true
2
+
1
3
  module I18n
2
4
  module Backend
3
5
  class ActiveRecord
4
6
  class Configuration
5
- attr_accessor :cleanup_with_destroy
7
+ attr_accessor :cleanup_with_destroy, :cache_translations, :translation_model, :scope
6
8
 
7
9
  def initialize
8
10
  @cleanup_with_destroy = false
11
+ @cache_translations = false
12
+ @translation_model = I18n::Backend::ActiveRecord::Translation
13
+ @scope = nil
9
14
  end
10
15
  end
11
16
  end
@@ -1,3 +1,5 @@
1
+ # frozen_string_literal: true
2
+
1
3
  # This extension stores translation stub records for missing translations to
2
4
  # the database.
3
5
  #
@@ -34,29 +36,31 @@ module I18n
34
36
  class ActiveRecord
35
37
  module Missing
36
38
  include Flatten
39
+ include TranslationModel
37
40
 
38
41
  def store_default_translations(locale, key, options = {})
39
- count, scope, default, separator = options.values_at(:count, :scope, :default, :separator)
42
+ count, scope, _, separator = options.values_at(:count, :scope, :default, :separator)
40
43
  separator ||= I18n.default_separator
41
44
  key = normalize_flat_keys(locale, key, scope, separator)
42
45
 
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
46
+ return if translation_model.locale(locale).lookup(key).exists?
47
+
48
+ interpolations = options.keys - I18n::RESERVED_KEYS
49
+ keys = count ? I18n.t('i18n.plural.keys', locale: locale).map { |k| [key, k].join(FLATTEN_SEPARATOR) } : [key]
50
+ keys.each { |k| store_default_translation(locale, k, interpolations) }
48
51
  end
49
52
 
50
53
  def store_default_translation(locale, key, interpolations)
51
- translation = ActiveRecord::Translation.new :locale => locale.to_s, :key => key
54
+ translation = translation_model.new locale: locale.to_s, key: key
52
55
  translation.interpolations = interpolations
53
56
  translation.save
54
57
  end
55
58
 
56
59
  def translate(locale, key, options = {})
57
60
  result = catch(:exception) { super }
61
+
58
62
  if result.is_a?(I18n::MissingTranslation)
59
- self.store_default_translations(locale, key, options)
63
+ store_default_translations(locale, key, options)
60
64
  throw(:exception, result)
61
65
  else
62
66
  result
@@ -1,3 +1,5 @@
1
+ # frozen_string_literal: true
2
+
1
3
  # This module is intended to be mixed into the ActiveRecord backend to allow
2
4
  # storing Ruby Procs as translation values in the database.
3
5
  #
@@ -21,19 +23,20 @@ module I18n
21
23
  module Backend
22
24
  class ActiveRecord
23
25
  module StoreProcs
24
- def value=(v)
25
- case v
26
+ extend TranslationModel
27
+
28
+ def value=(val)
29
+ case val
26
30
  when Proc
27
- write_attribute(:value, v.to_ruby)
31
+ write_attribute(:value, val.to_ruby)
28
32
  write_attribute(:is_proc, true)
29
33
  else
30
- write_attribute(:value, v)
34
+ write_attribute(:value, val)
31
35
  end
32
36
  end
33
37
 
34
- Translation.send(:include, self) if method(:to_s).respond_to?(:to_ruby)
38
+ translation_model.send(:include, self) if method(:to_s).respond_to?(:to_ruby)
35
39
  end
36
40
  end
37
41
  end
38
42
  end
39
-
@@ -1,3 +1,5 @@
1
+ # frozen_string_literal: true
2
+
1
3
  require 'active_record'
2
4
 
3
5
  module I18n
@@ -51,21 +53,39 @@ module I18n
51
53
 
52
54
  self.table_name = 'translations'
53
55
 
54
- serialize :value
55
- serialize :interpolations, Array
56
+ if ::ActiveRecord.version >= Gem::Version.new('7.1.0.alpha')
57
+ serialize :value, coder: YAML
58
+ serialize :interpolations, coder: YAML, type: Array
59
+ else
60
+ serialize :value
61
+ serialize :interpolations, Array
62
+ end
63
+
64
+ before_validation :set_scope
65
+ after_commit :invalidate_translations_cache
66
+
67
+ default_scope { scoped }
56
68
 
57
69
  class << self
58
70
  def locale(locale)
59
- where(:locale => locale.to_s)
71
+ where(locale: locale.to_s)
72
+ end
73
+
74
+ def scoped
75
+ if (record_scope = ActiveRecord.config.scope)
76
+ where(scope: record_scope)
77
+ else
78
+ all
79
+ end
60
80
  end
61
81
 
62
82
  def lookup(keys, *separator)
63
83
  column_name = connection.quote_column_name('key')
64
- keys = Array(keys).map! { |key| key.to_s }
84
+ keys = Array(keys).map!(&:to_s)
65
85
 
66
86
  unless separator.empty?
67
- warn "[DEPRECATION] Giving a separator to Translation.lookup is deprecated. " <<
68
- "You can change the internal separator by overwriting FLATTEN_SEPARATOR."
87
+ warn '[DEPRECATION] Giving a separator to Translation.lookup is deprecated. ' \
88
+ 'You can change the internal separator by overwriting FLATTEN_SEPARATOR.'
69
89
  end
70
90
 
71
91
  namespace = "#{keys.last}#{I18n::Backend::Flatten::FLATTEN_SEPARATOR}%"
@@ -73,12 +93,24 @@ module I18n
73
93
  end
74
94
 
75
95
  def available_locales
76
- Translation.select('DISTINCT locale').to_a.map { |t| t.locale.to_sym }
96
+ select('DISTINCT locale').to_a.map { |t| t.locale.to_sym }
97
+ end
98
+
99
+ def to_h
100
+ all.each.with_object({}) do |t, memo|
101
+ locale_hash = (memo[t.locale.to_sym] ||= {})
102
+ keys = t.key.split('.')
103
+ keys.each.with_index.inject(locale_hash) do |iterator, (key_part, index)|
104
+ key = key_part.to_sym
105
+ iterator[key] = keys[index + 1] ? (iterator[key] || {}) : t.value
106
+ iterator[key] # rubocop:disable Lint/UnmodifiedReduceAccumulator
107
+ end
108
+ end
77
109
  end
78
110
  end
79
111
 
80
112
  def interpolates?(key)
81
- self.interpolations.include?(key) if self.interpolations
113
+ interpolations&.include?(key)
82
114
  end
83
115
 
84
116
  def value
@@ -95,14 +127,25 @@ module I18n
95
127
  end
96
128
 
97
129
  def value=(value)
98
- if value === false
130
+ case value
131
+ when false
99
132
  value = FALSY_CHAR
100
- elsif value === true
133
+ when true
101
134
  value = TRUTHY_CHAR
102
135
  end
103
136
 
104
137
  write_attribute(:value, value)
105
138
  end
139
+
140
+ def invalidate_translations_cache
141
+ I18n.backend.reload! if I18n::Backend::ActiveRecord.config.cache_translations
142
+ end
143
+
144
+ private
145
+
146
+ def set_scope
147
+ self.scope ||= ActiveRecord.config.scope if ActiveRecord.config.scope
148
+ end
106
149
  end
107
150
  end
108
151
  end
@@ -1,3 +1,5 @@
1
+ # frozen_string_literal: true
2
+
1
3
  require 'i18n/backend/base'
2
4
  require 'i18n/backend/active_record/translation'
3
5
 
@@ -19,47 +21,83 @@ module I18n
19
21
  end
20
22
  end
21
23
 
24
+ def initialize
25
+ reload!
26
+ end
27
+
28
+ module TranslationModel
29
+ private
30
+
31
+ def translation_model
32
+ I18n::Backend::ActiveRecord.config.translation_model
33
+ end
34
+ end
35
+
22
36
  module Implementation
23
- include Base, Flatten
37
+ include Base
38
+ include Flatten
39
+ include TranslationModel
24
40
 
25
41
  def available_locales
26
- begin
27
- Translation.available_locales
28
- rescue ::ActiveRecord::StatementInvalid
29
- []
30
- end
42
+ translation_model.available_locales
43
+ rescue ::ActiveRecord::StatementInvalid
44
+ []
31
45
  end
32
46
 
33
47
  def store_translations(locale, data, options = {})
34
48
  escape = options.fetch(:escape, true)
49
+
35
50
  flatten_translations(locale, data, escape, false).each do |key, value|
36
- translation = Translation.locale(locale).lookup(expand_keys(key))
51
+ translation = translation_model.locale(locale).lookup(expand_keys(key))
37
52
 
38
- if ActiveRecord.config.cleanup_with_destroy
53
+ if self.class.config.cleanup_with_destroy
39
54
  translation.destroy_all
40
55
  else
41
56
  translation.delete_all
42
57
  end
43
58
 
44
- Translation.create(:locale => locale.to_s, :key => key.to_s, :value => value)
59
+ translation_model.create(locale: locale.to_s, key: key.to_s, value: value)
45
60
  end
61
+
62
+ reload! if self.class.config.cache_translations
63
+ end
64
+
65
+ def reload!
66
+ @translations = nil
67
+
68
+ self
69
+ end
70
+
71
+ def initialized?
72
+ !@translations.nil?
73
+ end
74
+
75
+ def init_translations
76
+ @translations = translation_model.to_h
77
+ end
78
+
79
+ def translations(do_init: false)
80
+ init_translations if do_init || !initialized?
81
+ @translations ||= {}
46
82
  end
47
83
 
48
- protected
84
+ protected
49
85
 
50
86
  def lookup(locale, key, scope = [], options = {})
51
87
  key = normalize_flat_keys(locale, key, scope, options[:separator])
52
- if key.first == '.'
53
- key = key[1..-1]
54
- end
55
- if key.last == '.'
56
- key = key[0..-2]
88
+ key = key[1..-1] if key.first == '.'
89
+ key = key[0..-2] if key.last == '.'
90
+
91
+ if self.class.config.cache_translations
92
+ keys = ([locale] + key.split(I18n::Backend::Flatten::FLATTEN_SEPARATOR)).map(&:to_sym)
93
+
94
+ return translations.dig(*keys)
57
95
  end
58
96
 
59
97
  result = if key == ''
60
- Translation.locale(locale).all
98
+ translation_model.locale(locale).all
61
99
  else
62
- Translation.locale(locale).lookup(key)
100
+ translation_model.locale(locale).lookup(key)
63
101
  end
64
102
 
65
103
  if result.empty?
@@ -76,23 +114,25 @@ module I18n
76
114
 
77
115
  def build_translation_hash_by_key(lookup_key, translation)
78
116
  hash = {}
79
- if lookup_key == ''
80
- chop_range = 0..-1
117
+
118
+ chop_range = if lookup_key == ''
119
+ 0..-1
81
120
  else
82
- chop_range = (lookup_key.size + FLATTEN_SEPARATOR.size)..-1
121
+ (lookup_key.size + FLATTEN_SEPARATOR.size)..-1
83
122
  end
84
123
  translation_nested_keys = translation.key.slice(chop_range).split(FLATTEN_SEPARATOR)
85
124
  translation_nested_keys.each.with_index.inject(hash) do |iterator, (key, index)|
86
125
  iterator[key] = translation_nested_keys[index + 1] ? {} : translation.value
87
126
  iterator[key]
88
127
  end
128
+
89
129
  hash
90
130
  end
91
131
 
92
132
  # For a key :'foo.bar.baz' return ['foo', 'foo.bar', 'foo.bar.baz']
93
133
  def expand_keys(key)
94
- key.to_s.split(FLATTEN_SEPARATOR).inject([]) do |keys, key|
95
- keys << [keys.last, key].compact.join(FLATTEN_SEPARATOR)
134
+ key.to_s.split(FLATTEN_SEPARATOR).inject([]) do |keys, k|
135
+ keys << [keys.last, k].compact.join(FLATTEN_SEPARATOR)
96
136
  end
97
137
  end
98
138
  end