From daf3ca858f48dcb42247713b2ddd53c81f9d83ad Mon Sep 17 00:00:00 2001 From: Marin Rukavina Date: Tue, 12 Nov 2019 12:26:50 +0100 Subject: [PATCH 1/2] Use activesupport implementation of Hash#deep_merge! Activesupport's Hash#deep_merge! has support for a block that describes how two values are merged. --- lib/i18n/core_ext/hash.rb | 16 +++++++++++----- 1 file changed, 11 insertions(+), 5 deletions(-) diff --git a/lib/i18n/core_ext/hash.rb b/lib/i18n/core_ext/hash.rb index 95434acd..cf45435c 100644 --- a/lib/i18n/core_ext/hash.rb +++ b/lib/i18n/core_ext/hash.rb @@ -18,12 +18,18 @@ def deep_symbolize_keys end end - # deep_merge_hash! by Stefan Rusterholz, see http://www.ruby-forum.com/topic/142809 - def deep_merge!(data) - merger = lambda do |_key, v1, v2| - Hash === v1 && Hash === v2 ? v1.merge(v2, &merger) : v2 + # deep_merge! from activesupport 5 + # Copyright (c) 2005-2019 David Heinemeier Hansson + def deep_merge!(other_hash, &block) + merge!(other_hash) do |key, this_val, other_val| + if this_val.is_a?(Hash) && other_val.is_a?(Hash) + this_val.deep_merge(other_val, &block) + elsif block_given? + block.call(key, this_val, other_val) + else + other_val + end end - merge!(data, &merger) end def symbolize_key(key) From bdae7017dcf7ba7f8b114f25932b5e8e854c8781 Mon Sep 17 00:00:00 2001 From: Marin Rukavina Date: Tue, 12 Nov 2019 12:26:39 +0100 Subject: [PATCH 2/2] I18n::Backend::Chain#translations fallback merge When merging translations from all backends, fall back to the next backend if the current backend presents a nil value. --- lib/i18n/backend/chain.rb | 3 +-- test/backend/chain_test.rb | 41 ++++++++++++++++++++++++-------------- 2 files changed, 27 insertions(+), 17 deletions(-) diff --git a/lib/i18n/backend/chain.rb b/lib/i18n/backend/chain.rb index 123f7e3c..fb12f197 100644 --- a/lib/i18n/backend/chain.rb +++ b/lib/i18n/backend/chain.rb @@ -101,8 +101,7 @@ def translations init_translations unless initialized? translations end - - memo.deep_merge!(partial_translations) + memo.deep_merge!(partial_translations) { |_, a, b| b || a } end end diff --git a/test/backend/chain_test.rb b/test/backend/chain_test.rb index 97e64b8f..b5633746 100644 --- a/test/backend/chain_test.rb +++ b/test/backend/chain_test.rb @@ -9,7 +9,8 @@ def setup :subformats => {:short => 'short'}, }, :plural_1 => { :one => '%{count}' }, - :dates => {:a => "A"} + :dates => {:a => "A"}, + :fallback_bar => nil, }) @second = backend(:en => { :bar => 'Bar', :formats => { @@ -17,7 +18,8 @@ def setup :subformats => {:long => 'long'}, }, :plural_2 => { :one => 'one' }, - :dates => {:a => "B", :b => "B"} + :dates => {:a => "B", :b => "B"}, + :fallback_bar => 'Bar', }) @chain = I18n.backend = I18n::Backend::Chain.new(@first, @second) end @@ -107,20 +109,29 @@ def setup assert @second.initialized? end + test "falls back to other backends for nil values" do + assert_nil @first.send(:translations)[:en][:fallback_bar] + assert_equal 'Bar', @second.send(:translations)[:en][:fallback_bar] + assert_equal 'Bar', I18n.t(:fallback_bar) + end + test 'should be able to get all translations of all backends merged together' do - assert_equal I18n.backend.send(:translations), - en: { - foo: 'Foo', - bar: 'Bar', - formats: { - short: 'short', - long: 'long', - subformats: { short: 'short', long: 'long' } - }, - plural_1: { one: "%{count}" }, - plural_2: { one: 'one' }, - dates: { a: 'A', b: 'B' } - } + expected = { + en: { + foo: 'Foo', + bar: 'Bar', + formats: { + short: 'short', + long: 'long', + subformats: { short: 'short', long: 'long' } + }, + plural_1: { one: "%{count}" }, + plural_2: { one: 'one' }, + dates: { a: 'A', b: 'B' }, + fallback_bar: 'Bar' + } + } + assert_equal expected, I18n.backend.send(:translations) end protected