singleton-client-test 0.7.0.32 → 0.7.0.33

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.
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: 7c3518e9f8e872dd00acd151a9157c273f274c5398d773c42e75d07e0667413b
4
- data.tar.gz: 0eec546d1df60f066a1f346c04da0cac374f1944980477ccb32b5055a70e62b0
3
+ metadata.gz: a2a32a268d9bc9b395baeb2d296049cbbb29a40c081968d6e8a5ae364c39444c
4
+ data.tar.gz: fdf427aaf792fbff1bf6afa404d6e0aeeea030b9fa90b7eab578cbe46659656e
5
5
  SHA512:
6
- metadata.gz: b8eb7e6e83057a56fa3a0d618b14ef83e61458319ccbbea388028961bbeae0ea061c82c87ed34f89cfe43c2336fc390b4ffe6801c1e9e6c85e43a2c4dd366e9f
7
- data.tar.gz: 10eb576187a7ff47e04e409ff292862397e956de6adfbe9f2a39565cd5219c22397a959a23b399c96627aeab85562992f0abc92edec3a590f0ec7a7b610c4794
6
+ metadata.gz: 1ecfa3b8fbc1ef494e41a517a102856f4717d408845eeac43cd751c24df2a590404082cd00670b280fd8c404b3dd95ecd2ae5c06f7b0c0b23172b9eb7ab2fff7
7
+ data.tar.gz: 0a8aee2dd03eaa02c981cdfaa097ffbddebc2118c7c7a63625ad19ca332ecf582fac19a812339ef9920dac37765a03b30d9800d69cfe9dd2b854762ee0796170
@@ -1,73 +1,24 @@
1
1
  # Copyright 2022 VMware, Inc.
2
2
  # SPDX-License-Identifier: EPL-2.0
3
3
 
4
+ require 'sgtn-client/loader/local_source_bundle'
5
+
4
6
  module SgtnClient
5
-
6
- autoload :CacheUtil, "sgtn-client/util/cache-util"
7
+ autoload :CacheUtil, 'sgtn-client/util/cache-util'
7
8
 
8
9
  class Source
9
-
10
- def self.getSource(component, key, locale)
11
- SgtnClient.logger.debug "[Source][getSource]component=#{component}, key=#{key}, locale=#{locale}"
12
- cache_key = SgtnClient::CacheUtil.get_cachekey(component, locale)
13
- expired, items = SgtnClient::CacheUtil.get_cache(cache_key)
14
- if items.nil?
15
- items = getBundle(component, locale)
16
- SgtnClient::CacheUtil.write_cache(cache_key, items)
17
- else
18
- SgtnClient.logger.debug "[Source][getSource]getting sources from cache with key: " + cache_key
19
- end
20
- s = (items.nil? || items[locale].nil?)? nil : items[locale][key]
21
- if items.nil? || s.nil?
22
- SgtnClient.logger.debug "[Source][getSource]source not found, return key: " + key
23
- #return key
24
- return nil
25
- else
26
- return s
27
- end
28
- end
29
-
30
- def self.getSources(component, locale)
31
- SgtnClient.logger.debug "[Source][getSources]component=#{component}, locale=#{locale}"
32
- cache_key = SgtnClient::CacheUtil.get_cachekey(component, locale)
33
- expired, items = SgtnClient::CacheUtil.get_cache(cache_key)
34
- if items.nil? || expired
35
- items = getBundle(component, locale)
36
- SgtnClient::CacheUtil.write_cache(cache_key, items)
37
- else
38
- SgtnClient.logger.debug "[Source][getSources]getting sources from cache with key: " + cache_key
39
- end
40
- return items
41
- end
42
-
43
- def self.loadBundles(locale)
44
- SgtnClient.logger.debug "[Source][loadBundles]locale=#{locale}"
45
- env = SgtnClient::Config.default_environment
46
- SgtnClient::Config.configurations.default = locale
47
- source_bundle = SgtnClient::Config.configurations[env]["source_bundle"]
48
- Dir.foreach(source_bundle) do |component|
49
- next if component == '.' || component == '..'
50
- yamlfile = File.join(source_bundle, component + "/" + locale + ".yml")
51
- bundle = SgtnClient::FileUtil.read_yml(yamlfile)
52
- cachekey = SgtnClient::CacheUtil.get_cachekey(component, locale)
53
- SgtnClient::CacheUtil.write_cache(cachekey,bundle)
54
- end
55
- end
56
-
57
- private
58
- def self.getBundle(component, locale)
59
- SgtnClient.logger.debug "[Source][getBundle]component=#{component}, locale=#{locale}"
60
- env = SgtnClient::Config.default_environment
61
- source_bundle = SgtnClient::Config.configurations[env]["source_bundle"]
62
- bundlepath = source_bundle + "/" + component + "/" + locale + ".yml"
63
- begin
64
- bundle = SgtnClient::FileUtil.read_yml(bundlepath)
65
- rescue => exception
66
- SgtnClient.logger.error exception.message
67
- end
68
- return bundle
10
+ def self.loadBundles(locale)
11
+ SgtnClient.logger.debug "[Source][loadBundles]locale=#{locale}"
12
+ env = SgtnClient::Config.default_environment
13
+ SgtnClient::Config.configurations.default = locale
14
+ source_bundle = SgtnClient::Config.configurations[env]['source_bundle']
15
+ Dir.foreach(source_bundle) do |component|
16
+ next if %w[. ..].include? component
17
+
18
+ bundle = load_bundle(component)
19
+ cachekey = SgtnClient::CacheUtil.get_cachekey(component, LocaleUtil.get_source_locale)
20
+ SgtnClient::CacheUtil.write_cache(cachekey, bundle)
69
21
  end
70
-
22
+ end
71
23
  end
72
-
73
24
  end
@@ -2,24 +2,23 @@
2
2
  # SPDX-License-Identifier: EPL-2.0
3
3
 
4
4
  module SgtnClient
5
- class T < Translation
6
-
7
- def self.s(key)
8
- locale = RequestStore.store[:locale]
9
- component = RequestStore.store[:component]
10
- return getString(component, key, locale)
11
- end
5
+ class T
6
+ def self.s(key)
7
+ locale = RequestStore.store[:locale]
8
+ component = RequestStore.store[:component]
9
+ Translation.getString(component, key, locale)
10
+ end
12
11
 
13
- def self.s_f(key, args)
14
- locale = RequestStore.store[:locale]
15
- component = RequestStore.store[:component]
16
- return getString_f(component, key, args, locale)
17
- end
12
+ def self.s_f(key, args)
13
+ locale = RequestStore.store[:locale]
14
+ component = RequestStore.store[:component]
15
+ Translation.getString_f(component, key, args, locale)
16
+ end
18
17
 
19
- def self.c()
20
- locale = RequestStore.store[:locale]
21
- component = RequestStore.store[:component]
22
- return getStrings(component, locale)
23
- end
18
+ def self.c
19
+ locale = RequestStore.store[:locale]
20
+ component = RequestStore.store[:component]
21
+ Translation.getStrings(component, locale)
24
22
  end
23
+ end
25
24
  end
@@ -1,158 +1,110 @@
1
1
  # Copyright 2022 VMware, Inc.
2
2
  # SPDX-License-Identifier: EPL-2.0
3
3
 
4
- require 'multi_json'
5
-
6
4
  module SgtnClient
7
-
8
- module Core
9
- autoload :Request, "sgtn-client/core/request"
10
- autoload :Cache, "sgtn-client/core/cache"
11
- autoload :CacheUtil, "sgtn-client/util/cache-util"
12
- autoload :LocaleUtil, "sgtn-client/util/locale-util"
5
+ autoload :StringUtil, 'sgtn-client/util/string-util'
6
+
7
+ module TranslationLoader
8
+ autoload :LocalBundle, 'sgtn-client/loader/local_bundle'
9
+ autoload :ServerBundle, 'sgtn-client/loader/server_bundle'
10
+ autoload :SourceComparer, 'sgtn-client/loader/source_comparer'
11
+ autoload :SingleLoader, 'sgtn-client/loader/single_loader'
12
+ autoload :Cache, 'sgtn-client/loader/cache'
13
13
  end
14
-
15
- class Translation
16
-
17
- def self.getString(component, key, locale)
18
- SgtnClient.logger.debug "[Translation.getString]component: #{component}, key: #{key}, locale: #{locale}"
19
- str = getTranslation(component, key, locale)
20
- if str.nil?
21
- str = SgtnClient::Source.getSource(component, key, SgtnClient::Config.configurations.default)
22
- if str.nil?
23
- SgtnClient.logger.debug "[Translation][getString] Missing source string with key: #{key}, component: #{component}, locale: #{locale}"
24
- end
25
- end
26
- str
27
- end
28
14
 
29
- def self.getString_p(component, key, plural_args, locale)
30
- SgtnClient.logger.debug "[Translation][getString_p]component=#{component}, key=#{key}, locale=#{locale}"
31
- str = getTranslation(component, key, locale)
32
- if str.nil?
33
- str = SgtnClient::Source.getSource(component, key, SgtnClient::Config.configurations.default)
34
- if str.nil?
35
- SgtnClient.logger.debug "[Translation][getString_p] Missing source string with key: #{key}, component: #{component}, locale: #{locale}"
36
- return nil
37
- end
38
- str.to_plural_s(:en, plural_args)
39
- else
40
- str.to_plural_s(locale, plural_args)
15
+ module Translation
16
+ def self.getString(component, key, locale)
17
+ SgtnClient.logger.debug "[Translation.getString]component: #{component}, key: #{key}, locale: #{locale}"
18
+ str = getTranslation(component, key, locale)
19
+ if str.nil? && !LocaleUtil.is_source_locale(locale)
20
+ str = getTranslation(component, key, LocaleUtil.get_source_locale)
21
+ end
22
+ str
23
+ end
24
+
25
+ def self.getString_p(component, key, plural_args, locale)
26
+ SgtnClient.logger.debug "[Translation][getString_p]component=#{component}, key=#{key}, locale=#{locale}"
27
+ str = getTranslation(component, key, locale)
28
+ if str.nil?
29
+ unless LocaleUtil.is_source_locale(locale)
30
+ str = getTranslation(component, key, LocaleUtil.get_source_locale)
31
+ str.to_plural_s(LocaleUtil.get_source_locale, plural_args) if str
41
32
  end
33
+ else
34
+ locale = str.locale if str.is_a?(SgtnClient::StringUtil)
35
+ str.to_plural_s(locale, plural_args)
42
36
  end
37
+ end
43
38
 
44
- def self.getString_f(component, key, args, locale, *optionals)
45
- SgtnClient.logger.debug "[Translation][getString_f]component=#{component}, key=#{key}, locale=#{locale}"
46
- s = getString(component, key, locale, *optionals)
47
- if s.nil?
48
- return nil
49
- end
50
- if args.is_a?(Hash)
51
- args.each do |source, arg|
52
- s.gsub! "{#{source}}", arg
53
- end
54
- elsif args.is_a?(Array)
55
- s = sprintf s % args
56
- end
57
- return s
58
- end
39
+ def self.getString_f(component, key, args, locale, *optionals)
40
+ SgtnClient.logger.debug "[Translation][getString_f]component=#{component}, key=#{key}, locale=#{locale}"
41
+ s = getString(component, key, locale, *optionals)
42
+ return nil if s.nil?
59
43
 
60
- def self.getStrings(component, locale)
61
- SgtnClient.logger.debug "[Translation][getStrings]component=#{component}, locale=#{locale}"
62
- locale = SgtnClient::LocaleUtil.get_best_locale(locale)
63
- items = get_cs(component, locale)
64
- default = SgtnClient::Config.configurations.default
65
- if items.nil? || items["messages"] == nil
66
- items = {}
67
- s = SgtnClient::Source.getSources(component, default)
68
- if s.nil?
69
- SgtnClient.logger.error "[Translation][getStrings] Missing component: #{component}, locale: #{locale}"
70
- else
71
- default_component, value = s.first
72
- items["component"] = component
73
- items["messages"] = value
74
- items["locale"] = 'source'
75
- end
44
+ if args.is_a?(Hash)
45
+ args.each do |source, arg|
46
+ s.gsub! "{#{source}}", arg
76
47
  end
77
- return items
78
- end
79
-
48
+ elsif args.is_a?(Array)
49
+ s = s % args
50
+ end
51
+ s
52
+ end
53
+
54
+ def self.getStrings(component, locale)
55
+ SgtnClient.logger.debug "[Translation][getStrings]component=#{component}, locale=#{locale}"
56
+ locale = SgtnClient::LocaleUtil.get_best_locale(locale)
57
+ items = get_cs(component, locale)
58
+ if (items.nil? || items['messages'].nil?) && !LocaleUtil.is_source_locale(locale)
59
+ items = get_cs(component, LocaleUtil.get_source_locale)
60
+ end
80
61
 
81
- private
62
+ items
63
+ end
82
64
 
83
- def self.getTranslation(component, key, locale)
84
- locale = SgtnClient::LocaleUtil.get_best_locale(locale)
85
- items = get_cs(component, locale)
86
- if items.nil? || items["messages"] == nil
87
- nil
88
- else
89
- items["messages"][key]
90
- end
91
- end
65
+ def self.getTranslation(component, key, locale)
66
+ locale = SgtnClient::LocaleUtil.get_best_locale(locale)
67
+ items = get_cs(component, locale)
68
+ items&.dig('messages', key)
69
+ end
92
70
 
93
- def self.get_cs(component, locale)
94
- # source locale always return source bundle
95
- if locale == LocaleUtil.get_source_locale
96
- sources = SgtnClient::Source.getSources(component, SgtnClient::Config.configurations.default)
97
- messages = sources&.first&.last
98
- return {'locale' => locale, 'component' => component, 'messages' => messages} if messages
99
- end
71
+ def self.get_cs(component, locale)
72
+ cache_item = load_bundle(component, locale)
73
+ cache_item&.dig(:items)
74
+ end
100
75
 
101
- cache_key = SgtnClient::CacheUtil.get_cachekey(component, locale)
102
- SgtnClient.logger.debug "[Translation][get_cs]cache_key=#{cache_key}"
103
- expired, items = SgtnClient::CacheUtil.get_cache(cache_key)
104
- if items.nil? || expired
105
- items = load(component, locale)
106
- if items.nil?
107
- items = SgtnClient::Source.getSources(component, SgtnClient::Config.configurations.default)
108
- SgtnClient::Core::Cache.put(cache_key, items, 60)
109
- else
110
- SgtnClient::CacheUtil.write_cache(cache_key, items)
111
- end
112
- else
113
- SgtnClient.logger.debug "[Translation]get translations from cache with key: " + cache_key
114
- end
76
+ def self.load_bundle(component, locale)
77
+ init_translations unless initialized?
78
+ super
79
+ end
115
80
 
116
- return items
117
- end
81
+ class << self
82
+ def initialized?
83
+ @initialized ||= false
84
+ end
118
85
 
119
- def self.load(component, locale)
86
+ def init_translations
87
+ # TODO: Lock to initialize?
120
88
  env = SgtnClient::Config.default_environment
121
- mode = SgtnClient::Config.configurations[env]["bundle_mode"]
122
- SgtnClient.logger.debug "[Translation][load]mode=#{mode}"
89
+ mode = SgtnClient::Config.configurations[env]['bundle_mode']
90
+ SgtnClient.logger.debug "[Translation][init_translations]mode=#{mode}"
91
+
123
92
  if mode == 'offline'
124
- return load_o(component, locale)
93
+ extend SgtnClient::TranslationLoader::LocalBundle
125
94
  else
126
- return load_s(component, locale)
95
+ extend SgtnClient::TranslationLoader::ServerBundle
127
96
  end
128
- end
129
97
 
130
- def self.load_o(component, locale)
131
- env = SgtnClient::Config.default_environment
132
- product_name = SgtnClient::Config.configurations[env]["product_name"]
133
- version = SgtnClient::Config.configurations[env]["version"].to_s
134
- translation_bundle = SgtnClient::Config.configurations[env]["translation_bundle"]
135
- bundlepath = translation_bundle + "/" + product_name + "/" + version + "/" + component + "/messages_" + locale + ".json"
136
- SgtnClient::FileUtil.read_json(bundlepath)
137
- end
98
+ extend SgtnClient::TranslationLoader::SourceComparer
99
+ extend SgtnClient::TranslationLoader::Cache
138
100
 
139
- def self.load_s(component, locale)
140
- env = SgtnClient::Config.default_environment
141
- product_name = SgtnClient::Config.configurations[env]["product_name"]
142
- vip_server = SgtnClient::Config.configurations[env]["vip_server"]
143
- version = SgtnClient::Config.configurations[env]["version"].to_s
144
- url = vip_server + "/i18n/api/v2/translation/products/" + product_name + "/versions/" + version + "/locales/" + locale + "/components/" + component+ "?checkTranslationStatus=false&machineTranslation=false&pseudo=false"
145
- begin
146
- obj = SgtnClient::Core::Request.get(url)
147
- rescue => exception
148
- SgtnClient.logger.error exception.message
149
- end
150
- if obj != nil
151
- obj = obj["data"]
152
- end
153
- return obj
101
+ load_translations
102
+ @initialized = true
154
103
  end
155
104
 
156
- end
105
+ def load_translations; end
106
+ end
157
107
 
108
+ private_class_method :getTranslation, :get_cs, :load_bundle, :initialized?, :load_translations
109
+ end
158
110
  end
@@ -0,0 +1,33 @@
1
+ # Copyright 2022 VMware, Inc.
2
+ # SPDX-License-Identifier: EPL-2.0
3
+
4
+ module SgtnClient
5
+ class SingleOperation
6
+ def initialize(*conditions, &block)
7
+ raise 'no way to create a new obj' unless block
8
+
9
+ @lock = Mutex.new
10
+ @hash = {}
11
+
12
+ @conditions = conditions
13
+ @creator = block
14
+ end
15
+
16
+ # return new created object
17
+ def operate(id, *args)
18
+ @lock.synchronize do
19
+ obj = @hash[id]
20
+ @conditions.each do |con|
21
+ return obj unless con.call(id, obj, *args)
22
+ end
23
+ @hash[id] = @creator.call(id, obj, *args)
24
+ end
25
+ end
26
+
27
+ def remove_object(id)
28
+ @lock.synchronize do
29
+ @hash.delete(id)
30
+ end
31
+ end
32
+ end
33
+ end
@@ -5,99 +5,30 @@ require 'date'
5
5
 
6
6
  module SgtnClient::Core
7
7
  class Cache
8
- Entry = Struct.new(:expiry, :value)
8
+ Entry = Struct.new(:expiry, :items)
9
9
 
10
10
  def self.initialize(disabled=false, opts={})
11
11
  @@opts = opts
12
- @mutex = Mutex.new
13
- if disabled == false
14
- @@data = Hash.new
15
- SgtnClient.logger.debug "[Cache][initialize]cache is enabled!"
16
- else
17
- @@data = nil
18
- SgtnClient.logger.debug "[Cache][initialize]cache is disabled!"
19
- end
20
- end
21
-
22
- def self.keys
23
- if @@data == nil
24
- return nil
25
- end
26
- SgtnClient.logger.debug "[Cache][keys]get cache keys"
27
- @@data.keys
12
+ SgtnClient.logger.debug "[Cache][initialize] Disable cache? #{disabled}"
13
+ @@data = Hash.new
28
14
  end
29
15
 
30
16
  def self.get(key)
31
- if @@data == nil
32
- return nil, nil
33
- end
34
17
  SgtnClient.logger.debug "[Cache][get]get cache for key: " + key
35
- invalidate(key)
36
- end
37
-
38
- def self.has(key)
39
- if @@data == nil
40
- return nil
41
- end
42
- SgtnClient.logger.debug "[Cache][has]check if the cache has key: #{(@@data.has_key? key)}"
43
- @@data.has_key? key
18
+ return @@data&.dig(key)
44
19
  end
45
20
 
46
- def self.put(key, value, ttl=nil)
47
- @mutex.synchronize do
48
- if @@data == nil || value == nil
49
- return nil
50
- end
51
- ttl ||= @@opts[:ttl]
52
- # hours from new
53
- SgtnClient.logger.debug "[Cache][put]put cache for key '" + key + "' with expired time at'" + (Time.now + ttl*60).to_s
54
- @@data[key] = Entry.new(Time.now + ttl*60, value)
55
- end
56
- end
57
-
58
- def self.delete(key)
59
- @mutex.synchronize do
60
- if @@data == nil
61
- return nil
62
- end
63
- SgtnClient.logger.debug "[Cache][delete]delete cache for key: " + key
64
- @@data.delete key
65
- end
21
+ def self.put(key, items, ttl=nil)
22
+ ttl ||= @@opts[:ttl]
23
+ # hours from new
24
+ SgtnClient.logger.debug "[Cache][put]put cache for key '" + key + "' with expired time at'" + (Time.now + ttl*60).to_s
25
+ @@data[key] = Entry.new(Time.now + ttl*60, items)
66
26
  end
67
27
 
68
28
  def self.clear
69
- @mutex.synchronize do
70
- if @@data == nil
71
- return nil
72
- end
73
- SgtnClient.logger.debug "[Cache][clear]clear cache!"
74
- @@data = Hash.new
75
- end
76
- end
77
-
78
- def self.invalidate(key)
79
- @mutex.synchronize do
80
- if @@data == nil
81
- return nil, nil
82
- end
83
- SgtnClient.logger.debug "[Cache][invalidate]invalidate expired cache......"
84
- now = Time.now
85
- if has(key)
86
- v = @@data[key]
87
- expired = false
88
- SgtnClient.logger.debug "[Cache][invalidate]check cache: key=#{key}, expiredtime=#{v[:expiry]}, now=#{now}, expired=#{(v[:expiry] < now)}"
89
- if v[:expiry] < now
90
- SgtnClient.logger.debug "[Cache][invalidate]before deleting the cache: data=#{@@data}"
91
- @@data.delete(key)
92
- SgtnClient.logger.debug "[Cache][invalidate]after deleting the cache: data=#{@@data}"
93
- expired = true
94
- end
95
- return expired, v[:value]
96
- else
97
- return nil, nil
98
- end
99
- end
29
+ SgtnClient.logger.debug "[Cache][clear]clear cache!"
30
+ @@data = Hash.new
100
31
  end
101
32
  end
102
33
 
103
- end
34
+ end
@@ -0,0 +1,47 @@
1
+ # Copyright 2022 VMware, Inc.
2
+ # SPDX-License-Identifier: EPL-2.0
3
+
4
+ module SgtnClient
5
+ autoload :CacheUtil, 'sgtn-client/util/cache-util'
6
+ autoload :SingleOperation, 'sgtn-client/common/single_operation'
7
+ end
8
+ module SgtnClient::TranslationLoader::Cache
9
+ def load_bundle(component, locale)
10
+ cache_key = SgtnClient::CacheUtil.get_cachekey(component, locale)
11
+ SgtnClient.logger.debug "[#{self.to_s}][#{__FILE__}][#{__method__}] cache_key=#{cache_key}"
12
+ cache_item = SgtnClient::CacheUtil.get_cache(cache_key)
13
+ if cache_item.nil?
14
+ # refresh synchronously if not in cache
15
+ SgtnClient.logger.debug "[#{self.to_s}][#{__FILE__}][#{__method__}] Cache miss. cache_key=#{cache_key}"
16
+ cache_item = (single_loader { |c, l| super(c, l) }).operate(cache_key, component, locale).value
17
+ # TODO: if an error occurs when requesting a bundle, need to avoid more requests
18
+ elsif SgtnClient::CacheUtil.is_expired(cache_item) && locale != SgtnClient::LocaleUtil.get_source_locale # local source never expires.
19
+ SgtnClient.logger.debug "[#{self.to_s}][#{__FILE__}][#{__method__}] Bundle cache is expired. cache_key=#{cache_key}"
20
+ @single_loader.operate(cache_key, component, locale) # refresh in background
21
+ end
22
+ cache_item
23
+ end
24
+
25
+ private
26
+
27
+ def single_loader
28
+ @single_loader ||= begin
29
+ none_alive = proc { |_, thread| thread.nil? || thread.alive? == false }
30
+ to_run = proc do |id|
31
+ cache_item = SgtnClient::CacheUtil.get_cache(id)
32
+ cache_item&.dig(:items).nil? || SgtnClient::CacheUtil.is_expired(cache_item)
33
+ end
34
+ creator = proc do |id, _, c, l|
35
+ Thread.new do
36
+ SgtnClient.logger.debug "Refreshing cache for #{c}/#{l}"
37
+ cache_item = SgtnClient::CacheUtil.write_cache(id, yield(c, l))
38
+ # delete thread from hash after finish
39
+ Thread.new { @single_loader.remove_object(id) }
40
+ cache_item
41
+ end
42
+ end
43
+
44
+ SgtnClient::SingleOperation.new(none_alive, to_run, &creator)
45
+ end
46
+ end
47
+ end
@@ -0,0 +1,13 @@
1
+ # Copyright 2022 VMware, Inc.
2
+ # SPDX-License-Identifier: EPL-2.0
3
+
4
+ module SgtnClient::TranslationLoader::LocalBundle
5
+ def load_bundle(component, locale)
6
+ env = SgtnClient::Config.default_environment
7
+ product_name = SgtnClient::Config.configurations[env]['product_name']
8
+ version = SgtnClient::Config.configurations[env]['version'].to_s
9
+ translation_bundle = SgtnClient::Config.configurations[env]['translation_bundle']
10
+ bundlepath = translation_bundle + '/' + product_name + '/' + version + '/' + component + '/messages_' + locale + '.json'
11
+ SgtnClient::FileUtil.read_json(bundlepath)
12
+ end
13
+ end
@@ -0,0 +1,29 @@
1
+ # Copyright 2022 VMware, Inc.
2
+ # SPDX-License-Identifier: EPL-2.0
3
+
4
+ module SgtnClient
5
+ class Source
6
+ def self.load_bundle(component)
7
+ SgtnClient.logger.debug "[Source][getBundle]component=#{component}"
8
+ env = SgtnClient::Config.default_environment
9
+ source_bundle = SgtnClient::Config.configurations[env]['source_bundle']
10
+ component_path = "#{source_bundle}/#{component}"
11
+ total_messages = nil
12
+ Dir.glob('**/*.{yml, yaml}', base: component_path) do |f|
13
+ bundle = SgtnClient::FileUtil.read_yml("#{component_path}/#{f}")
14
+ if total_messages.nil?
15
+ total_messages = bundle&.first&.last
16
+ else
17
+ total_messages.merge!(bundle&.first&.last)
18
+ end
19
+ end
20
+
21
+ if total_messages
22
+ return { 'component' => component, 'locale' => SgtnClient::LocaleUtil.get_source_locale, 'messages' => total_messages }
23
+ end
24
+ rescue StandardError => e
25
+ SgtnClient.logger.error e.message
26
+ nil
27
+ end
28
+ end
29
+ end
@@ -0,0 +1,22 @@
1
+ # Copyright 2022 VMware, Inc.
2
+ # SPDX-License-Identifier: EPL-2.0
3
+
4
+ module SgtnClient::Core
5
+ autoload :Request, 'sgtn-client/core/request'
6
+ end
7
+
8
+ module SgtnClient::TranslationLoader::ServerBundle
9
+ def load_bundle(component, locale)
10
+ env = SgtnClient::Config.default_environment
11
+ product_name = SgtnClient::Config.configurations[env]['product_name']
12
+ vip_server = SgtnClient::Config.configurations[env]['vip_server']
13
+ version = SgtnClient::Config.configurations[env]['version'].to_s
14
+ url = vip_server + '/i18n/api/v2/translation/products/' + product_name + '/versions/' + version + '/locales/' + locale + '/components/' + component + '?checkTranslationStatus=false&machineTranslation=false&pseudo=false'
15
+ begin
16
+ obj = SgtnClient::Core::Request.get(url)
17
+ rescue StandardError => e
18
+ SgtnClient.logger.error e.message
19
+ end
20
+ obj && obj['data']
21
+ end
22
+ end
@@ -0,0 +1,38 @@
1
+ # Copyright 2022 VMware, Inc.
2
+ # SPDX-License-Identifier: EPL-2.0
3
+
4
+ module SgtnClient
5
+ autoload :Source, 'sgtn-client/loader/local_source_bundle'
6
+ end
7
+ module SgtnClient::TranslationLoader::SourceComparer
8
+ def load_bundle(component, locale)
9
+ # source locale always uses source bundles
10
+ return SgtnClient::Source.load_bundle(component) if SgtnClient::LocaleUtil.is_source_locale(locale)
11
+
12
+ translation_bundle_thread = Thread.new { super(component, locale) }
13
+ old_source_bundle = super(component, SgtnClient::LocaleUtil.get_source_locale)
14
+ source_bundle = get_cs(component, SgtnClient::LocaleUtil.get_source_locale)
15
+ translation_bundle = translation_bundle_thread.value
16
+
17
+ compare_source(translation_bundle, old_source_bundle, source_bundle)
18
+ end
19
+
20
+ private
21
+
22
+ def compare_source(translation_bundle, old_source_bundle, source_bundle)
23
+ return translation_bundle if translation_bundle.nil? || source_bundle.nil? || old_source_bundle.nil?
24
+
25
+ old_source_messages = old_source_bundle['messages']
26
+ translation_messages = translation_bundle['messages']
27
+ translation_bundle['messages'] = new_translation_messages = {}
28
+ source_bundle['messages'].each do |key, value|
29
+ translation = translation_messages[key]
30
+ new_translation_messages[key] = if old_source_messages[key] == value && !translation.nil?
31
+ translation
32
+ else
33
+ SgtnClient::StringUtil.new(value, SgtnClient::LocaleUtil.get_source_locale)
34
+ end
35
+ end
36
+ translation_bundle
37
+ end
38
+ end
@@ -1,48 +1,43 @@
1
1
  # Copyright 2022 VMware, Inc.
2
2
  # SPDX-License-Identifier: EPL-2.0
3
3
 
4
- require 'erb'
5
- require 'yaml'
6
-
7
4
  module SgtnClient
8
-
9
5
  module Core
10
- autoload :Cache, "sgtn-client/core/cache"
6
+ autoload :Cache, 'sgtn-client/core/cache'
11
7
  end
12
-
8
+
13
9
  class CacheUtil
10
+ def self.get_cache(cache_key)
11
+ SgtnClient.logger.debug "[CacheUtil]get cache with key #{cache_key}"
12
+ SgtnClient::Core::Cache.get(cache_key)
13
+ end
14
+
15
+ def self.clear_cache
16
+ SgtnClient::Core::Cache.clear
17
+ SgtnClient.logger.debug '[CacheUtil]clear cache'
18
+ end
19
+
20
+ def self.write_cache(cache_key, items)
21
+ return nil if items.nil? || items.empty?
22
+
23
+ env = SgtnClient::Config.default_environment
24
+ cache_expiry_period = SgtnClient::Config.configurations[env]['cache_expiry_period']
25
+ # expired after 24 hours
26
+ cache_expiry_period = 24 * 60 if cache_expiry_period.nil?
27
+ SgtnClient.logger.debug "[CacheUtil]write cache with key #{cache_key}, cache_expiry_period #{cache_expiry_period}"
28
+ SgtnClient::Core::Cache.put(cache_key, items, cache_expiry_period)
29
+ end
30
+
31
+ def self.get_cachekey(component, locale)
32
+ env = SgtnClient::Config.default_environment
33
+ product_name = SgtnClient::Config.configurations[env]['product_name']
34
+ version = SgtnClient::Config.configurations[env]['version'].to_s
35
+ product_name + '_' + version + '_' + component + '_' + locale
36
+ end
37
+
38
+ def self.is_expired(cache_item)
39
+ cache_item[:expiry] < Time.now
40
+ end
14
41
 
15
- def self.get_cache(cache_key)
16
- expired, items = SgtnClient::Core::Cache.get(cache_key)
17
- SgtnClient.logger.debug "[CacheUtil]get cache with key #{cache_key}, expired #{expired}"
18
- return expired, items
19
- end
20
-
21
- def self.clear_cache()
22
- SgtnClient::Core::Cache.clear()
23
- SgtnClient.logger.debug "[CacheUtil]clear cache"
24
- end
25
-
26
- def self.write_cache(cache_key, items)
27
- if items.nil?
28
- return nil
29
- end
30
- env = SgtnClient::Config.default_environment
31
- cache_expiry_period = SgtnClient::Config.configurations[env]["cache_expiry_period"]
32
- # expired after 24 hours
33
- if cache_expiry_period == nil
34
- cache_expiry_period = 24*60
35
- end
36
- SgtnClient.logger.debug "[CacheUtil]write cache with key #{cache_key}, cache_expiry_period #{cache_expiry_period}, itmes #{items}"
37
- SgtnClient::Core::Cache.put(cache_key, items, cache_expiry_period)
38
- end
39
-
40
- def self.get_cachekey(component, locale)
41
- env = SgtnClient::Config.default_environment
42
- product_name = SgtnClient::Config.configurations[env]["product_name"]
43
- version = SgtnClient::Config.configurations[env]["version"].to_s
44
- product_name + "_" + version + "_" + component + "_" + locale
45
- end
46
42
  end
47
-
48
43
  end
@@ -1,37 +1,24 @@
1
1
  # Copyright 2022 VMware, Inc.
2
2
  # SPDX-License-Identifier: EPL-2.0
3
3
 
4
- require 'erb'
5
- require 'yaml'
4
+ autoload :YAML, 'yaml'
5
+ autoload :MultiJson, 'multi_json'
6
6
 
7
7
  module SgtnClient
8
8
 
9
9
  class FileUtil
10
-
11
- @mutex = Mutex.new
12
-
13
10
  def self.read_json(bundlepath)
14
11
  SgtnClient.logger.debug "[FileUtil]read json file from: " + bundlepath
15
- @mutex.synchronize do
16
- data_hash = nil
17
- begin
18
- file = File.read(bundlepath)
19
- data_hash = MultiJson.load(file)
20
- rescue => exception
21
- SgtnClient.logger.error exception.message
22
- end
23
- return data_hash
12
+ begin
13
+ return MultiJson.load(File.read(bundlepath))
14
+ rescue => exception
15
+ SgtnClient.logger.error exception.message
24
16
  end
17
+ nil
25
18
  end
26
19
 
27
20
  def self.read_yml(file_name)
28
- SgtnClient.logger.debug "[FileUtil]read yml file from: " + file_name
29
- @mutex.synchronize do
30
- erb = ERB.new(File.read(file_name))
31
- erb.filename = file_name
32
- YAML.load(erb.result)
33
- end
21
+ YAML::load(File.read(file_name))
34
22
  end
35
23
  end
36
-
37
24
  end
@@ -1,46 +1,48 @@
1
1
  # Copyright 2022 VMware, Inc.
2
2
  # SPDX-License-Identifier: EPL-2.0
3
+ require 'set'
3
4
 
4
5
  module SgtnClient
6
+ SUPPORTED_LOCALES = %w[en de es fr ko ja zh-Hans zh-Hant zh de-CH].freeze # TODO get this from service in online mode
7
+
8
+ MAP_LOCALES = {
9
+ 'zh-CN' => 'zh-Hans',
10
+ 'zh-TW' => 'zh-Hant',
11
+ 'zh-Hans-CN' => 'zh-Hans',
12
+ 'zh-Hant-TW' => 'zh-Hant'
13
+ }.freeze
5
14
 
6
- DEFAULT_LOCALES = ['en', 'de', 'es', 'fr', 'ko', 'ja', 'zh-Hans', 'zh-Hant']
7
-
8
- MAP_LOCALES = {
9
- "zh-CN" =>"zh-Hans",
10
- "zh-TW" =>"zh-Hant",
11
- "zh-Hans-CN" =>"zh-Hans",
12
- "zh-Hant-TW" =>"zh-Hant",
13
- }
14
-
15
- class LocaleUtil
16
- def self.get_best_locale(locale)
17
- fallback(process_locale(locale))
18
- end
19
- def self.process_locale(locale=nil)
20
- locale ||= SgtnClient::Config.configurations.default
21
- locale.to_s
22
- end
23
- def self.fallback(locale)
24
- found = SgtnClient::DEFAULT_LOCALES.select {|e| e == locale}
25
- if !found.empty?
26
- return found[0]
27
- end
28
- if SgtnClient::MAP_LOCALES.key?(locale)
29
- return SgtnClient::MAP_LOCALES[locale]
30
- end
31
- parts = locale.split("-")
32
- if parts.size > 1
33
- f = SgtnClient::DEFAULT_LOCALES.select {|e| e == parts[0]}
34
- if !f.empty?
35
- return f[0]
36
- end
37
- end
38
- return locale
39
- end
40
- def self.get_source_locale
41
- env = SgtnClient::Config.default_environment
42
- source_locale = SgtnClient::Config.configurations[env]["default_language"]
43
- source_locale || 'en'
44
- end
15
+ class LocaleUtil
16
+ def self.get_best_locale(locale)
17
+ return get_default_locale if locale.nil?
18
+
19
+ locale = locale.to_s
20
+ return get_default_locale if locale.empty?
21
+
22
+ get_best_match(locale)
23
+ end
24
+
25
+ def self.is_source_locale(locale = nil)
26
+ locale == get_source_locale
27
+ end
28
+
29
+ def self.get_best_match(locale)
30
+ locale = locale.gsub('_', '-')
31
+ locale = SgtnClient::MAP_LOCALES[locale] if SgtnClient::MAP_LOCALES.key?(locale)
32
+ return locale if SUPPORTED_LOCALES.include?(locale)
33
+ return LocaleUtil.get_source_locale if locale.index('-').nil?
34
+ get_best_match(locale.slice(0..(locale.rindex('-')-1)) )
45
35
  end
36
+
37
+ def self.get_source_locale
38
+ 'en'
39
+ end
40
+
41
+ def self.get_default_locale
42
+ env = SgtnClient::Config.default_environment
43
+ SgtnClient::Config.configurations[env]['default_language'] || 'en'
44
+ end
45
+
46
+ private_class_method :get_best_match
47
+ end
46
48
  end
@@ -0,0 +1,12 @@
1
+ # Copyright 2022 VMware, Inc.
2
+ # SPDX-License-Identifier: EPL-2.0
3
+
4
+ module SgtnClient
5
+ class StringUtil < String
6
+ def initialize(str, locale)
7
+ super(str)
8
+ @locale = locale
9
+ end
10
+ attr_accessor :locale
11
+ end
12
+ end
metadata CHANGED
@@ -1,29 +1,15 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: singleton-client-test
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.7.0.32
4
+ version: 0.7.0.33
5
5
  platform: ruby
6
6
  authors:
7
7
  - VMware G11n Team
8
8
  autorequire:
9
9
  bindir: bin
10
10
  cert_chain: []
11
- date: 2022-03-09 00:00:00.000000000 Z
11
+ date: 2022-03-30 00:00:00.000000000 Z
12
12
  dependencies:
13
- - !ruby/object:Gem::Dependency
14
- name: rest-client
15
- requirement: !ruby/object:Gem::Requirement
16
- requirements:
17
- - - "~>"
18
- - !ruby/object:Gem::Version
19
- version: '2.0'
20
- type: :development
21
- prerelease: false
22
- version_requirements: !ruby/object:Gem::Requirement
23
- requirements:
24
- - - "~>"
25
- - !ruby/object:Gem::Version
26
- version: '2.0'
27
13
  - !ruby/object:Gem::Dependency
28
14
  name: multi_json
29
15
  requirement: !ruby/object:Gem::Requirement
@@ -94,34 +80,6 @@ dependencies:
94
80
  - - "~>"
95
81
  - !ruby/object:Gem::Version
96
82
  version: '3.0'
97
- - !ruby/object:Gem::Dependency
98
- name: pry
99
- requirement: !ruby/object:Gem::Requirement
100
- requirements:
101
- - - "~>"
102
- - !ruby/object:Gem::Version
103
- version: '0'
104
- type: :development
105
- prerelease: false
106
- version_requirements: !ruby/object:Gem::Requirement
107
- requirements:
108
- - - "~>"
109
- - !ruby/object:Gem::Version
110
- version: '0'
111
- - !ruby/object:Gem::Dependency
112
- name: pry-doc
113
- requirement: !ruby/object:Gem::Requirement
114
- requirements:
115
- - - "~>"
116
- - !ruby/object:Gem::Version
117
- version: '0'
118
- type: :development
119
- prerelease: false
120
- version_requirements: !ruby/object:Gem::Requirement
121
- requirements:
122
- - - "~>"
123
- - !ruby/object:Gem::Version
124
- version: '0'
125
83
  - !ruby/object:Gem::Dependency
126
84
  name: rdoc
127
85
  requirement: !ruby/object:Gem::Requirement
@@ -244,6 +202,20 @@ dependencies:
244
202
  - - "~>"
245
203
  - !ruby/object:Gem::Version
246
204
  version: '1.0'
205
+ - !ruby/object:Gem::Dependency
206
+ name: rest-client
207
+ requirement: !ruby/object:Gem::Requirement
208
+ requirements:
209
+ - - "~>"
210
+ - !ruby/object:Gem::Version
211
+ version: '2.0'
212
+ type: :runtime
213
+ prerelease: false
214
+ version_requirements: !ruby/object:Gem::Requirement
215
+ requirements:
216
+ - - "~>"
217
+ - !ruby/object:Gem::Version
218
+ version: '2.0'
247
219
  - !ruby/object:Gem::Dependency
248
220
  name: twitter_cldr
249
221
  requirement: !ruby/object:Gem::Requirement
@@ -274,16 +246,23 @@ files:
274
246
  - lib/sgtn-client/cldr/localized_datetime.rb
275
247
  - lib/sgtn-client/cldr/localized_str.rb
276
248
  - lib/sgtn-client/cldr/localized_time.rb
249
+ - lib/sgtn-client/common/single_operation.rb
277
250
  - lib/sgtn-client/core/cache.rb
278
251
  - lib/sgtn-client/core/config.rb
279
252
  - lib/sgtn-client/core/exceptions.rb
280
253
  - lib/sgtn-client/core/logging.rb
281
254
  - lib/sgtn-client/core/request.rb
282
255
  - lib/sgtn-client/formatters/plurals/plural_formatter.rb
256
+ - lib/sgtn-client/loader/cache.rb
257
+ - lib/sgtn-client/loader/local_bundle.rb
258
+ - lib/sgtn-client/loader/local_source_bundle.rb
259
+ - lib/sgtn-client/loader/server_bundle.rb
260
+ - lib/sgtn-client/loader/source_comparer.rb
283
261
  - lib/sgtn-client/sgtn-client.rb
284
262
  - lib/sgtn-client/util/cache-util.rb
285
263
  - lib/sgtn-client/util/file-util.rb
286
264
  - lib/sgtn-client/util/locale-util.rb
265
+ - lib/sgtn-client/util/string-util.rb
287
266
  - lib/sgtn-client/util/validate-util.rb
288
267
  - lib/singleton-ruby.rb
289
268
  - lib/version.rb