copy_tuner_client 2.1.2 → 2.2.0
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 +4 -4
- data/.gitignore +5 -0
- data/.rubocop.yml +46 -1
- data/CLAUDE.md +1 -0
- data/Gemfile +1 -0
- data/copy_tuner_client.gemspec +3 -3
- data/gemfiles/8.0.gemfile +3 -3
- data/gemfiles/8.1.gemfile +3 -3
- data/gemfiles/main.gemfile +3 -3
- data/lib/copy_tuner_client/cache.rb +34 -27
- data/lib/copy_tuner_client/client.rb +35 -23
- data/lib/copy_tuner_client/configuration.rb +62 -40
- data/lib/copy_tuner_client/copyray/rewriter.rb +1 -1
- data/lib/copy_tuner_client/copyray.rb +1 -0
- data/lib/copy_tuner_client/copyray_middleware.rb +31 -24
- data/lib/copy_tuner_client/dotted_hash.rb +7 -7
- data/lib/copy_tuner_client/engine.rb +4 -6
- data/lib/copy_tuner_client/helper_extension.rb +58 -54
- data/lib/copy_tuner_client/i18n_backend.rb +12 -14
- data/lib/copy_tuner_client/i18n_compat.rb +2 -1
- data/lib/copy_tuner_client/poller.rb +3 -4
- data/lib/copy_tuner_client/prefixed_logger.rb +13 -12
- data/lib/copy_tuner_client/process_guard.rb +29 -26
- data/lib/copy_tuner_client/queue_with_timeout.rb +29 -19
- data/lib/copy_tuner_client/rails.rb +9 -8
- data/lib/copy_tuner_client/request_sync.rb +26 -24
- data/lib/copy_tuner_client/simple_form_extention.rb +10 -6
- data/lib/copy_tuner_client/translation_log.rb +10 -5
- data/lib/copy_tuner_client/version.rb +1 -1
- data/lib/copy_tuner_client.rb +4 -8
- data/lib/tasks/copy_tuner_client_tasks.rake +14 -16
- data/skills/copy-tuner-to-locales-migrate-prefix/scripts/migrate_prefix.rb +14 -7
- data/skills/copy-tuner-to-t-migrate/scripts/migrate_tt.rb +19 -17
- data/spec/copy_tuner_client/cache_spec.rb +63 -57
- data/spec/copy_tuner_client/client_spec.rb +82 -81
- data/spec/copy_tuner_client/configuration_spec.rb +223 -222
- data/spec/copy_tuner_client/copyray/marker_spec.rb +2 -1
- data/spec/copy_tuner_client/copyray/rewriter_spec.rb +15 -10
- data/spec/copy_tuner_client/copyray_middleware_spec.rb +9 -6
- data/spec/copy_tuner_client/copyray_spec.rb +8 -8
- data/spec/copy_tuner_client/dotted_hash_spec.rb +33 -33
- data/spec/copy_tuner_client/helper_extension_spec.rb +47 -44
- data/spec/copy_tuner_client/i18n_backend_spec.rb +144 -143
- data/spec/copy_tuner_client/poller_spec.rb +25 -24
- data/spec/copy_tuner_client/prefixed_logger_spec.rb +15 -12
- data/spec/copy_tuner_client/process_guard_spec.rb +27 -27
- data/spec/copy_tuner_client/request_sync_spec.rb +51 -58
- data/spec/copy_tuner_client/translation_log_spec.rb +38 -24
- data/spec/copy_tuner_client_spec.rb +5 -6
- data/spec/support/client_spec_helpers.rb +1 -1
- data/spec/support/defines_constants.rb +3 -34
- data/spec/support/fake_client.rb +1 -3
- data/spec/support/fake_copy_tuner_app.rb +54 -62
- data/spec/support/fake_html_safe_string.rb +2 -3
- data/spec/support/fake_logger.rb +22 -21
- data/spec/support/fake_passenger.rb +4 -6
- data/spec/support/fake_unicorn.rb +2 -4
- data/spec/support/middleware_stack.rb +3 -3
- data/spec/support/writing_cache.rb +4 -4
- metadata +1 -1
|
@@ -2,34 +2,39 @@ require 'spec_helper'
|
|
|
2
2
|
|
|
3
3
|
describe 'CopyTunerClient::I18nBackend' do
|
|
4
4
|
# テスト用のキャッシュクラス:既存のHashインターフェースを維持しつつ新機能をサポート
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
|
|
5
|
+
def test_cache_class
|
|
6
|
+
Class.new(Hash) do
|
|
7
|
+
def initialize(initial_etag = 'test-etag-1')
|
|
8
|
+
super()
|
|
9
|
+
@test_etag = initial_etag
|
|
10
|
+
end
|
|
10
11
|
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
12
|
+
def version
|
|
13
|
+
@test_etag
|
|
14
|
+
end
|
|
14
15
|
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
16
|
+
def to_tree_hash
|
|
17
|
+
CopyTunerClient::DottedHash.to_h(self)
|
|
18
|
+
end
|
|
18
19
|
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
20
|
+
def wait_for_download
|
|
21
|
+
# テスト用のスタブメソッド
|
|
22
|
+
end
|
|
22
23
|
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
24
|
+
def etag=(value)
|
|
25
|
+
@test_etag = value
|
|
26
|
+
end
|
|
26
27
|
|
|
27
|
-
|
|
28
|
-
|
|
28
|
+
def etag
|
|
29
|
+
@test_etag
|
|
30
|
+
end
|
|
29
31
|
end
|
|
30
32
|
end
|
|
31
33
|
|
|
32
|
-
|
|
34
|
+
subject(:backend) { build_backend }
|
|
35
|
+
|
|
36
|
+
let(:cache) { test_cache_class.new }
|
|
37
|
+
let!(:default_backend) { I18n.backend }
|
|
33
38
|
|
|
34
39
|
def build_backend
|
|
35
40
|
backend = CopyTunerClient::I18nBackend.new(cache)
|
|
@@ -37,23 +42,18 @@ describe 'CopyTunerClient::I18nBackend' do
|
|
|
37
42
|
backend
|
|
38
43
|
end
|
|
39
44
|
|
|
40
|
-
|
|
41
|
-
@default_backend = I18n.backend
|
|
42
|
-
end
|
|
43
|
-
|
|
44
|
-
after { I18n.backend = @default_backend }
|
|
45
|
-
|
|
46
|
-
subject { build_backend }
|
|
45
|
+
after { I18n.backend = default_backend }
|
|
47
46
|
|
|
48
47
|
it 'ロケールファイルをリロードし、ダウンロード完了まで待機すること' do
|
|
49
|
-
|
|
48
|
+
allow(I18n).to receive(:load_path).and_return([])
|
|
50
49
|
# wait_for_downloadはTestCacheクラス内で呼ばれる
|
|
51
|
-
|
|
52
|
-
|
|
50
|
+
backend.reload!
|
|
51
|
+
backend.translate('en', 'test.key', default: 'something')
|
|
52
|
+
expect(I18n).to have_received(:load_path)
|
|
53
53
|
end
|
|
54
54
|
|
|
55
55
|
it 'i18nのBaseバックエンドを継承していること' do
|
|
56
|
-
|
|
56
|
+
expect(backend).to be_a(I18n::Backend::Base)
|
|
57
57
|
end
|
|
58
58
|
|
|
59
59
|
it 'キャッシュからキーを検索できること' do
|
|
@@ -62,23 +62,23 @@ describe 'CopyTunerClient::I18nBackend' do
|
|
|
62
62
|
|
|
63
63
|
backend = build_backend
|
|
64
64
|
|
|
65
|
-
expect(backend.translate('en', 'test.key', :
|
|
65
|
+
expect(backend.translate('en', 'test.key', scope: 'prefix')).to eq(value)
|
|
66
66
|
end
|
|
67
67
|
|
|
68
68
|
it 'ロケールファイルとキャッシュから利用可能なロケールを取得できること' do
|
|
69
69
|
allow(YAML).to receive(:unsafe_load_file).and_return({ 'es' => { 'key' => 'value' } })
|
|
70
|
-
allow(I18n).to receive(:load_path).and_return([
|
|
70
|
+
allow(I18n).to receive(:load_path).and_return(['test.yml'])
|
|
71
71
|
|
|
72
72
|
cache['en.key'] = ''
|
|
73
73
|
cache['fr.key'] = ''
|
|
74
74
|
|
|
75
|
-
expect(
|
|
75
|
+
expect(backend.available_locales).to contain_exactly(:en, :es, :fr)
|
|
76
76
|
end
|
|
77
77
|
|
|
78
78
|
it 'default付きで未登録キーをキューイングすること' do
|
|
79
79
|
default = 'default value'
|
|
80
80
|
|
|
81
|
-
expect(
|
|
81
|
+
expect(backend.translate('en', 'test.key', default:)).to eq(default)
|
|
82
82
|
|
|
83
83
|
expect(cache['en.test.key']).to eq(default)
|
|
84
84
|
end
|
|
@@ -86,14 +86,14 @@ describe 'CopyTunerClient::I18nBackend' do
|
|
|
86
86
|
it 'defaultが配列(文字列1つ)の場合も未登録キーをキューイングすること' do
|
|
87
87
|
default = 'default value'
|
|
88
88
|
|
|
89
|
-
expect(
|
|
89
|
+
expect(backend.translate('en', 'test.key', default: [default])).to eq(default)
|
|
90
90
|
|
|
91
91
|
expect(cache['en.test.key']).to eq(default)
|
|
92
92
|
end
|
|
93
93
|
|
|
94
94
|
it 'defaultなしで未登録キーをキューイングすること' do
|
|
95
|
-
expect {
|
|
96
|
-
to throw_symbol(:exception)
|
|
95
|
+
expect { backend.translate('en', 'test.key') }
|
|
96
|
+
.to throw_symbol(:exception)
|
|
97
97
|
|
|
98
98
|
expect(cache).to have_key 'en.test.key'
|
|
99
99
|
expect(cache['en.test.key']).to be_nil
|
|
@@ -102,123 +102,121 @@ describe 'CopyTunerClient::I18nBackend' do
|
|
|
102
102
|
it 'scope付きで未登録キーをキューイングすること' do
|
|
103
103
|
default = 'default value'
|
|
104
104
|
|
|
105
|
-
expect(
|
|
106
|
-
to eq(default)
|
|
105
|
+
expect(backend.translate('en', 'key', default:, scope: ['test']))
|
|
106
|
+
.to eq(default)
|
|
107
107
|
|
|
108
108
|
expect(cache['en.test.key']).to eq(default)
|
|
109
109
|
end
|
|
110
110
|
|
|
111
111
|
it 'defaultがシンボルの場合は未登録キーをキューイングしないこと' do
|
|
112
|
-
cache['en.key.one'] =
|
|
112
|
+
cache['en.key.one'] = 'Expected'
|
|
113
113
|
|
|
114
|
-
expect(
|
|
114
|
+
expect(backend.translate('en', 'key.three', default: :'key.one')).to eq 'Expected'
|
|
115
115
|
|
|
116
116
|
expect(cache).to have_key 'en.key.three'
|
|
117
117
|
expect(cache['en.key.three']).to be_nil
|
|
118
118
|
|
|
119
|
-
expect(
|
|
119
|
+
expect(backend.translate('en', 'key.three', default: :'key.one')).to eq 'Expected'
|
|
120
120
|
end
|
|
121
121
|
|
|
122
122
|
it 'defaultが配列(シンボル含む)の場合は未登録キーをキューイングしないこと' do
|
|
123
|
-
cache['en.key.one'] =
|
|
123
|
+
cache['en.key.one'] = 'Expected'
|
|
124
124
|
|
|
125
|
-
expect(
|
|
125
|
+
expect(backend.translate('en', 'key.three', default: %i[key.two key.one])).to eq 'Expected'
|
|
126
126
|
|
|
127
127
|
expect(cache).to have_key 'en.key.three'
|
|
128
128
|
expect(cache['en.key.three']).to be_nil
|
|
129
129
|
|
|
130
|
-
expect(
|
|
130
|
+
expect(backend.translate('en', 'key.three', default: %i[key.two key.one])).to eq 'Expected'
|
|
131
131
|
end
|
|
132
132
|
|
|
133
133
|
it '補間付きで未登録キーをキューイングすること' do
|
|
134
|
-
|
|
134
|
+
# I18n の補間構文 %{interpolate} であり Kernel#format 用の printf トークンではないため annotated 化は不適切
|
|
135
|
+
default = 'default %{interpolate}' # rubocop:disable Style/FormatStringToken
|
|
135
136
|
|
|
136
|
-
expect(
|
|
137
|
+
expect(backend.translate('en', 'test.key', default:, interpolate: 'interpolated')).to eq 'default interpolated'
|
|
137
138
|
|
|
138
|
-
expect(cache['en.test.key']).to eq 'default %{interpolate}'
|
|
139
|
+
expect(cache['en.test.key']).to eq 'default %{interpolate}' # rubocop:disable Style/FormatStringToken
|
|
139
140
|
end
|
|
140
141
|
|
|
141
142
|
# NOTE: backend は html_safe 化をしない(.html/_html キーの html_safe 化は ActionView の
|
|
142
143
|
# TranslationHelper が担う)。html_escape 設定の有無に関わらず素の content を返す i18n 標準準拠の挙動。
|
|
143
144
|
it 'html safeを付与しないこと' do
|
|
144
|
-
cache['en.test.key'] = FakeHtmlSafeString.new(
|
|
145
|
+
cache['en.test.key'] = FakeHtmlSafeString.new('Hello')
|
|
145
146
|
backend = build_backend
|
|
146
|
-
expect(backend.translate('en', 'test.key')).
|
|
147
|
+
expect(backend.translate('en', 'test.key')).not_to be_html_safe
|
|
147
148
|
end
|
|
148
149
|
|
|
149
150
|
it 'html_safe な値を渡しても backend が独自に html_safe 化しないこと' do
|
|
150
|
-
cache['en.test.key'] = FakeHtmlSafeString.new(
|
|
151
|
+
cache['en.test.key'] = FakeHtmlSafeString.new('Hello').html_safe
|
|
151
152
|
backend = build_backend
|
|
152
153
|
expect(backend.translate('en', 'test.key')).to be_html_safe
|
|
153
154
|
end
|
|
154
155
|
|
|
155
156
|
it 'defaultが配列の場合に順に検索できること' do
|
|
156
|
-
cache['en.key.one'] =
|
|
157
|
+
cache['en.key.one'] = 'Expected'
|
|
157
158
|
backend = build_backend
|
|
158
|
-
expect(backend.translate('en', 'key.three', :
|
|
159
|
-
to eq('Expected')
|
|
159
|
+
expect(backend.translate('en', 'key.three', default: %i[key.two key.one]))
|
|
160
|
+
.to eq('Expected')
|
|
160
161
|
end
|
|
161
162
|
|
|
162
163
|
context '非文字列キーの場合' do
|
|
163
164
|
it 'キャッシュに登録されないこと' do
|
|
164
|
-
expect {
|
|
165
|
+
expect { backend.translate('en', {}) }.to throw_symbol(:exception)
|
|
165
166
|
expect(cache).not_to have_key 'en.{}'
|
|
166
167
|
end
|
|
167
168
|
end
|
|
168
169
|
|
|
169
170
|
describe 'store_translations利用時' do
|
|
170
|
-
subject { build_backend }
|
|
171
|
-
|
|
172
171
|
it 'store_translationsで登録した値をdefaultとして利用できること' do
|
|
173
|
-
|
|
174
|
-
expect(
|
|
175
|
-
to include('Expected')
|
|
172
|
+
backend.store_translations('en', 'test' => { 'key' => 'Expected' })
|
|
173
|
+
expect(backend.translate('en', 'test.key', default: 'Unexpected'))
|
|
174
|
+
.to include('Expected')
|
|
176
175
|
expect(cache['en.test.key']).to eq('Expected')
|
|
177
176
|
end
|
|
178
177
|
|
|
179
178
|
it '補間マーカーを保持したまま保存できること' do
|
|
180
|
-
|
|
181
|
-
|
|
182
|
-
|
|
183
|
-
|
|
179
|
+
# I18n の補間構文 %{interpolate} であり Kernel#format 用の printf トークンではないため annotated 化は不適切
|
|
180
|
+
backend.store_translations('en', 'test' => { 'key' => '%{interpolate}' }) # rubocop:disable Style/FormatStringToken
|
|
181
|
+
expect(backend.translate('en', 'test.key', interpolate: 'interpolated'))
|
|
182
|
+
.to include('interpolated')
|
|
183
|
+
expect(cache['en.test.key']).to eq('%{interpolate}') # rubocop:disable Style/FormatStringToken
|
|
184
184
|
end
|
|
185
185
|
|
|
186
186
|
it 'store_translationsでキーがなければdefaultを利用すること' do
|
|
187
|
-
expect(
|
|
188
|
-
to include('Expected')
|
|
187
|
+
expect(backend.translate('en', 'test.key', default: 'Expected'))
|
|
188
|
+
.to include('Expected')
|
|
189
189
|
end
|
|
190
190
|
|
|
191
191
|
it 'キャッシュにキーがあればそちらを優先すること' do
|
|
192
|
-
|
|
192
|
+
backend.store_translations('en', 'test' => { 'key' => 'Unexpected' })
|
|
193
193
|
cache['en.test.key'] = 'Expected'
|
|
194
|
-
expect(
|
|
195
|
-
to include('Expected')
|
|
194
|
+
expect(backend.translate('en', 'test.key', default: 'default'))
|
|
195
|
+
.to include('Expected')
|
|
196
196
|
end
|
|
197
197
|
|
|
198
198
|
it 'ネストしたハッシュを保存できること' do
|
|
199
|
-
nested = { :
|
|
200
|
-
|
|
201
|
-
expect(
|
|
199
|
+
nested = { nested: 'value' }
|
|
200
|
+
backend.store_translations('en', 'key' => nested)
|
|
201
|
+
expect(backend.translate('en', 'key', default: 'Unexpected')).to eq(nested)
|
|
202
202
|
expect(cache['en.key.nested']).to eq('value')
|
|
203
203
|
end
|
|
204
204
|
|
|
205
205
|
it '配列はそのまま返しキャッシュしないこと' do
|
|
206
206
|
array = ['value']
|
|
207
|
-
|
|
208
|
-
expect(
|
|
207
|
+
backend.store_translations('en', 'key' => array)
|
|
208
|
+
expect(backend.translate('en', 'key', default: 'Unexpected')).to eq(array)
|
|
209
209
|
expect(cache['en.key']).to be_nil
|
|
210
210
|
end
|
|
211
211
|
|
|
212
212
|
it 'defaultが配列の場合に順に検索できること' do
|
|
213
|
-
|
|
214
|
-
expect(
|
|
215
|
-
to include('Expected')
|
|
213
|
+
backend.store_translations('en', 'key' => { 'one' => 'Expected' })
|
|
214
|
+
expect(backend.translate('en', 'key.three', default: %i[key.two key.one]))
|
|
215
|
+
.to include('Expected')
|
|
216
216
|
end
|
|
217
217
|
end
|
|
218
218
|
|
|
219
219
|
describe 'Fallbacks利用時' do
|
|
220
|
-
subject { build_backend }
|
|
221
|
-
|
|
222
220
|
before do
|
|
223
221
|
CopyTunerClient::I18nBackend.class_eval do
|
|
224
222
|
include I18n::Backend::Fallbacks
|
|
@@ -227,7 +225,7 @@ describe 'CopyTunerClient::I18nBackend' do
|
|
|
227
225
|
|
|
228
226
|
it 'defaultとFallbacks併用時はキャッシュにデフォルト値を入れないこと' do
|
|
229
227
|
default = 'default value'
|
|
230
|
-
expect(
|
|
228
|
+
expect(backend.translate('en', 'test.key', default:)).to eq(default)
|
|
231
229
|
|
|
232
230
|
# default と Fallbacks を併用した場合、キャッシュにデフォルト値は入らない仕様に変えた
|
|
233
231
|
# その仕様にしないと、うまく Fallbacks の処理が動かないため
|
|
@@ -237,15 +235,13 @@ describe 'CopyTunerClient::I18nBackend' do
|
|
|
237
235
|
end
|
|
238
236
|
|
|
239
237
|
# NOTE: 色々考慮する必要があることが分かったため暫定対応として、ツリーキャッシュを使用しないようにしている
|
|
240
|
-
describe 'ツリー構造のlookup' do
|
|
241
|
-
subject { build_backend }
|
|
242
|
-
|
|
238
|
+
describe 'ツリー構造のlookup' do
|
|
243
239
|
context '完全一致が存在する場合' do
|
|
244
240
|
it 'ツリー構造より完全一致を優先すること' do
|
|
245
241
|
cache['ja.views.hoge'] = 'exact_value'
|
|
246
242
|
cache['ja.views.hoge.sub'] = 'sub_value'
|
|
247
243
|
|
|
248
|
-
result =
|
|
244
|
+
result = backend.translate('ja', 'views.hoge')
|
|
249
245
|
expect(result).to eq('exact_value')
|
|
250
246
|
end
|
|
251
247
|
end
|
|
@@ -256,17 +252,17 @@ describe 'CopyTunerClient::I18nBackend' do
|
|
|
256
252
|
cache['ja.views.fuga'] = 'test2'
|
|
257
253
|
cache['ja.other.key'] = 'other'
|
|
258
254
|
|
|
259
|
-
result =
|
|
255
|
+
result = backend.translate('ja', 'views')
|
|
260
256
|
expect(result).to eq({
|
|
261
|
-
|
|
262
|
-
|
|
263
|
-
|
|
257
|
+
hoge: 'test',
|
|
258
|
+
fuga: 'test2',
|
|
259
|
+
})
|
|
264
260
|
end
|
|
265
261
|
|
|
266
262
|
it '存在しない部分キーはnilを返すこと' do
|
|
267
263
|
cache['ja.views.hoge'] = 'test'
|
|
268
264
|
|
|
269
|
-
result =
|
|
265
|
+
result = backend.translate('ja', 'nonexistent', default: nil)
|
|
270
266
|
expect(result).to be_nil
|
|
271
267
|
end
|
|
272
268
|
|
|
@@ -275,16 +271,16 @@ describe 'CopyTunerClient::I18nBackend' do
|
|
|
275
271
|
cache['ja.views.users.show'] = 'user show'
|
|
276
272
|
cache['ja.views.posts.index'] = 'post index'
|
|
277
273
|
|
|
278
|
-
result =
|
|
274
|
+
result = backend.translate('ja', 'views')
|
|
279
275
|
expect(result).to eq({
|
|
280
|
-
|
|
281
|
-
|
|
282
|
-
|
|
283
|
-
|
|
284
|
-
|
|
285
|
-
|
|
286
|
-
|
|
287
|
-
|
|
276
|
+
users: {
|
|
277
|
+
index: 'user index',
|
|
278
|
+
show: 'user show',
|
|
279
|
+
},
|
|
280
|
+
posts: {
|
|
281
|
+
index: 'post index',
|
|
282
|
+
},
|
|
283
|
+
})
|
|
288
284
|
end
|
|
289
285
|
end
|
|
290
286
|
|
|
@@ -297,18 +293,18 @@ describe 'CopyTunerClient::I18nBackend' do
|
|
|
297
293
|
end
|
|
298
294
|
|
|
299
295
|
it '完全一致を正しく扱うこと' do
|
|
300
|
-
expect(
|
|
296
|
+
expect(backend.translate('ja', 'views.hoge')).to eq('exact_hoge')
|
|
301
297
|
end
|
|
302
298
|
|
|
303
299
|
it 'ツリー構造を正しく扱うこと' do
|
|
304
|
-
expect(
|
|
305
|
-
|
|
306
|
-
|
|
307
|
-
|
|
300
|
+
expect(backend.translate('ja', 'views.fuga')).to eq({
|
|
301
|
+
one: 'one',
|
|
302
|
+
two: 'two',
|
|
303
|
+
})
|
|
308
304
|
end
|
|
309
305
|
|
|
310
306
|
it 'より深い完全一致も正しく扱うこと' do
|
|
311
|
-
expect(
|
|
307
|
+
expect(backend.translate('ja', 'views.hoge.sub')).to eq('sub_value')
|
|
312
308
|
end
|
|
313
309
|
end
|
|
314
310
|
|
|
@@ -318,45 +314,47 @@ describe 'CopyTunerClient::I18nBackend' do
|
|
|
318
314
|
cache['ja.views.fuga'] = 'test2'
|
|
319
315
|
|
|
320
316
|
# 最初のlookupでツリーキャッシュが構築される
|
|
321
|
-
result =
|
|
317
|
+
result = backend.translate('ja', 'views')
|
|
322
318
|
expect(result).to eq({
|
|
323
|
-
|
|
324
|
-
|
|
325
|
-
|
|
319
|
+
hoge: 'test',
|
|
320
|
+
fuga: 'test2',
|
|
321
|
+
})
|
|
326
322
|
end
|
|
327
323
|
|
|
328
324
|
it '2回目以降はツリーキャッシュを再利用すること' do
|
|
329
325
|
cache['ja.views.hoge'] = 'test'
|
|
330
326
|
|
|
331
327
|
# 1回目
|
|
332
|
-
|
|
328
|
+
backend.translate('ja', 'views')
|
|
333
329
|
|
|
334
330
|
# ツリーキャッシュの再構築が発生しないことを確認
|
|
335
|
-
|
|
331
|
+
allow(cache).to receive(:to_tree_hash)
|
|
336
332
|
|
|
337
333
|
# 2回目
|
|
338
|
-
|
|
334
|
+
backend.translate('ja', 'views')
|
|
335
|
+
|
|
336
|
+
expect(cache).not_to have_received(:to_tree_hash)
|
|
339
337
|
end
|
|
340
338
|
|
|
341
339
|
it 'キャッシュバージョンが変わった場合はツリーキャッシュを再構築すること' do
|
|
342
340
|
cache['ja.views.hoge'] = 'test'
|
|
343
|
-
|
|
341
|
+
backend.translate('ja', 'views')
|
|
344
342
|
|
|
345
343
|
# ETag(バージョン)を変更してキャッシュを更新
|
|
346
344
|
cache.etag = '"new_etag"'
|
|
347
345
|
|
|
348
346
|
# 新しい値を追加
|
|
349
347
|
cache['ja.views.new'] = 'new value'
|
|
350
|
-
result =
|
|
351
|
-
expect(result).to include(:
|
|
348
|
+
result = backend.translate('ja', 'views')
|
|
349
|
+
expect(result).to include(new: 'new value')
|
|
352
350
|
end
|
|
353
351
|
|
|
354
352
|
it 'キャッシュバージョンがnilでも正常に動作すること' do
|
|
355
353
|
cache['ja.views.test'] = 'value'
|
|
356
354
|
cache.etag = nil
|
|
357
355
|
|
|
358
|
-
result =
|
|
359
|
-
expect(result).to eq({ :
|
|
356
|
+
result = backend.translate('ja', 'views')
|
|
357
|
+
expect(result).to eq({ test: 'value' })
|
|
360
358
|
end
|
|
361
359
|
end
|
|
362
360
|
|
|
@@ -368,16 +366,17 @@ describe 'CopyTunerClient::I18nBackend' do
|
|
|
368
366
|
end
|
|
369
367
|
|
|
370
368
|
# 初回のツリーキャッシュ構築
|
|
371
|
-
|
|
369
|
+
backend.translate('ja', 'category1')
|
|
372
370
|
|
|
373
371
|
# ETag が変わらない限り、再構築されない
|
|
374
|
-
|
|
372
|
+
allow(cache).to receive(:to_tree_hash)
|
|
375
373
|
|
|
376
374
|
# 複数回の lookup が高速で実行される
|
|
377
375
|
start_time = Time.now
|
|
378
|
-
10.times {
|
|
376
|
+
10.times { backend.translate('ja', 'category2') }
|
|
379
377
|
end_time = Time.now
|
|
380
378
|
|
|
379
|
+
expect(cache).not_to have_received(:to_tree_hash)
|
|
381
380
|
# 10ms 以下で完了することを確認
|
|
382
381
|
expect((end_time - start_time) * 1000).to be < 10
|
|
383
382
|
end
|
|
@@ -385,37 +384,39 @@ describe 'CopyTunerClient::I18nBackend' do
|
|
|
385
384
|
|
|
386
385
|
context 'エッジケース' do
|
|
387
386
|
it '空キャッシュでも正常に動作すること' do
|
|
388
|
-
result =
|
|
387
|
+
result = backend.translate('ja', 'views', default: nil)
|
|
389
388
|
expect(result).to be_nil
|
|
390
389
|
end
|
|
391
390
|
|
|
392
391
|
it '1階層のキーも正常に扱えること' do
|
|
393
392
|
cache['ja.simple'] = 'simple value'
|
|
394
393
|
|
|
395
|
-
result =
|
|
394
|
+
result = backend.translate('ja', 'simple')
|
|
396
395
|
expect(result).to eq('simple value')
|
|
397
396
|
end
|
|
398
397
|
|
|
399
398
|
it 'ignored_keysの機能がツリーlookupでも維持されること' do
|
|
400
399
|
# ignored_keys 設定
|
|
401
|
-
|
|
402
|
-
|
|
403
|
-
|
|
400
|
+
handler = instance_double(Proc)
|
|
401
|
+
allow(CopyTunerClient.configuration).to receive_messages(ignored_keys: ['views.secret'],
|
|
402
|
+
ignored_key_handler: handler)
|
|
404
403
|
|
|
405
404
|
cache['ja.views.public'] = 'public'
|
|
406
405
|
cache['ja.views.secret'] = 'secret'
|
|
407
406
|
|
|
408
407
|
# ignored_key_handler が呼ばれることを確認
|
|
409
|
-
|
|
408
|
+
allow(handler).to receive(:call)
|
|
410
409
|
|
|
411
410
|
# ignored_keys が動作することを確認
|
|
412
|
-
|
|
411
|
+
backend.translate('ja', 'views.secret')
|
|
412
|
+
|
|
413
|
+
expect(handler).to have_received(:call).with(instance_of(CopyTunerClient::IgnoredKey))
|
|
413
414
|
end
|
|
414
415
|
|
|
415
416
|
it 'stringキーが存在する場合のsub-keyアクセスでエラーが発生しないこと' do
|
|
416
417
|
cache['ja.hoge'] = 'hoge value'
|
|
417
418
|
|
|
418
|
-
result =
|
|
419
|
+
result = backend.translate('ja', 'hoge.hello', default: nil)
|
|
419
420
|
expect(result).to be_nil
|
|
420
421
|
end
|
|
421
422
|
|
|
@@ -425,20 +426,20 @@ describe 'CopyTunerClient::I18nBackend' do
|
|
|
425
426
|
cache['ja.dummy'] = 'dummy'
|
|
426
427
|
|
|
427
428
|
expect {
|
|
428
|
-
|
|
429
|
+
backend.translate('ja', 'enumerize.infection_control.body_temperature.36.5', default: nil)
|
|
429
430
|
}.not_to raise_error
|
|
430
431
|
end
|
|
431
432
|
|
|
432
433
|
it '数値セグメントキーが存在しても通常キーのlookupが壊れないこと' do
|
|
433
434
|
cache['ja.views.hoge'] = 'normal'
|
|
434
435
|
|
|
435
|
-
expect {
|
|
436
|
-
expect(
|
|
436
|
+
expect { backend.translate('ja', 'enumerize.body_temperature.36.5', default: nil) }.not_to raise_error
|
|
437
|
+
expect(backend.translate('ja', 'views.hoge')).to eq('normal')
|
|
437
438
|
end
|
|
438
439
|
end
|
|
439
440
|
end
|
|
440
441
|
|
|
441
|
-
describe 'local_first_key_regexp(ローカル優先キー)' do
|
|
442
|
+
describe 'local_first_key_regexp(ローカル優先キー)' do
|
|
442
443
|
after { CopyTunerClient.configuration.local_first_key_regexp = nil }
|
|
443
444
|
|
|
444
445
|
# ローカル config/locales 相当のデータを I18n::Backend::Simple 側だけに格納する。
|
|
@@ -457,9 +458,9 @@ describe 'CopyTunerClient::I18nBackend' do
|
|
|
457
458
|
it 'views.* でも従来どおり copy_tuner(cache)を優先すること' do
|
|
458
459
|
CopyTunerClient.configuration.local_first_key_regexp = nil
|
|
459
460
|
cache['ja.views.foo'] = 'copy tuner value'
|
|
460
|
-
store_local(
|
|
461
|
+
store_local(backend, :ja, views: { foo: 'local value' })
|
|
461
462
|
|
|
462
|
-
expect(
|
|
463
|
+
expect(backend.translate('ja', 'views.foo')).to eq('copy tuner value')
|
|
463
464
|
end
|
|
464
465
|
|
|
465
466
|
# NOTE: number.*.format は precision 等の非文字列値が store_item で落ちるため、
|
|
@@ -467,17 +468,17 @@ describe 'CopyTunerClient::I18nBackend' do
|
|
|
467
468
|
it 'number.*.format は cache に値があってもローカル YAML を優先すること' do
|
|
468
469
|
CopyTunerClient.configuration.local_first_key_regexp = nil
|
|
469
470
|
cache['ja.number.currency.format.unit'] = '$'
|
|
470
|
-
store_local(
|
|
471
|
+
store_local(backend, :ja, number: { currency: { format: { unit: '円' } } })
|
|
471
472
|
|
|
472
|
-
expect(
|
|
473
|
+
expect(backend.translate('ja', 'number.currency.format')).to eq(unit: '円')
|
|
473
474
|
end
|
|
474
475
|
|
|
475
476
|
it 'アプリ独自の number キーは従来どおり copy_tuner を優先すること' do
|
|
476
477
|
CopyTunerClient.configuration.local_first_key_regexp = nil
|
|
477
478
|
cache['ja.number.gift_amount'] = 'copy tuner value'
|
|
478
|
-
store_local(
|
|
479
|
+
store_local(backend, :ja, number: { gift_amount: 'local value' })
|
|
479
480
|
|
|
480
|
-
expect(
|
|
481
|
+
expect(backend.translate('ja', 'number.gift_amount')).to eq('copy tuner value')
|
|
481
482
|
end
|
|
482
483
|
end
|
|
483
484
|
|
|
@@ -486,20 +487,20 @@ describe 'CopyTunerClient::I18nBackend' do
|
|
|
486
487
|
|
|
487
488
|
it 'views.* は cache に値があってもローカル YAML を優先すること' do
|
|
488
489
|
cache['ja.views.foo'] = 'copy tuner value'
|
|
489
|
-
store_local(
|
|
490
|
+
store_local(backend, :ja, views: { foo: 'local value' })
|
|
490
491
|
|
|
491
|
-
expect(
|
|
492
|
+
expect(backend.translate('ja', 'views.foo')).to eq('local value')
|
|
492
493
|
end
|
|
493
494
|
|
|
494
495
|
it 'views.* 以外のキーは従来どおり copy_tuner を優先すること' do
|
|
495
496
|
cache['ja.messages.foo'] = 'copy tuner value'
|
|
496
|
-
store_local(
|
|
497
|
+
store_local(backend, :ja, messages: { foo: 'local value' })
|
|
497
498
|
|
|
498
|
-
expect(
|
|
499
|
+
expect(backend.translate('ja', 'messages.foo')).to eq('copy tuner value')
|
|
499
500
|
end
|
|
500
501
|
|
|
501
502
|
it 'views.* がローカルにも cache にも無いとき nil を返し、空キー登録(アップロード)をしないこと' do
|
|
502
|
-
spy_cache =
|
|
503
|
+
spy_cache = test_cache_class.new
|
|
503
504
|
allow(spy_cache).to receive(:[]=).and_call_original
|
|
504
505
|
backend = CopyTunerClient::I18nBackend.new(spy_cache)
|
|
505
506
|
I18n.backend = backend
|