copy_tuner_client 1.2.2 → 1.2.3
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/CLAUDE.md +5 -0
- data/lib/copy_tuner_client/i18n_backend.rb +18 -12
- data/lib/copy_tuner_client/version.rb +1 -1
- data/spec/copy_tuner_client/i18n_backend_spec.rb +17 -0
- metadata +1 -1
checksums.yaml
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
---
|
|
2
2
|
SHA256:
|
|
3
|
-
metadata.gz:
|
|
4
|
-
data.tar.gz:
|
|
3
|
+
metadata.gz: f671e8161b117c8d8d46b5ae56810ccd0e2fc88dbe9d35ab2175d303c89df11c
|
|
4
|
+
data.tar.gz: 5cf906cd134cda913900d2e15e970a094b23f01a03f9914c746b0e2da3ee6c26
|
|
5
5
|
SHA512:
|
|
6
|
-
metadata.gz:
|
|
7
|
-
data.tar.gz:
|
|
6
|
+
metadata.gz: 84f11e2d259e496f0638b3b8914cc3f88ceda67c6ae1e497f37192fd55347b0f8948abe115c5b91d33ee8feb3acdfb7994fd0af0b4a3118a64ee763dfc458b89
|
|
7
|
+
data.tar.gz: 97f296346a8eff7bb3b09ae4b6de6757973ec859e771492962031440626df13548dc25705ebcb355a14e94038444d1223b325c49caff3a1d87f3ec034bde1561
|
data/CLAUDE.md
CHANGED
|
@@ -18,6 +18,11 @@ CopyTuner の Ruby クライアント gem。Rails アプリの I18n を CopyTune
|
|
|
18
18
|
- Rack middleware `RequestSync` / `CopyrayMiddleware` — 開発環境でのリクエスト毎同期とオーバーレイ
|
|
19
19
|
Rails 統合は engine.rb のイニシャライザ経由(ヘルパー/SimpleForm フック、アセット precompile)。
|
|
20
20
|
|
|
21
|
+
## 開発スタイル
|
|
22
|
+
- **RED/TDD で進める**: 実装前に必ず失敗するテストを書き、テストが RED になることを確認してから実装する
|
|
23
|
+
- 新機能・バグ修正ともに「テスト追加 → RED 確認 → 実装 → GREEN」のサイクルを守る
|
|
24
|
+
- テストを書かずに実装を先行させない
|
|
25
|
+
|
|
21
26
|
## Gotchas
|
|
22
27
|
- **フロントエンドは `src/*.ts` を編集する。`app/assets/*` は Vite のビルド成果物なので直接編集しない**
|
|
23
28
|
(vite.config.ts が `src/main.ts` → `app/assets/javascripts/copytuner.js` を出力)。
|
|
@@ -21,12 +21,13 @@ module CopyTunerClient
|
|
|
21
21
|
@cache = cache
|
|
22
22
|
@tree_cache = nil
|
|
23
23
|
@cache_version = nil
|
|
24
|
-
end
|
|
24
|
+
end
|
|
25
|
+
|
|
25
26
|
#
|
|
26
27
|
# @return [Object] the translated key (usually a String)
|
|
27
28
|
def translate(locale, key, options = {})
|
|
28
29
|
# I18nの標準処理に任せる(内部でlookupが呼ばれる)
|
|
29
|
-
content = super
|
|
30
|
+
content = super
|
|
30
31
|
|
|
31
32
|
return content if content.nil? || content.is_a?(Hash)
|
|
32
33
|
|
|
@@ -43,8 +44,9 @@ module CopyTunerClient
|
|
|
43
44
|
# @return [Array<String>] available locales
|
|
44
45
|
def available_locales
|
|
45
46
|
return @available_locales if defined?(@available_locales)
|
|
47
|
+
|
|
46
48
|
cached_locales = cache.keys.map { |key| key.split('.').first }
|
|
47
|
-
@available_locales = (cached_locales + super).uniq.map
|
|
49
|
+
@available_locales = (cached_locales + super).uniq.map(&:to_sym)
|
|
48
50
|
end
|
|
49
51
|
|
|
50
52
|
# Stores the given translations.
|
|
@@ -62,7 +64,7 @@ module CopyTunerClient
|
|
|
62
64
|
|
|
63
65
|
private
|
|
64
66
|
|
|
65
|
-
def lookup(locale, key, scope = [], options = {})
|
|
67
|
+
def lookup(locale, key, scope = [], options = {}) # rubocop:disable Metrics/CyclomaticComplexity,Metrics/MethodLength
|
|
66
68
|
return nil if !key.is_a?(String) && !key.is_a?(Symbol)
|
|
67
69
|
|
|
68
70
|
parts = I18n.normalize_keys(locale, key, scope, options[:separator])
|
|
@@ -77,8 +79,9 @@ module CopyTunerClient
|
|
|
77
79
|
return super
|
|
78
80
|
end
|
|
79
81
|
|
|
80
|
-
|
|
81
|
-
|
|
82
|
+
config = CopyTunerClient.configuration
|
|
83
|
+
if config.ignored_keys.include?(key_without_locale)
|
|
84
|
+
config.ignored_key_handler.call(IgnoredKey.new("Ignored key: #{key_without_locale}"))
|
|
82
85
|
end
|
|
83
86
|
|
|
84
87
|
# NOTE: ハッシュ化した場合に削除されるキーに対応するため、最初に完全一致をチェック(旧クライアントの動作を維持)
|
|
@@ -114,7 +117,9 @@ module CopyTunerClient
|
|
|
114
117
|
def lookup_in_tree_cache(keys)
|
|
115
118
|
return nil if @tree_cache.nil?
|
|
116
119
|
|
|
117
|
-
|
|
120
|
+
# NOTE: keys は I18n.normalize_keys 済みの配列で、数字だけのセグメントは Integer になっている
|
|
121
|
+
# (例: "...body_temperature.36.5" は [..., 36, 5] に分割される)。Integer#to_sym は無いため to_s を経由する。
|
|
122
|
+
symbol_keys = keys.map { |k| k.to_s.to_sym }
|
|
118
123
|
begin
|
|
119
124
|
result = @tree_cache.dig(*symbol_keys)
|
|
120
125
|
result.is_a?(Hash) ? result : nil
|
|
@@ -146,21 +151,22 @@ module CopyTunerClient
|
|
|
146
151
|
end
|
|
147
152
|
|
|
148
153
|
def default(locale, object, subject, options = {})
|
|
149
|
-
content = super
|
|
154
|
+
content = super
|
|
150
155
|
return content if !object.is_a?(String) && !object.is_a?(Symbol)
|
|
151
156
|
|
|
152
157
|
if content.respond_to?(:to_str)
|
|
153
158
|
parts = I18n.normalize_keys(locale, object, options[:scope], options[:separator])
|
|
154
159
|
# NOTE: ActionView::Helpers::TranslationHelper#translate wraps default String in an Array
|
|
155
160
|
# NOTE: local_first キーのアップロード抑止は Cache#[]= 側に集約している
|
|
156
|
-
|
|
157
|
-
key = parts.join('.')
|
|
158
|
-
cache[key] = content.to_str
|
|
159
|
-
end
|
|
161
|
+
cache[parts.join('.')] = content.to_str if default_string_subject?(subject)
|
|
160
162
|
end
|
|
161
163
|
content
|
|
162
164
|
end
|
|
163
165
|
|
|
166
|
+
def default_string_subject?(subject)
|
|
167
|
+
subject.is_a?(String) || (subject.is_a?(Array) && subject.size == 1 && subject.first.is_a?(String))
|
|
168
|
+
end
|
|
169
|
+
|
|
164
170
|
attr_reader :cache
|
|
165
171
|
end
|
|
166
172
|
end
|
|
@@ -425,6 +425,23 @@ describe 'CopyTunerClient::I18nBackend' do
|
|
|
425
425
|
result = subject.translate('ja', 'hoge.hello', default: nil)
|
|
426
426
|
expect(result).to be_nil
|
|
427
427
|
end
|
|
428
|
+
|
|
429
|
+
it '数値セグメントを含むキー(数値enum)でクラッシュしないこと' do
|
|
430
|
+
# NOTE: enumerize の Float range など、normalize_keys が末尾を Integer に分割するキー。
|
|
431
|
+
# exact_match(完全一致)を回避するため別キーを格納し、tree_cache 探索経路を必ず通す。
|
|
432
|
+
cache['ja.dummy'] = 'dummy'
|
|
433
|
+
|
|
434
|
+
expect {
|
|
435
|
+
subject.translate('ja', 'enumerize.infection_control.body_temperature.36.5', default: nil)
|
|
436
|
+
}.not_to raise_error
|
|
437
|
+
end
|
|
438
|
+
|
|
439
|
+
it '数値セグメントキーが存在しても通常キーのlookupが壊れないこと' do
|
|
440
|
+
cache['ja.views.hoge'] = 'normal'
|
|
441
|
+
|
|
442
|
+
expect { subject.translate('ja', 'enumerize.body_temperature.36.5', default: nil) }.not_to raise_error
|
|
443
|
+
expect(subject.translate('ja', 'views.hoge')).to eq('normal')
|
|
444
|
+
end
|
|
428
445
|
end
|
|
429
446
|
end
|
|
430
447
|
|