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

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

diff --git a/lib/freedom_patches/translate_accelerator.rb b/lib/freedom_patches/translate_accelerator.rb
index 0ba2ac5..2bc4cac 100644
--- a/lib/freedom_patches/translate_accelerator.rb
+++ b/lib/freedom_patches/translate_accelerator.rb
@@ -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
diff --git a/spec/components/freedom_patches/translate_accelerator_spec.rb b/spec/components/freedom_patches/translate_accelerator_spec.rb
index ba4d377..effea35 100644
--- a/spec/components/freedom_patches/translate_accelerator_spec.rb
+++ b/spec/components/freedom_patches/translate_accelerator_spec.rb
@@ -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

GitHub sha: 1bc1a439

This commit appears in #12897 which was approved by eviltrout and gschlager. It was merged by davidtaylorhq.