singleton-client-test 0.7.7.3 → 0.7.7.4

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -1,6 +1,8 @@
1
1
  # Copyright 2022 VMware, Inc.
2
2
  # SPDX-License-Identifier: EPL-2.0
3
3
 
4
+ require 'set'
5
+
4
6
  module SgtnClient
5
7
  module TranslationLoader
6
8
  class Chain
@@ -23,7 +25,7 @@ module SgtnClient
23
25
  end
24
26
  end
25
27
 
26
- raise exception || SgtnClient::SingletonError.new("can't load component: #{component}, locale: #{locale}")
28
+ raise exception || SingletonError.new("can't load component: #{component}, locale: #{locale}")
27
29
  end
28
30
 
29
31
  def available_bundles
@@ -3,26 +3,19 @@
3
3
 
4
4
  module SgtnClient
5
5
  module TranslationLoader
6
- autoload :Source, 'sgtn-client/loader/source'
7
- autoload :SgtnServer, 'sgtn-client/loader/server'
8
- autoload :LocalTranslation, 'sgtn-client/loader/local_translation'
9
- autoload :Chain, 'sgtn-client/loader/chain_loader'
10
- autoload :SourceComparer, 'sgtn-client/loader/source_comparer'
11
- autoload :SingleLoader, 'sgtn-client/loader/single_loader'
12
- autoload :Cache, 'sgtn-client/loader/cache'
13
-
14
6
  module LoaderFactory
15
7
  def self.create(config)
16
- SgtnClient.logger.info "[#{method(__callee__).owner}.#{__callee__}] config=#{config}"
8
+ SgtnClient.logger.info "[#{method(__callee__).owner}.#{__callee__}] config=#{config.inspect}"
17
9
 
18
10
  loaders = []
19
- loaders << Source.new(config) if config['source_bundle']
20
- loaders << SgtnServer.new(config) if config['vip_server']
21
- loaders << LocalTranslation.new(config) if config['translation_bundle']
22
- raise SgtnClient::SingletonError, 'no translation is available!' if loaders.empty?
11
+ loaders << Source.new(config) if config.source_bundle
12
+ loaders << SgtnServer.new(config) if config.vip_server
13
+ loaders << LocalTranslation.new(config) if config.translation_bundle
14
+ raise SingletonError, 'no translation is available!' if loaders.empty?
23
15
 
24
16
  chain_loader = Class.new(Chain)
25
17
  chain_loader.include SourceComparer
18
+ chain_loader.include CacheFiller
26
19
  chain_loader.include SingleLoader
27
20
  chain_loader.include Cache
28
21
 
@@ -3,25 +3,20 @@
3
3
 
4
4
  require 'json'
5
5
  require 'pathname'
6
+ require 'set'
6
7
 
7
8
  module SgtnClient
8
- module Common
9
- autoload :BundleID, 'sgtn-client/common/data'
10
- end
11
-
12
9
  module TranslationLoader
13
- autoload :CONSTS, 'sgtn-client/loader/consts'
14
-
15
10
  class LocalTranslation
16
11
  BUNDLE_PREFIX = 'messages_'.freeze
17
12
  BUNDLE_SUFFIX = '.json'.freeze
18
13
 
19
14
  def initialize(config)
20
- @base_path = Pathname.new(config['translation_bundle']) + config['product_name'] + config['version'].to_s
15
+ @base_path = Pathname.new(config.translation_bundle) + config.product_name + config.version.to_s
21
16
  end
22
17
 
23
18
  def load_bundle(component, locale)
24
- SgtnClient.logger.debug "[#{method(__callee__).owner}.#{__callee__}] component=#{component}, locale=#{locale}"
19
+ SgtnClient.logger.debug { "[#{method(__callee__).owner}.#{__callee__}] component=#{component}, locale=#{locale}" }
25
20
 
26
21
  file_name = BUNDLE_PREFIX + locale + BUNDLE_SUFFIX
27
22
  file_path = @base_path + component + file_name
@@ -29,13 +24,13 @@ module SgtnClient
29
24
  bundle_data = JSON.parse(File.read(file_path))
30
25
  messages = bundle_data['messages']
31
26
 
32
- raise SgtnClient::SingletonError, "no messages in local bundle file: #{file_path}." unless messages
27
+ raise SingletonError, "no messages in local bundle file: #{file_path}." unless messages
33
28
 
34
29
  messages
35
30
  end
36
31
 
37
32
  def available_bundles
38
- SgtnClient.logger.debug "[#{method(__callee__).owner}.#{__callee__}]"
33
+ SgtnClient.logger.debug { "[#{method(__callee__).owner}.#{__callee__}]" }
39
34
 
40
35
  @available_bundles ||= begin
41
36
  @base_path.glob('*/*.json').reduce(Set.new) do |bundles, f|
@@ -5,15 +5,10 @@
5
5
 
6
6
  require 'faraday'
7
7
  require 'faraday_middleware'
8
+ require 'set'
8
9
 
9
10
  module SgtnClient
10
- module Common
11
- autoload :BundleID, 'sgtn-client/common/data'
12
- end
13
-
14
11
  module TranslationLoader
15
- autoload :CONSTS, 'sgtn-client/loader/consts'
16
-
17
12
  class SgtnServer
18
13
  ERROR_ILLEGAL_DATA = 'server returned illegal data.'
19
14
  ERROR_BUSINESS_ERROR = 'server returned business error.'
@@ -21,9 +16,9 @@ module SgtnClient
21
16
  REQUEST_ARGUMENTS = { timeout: 10 }.freeze
22
17
 
23
18
  def initialize(config)
24
- @server_url = config['vip_server']
19
+ @server_url = config.vip_server
25
20
 
26
- product_root = format('i18n/api/v2/translation/products/%s/versions/%s', config['product_name'], config['version'])
21
+ product_root = format('i18n/api/v2/translation/products/%s/versions/%s', config.product_name, config.version)
27
22
 
28
23
  @bundle_url = "#{product_root}/locales/%s/components/%s"
29
24
  @locales_url = "#{product_root}/localelist"
@@ -31,14 +26,14 @@ module SgtnClient
31
26
  end
32
27
 
33
28
  def load_bundle(component, locale)
34
- SgtnClient.logger.debug "[#{method(__callee__).owner}.#{__callee__}] component=#{component}, locale=#{locale}"
29
+ SgtnClient.logger.debug { "[#{method(__callee__).owner}.#{__callee__}] component=#{component}, locale=#{locale}" }
35
30
 
36
31
  messages = query_server(format(@bundle_url, locale, component), ['messages'])
37
32
  messages
38
33
  end
39
34
 
40
35
  def available_bundles
41
- SgtnClient.logger.debug "[#{method(__callee__).owner}.#{__callee__}]"
36
+ SgtnClient.logger.debug { "[#{method(__callee__).owner}.#{__callee__}]" }
42
37
 
43
38
  components_thread = Thread.new { available_components }
44
39
  available_locales.reduce(Set.new) do |bundles, locale|
@@ -73,7 +68,7 @@ module SgtnClient
73
68
 
74
69
  def extract_data(parsedbody, path_to_data)
75
70
  data = parsedbody.dig('data', *path_to_data)
76
- raise SgtnClient::SingletonError, "no expected data in response. Body is: #{parsedbody}" unless data
71
+ raise SingletonError, "no expected data in response. Body is: #{parsedbody}" unless data
77
72
 
78
73
  data
79
74
  end
@@ -81,13 +76,13 @@ module SgtnClient
81
76
  def process_business_error(parsedbody)
82
77
  b_code = parsedbody.dig('response', 'code')
83
78
  unless b_code >= 200 && b_code < 300 || b_code >= 600 && b_code < 700
84
- raise SgtnClient::SingletonError, "#{ERROR_BUSINESS_ERROR} #{parsedbody['response']}"
79
+ raise SingletonError, "#{ERROR_BUSINESS_ERROR} #{parsedbody['response']}"
85
80
  end
86
81
 
87
82
  # 600 means a successful response, 6xx means partial successful.
88
83
  SgtnClient.logger.warn "#{ERROR_BUSINESS_ERROR} #{parsedbody['response']}" if b_code > 600
89
84
  rescue TypeError, ArgumentError, NoMethodError => e
90
- raise SgtnClient::SingletonError, "#{ERROR_ILLEGAL_DATA} #{e}. Body is: #{parsedbody}"
85
+ raise SingletonError, "#{ERROR_ILLEGAL_DATA} #{e}. Body is: #{parsedbody}"
91
86
  end
92
87
  end
93
88
  end
@@ -2,46 +2,44 @@
2
2
  # SPDX-License-Identifier: EPL-2.0
3
3
 
4
4
  module SgtnClient
5
- autoload :SingleOperation, 'sgtn-client/common/single_operation'
6
- autoload :CacheUtil, 'sgtn-client/util/cache-util'
7
-
8
5
  module TranslationLoader
9
- autoload :CONSTS, 'sgtn-client/loader/consts'
10
-
11
6
  module SingleLoader
12
- def load_bundle(component, locale)
13
- SgtnClient.logger.debug "[#{__FILE__}][#{__callee__}] component=#{component}, locale=#{locale}"
7
+ def load_bundle(component, locale, sync: true)
8
+ SgtnClient.logger.debug { "[#{__FILE__}][#{__callee__}] component=#{component}, locale=#{locale}" }
14
9
 
15
- @single_bundle_loader ||= single_loader { |c, l| super(c, l) }
16
- id = CacheUtil.get_cachekey(component, locale)
17
- @single_bundle_loader.operate(id, component, locale)&.value
10
+ do_single_load(Common::BundleID.new(component, locale), sync) { super(component, locale) }
18
11
  end
19
12
 
20
- def available_bundles
21
- SgtnClient.logger.debug "[#{__FILE__}][#{__callee__}]"
13
+ def available_bundles(sync: true)
14
+ SgtnClient.logger.debug { "[#{__FILE__}][#{__callee__}]" }
22
15
 
23
- @single_available_bundles_loader ||= single_loader { super }
24
- @single_available_bundles_loader.operate(CONSTS::AVAILABLE_BUNDLES_KEY)&.value
16
+ do_single_load(CONSTS::AVAILABLE_BUNDLES_KEY, sync) { super() }
25
17
  end
26
18
 
27
- private
28
-
29
- def single_loader(&block)
30
- loader = nil
31
- none_alive = proc { |_, thread| thread.nil? }
32
- creator = proc do |id, _, *args|
19
+ def initialize(*args)
20
+ none_alive = proc { |_, thread| thread.nil? || thread.alive? == false }
21
+ creator = proc do |id, &block|
33
22
  Thread.new do
34
- SgtnClient.logger.debug "start single loading #{id}"
23
+ SgtnClient.logger.debug { "start single loading #{id}" }
35
24
  begin
36
- block.call(*args)
25
+ block.call
37
26
  ensure
38
27
  # delete thread from hash after finish
39
- loader.remove_object(id)
28
+ @single_loader.remove_object(id)
40
29
  end
41
30
  end
42
31
  end
43
32
 
44
- loader = SgtnClient::SingleOperation.new(none_alive, &creator)
33
+ @single_loader = SingleOperation.new(none_alive, &creator)
34
+
35
+ super
36
+ end
37
+
38
+ private
39
+
40
+ def do_single_load(id, sync, &block)
41
+ thread = @single_loader.operate(id, &block)
42
+ thread&.value if sync
45
43
  end
46
44
  end
47
45
  end
@@ -2,25 +2,20 @@
2
2
  # SPDX-License-Identifier: EPL-2.0
3
3
 
4
4
  require 'pathname'
5
+ require 'set'
5
6
  require 'yaml'
6
7
 
7
8
  module SgtnClient
8
- module Common
9
- autoload :BundleID, 'sgtn-client/common/data'
10
- end
11
-
12
9
  module TranslationLoader
13
- autoload :CONSTS, 'sgtn-client/loader/consts'
14
-
15
10
  class Source
16
11
  def initialize(config)
17
- @source_bundle_path = Pathname.new(config['source_bundle'])
12
+ @source_bundle_path = Pathname.new(config.source_bundle)
18
13
  end
19
14
 
20
15
  def load_bundle(component, locale = nil)
21
16
  return if locale && locale != CONSTS::REAL_SOURCE_LOCALE # return when NOT querying source
22
17
 
23
- SgtnClient.logger.debug "[#{method(__callee__).owner}.#{__callee__}] component=#{component}"
18
+ SgtnClient.logger.debug { "[#{method(__callee__).owner}.#{__callee__}] component=#{component}" }
24
19
 
25
20
  total_messages = {}
26
21
 
@@ -34,18 +29,18 @@ module SgtnClient
34
29
  end
35
30
  end
36
31
 
37
- raise SgtnClient::SingletonError, "no local source messages for component #{component}" if total_messages.empty?
32
+ raise SingletonError, "no local source messages for component #{component}" if total_messages.empty?
38
33
 
39
34
  total_messages
40
35
  end
41
36
 
42
37
  def available_bundles
43
- SgtnClient.logger.debug "[#{method(__callee__).owner}.#{__callee__}]"
38
+ SgtnClient.logger.debug { "[#{method(__callee__).owner}.#{__callee__}]" }
44
39
 
45
40
  @available_bundles ||= begin
46
41
  @source_bundle_path.children.select(&:directory?).reduce(Set.new) do |bundles, component|
47
42
  component.glob('**/*.{yml, yaml}') do |_|
48
- bundles << Common::BundleID.new(component.basename.to_s, SgtnClient::LocaleUtil.get_source_locale)
43
+ bundles << Common::BundleID.new(component.basename.to_s, LocaleUtil.get_source_locale)
49
44
  break bundles
50
45
  end || bundles
51
46
  end
@@ -2,15 +2,10 @@
2
2
  # SPDX-License-Identifier: EPL-2.0
3
3
 
4
4
  module SgtnClient
5
- autoload :StringUtil, 'sgtn-client/util/string-util'
6
- autoload :LocaleUtil, 'sgtn-client/util/locale-util'
7
-
8
5
  module TranslationLoader
9
- autoload :CONSTS, 'sgtn-client/loader/consts'
10
-
11
6
  module SourceComparer
12
7
  def load_bundle(component, locale)
13
- SgtnClient.logger.debug "[#{__FILE__}][#{__callee__}] component=#{component}, locale=#{locale}"
8
+ SgtnClient.logger.debug { "[#{__FILE__}][#{__callee__}] component=#{component}, locale=#{locale}" }
14
9
 
15
10
  # source locale and old source locale don't need comparison because they are bases of comparison
16
11
  real_locale = cache_to_real_map[locale]
@@ -0,0 +1,19 @@
1
+ # frozen_string_literal: true
2
+
3
+ # Copyright 2022 VMware, Inc.
4
+ # SPDX-License-Identifier: EPL-2.0
5
+
6
+ module SgtnClient
7
+ module TranslationLoader # :nodoc:
8
+ autoload :Cache, 'sgtn-client/loader/cache'
9
+ autoload :CacheFiller, 'sgtn-client/loader/cache'
10
+ autoload :Chain, 'sgtn-client/loader/chain_loader'
11
+ autoload :CONSTS, 'sgtn-client/loader/consts'
12
+ autoload :LoaderFactory, 'sgtn-client/loader/loader_factory'
13
+ autoload :LocalTranslation, 'sgtn-client/loader/local_translation'
14
+ autoload :SgtnServer, 'sgtn-client/loader/server'
15
+ autoload :SingleLoader, 'sgtn-client/loader/single_loader'
16
+ autoload :SourceComparer, 'sgtn-client/loader/source_comparer'
17
+ autoload :Source, 'sgtn-client/loader/source'
18
+ end
19
+ end
@@ -1,88 +1,48 @@
1
1
  # Copyright 2022 VMware, Inc.
2
2
  # SPDX-License-Identifier: EPL-2.0
3
3
 
4
- module SgtnClient
5
- LOGFILE_SHIFT_AGE = 4
6
-
7
- module Common
8
- autoload :BundleID, "sgtn-client/common/data"
9
- end
10
- module Core
11
- autoload :Cache, "sgtn-client/core/cache"
12
- end
13
-
14
- autoload :Translation, "sgtn-client/api/translation"
15
- autoload :T, "sgtn-client/api/t"
16
- autoload :Source, "sgtn-client/api/source"
17
- autoload :Config, "sgtn-client/core/config"
18
- autoload :Logging, "sgtn-client/core/logging"
19
- autoload :Exceptions, "sgtn-client/core/exceptions"
20
- autoload :ValidateUtil, "sgtn-client/util/validate-util"
21
- autoload :LocaleUtil, "sgtn-client/util/locale-util"
22
- autoload :FileUtil, "sgtn-client/util/file-util"
23
- autoload :CacheUtil, "sgtn-client/util/cache-util"
24
- autoload :StringUtil, "sgtn-client/util/string-util"
25
-
26
- module Formatters
27
- autoload :PluralFormatter, "sgtn-client/formatters/plurals/plural_formatter"
28
- end
29
-
30
-
31
- class << self
32
- def configure(options = {}, &block)
33
- SgtnClient::Config.configure(options, &block)
34
- end
35
-
36
- include Logging
37
- def load(*args)
38
- # load configuration file
39
- begin
40
- SgtnClient::Config.load(args[0], args[1])
41
- SgtnClient::ValidateUtil.validate_config()
42
- rescue => exception
43
- file = File.open('./error.log', 'a')
44
- file.sync = true
45
- log = Logger.new(file)
46
- log.error exception.message
47
- end
48
-
49
- # create log file
50
- file = './sgtnclient_d.log'
51
- SgtnClient.logger.debug "[Client][load]create log file=#{file}"
52
- if args[2] != nil
53
- file = args[2]
54
- end
55
- file = File.open(file, 'a')
56
- file.sync = true
57
- SgtnClient.logger = Logger.new(file, LOGFILE_SHIFT_AGE)
58
-
59
- # Set log level for sandbox mode
60
- env = SgtnClient::Config.default_environment
61
- mode = SgtnClient::Config.configurations[env]["mode"]
62
- SgtnClient.logger.debug "[Client][load]set log level, mode=#{mode}"
63
- if mode == 'sandbox'
64
- SgtnClient.logger.level = Logger::DEBUG
65
- else
66
- SgtnClient.logger.level = Logger::INFO
67
- end
68
-
69
- # initialize cache
70
- disable_cache = SgtnClient::Config.configurations[env]["disable_cache"]
71
- SgtnClient.logger.debug "[Client][load]cache initialize, disable_cache=#{disable_cache}"
72
- if disable_cache != nil
73
- SgtnClient::Core::Cache.initialize(disable_cache)
74
- else
75
- SgtnClient::Core::Cache.initialize()
76
- end
77
- end
78
-
79
- def logger
80
- SgtnClient::Config.logger
81
- end
82
-
83
- def logger=(log)
84
- SgtnClient::Config.logger = log
85
- end
86
- end
87
-
4
+ require 'forwardable'
5
+ require 'yaml'
6
+
7
+ module SgtnClient # :nodoc:
8
+ autoload :Common, 'sgtn-client/common'
9
+ autoload :TranslationLoader, 'sgtn-client/loader'
10
+ autoload :SingleOperation, 'sgtn-client/common/single_operation'
11
+
12
+ module Core # :nodoc:
13
+ autoload :Cache, 'sgtn-client/core/cache'
14
+ end
15
+
16
+ autoload :Translation, 'sgtn-client/api/translation'
17
+ autoload :T, 'sgtn-client/api/t'
18
+ autoload :Source, 'sgtn-client/api/source'
19
+ autoload :Config, 'sgtn-client/core/config'
20
+ autoload :Exceptions, 'sgtn-client/core/exceptions'
21
+ autoload :ValidateUtil, 'sgtn-client/util/validate-util'
22
+ autoload :LocaleUtil, 'sgtn-client/util/locale-util'
23
+ autoload :CacheUtil, 'sgtn-client/util/cache-util'
24
+ autoload :StringUtil, 'sgtn-client/util/string-util'
25
+ autoload :SingletonError, 'sgtn-client/exceptions'
26
+ autoload :I18nBackend, 'sgtn-client/i18n_backend'
27
+
28
+ module Formatters # :nodoc:
29
+ autoload :PluralFormatter, 'sgtn-client/formatters/plurals/plural_formatter'
30
+ end
31
+
32
+ class << self
33
+ extend Forwardable
34
+
35
+ def_delegator Config, :instance, :config
36
+ def_delegators :config, :logger, :logger=
37
+
38
+ def load(config_file, env, log_file = nil)
39
+ configurations = YAML.load(File.read(config_file))
40
+ config_hash = configurations[env]
41
+ raise "Configuration[#{env}] NotFound" unless config_hash
42
+
43
+ config_hash['log_file'] = log_file if log_file
44
+ config.update(config_hash)
45
+ ValidateUtil.validate_config
46
+ end
47
+ end
88
48
  end
@@ -1,35 +1,25 @@
1
1
  # Copyright 2022 VMware, Inc.
2
2
  # SPDX-License-Identifier: EPL-2.0
3
3
 
4
- module SgtnClient
5
- module Core
6
- autoload :Cache, 'sgtn-client/core/cache'
7
- end
4
+ require 'time'
8
5
 
6
+ module SgtnClient
9
7
  class CacheUtil
10
8
  def self.get_cache(cache_key)
11
- SgtnClient::Core::Cache.get(cache_key)
9
+ Core::Cache.get(cache_key)
12
10
  end
13
11
 
14
12
  def self.clear_cache
15
- SgtnClient::Core::Cache.clear
13
+ Core::Cache.clear
16
14
  end
17
15
 
18
16
  def self.write_cache(cache_key, items)
19
17
  return nil if items.nil? || items.empty?
20
18
 
21
- env = SgtnClient::Config.default_environment
22
- cache_expiry_period = SgtnClient::Config.configurations[env]['cache_expiry_period']
19
+ cache_expiry_period = SgtnClient.config.cache_expiry_period
23
20
  # expired after 24 hours
24
21
  cache_expiry_period = 24 * 60 if cache_expiry_period.nil?
25
- SgtnClient::Core::Cache.put(cache_key, items, cache_expiry_period)
26
- end
27
-
28
- def self.get_cachekey(component, locale)
29
- env = SgtnClient::Config.default_environment
30
- product_name = SgtnClient::Config.configurations[env]['product_name']
31
- version = SgtnClient::Config.configurations[env]['version'].to_s
32
- product_name + '_' + version + '_' + component + '_' + locale
22
+ Core::Cache.put(cache_key, items, cache_expiry_period)
33
23
  end
34
24
 
35
25
  def self.is_expired(cache_item)
@@ -3,10 +3,10 @@
3
3
  # Copyright 2022 VMware, Inc.
4
4
  # SPDX-License-Identifier: EPL-2.0
5
5
 
6
- require 'set'
6
+ require 'concurrent/map'
7
7
 
8
8
  module SgtnClient
9
- class LocaleUtil
9
+ class LocaleUtil # :nodoc:
10
10
  MAP_LOCALES = {
11
11
  'zh-cn' => 'zh-hans',
12
12
  'zh-tw' => 'zh-hant',
@@ -14,57 +14,88 @@ module SgtnClient
14
14
  'zh-hant-tw' => 'zh-hant'
15
15
  }.freeze
16
16
  LOCALE_SEPARATOR = '-'
17
+ EN_LOCALE = 'en'
18
+ @locale_match_results = Concurrent::Map.new
19
+ @lowercase_locales_map = Concurrent::Map.new
20
+
21
+ def self.get_best_locale(locale, component)
22
+ component_result = @locale_match_results[component] ||= begin
23
+ components = SgtnClient.config.available_components
24
+ unless components.empty? || components.include?(component)
25
+ raise SingletonError, "component '#{component}' doesn't exist!"
26
+ end
27
+
28
+ Concurrent::Map.new
29
+ end
17
30
 
18
- def self.get_best_locale(locale)
19
- return locale if Config.available_locales.include?(locale)
20
-
21
- return get_fallback_locale if locale.nil?
22
-
23
- locale = locale.to_s
24
- return get_fallback_locale if locale.empty?
25
-
26
- get_best_match(locale.gsub('_', LOCALE_SEPARATOR).downcase)
27
- end
28
-
29
- def self.is_source_locale(locale = nil)
30
- locale == get_source_locale
31
+ component_result[locale] ||= begin
32
+ # component_result.shift if component_result.size >= 50
33
+ if SgtnClient.config.available_locales(component).include?(locale)
34
+ locale
35
+ elsif locale.nil?
36
+ get_fallback_locale
37
+ else
38
+ locale = locale.to_s
39
+ if locale.empty?
40
+ get_fallback_locale
41
+ else
42
+ candidates = lowercase_locales_map(component)
43
+ if candidates.empty?
44
+ locale
45
+ else
46
+ get_best_match(locale.gsub('_', LOCALE_SEPARATOR).downcase, candidates)
47
+ end
48
+ end
49
+ end
50
+ end
31
51
  end
32
52
 
33
- def self.get_best_match(locale)
53
+ def self.get_best_match(locale, candidates)
34
54
  locale = MAP_LOCALES[locale] || locale
35
- lowercase_locales_map[locale] or begin
55
+ candidates[locale] or begin
36
56
  index = locale.rindex(LOCALE_SEPARATOR)
37
57
  return get_fallback_locale if index.nil?
38
58
 
39
- get_best_match(locale[0...index])
59
+ get_best_match(locale[0...index], candidates)
40
60
  end
41
61
  end
42
62
 
43
63
  def self.get_source_locale
44
- 'en'
64
+ EN_LOCALE
45
65
  end
46
66
 
47
67
  def self.get_default_locale
48
- env = SgtnClient::Config.default_environment
49
- SgtnClient::Config.configurations[env]['default_language']
68
+ EN_LOCALE
50
69
  end
51
70
 
52
71
  def self.get_fallback_locale
53
- @fallback_locale ||= get_default_locale || get_source_locale || 'en'
72
+ locale_fallbacks[0]
73
+ end
74
+
75
+ def self.locale_fallbacks
76
+ @locale_fallbacks ||= [get_default_locale, get_source_locale, EN_LOCALE].uniq(&:to_s) - [nil, '']
54
77
  end
55
78
 
56
- def self.lowercase_locales_map
57
- @lowercase_locales_map ||= Config.available_locales.each_with_object({}) do |locale, memo|
79
+ def self.lowercase_locales_map(component)
80
+ @lowercase_locales_map[component] ||= SgtnClient.config.available_locales(component).each_with_object({}) do |locale, memo|
58
81
  memo[locale.to_s.downcase] = locale
59
82
  end
60
83
  end
61
84
 
62
- def self.reset_available_locales(type)
63
- @lowercase_locales_map = nil if type == :available_locales
85
+ def self.reset_locale_data(type, component = nil)
86
+ return unless type == :available_locales
87
+
88
+ if component.nil?
89
+ @locale_match_results.clear
90
+ @lowercase_locales_map.clear
91
+ else
92
+ @locale_match_results.delete(component)
93
+ @lowercase_locales_map.delete(component)
94
+ end
64
95
  end
65
96
 
66
- SgtnClient::Config.add_observer(self, :reset_available_locales)
97
+ SgtnClient.config.add_observer(self, :reset_locale_data)
67
98
 
68
- private_class_method :get_best_match, :lowercase_locales_map, :reset_available_locales
99
+ private_class_method :get_best_match, :lowercase_locales_map, :reset_locale_data
69
100
  end
70
101
  end
@@ -7,6 +7,9 @@ module SgtnClient
7
7
  super(str)
8
8
  @locale = locale
9
9
  end
10
- attr_accessor :locale
10
+
11
+ def localize(locale)
12
+ super(@locale || locale)
13
+ end
11
14
  end
12
- end
15
+ end