Skip to content

Commit

Permalink
Делаю наши дополнения к I18n более потокобезопасными
Browse files Browse the repository at this point in the history
Избавляюсь от использования глобальных переменных.
В I18n.languages пока оставил, т.к. иначе придется инициализировать
языки в каждом потоке заново. Но т.к. языки мы инициализируем один раз в
инитиалайзере, то кажется из-за languages не должно быть проблем.
  • Loading branch information
hbda committed Oct 23, 2024
1 parent 060b105 commit 68b3518
Show file tree
Hide file tree
Showing 7 changed files with 52 additions and 21 deletions.
17 changes: 7 additions & 10 deletions lib/globalize/locale/active_record.rb
Original file line number Diff line number Diff line change
@@ -1,39 +1,36 @@
# frozen_string_literal: true

module I18n
@@ar_fallbacks = nil
@@ar_locale = nil

class << self
def ar_locale
@@ar_locale || locale
Thread.current[:ar_locale] || locale
end

def ar_locale=(val)
raise ::ArgumentError, "No language for locale `#{val}'" if !val.nil? && !I18n.language(val)

@@ar_locale = val
Thread.current[:ar_locale] = val
end

def reset_ar_locale
@@ar_locale = nil
Thread.current[:ar_locale] = nil
self
end

# Returns the current fallbacks. Defaults to +Globalize::Locale::Fallbacks+.
def ar_fallbacks(force = false)
return @@ar_fallbacks if @@ar_fallbacks
return Thread.current[:ar_fallbacks] if Thread.current[:ar_fallbacks]
return fallbacks unless force
@@ar_fallbacks = Globalize::Locale::Fallbacks.new
Thread.current[:ar_fallbacks] = Globalize::Locale::Fallbacks.new
end

# Sets the current fallbacks. Used to set a custom fallbacks instance.
def ar_fallbacks=(fallbacks)
@@ar_fallbacks = fallbacks
Thread.current[:ar_fallbacks] = fallbacks
end

def reset_ar_fallbacks
@@ar_fallbacks = nil
Thread.current[:ar_fallbacks] = nil
self
end
end
Expand Down
8 changes: 3 additions & 5 deletions lib/globalize/locale/fallbacks.rb
Original file line number Diff line number Diff line change
Expand Up @@ -3,21 +3,19 @@
require 'globalize/locale/language_tag'

module I18n
@@fallbacks = nil

class << self
# Returns the current fallbacks. Defaults to +Globalize::Locale::Fallbacks+.
def fallbacks
@@fallbacks ||= Globalize::Locale::Fallbacks.new
Thread.current[:fallbacks] ||= Globalize::Locale::Fallbacks.new
end

# Sets the current fallbacks. Used to set a custom fallbacks instance.
def fallbacks=(fallbacks)
@@fallbacks = fallbacks
Thread.current[:fallbacks] = fallbacks
end

def reset_fallbacks
@@fallbacks = nil
Thread.current[:fallbacks] = nil
self
end
end
Expand Down
4 changes: 2 additions & 2 deletions lib/globalize/locale/language_tag.rb
Original file line number Diff line number Diff line change
Expand Up @@ -14,11 +14,11 @@ module Rfc4646
class LanguageTag < Struct.new(*Rfc4646::SUBTAGS)
class << self
def parser
@@parser ||= SimpleParser
Thread.current[:parser] ||= SimpleParser
end

def parser=(parser)
@@parser = parser
Thread.current[:parser] = parser
end

def tag(tag)
Expand Down
4 changes: 2 additions & 2 deletions lib/globalize/model/active_record/translated.rb
Original file line number Diff line number Diff line change
Expand Up @@ -75,11 +75,11 @@ def respond_to_with_translations(method, include_private = false)
end

def locale=(locale)
@@locale = locale
Thread.current[:locale] = locale
end

def locale
(defined?(@@locale) && @@locale) || I18n.ar_locale
Thread.current[:locale] || I18n.ar_locale
end
end

Expand Down
27 changes: 27 additions & 0 deletions test/locale/active_record_test.rb
Original file line number Diff line number Diff line change
Expand Up @@ -31,6 +31,22 @@ def teardown
test 'raises on missing locale' do
assert_raise(ArgumentError) { I18n.ar_locale = 'unknown' }
end

test 'thread safety' do
I18n.locale = :es
I18n.ar_locale = :es
assert_equal :es, I18n.locale
assert_equal :es, I18n.ar_locale
thread = Thread.new do
I18n.locale = :fr
I18n.ar_locale = :fr
assert_equal :fr, I18n.locale
assert_equal :fr, I18n.ar_locale
end
thread.join
assert_equal :es, I18n.locale
assert_equal :es, I18n.ar_locale
end
end

class ActiveRecordFallbacksTest < ActiveSupport::TestCase
Expand All @@ -55,4 +71,15 @@ def teardown
assert_equal({ es: [:en], en: [:us] }, I18n.fallbacks)
assert_equal({ es: [:en], en: [:us] }, I18n.ar_fallbacks)
end

test 'thread safety' do
I18n.ar_fallbacks = { es: [:en] }
assert_equal({ es: [:en] }, I18n.ar_fallbacks)
thread = Thread.new do
I18n.ar_fallbacks = { de: [:fr] }
assert_equal({ de: [:fr] }, I18n.ar_fallbacks)
end
thread.join
assert_equal({ es: [:en] }, I18n.ar_fallbacks)
end
end
11 changes: 11 additions & 0 deletions test/locale/fallbacks_test.rb
Original file line number Diff line number Diff line change
Expand Up @@ -36,6 +36,17 @@ def teardown
I18n.fallbacks = Fallbacks.new(:'fi-FI', :'se-FI')
assert_equal(%i[fi-FI fi se-FI se root], I18n.fallbacks.defaults)
end

test "thread safety" do
I18n.fallbacks[:es] = [:en]
assert_equal({ es: [:en] }, I18n.fallbacks)
thread = Thread.new do
I18n.fallbacks[:en] = [:us]
assert_equal({ en: [:us] }, I18n.fallbacks)
end
thread.join
assert_equal({ es: [:en] }, I18n.fallbacks)
end
end

class NoMappingFallbacksTest < ActiveSupport::TestCase
Expand Down
2 changes: 0 additions & 2 deletions test/model/active_record/translated_test.rb
Original file line number Diff line number Diff line change
Expand Up @@ -431,8 +431,6 @@ def teardown
end

test "access content locale before setting" do
Globalize::Model::ActiveRecord::Translated::ActMethods.class_eval "remove_class_variable(:@@locale)", __FILE__,
__LINE__ - 1
assert_nothing_raised { ActiveRecord::Base.locale }
end

Expand Down

0 comments on commit 68b3518

Please sign in to comment.