Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
6 changes: 6 additions & 0 deletions .autotest
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
require 'autotest/restart'

Autotest.add_hook :initialize do |at|
at.testlib = "minitest/autorun"
end

1 change: 1 addition & 0 deletions .gitignore
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
.DS_Store
test/rails/fixtures
nbproject/
gemfiles/vendor/**/*
vendor/**/*
*.swp
pkg
Expand Down
2 changes: 2 additions & 0 deletions Gemfile
Original file line number Diff line number Diff line change
Expand Up @@ -6,3 +6,5 @@ gem 'mocha'
gem 'test_declarative'
gem 'rake'
gem 'minitest'
gem 'minitest-autotest'
gem 'autotest-suffix'
12 changes: 11 additions & 1 deletion Gemfile.lock
Original file line number Diff line number Diff line change
Expand Up @@ -6,8 +6,13 @@ PATH
GEM
remote: https://rubygems.org/
specs:
autotest-suffix (1.1.0)
metaclass (0.0.4)
minitest (5.5.1)
minitest (5.9.0)
minitest-autotest (1.0.3)
minitest-server (~> 1.0)
minitest-server (1.0.4)
minitest (~> 5.0)
mocha (1.1.0)
metaclass (~> 0.0.1)
rake (10.4.2)
Expand All @@ -18,8 +23,13 @@ PLATFORMS
ruby

DEPENDENCIES
autotest-suffix
i18n!
minitest
minitest-autotest
mocha
rake
test_declarative

BUNDLED WITH
1.11.2
23 changes: 23 additions & 0 deletions lib/i18n.rb
Original file line number Diff line number Diff line change
Expand Up @@ -285,6 +285,29 @@ def enforce_available_locales!(locale)
end
end

def deep_symbolize_keys(hash)
hash.inject({}) { |result, (key, value)|
value = deep_symbolize_keys(value) if value.is_a?(Hash)
the_key = (key.to_sym rescue key) || key
the_key = remove_ending_separator(the_key)
result[the_key] = value
result
}
end

# If a key ends with the separator, then removes the separator.
# This consolidates the storage and lookup of keys ending in a separator.
def remove_ending_separator(key)
if key[-1] == I18n.default_separator
new_key = key[0..key.length - 2]
if key.is_a? Symbol
new_key = new_key.to_sym
end
key = new_key
end
key
end

private

# Any exceptions thrown in translate will be sent to the @@exception_handler
Expand Down
2 changes: 1 addition & 1 deletion lib/i18n/backend/flatten.rb
Original file line number Diff line number Diff line change
Expand Up @@ -110,4 +110,4 @@ def escape_default_separator(key) #:nodoc:

end
end
end
end
7 changes: 5 additions & 2 deletions lib/i18n/backend/key_value.rb
Original file line number Diff line number Diff line change
Expand Up @@ -59,14 +59,15 @@ def initialize(store, subtrees=true)

def store_translations(locale, data, options = {})
escape = options.fetch(:escape, true)
data = I18n.deep_symbolize_keys(data)
flatten_translations(locale, data, escape, @subtrees).each do |key, value|
key = "#{locale}.#{key}"

case value
when Hash
if @subtrees && (old_value = @store[key])
old_value = ActiveSupport::JSON.decode(old_value)
value = old_value.deep_symbolize_keys.deep_merge!(value) if old_value.is_a?(Hash)
value = I18n.deep_symbolize_keys(old_value).deep_merge!(value) if old_value.is_a?(Hash)
end
when Proc
raise "Key-value stores cannot handle procs"
Expand All @@ -88,9 +89,11 @@ def available_locales

def lookup(locale, key, scope = [], options = {})
key = normalize_flat_keys(locale, key, scope, options[:separator])
key = I18n.remove_ending_separator key

value = @store["#{locale}.#{key}"]
value = ActiveSupport::JSON.decode(value) if value
value.is_a?(Hash) ? value.deep_symbolize_keys : value
value.is_a?(Hash) ? I18n.deep_symbolize_keys(value) : value
end
end

Expand Down
5 changes: 4 additions & 1 deletion lib/i18n/backend/simple.rb
Original file line number Diff line number Diff line change
Expand Up @@ -29,9 +29,12 @@ def initialized?
# translations will be overwritten by new ones only at the deepest
# level of the hash.
def store_translations(locale, data, options = {})
if options[:separator]
I18n.default_separator = options[:separator]
end
locale = locale.to_sym
translations[locale] ||= {}
data = data.deep_symbolize_keys
data = I18n.deep_symbolize_keys(data)
translations[locale].deep_merge!(data)
end

Expand Down
10 changes: 1 addition & 9 deletions lib/i18n/core_ext/hash.rb
Original file line number Diff line number Diff line change
Expand Up @@ -9,19 +9,11 @@ def except(*less_keys)
slice(*keys - less_keys)
end unless Hash.method_defined?(:except)

def deep_symbolize_keys
inject({}) { |result, (key, value)|
value = value.deep_symbolize_keys if value.is_a?(Hash)
result[(key.to_sym rescue key) || key] = value
result
}
end unless Hash.method_defined?(:deep_symbolize_keys)

# deep_merge_hash! by Stefan Rusterholz, see http://www.ruby-forum.com/topic/142809
MERGER = proc do |key, v1, v2|
Hash === v1 && Hash === v2 ? v1.merge(v2, &MERGER) : v2
end

def deep_merge!(data)
merge!(data, &MERGER)
end unless Hash.method_defined?(:deep_merge!)
Expand Down
6 changes: 6 additions & 0 deletions test/backend/key_value_test.rb
Original file line number Diff line number Diff line change
Expand Up @@ -40,4 +40,10 @@ def assert_flattens(expected, nested, escape=true, subtree=true)
I18n.t("foo", :raise => true)
end
end

test "key value store: can store and retrieve a translation which key ends with the escope separator character" do
setup_backend!
store_translations :'en', :"yyy." => "yyy value"
assert_equal("yyy value", I18n.t("yyy."))
end
end if I18n::TestCase.key_value?
6 changes: 6 additions & 0 deletions test/backend/memoize_test.rb
Original file line number Diff line number Diff line change
Expand Up @@ -44,4 +44,10 @@ def test_resets_available_locales_on_store_translations
assert I18n.available_locales.include?(:copa)
assert_equal 1, I18n.backend.spy_calls
end

def test_memoize_can_store_and_retrieve_a_translation_ending_in_separator
store_translations :'en', :"yyy." => "yyy value"
assert_equal("yyy value", I18n.t("yyy."))
end

end
5 changes: 5 additions & 0 deletions test/backend/simple_test.rb
Original file line number Diff line number Diff line change
Expand Up @@ -70,6 +70,11 @@ def setup
assert_equal Hash[:'en', {:foo => {:bar => 'bar', :baz => 'baz'}}], translations
end

test "simple store and lookup: can store and retrieve a translation which key ends with the escope separator character" do
store_translations :'en', :"yyy." => "yyy value"
assert_equal("yyy value", I18n.t("yyy."))
end

# reloading translations

test "simple reload_translations: unloads translations" do
Expand Down
2 changes: 1 addition & 1 deletion test/core_ext/hash_test.rb
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,7 @@ class I18nCoreExtHashInterpolationTest < I18n::TestCase
test "#deep_symbolize_keys" do
hash = { 'foo' => { 'bar' => { 'baz' => 'bar' } } }
expected = { :foo => { :bar => { :baz => 'bar' } } }
assert_equal expected, hash.deep_symbolize_keys
assert_equal expected, I18n.deep_symbolize_keys(hash)
end

test "#slice" do
Expand Down
1 change: 1 addition & 0 deletions test/test_helper.rb
Original file line number Diff line number Diff line change
Expand Up @@ -26,6 +26,7 @@ def self.key_value?
def setup
super
I18n.enforce_available_locales = false
I18n.default_separator = nil
end

def teardown
Expand Down