Skip to content

Commit

Permalink
Merge pull request #5 from doits/locale_dependent
Browse files Browse the repository at this point in the history
Allow to set different globals per locale
  • Loading branch information
attilahorvath authored Sep 9, 2016
2 parents 113110c + 29ef126 commit 1187f30
Show file tree
Hide file tree
Showing 2 changed files with 172 additions and 5 deletions.
79 changes: 74 additions & 5 deletions lib/i18n/globals.rb
Original file line number Diff line number Diff line change
Expand Up @@ -3,21 +3,90 @@

module I18n
class Config
class CachedGlobals < Hash
def []=(key, val)
clear_cache
annotate_hash(val) if val.is_a?(Hash) # see annotate hash below why whis must be done
super(key, val)
end

def for_locale(locale)
if key?(locale)
globals_cache[locale] ||= merge(fetch(locale)).reject { |_, i| i.is_a?(Hash) }
else
globals_cache[:default] ||= reject { |_, i| i.is_a?(Hash) }
end
end

def clear
clear_cache
super
end

def merge!(val)
clear_cache
# see annotate hash below why whis must be done
val.select { |_, v| v.is_a?(Hash) }.each { |_, v| annotate_hash(v) }
super(val)
end

private

def globals_cache
@globals_cache ||= {}
end

def clear_cache
@globals_cache = {}
end

# This is a little bit cumbersome. It might happen that this is done:
#
# I18n.config.globals[:en][:welcome] = 'Hello'
#
# What this does is changing the locale dependent version of `welcome`.
# Unfortunately we only override `:[]=` for our globals hash so it
# does not detect that the globals have been changed.
#
# To overcome this we annotate every hash that might passed in with this
# method. So when the sub hash is changed like above, the whole cache
# is cleared like it should.
def annotate_hash(hash)
return if hash.instance_variable_defined?(:@cached_global)
hash.instance_variable_set(:@cached_global, self)

def hash.[]=(key, value)
super(key, value)
@cached_global.send(:clear_cache)
end

def hash.merge!(other_hash)
super(other_hash)
@cached_global.send(:clear_cache)
end

def hash.clear
super
@cached_global.send(:clear_cache)
end
end
end

def globals
@@globals ||= {}
@@globals ||= CachedGlobals.new
end

def globals=(globals)
@@globals = globals
def globals=(new_globals)
globals.clear.merge!(new_globals) # maybe there is something better than `clear` and `merge!`
end
end

class << self
def translate(*args)
if args.last.is_a?(Hash)
args[-1] = config.globals.merge(args.last)
args[-1] = config.globals.for_locale(locale).merge(args.last)
else
args << config.globals
args << config.globals.for_locale(locale)
end
super(*args)
end
Expand Down
98 changes: 98 additions & 0 deletions test/test_i18n_globals.rb
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,8 @@ class TestI18nGlobals < Minitest::Test
def setup
I18n.backend.load_translations 'test/fixtures/translations.yml'
I18n.config = I18n::Config.new
I18n.config.globals = {} # glear globals between runs
I18n.locale = :en
end

def test_that_simple_translations_work
Expand Down Expand Up @@ -70,4 +72,100 @@ def test_that_global_variables_are_shared_between_config_instances

assert_equal I18n.translate('greeting'), 'Hi there, Greg!'
end

def test_that_locale_dependent_variable_overrides_default_one
I18n.config.globals = {
name: 'Greg',
en: { name: 'Debby' }
}

assert_equal 'Hi there, Debby!', I18n.translate('greeting')
end

def test_that_default_variable_is_used_if_no_special_locale_version_is_present
I18n.config.globals = {
name: 'Greg',
fr: { name: 'Debora' }
}

assert_equal 'Hi there, Greg!', I18n.translate('greeting')
end

def test_that_cache_is_cleared_after_setting_a_new_locale_global
I18n.config.globals = {
name: 'Greg',
en: { name: 'Debby' }
}

assert_equal 'Hi there, Debby!', I18n.translate('greeting')

I18n.config.globals[:en][:name] = 'Elisa'

assert_equal 'Hi there, Elisa!', I18n.translate('greeting')
end

def test_that_cache_is_cleared_after_setting_a_new_locale_hash
I18n.config.globals = {
name: 'Greg',
en: { name: 'Debby' }
}

assert_equal 'Hi there, Debby!', I18n.translate('greeting')

I18n.config.globals[:en] = {
name: 'Elisa'
}

assert_equal 'Hi there, Elisa!', I18n.translate('greeting')
end

def test_that_cache_is_cleared_after_merging_a_new_locale_hash
I18n.config.globals = {
name: 'Greg',
en: { name: 'Debby' }
}

assert_equal 'Hi there, Debby!', I18n.translate('greeting')

I18n.config.globals[:en].merge!(name: 'Elisa')

assert_equal 'Hi there, Elisa!', I18n.translate('greeting')
end

def test_that_cache_is_cleared_after_clearing_locale_hash
I18n.config.globals = {
name: 'Greg',
en: { name: 'Debby' }
}

assert_equal 'Hi there, Debby!', I18n.translate('greeting')

I18n.config.globals[:en].clear

assert_equal 'Hi there, Greg!', I18n.translate('greeting')
end

def test_that_cache_is_cleared_after_setting_a_new_global
I18n.config.globals = {
name: 'Greg'
}

assert_equal 'Hi there, Greg!', I18n.translate('greeting')

I18n.config.globals[:name] = 'Dobby'

assert_equal 'Hi there, Dobby!', I18n.translate('greeting')
end

def test_that_cache_is_cleared_after_merging_a_new_global
I18n.config.globals = {
name: 'Greg'
}

assert_equal 'Hi there, Greg!', I18n.translate('greeting')

I18n.config.globals.merge!(name: 'Dobby')

assert_equal 'Hi there, Dobby!', I18n.translate('greeting')
end
end

0 comments on commit 1187f30

Please sign in to comment.