From 288868e96bac2a275f6db9d2bc66840e620c530a Mon Sep 17 00:00:00 2001 From: fatkodima Date: Fri, 17 Feb 2023 16:43:24 +0200 Subject: [PATCH 1/2] Properly stub constants --- test/i18n_test.rb | 16 ++++++---------- test/test_helper.rb | 10 ++++++++++ 2 files changed, 16 insertions(+), 10 deletions(-) diff --git a/test/i18n_test.rb b/test/i18n_test.rb index 28becfc6..eb6a200b 100644 --- a/test/i18n_test.rb +++ b/test/i18n_test.rb @@ -501,18 +501,14 @@ def call(exception, locale, key, options); key; end test "can reserve a key" do begin - reserved_keys_were = I18n::RESERVED_KEYS.dup + stub_const(I18n, :RESERVED_KEYS, []) do + I18n.reserve_key(:foo) + I18n.reserve_key("bar") - assert !I18n::RESERVED_KEYS.include?(:foo) - assert !I18n::RESERVED_KEYS.include?(:bar) - - I18n.reserve_key(:foo) - I18n.reserve_key("bar") - - assert I18n::RESERVED_KEYS.include?(:foo) - assert I18n::RESERVED_KEYS.include?(:bar) + assert I18n::RESERVED_KEYS.include?(:foo) + assert I18n::RESERVED_KEYS.include?(:bar) + end ensure - I18n::RESERVED_KEYS = reserved_keys_were I18n.instance_variable_set(:@reserved_keys_pattern, nil) end end diff --git a/test/test_helper.rb b/test/test_helper.rb index 78b96358..f36b20b2 100644 --- a/test/test_helper.rb +++ b/test/test_helper.rb @@ -44,6 +44,16 @@ def store_translations(locale, data, options = I18n::EMPTY_HASH) def locales_dir File.dirname(__FILE__) + '/test_data/locales' end + + def stub_const(klass, constant, new_value) + old_value = klass.const_get(constant) + klass.send(:remove_const, constant) + klass.const_set(constant, new_value) + yield + ensure + klass.send(:remove_const, constant) + klass.const_set(constant, old_value) + end end class DummyRackApp From 048af5c2b93e831acbba4df9421279420ef5bf9c Mon Sep 17 00:00:00 2001 From: fatkodima Date: Fri, 17 Feb 2023 20:19:47 +0200 Subject: [PATCH 2/2] Optimize `I18n.t` --- lib/i18n.rb | 9 ++++----- lib/i18n/backend/base.rb | 9 +++++++-- lib/i18n/interpolate/ruby.rb | 10 +++++++++- 3 files changed, 20 insertions(+), 8 deletions(-) diff --git a/lib/i18n.rb b/lib/i18n.rb index d3369704..0075a360 100644 --- a/lib/i18n.rb +++ b/lib/i18n.rb @@ -331,12 +331,11 @@ def with_locale(tmp_locale = nil) # keys are Symbols. def normalize_keys(locale, key, scope, separator = nil) separator ||= I18n.default_separator + locale = locale.to_sym if locale - [ - *normalize_key(locale, separator), - *normalize_key(scope, separator), - *normalize_key(key, separator) - ] + result = [locale] + result.concat(normalize_key(scope, separator)) if scope + result.concat(normalize_key(key, separator)) end # Returns true when the passed locale, which can be either a String or a diff --git a/lib/i18n/backend/base.rb b/lib/i18n/backend/base.rb index 217c3ff0..57756758 100644 --- a/lib/i18n/backend/base.rb +++ b/lib/i18n/backend/base.rb @@ -54,7 +54,7 @@ def translate(locale, key, options = EMPTY_HASH) end deep_interpolation = options[:deep_interpolation] - values = Utils.except(options, *RESERVED_KEYS) + values = Utils.except(options, *RESERVED_KEYS) unless options.empty? if values entry = if deep_interpolation deep_interpolate(locale, entry, values) @@ -123,7 +123,12 @@ def subtrees? # first translation that can be resolved. Otherwise it tries to resolve # the translation directly. def default(locale, object, subject, options = EMPTY_HASH) - options = options.reject { |key, value| key == :default } + if options.size == 1 && options.has_key?(:default) + options = {} + else + options = Utils.except(options, :default) + end + case subject when Array subject.each do |item| diff --git a/lib/i18n/interpolate/ruby.rb b/lib/i18n/interpolate/ruby.rb index dab8f0ed..bfe484e8 100644 --- a/lib/i18n/interpolate/ruby.rb +++ b/lib/i18n/interpolate/ruby.rb @@ -1,3 +1,5 @@ +# frozen_string_literal: true + # heavily based on Masao Mutoh's gettext String interpolation extension # http://github.com/mutoh/gettext/blob/f6566738b981fe0952548c421042ad1e0cdfb31e/lib/gettext/core_ext/string.rb @@ -10,6 +12,11 @@ module I18n INTERPOLATION_PATTERN = Regexp.union(DEFAULT_INTERPOLATION_PATTERNS) deprecate_constant :INTERPOLATION_PATTERN + INTERPOLATION_PATTERNS_CACHE = Hash.new do |hash, patterns| + hash[patterns] = Regexp.union(patterns) + end + private_constant :INTERPOLATION_PATTERNS_CACHE + class << self # Return String or raises MissingInterpolationArgument exception. # Missing argument's logic is handled by I18n.config.missing_interpolation_argument_handler. @@ -20,7 +27,8 @@ def interpolate(string, values) end def interpolate_hash(string, values) - string.gsub(Regexp.union(config.interpolation_patterns)) do |match| + pattern = INTERPOLATION_PATTERNS_CACHE[config.interpolation_patterns] + string.gsub(pattern) do |match| if match == '%%' '%' else