PERF: Ensure locales are always handled as symbols internally (#12897)

Sometimes, parts of the application pass in the locale as a string, not a symbol. This was causing the translate_accelerator to cache two versions of the locale separately: one cache for the symbol version, and one cache for the string version. For example, in a running production process:

```
irb(main):001:0> I18n.instance_variable_get(:@loaded_locales)
=> [:en, "en"]
```

This commit ensures the `locale` key is always converted to a symbol, and adds a spec to ensure the same locale cannot appear twice in `@loaded_locales`
This commit is contained in:
David Taylor 2021-04-30 10:56:27 +01:00 committed by GitHub
parent ad8c7714c8
commit 1bc1a439ee
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
2 changed files with 17 additions and 4 deletions

View File

@ -33,6 +33,7 @@ module I18n
LOAD_MUTEX = Mutex.new
def load_locale(locale)
locale = locale.to_sym
LOAD_MUTEX.synchronize do
return if @loaded_locales.include?(locale)
@ -70,7 +71,7 @@ module I18n
def search(query, opts = {})
execute_reload if @requires_reload
locale = opts[:locale] || config.locale
locale = (opts[:locale] || config.locale).to_sym
load_locale(locale) unless @loaded_locales.include?(locale)
opts ||= {}
@ -87,6 +88,7 @@ module I18n
end
def ensure_loaded!(locale)
locale = locale.to_sym
@loaded_locales ||= []
load_locale(locale) unless @loaded_locales.include?(locale)
end
@ -119,6 +121,7 @@ module I18n
end
locale ||= config.locale
locale = locale.to_sym
@cache ||= LruRedux::ThreadSafeCache.new(LRU_CACHE_SIZE)
k = "#{key}#{locale}#{config.backend.object_id}"
@ -143,6 +146,7 @@ module I18n
def overrides_by_locale(locale)
return unless @overrides_enabled
return {} if GlobalSetting.skip_db?
locale = locale.to_sym
execute_reload if @requires_reload
@ -181,7 +185,7 @@ module I18n
options = args.last.is_a?(Hash) ? args.pop.dup : {}
key = args.shift
locale = options[:locale] || config.locale
locale = (options[:locale] || config.locale).to_sym
load_locale(locale) unless @loaded_locales.include?(locale)
@ -224,11 +228,13 @@ module I18n
execute_reload if @requires_reload
locale ||= config.locale
locale = locale.to_sym
load_locale(locale) unless @loaded_locales.include?(locale)
exists_no_cache?(key, locale)
end
def locale=(value)
value = value.to_sym
execute_reload if @requires_reload
self.locale_no_cache = value
end

View File

@ -46,6 +46,13 @@ describe "translate accelerator" do
end
end
it "converts language keys to symbols" do
expect(I18n.t('foo', locale: :en)).to eq('Foo in :en')
expect(I18n.t('foo', locale: "en")).to eq('Foo in :en')
expect(I18n.instance_variable_get(:@loaded_locales)).to contain_exactly(:en)
end
it "overrides for both string and symbol keys" do
key = 'user.email.not_allowed'
text_overriden = 'foobar'
@ -68,8 +75,8 @@ describe "translate accelerator" do
expect(I18n.instance_variable_get(:@overrides_by_site)).to eq(
'default' => {
'en' => { 'got' => 'summer' },
'zh_TW' => { 'got' => '冬季' }
en: { 'got' => 'summer' },
zh_TW: { 'got' => '冬季' }
}
)
end