PERF: bypass slow locale lookups in various cases

Previously as soon as any override was defined we would regress to the slow
path for locale lookups. Additionally if `raise: true` was specified which
rails likes to add in views we would bypass the cache

The new design manages to use the fast path for many more cases
This commit is contained in:
Sam Saffron 2019-06-05 14:30:25 +10:00
parent 78509eacb7
commit 6d8eb9c144
2 changed files with 52 additions and 11 deletions

View File

@ -19,7 +19,7 @@ module I18n
alias_method :reload_no_cache!, :reload!
alias_method :locale_no_cache=, :locale=
LRU_CACHE_SIZE = 300
LRU_CACHE_SIZE = 400
def init_accelerator!
@overrides_enabled = true
@ -43,7 +43,8 @@ module I18n
# load plural rules from plugins
DiscoursePluginRegistry.locales.each do |plugin_locale, options|
if options[:plural]
I18n.backend.store_translations(plugin_locale,
I18n.backend.store_translations(
plugin_locale,
i18n: { plural: options[:plural] }
)
end
@ -94,18 +95,43 @@ module I18n
@overrides_enabled = true
end
def translate_no_override(*args)
return translate_no_cache(*args) if args.length > 1 && args[1].present?
class MissingTranslation; end
options = args.last.is_a?(Hash) ? args.pop.dup : {}
key = args.shift
locale = options[:locale] || config.locale
def translate_no_override(key, options)
# note we skip cache for :format and :count
should_raise = false
locale = nil
dup_options = nil
if options
dup_options = options.dup
should_raise = dup_options.delete(:raise)
locale = dup_options.delete(:locale)
end
if dup_options.present?
return translate_no_cache(key, options)
end
locale ||= config.locale
@cache ||= LruRedux::ThreadSafeCache.new(LRU_CACHE_SIZE)
k = "#{key}#{locale}#{config.backend.object_id}"
@cache.getset(k) do
translate_no_cache(key, options).freeze
val = @cache.getset(k) do
begin
translate_no_cache(key, raise: true).freeze
rescue I18n::MissingTranslationData
MissingTranslation
end
end
if val != MissingTranslation
val
elsif should_raise
raise I18n::MissingTranslationData.new(locale, key)
else
-"translation missing: #{locale}.#{key}"
end
end
@ -153,11 +179,16 @@ module I18n
if @overrides_enabled
overrides = {}
# for now lets do all the expensive work for keys with count
# no choice really
has_override = !!options[:count]
I18n.fallbacks[locale].each do |l|
overrides[l] = overrides_by_locale(l)
override = overrides[l] = overrides_by_locale(l)
has_override ||= override.key?(key)
end
if overrides.present?
if has_override && overrides.present?
if options.present?
options[:overrides] = overrides

View File

@ -24,6 +24,15 @@ describe "translate accelerator" do
expect(override.persisted?).to eq(true)
end
it "supports raising if requested, and cache bypasses" do
expect { I18n.t('i_am_an_unknown_key99', raise: true) }.to raise_error(I18n::MissingTranslationData)
orig = I18n.t('i_am_an_unknown_key99')
expect(I18n.t('i_am_an_unknown_key99').object_id).to eq(orig.object_id)
expect(I18n.t('i_am_an_unknown_key99')).to eq("translation missing: en_US.i_am_an_unknown_key99")
end
it "overrides for both string and symbol keys" do
key = 'user.email.not_allowed'
text_overriden = 'foobar'
@ -124,6 +133,7 @@ describe "translate accelerator" do
I18n.overrides_disabled do
expect(I18n.t('title')).to eq(orig_title)
end
expect(I18n.t('title')).to eq('overridden title')
end