copy_tuner_client 1.2.0 → 1.2.1
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/lib/copy_tuner_client/version.rb +1 -1
- data/skills/copy-tuner/SKILL.md +32 -21
- data/skills/copy-tuner-to-locales-cleanup/SKILL.md +165 -0
- data/skills/copy-tuner-to-locales-cleanup/references/example-touchpoints.md +111 -0
- data/skills/copy-tuner-to-locales-cleanup/references/verification-final.md +73 -0
- data/skills/copy-tuner-to-locales-migrate-prefix/SKILL.md +265 -0
- data/skills/copy-tuner-to-locales-migrate-prefix/references/example-touchpoints.md +126 -0
- data/skills/copy-tuner-to-locales-migrate-prefix/references/export-and-split.md +126 -0
- data/skills/copy-tuner-to-locales-migrate-prefix/references/local-first-regexp.md +72 -0
- data/skills/copy-tuner-to-locales-migrate-prefix/references/verification-per-prefix.md +63 -0
- data/skills/copy-tuner-to-locales-migrate-prefix/scripts/migrate_prefix.rb +279 -0
- metadata +10 -1
|
@@ -0,0 +1,63 @@
|
|
|
1
|
+
# prefix 移行後の検証
|
|
2
|
+
|
|
3
|
+
SKILL.md 手順 8 の詳細。対象 prefix を `local_first_key_regexp` に足した後、その範囲がローカルだけで解決する
|
|
4
|
+
ことを確かめる。完全分離(マッチキーは CopyTuner を見ない)なので、ローカルへの書き忘れは未訳として現れる。
|
|
5
|
+
|
|
6
|
+
## 1. regexp が意図どおりマッチするか
|
|
7
|
+
|
|
8
|
+
gem の判定そのものを使って、今回の prefix のキーがマッチし、隣接キーが誤マッチしないことを確認する。
|
|
9
|
+
|
|
10
|
+
```bash
|
|
11
|
+
bin/rails runner 'p [
|
|
12
|
+
CopyTunerClient.configuration.local_first_key?("views.foo.bar"), # => true を期待
|
|
13
|
+
CopyTunerClient.configuration.local_first_key?("reviews.foo") # => false を期待(部分マッチ事故の確認)
|
|
14
|
+
]'
|
|
15
|
+
```
|
|
16
|
+
|
|
17
|
+
## 2. テスト
|
|
18
|
+
|
|
19
|
+
プロジェクトの品質コマンドに従う。多くの Rails プロジェクトでは:
|
|
20
|
+
|
|
21
|
+
```bash
|
|
22
|
+
docker compose up -d db # 未起動なら
|
|
23
|
+
bundle exec rspec
|
|
24
|
+
```
|
|
25
|
+
|
|
26
|
+
`translation missing` が出ないこと。完全分離した prefix のキーがローカル YAML に揃っていないと、ここで
|
|
27
|
+
未訳が顕在化する(それが狙い)。落ちたら、抜き出したサブツリーに漏れがないか・配置ファイルがロードされて
|
|
28
|
+
いるかを確認する。
|
|
29
|
+
|
|
30
|
+
## 3. 未翻訳キーの検出
|
|
31
|
+
|
|
32
|
+
対象 prefix が関わる主要画面・フローを動かし、`translation missing` が出ないか確認する。
|
|
33
|
+
ログから機械的に拾うなら:
|
|
34
|
+
|
|
35
|
+
```bash
|
|
36
|
+
grep -rni 'translation missing' log/ tmp/ 2>/dev/null || echo 'none'
|
|
37
|
+
```
|
|
38
|
+
|
|
39
|
+
より厳密にやるなら、開発・テスト環境で `config.i18n.raise_on_missing_translations = true` を一時的に
|
|
40
|
+
有効化してテストを流し、未定義キーで例外が出るかを確認する手もある(任意・恒久設定にするかはプロジェクト判断)。
|
|
41
|
+
|
|
42
|
+
## 4. i18n の主要参照が解決するか
|
|
43
|
+
|
|
44
|
+
移行した prefix に応じて、影響しやすい参照パターンを主要画面または rails runner で確認する:
|
|
45
|
+
|
|
46
|
+
- `views.*` を移したら … ビューの `t('...')` / `t('.lazy_key')`
|
|
47
|
+
- `activerecord.attributes` を移したら … `Model.human_attribute_name(:attr)`(CSV ヘッダ・フォームラベル)
|
|
48
|
+
- `activerecord.models` を移したら … `Model.model_name.human`
|
|
49
|
+
- `activerecord.enums` を移したら … enum の表示名(`human_enum_name` 等のヘルパ経由)
|
|
50
|
+
|
|
51
|
+
例:
|
|
52
|
+
|
|
53
|
+
```bash
|
|
54
|
+
bin/rails runner 'puts [User.model_name.human, User.human_attribute_name(:name)].inspect'
|
|
55
|
+
```
|
|
56
|
+
|
|
57
|
+
`translation missing` を含まず、期待する日本語が返ること。
|
|
58
|
+
|
|
59
|
+
## 5. 移行していない prefix が壊れていないこと
|
|
60
|
+
|
|
61
|
+
未移行 prefix は `local_first_key_regexp` にマッチしないので、引き続き CopyTuner から引かれる。今回の移行で
|
|
62
|
+
未移行 prefix の表示が変わっていないことも、主要画面で軽く確認しておく(regexp のアンカー漏れで意図せず
|
|
63
|
+
広くマッチしていないかの確認も兼ねる)。
|
|
@@ -0,0 +1,279 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
# copy_tuner → config/locales prefix-unit migration script (SKILL.md step 6).
|
|
4
|
+
#
|
|
5
|
+
# Run via `bin/rails runner` so that the Rails i18n load path and CopyTuner
|
|
6
|
+
# configuration are available:
|
|
7
|
+
#
|
|
8
|
+
# bin/rails runner .claude/skills/copy-tuner-to-locales-migrate-prefix/scripts/migrate_prefix.rb \
|
|
9
|
+
# -- --prefix date --export tmp/copy_tuner_all.yml --out config/locales/0010_date.yml
|
|
10
|
+
#
|
|
11
|
+
# What it does, in one pass:
|
|
12
|
+
# (1) Place : extract the target prefix subtree from the 0000_original_*.yml
|
|
13
|
+
# originals (load-order deep_merge), deep_merge the export subtree on top
|
|
14
|
+
# (export wins for string blurbs), then re-apply the originals'
|
|
15
|
+
# non-representable values (arrays/symbols/numbers/booleans such as the
|
|
16
|
+
# `date.order` symbol array) last so a corrupted export value cannot
|
|
17
|
+
# overwrite them, and write it to --out.
|
|
18
|
+
# (2) Static guards : YAML round-trip, --out is on the i18n load path, every
|
|
19
|
+
# leaf key matches the prefix regexp.
|
|
20
|
+
# (3) Leak check : simulate the original-deletion in memory and resolve every
|
|
21
|
+
# target-prefix key through a fresh I18n::Backend::Simple. A key that goes
|
|
22
|
+
# missing after deletion is a migration leak.
|
|
23
|
+
# (4) Gate : only when there are zero leaks, prune the prefix subtree from the
|
|
24
|
+
# originals on disk. Any leak aborts with the originals untouched.
|
|
25
|
+
#
|
|
26
|
+
# 対象 locale はプロジェクトの I18n.available_locales を実行時に参照して決める(default_locale を先頭に並べる)。
|
|
27
|
+
# `--locales ja,en` で明示上書きできる(fixture を使った検証用。指定時は指定順を尊重する)。
|
|
28
|
+
|
|
29
|
+
require 'optparse'
|
|
30
|
+
require 'yaml'
|
|
31
|
+
|
|
32
|
+
# NOTE: `bin/rails runner` は Kernel#abort が投げる SystemExit を握りつぶし終了コードが 0 になる
|
|
33
|
+
# (実機確認済み)。中断を呼び出し側へ確実に伝えるため、abort ではなく warn + exit(1) を使う。
|
|
34
|
+
def die(message)
|
|
35
|
+
warn message
|
|
36
|
+
exit(1)
|
|
37
|
+
end
|
|
38
|
+
|
|
39
|
+
# ---- 引数 ----
|
|
40
|
+
options = {}
|
|
41
|
+
parser =
|
|
42
|
+
OptionParser.new do |opts|
|
|
43
|
+
opts.banner = 'Usage: bin/rails runner migrate_prefix.rb -- --prefix PREFIX --export PATH --out PATH [--regexp PATTERN] [--originals-glob GLOB]'
|
|
44
|
+
opts.on('--prefix PREFIX', 'ドット区切りの対象 prefix(例: date / activerecord.attributes)') { |v| options[:prefix] = v }
|
|
45
|
+
opts.on('--export PATH', '全件 export YAML(手順3で出力)') { |v| options[:export] = v }
|
|
46
|
+
opts.on('--out PATH', '移行分の出力先(例: config/locales/0010_date.yml)') { |v| options[:out] = v }
|
|
47
|
+
opts.on('--regexp PATTERN', 'leaf キー検証用の正規表現(省略時は prefix から \A<prefix>\. を生成)') { |v| options[:regexp] = v }
|
|
48
|
+
opts.on('--originals-glob GLOB', 'オリジナルファイルの glob(既定: config/locales/0000_original_*.yml)') { |v| options[:originals_glob] = v }
|
|
49
|
+
opts.on('--locales LIST', 'カンマ区切りの対象 locale(既定: I18n.available_locales。検証用の上書き)') { |v| options[:locales] = v }
|
|
50
|
+
end
|
|
51
|
+
# `bin/rails runner script -- ...` の `--` 以降だけを渡したいが、runner が剥がさない環境もあるため両対応。
|
|
52
|
+
argv = ARGV.include?('--') ? ARGV[(ARGV.index('--') + 1)..] : ARGV
|
|
53
|
+
parser.parse!(argv)
|
|
54
|
+
|
|
55
|
+
die(parser.banner) unless options[:prefix] && options[:export] && options[:out]
|
|
56
|
+
|
|
57
|
+
PREFIX = options[:prefix]
|
|
58
|
+
prefix_keys = PREFIX.split('.')
|
|
59
|
+
|
|
60
|
+
# 対象 locale 群。--locales 指定時はその順を尊重、未指定なら default_locale を先頭にした available_locales。
|
|
61
|
+
LOCALES =
|
|
62
|
+
if options[:locales]
|
|
63
|
+
options[:locales].split(',').map(&:strip).reject(&:empty?)
|
|
64
|
+
else
|
|
65
|
+
([I18n.default_locale.to_s] + I18n.available_locales.map(&:to_s)).uniq
|
|
66
|
+
end
|
|
67
|
+
# 黙って 'ja' に倒すと将来 locale 追加時にサイレント脱落を招くため、空なら明示的に中断する。
|
|
68
|
+
die('対象 locale が空。I18n.available_locales が取れているか(Rails 環境のロード)、--locales の指定を確認すること。') if LOCALES.empty?
|
|
69
|
+
# 既定の regexp は prefix に \A アンカーを付けたもの(手順7の local_first_key_regexp と整合させる)。
|
|
70
|
+
regexp = options[:regexp] ? Regexp.new(options[:regexp]) : /\A#{Regexp.escape(PREFIX)}\./o
|
|
71
|
+
originals_glob = options.fetch(:originals_glob, 'config/locales/0000_original_*.yml')
|
|
72
|
+
|
|
73
|
+
# ---- ヘルパ ----
|
|
74
|
+
|
|
75
|
+
# ネスト Hash を非破壊 deep merge(右辺優先)。配列・スカラはそのまま右辺で置換。
|
|
76
|
+
def deep_merge(base, override)
|
|
77
|
+
base.merge(override) do |_key, b, o|
|
|
78
|
+
b.is_a?(Hash) && o.is_a?(Hash) ? deep_merge(b, o) : o
|
|
79
|
+
end
|
|
80
|
+
end
|
|
81
|
+
|
|
82
|
+
def deep_merge!(base, override)
|
|
83
|
+
base.replace(deep_merge(base, override))
|
|
84
|
+
end
|
|
85
|
+
|
|
86
|
+
# YAML をロードして指定 locale ルート(例 `ja:`)配下の Hash を返す。シンボル(date.order の :year 等)を許可。
|
|
87
|
+
def load_locale_tree(path, locale)
|
|
88
|
+
raw = YAML.safe_load_file(path, permitted_classes: [Symbol], aliases: true) || {}
|
|
89
|
+
raw[locale] || {}
|
|
90
|
+
end
|
|
91
|
+
|
|
92
|
+
# prefix(["date"] や ["activerecord","attributes"])のサブツリーを掘り出す。無ければ nil。
|
|
93
|
+
def dig_prefix(tree, keys)
|
|
94
|
+
keys.reduce(tree) do |node, key|
|
|
95
|
+
return nil unless node.is_a?(Hash) && node.key?(key)
|
|
96
|
+
|
|
97
|
+
node[key]
|
|
98
|
+
end
|
|
99
|
+
end
|
|
100
|
+
|
|
101
|
+
# prefix サブツリーを {"date" => {...}} のように prefix で包んだ Hash にして返す(無ければ {})。
|
|
102
|
+
def extract_prefix(tree, keys)
|
|
103
|
+
sub = dig_prefix(tree, keys)
|
|
104
|
+
return {} if sub.nil?
|
|
105
|
+
|
|
106
|
+
keys.reverse.reduce(sub) { |acc, key| { key => acc } }
|
|
107
|
+
end
|
|
108
|
+
|
|
109
|
+
# prefix サブツリーを取り除いた新しい Hash を返す。空になった親も刈る(非破壊)。
|
|
110
|
+
def prune_prefix(tree, keys)
|
|
111
|
+
head, *rest = keys
|
|
112
|
+
return tree unless tree.is_a?(Hash) && tree.key?(head)
|
|
113
|
+
|
|
114
|
+
dup = tree.dup
|
|
115
|
+
if rest.empty?
|
|
116
|
+
dup.delete(head)
|
|
117
|
+
else
|
|
118
|
+
pruned_child = prune_prefix(dup[head], rest)
|
|
119
|
+
if pruned_child.is_a?(Hash) && pruned_child.empty?
|
|
120
|
+
dup.delete(head) # 空親を刈る
|
|
121
|
+
else
|
|
122
|
+
dup[head] = pruned_child
|
|
123
|
+
end
|
|
124
|
+
end
|
|
125
|
+
dup
|
|
126
|
+
end
|
|
127
|
+
|
|
128
|
+
# ネスト Hash の全 leaf を「ドット区切りキー => 値」で返す。配列・シンボル・nil 値は leaf として扱い、
|
|
129
|
+
# その中までは展開しない(date.order の [:year,...] は date.order 1 個)。
|
|
130
|
+
def leaf_entries(tree, prefix = [])
|
|
131
|
+
tree.each_with_object({}) do |(key, value), acc|
|
|
132
|
+
path = prefix + [key]
|
|
133
|
+
if value.is_a?(Hash) && !value.empty?
|
|
134
|
+
acc.merge!(leaf_entries(value, path))
|
|
135
|
+
else
|
|
136
|
+
acc[path.join('.')] = value
|
|
137
|
+
end
|
|
138
|
+
end
|
|
139
|
+
end
|
|
140
|
+
|
|
141
|
+
# ネスト Hash から「非表現値(非 String・非 Hash の leaf)だけ」を残したネスト Hash を返す。
|
|
142
|
+
# 配列・シンボル・数値・真偽値・nil が対象。String leaf は捨てる(export 勝ちに委ねる)。
|
|
143
|
+
# copy_tuner は flat な文字列 blurb しか持てず、これらは export に出てこない/壊れて出る可能性がある。
|
|
144
|
+
# orig 由来のこの結果を最後に deep_merge することで、壊れた export 値が非表現値を上書きするのを防ぐ。
|
|
145
|
+
def select_non_blurb(tree)
|
|
146
|
+
tree.each_with_object({}) do |(key, value), acc|
|
|
147
|
+
if value.is_a?(Hash) && !value.empty?
|
|
148
|
+
child = select_non_blurb(value)
|
|
149
|
+
acc[key] = child unless child.empty? # 非表現値が残った枝だけ保持
|
|
150
|
+
elsif !value.is_a?(String) && !value.is_a?(Hash)
|
|
151
|
+
acc[key] = value # Array / Symbol / Integer / Float / true / false / nil
|
|
152
|
+
end
|
|
153
|
+
end
|
|
154
|
+
end
|
|
155
|
+
|
|
156
|
+
# locale ルートを持つ raw Hash(`{ "ja" => {...}, "en" => {...} }`)から、対象 prefix を全 locale で刈った
|
|
157
|
+
# 新しい Hash を返す(非破壊)。移行漏れ検証のシミュレーションと実削除の両方で使う。
|
|
158
|
+
def prune_prefix_all_locales(raw, locales, keys)
|
|
159
|
+
locales.reduce(raw) { |acc, locale| acc.merge(locale => prune_prefix(acc[locale] || {}, keys)) }
|
|
160
|
+
end
|
|
161
|
+
|
|
162
|
+
# ---- (1) 配置 ----
|
|
163
|
+
out_path = options[:out]
|
|
164
|
+
# Dir.glob は Ruby 3.0+ で昇順ソート済み(= Rails の i18n ロード順と同じ)を返す。
|
|
165
|
+
original_files = Dir.glob(originals_glob)
|
|
166
|
+
die("オリジナルが見つからない: #{originals_glob}") if original_files.empty?
|
|
167
|
+
|
|
168
|
+
# locale ごとに merged サブツリーを構築する。{ "ja" => {...}, "en" => {...} } の形。
|
|
169
|
+
# あるロケールに当該 prefix のキーが一つも無い(orig も export も空)場合は warn してスキップし、
|
|
170
|
+
# 書き出し・検証から自然に除外する(複数ロケールでは「en は別 prefix しか持たない」等が正常に起こりうる)。
|
|
171
|
+
merged_by_locale = {}
|
|
172
|
+
LOCALES.each do |locale|
|
|
173
|
+
orig_sub = {}
|
|
174
|
+
original_files.each { |f| deep_merge!(orig_sub, extract_prefix(load_locale_tree(f, locale), prefix_keys)) }
|
|
175
|
+
|
|
176
|
+
exp_sub = extract_prefix(load_locale_tree(options[:export], locale), prefix_keys)
|
|
177
|
+
|
|
178
|
+
if orig_sub.empty? && exp_sub.empty?
|
|
179
|
+
warn("locale #{locale}: prefix '#{PREFIX}' のキーが無いためスキップ")
|
|
180
|
+
next
|
|
181
|
+
end
|
|
182
|
+
|
|
183
|
+
# orig がベース・export で上書き(String leaf は export 勝ち)し、最後に非表現値(非 String leaf)を
|
|
184
|
+
# orig 値で再適用して必ず勝たせる。export 側に壊れた非表現値(文字列化等)が出ても置換されない。
|
|
185
|
+
merged_by_locale[locale] = deep_merge(deep_merge(orig_sub, exp_sub), select_non_blurb(orig_sub))
|
|
186
|
+
end
|
|
187
|
+
|
|
188
|
+
# 全 locale でスキップ=当該 prefix がどこにも存在しない(prefix の typo)。
|
|
189
|
+
if merged_by_locale.empty?
|
|
190
|
+
die("prefix '#{PREFIX}' のキーが export にもオリジナルにも見つからない。prefix を確認すること。")
|
|
191
|
+
end
|
|
192
|
+
|
|
193
|
+
# ---- (2) 静的ガード(書き出し前にできる検証を先に。中途半端な --out を残さない)----
|
|
194
|
+
# --out が次回起動時に Rails の i18n glob でロードされる場所か(採番ミス・配置ミスの検出)。
|
|
195
|
+
# NOTE: I18n.load_path は runner 起動時に確定済みで、いま書き出す --out は含まれない。よって
|
|
196
|
+
# 「現在の load_path に在るか」ではなく「Rails 標準 glob(config/locales/**/*.yml)に合致するか」を確認する。
|
|
197
|
+
abs_out = File.expand_path(out_path)
|
|
198
|
+
locales_root = File.expand_path('config/locales')
|
|
199
|
+
unless abs_out.start_with?("#{locales_root}/") && abs_out.end_with?('.yml', '.yaml')
|
|
200
|
+
die("#{out_path} が config/locales 配下の .yml ではない。Rails の i18n ロード対象になる場所へ出力すること。")
|
|
201
|
+
end
|
|
202
|
+
|
|
203
|
+
# 全 leaf キーが regexp にマッチするか(regexp と prefix の不一致の早期検出)。leaf キーは locale を
|
|
204
|
+
# 含まない(merged は locale ルート配下)ので、全 locale を同じ regexp で検証できる。
|
|
205
|
+
merged_by_locale.each do |locale, merged|
|
|
206
|
+
non_matching = leaf_entries(merged).keys.grep_v(regexp)
|
|
207
|
+
next if non_matching.empty?
|
|
208
|
+
|
|
209
|
+
die("locale #{locale}: regexp #{regexp.inspect} にマッチしない leaf キーがある(regexp/prefix 不一致):\n #{non_matching.join("\n ")}")
|
|
210
|
+
end
|
|
211
|
+
|
|
212
|
+
# 書き出し(ここまでの検証を通過してから)。merged_by_locale は { "ja" => {...}, "en" => {...} } 形なので
|
|
213
|
+
# そのまま全 locale ルートを持つ YAML になる(スキップした locale は含まれない)。
|
|
214
|
+
File.write(out_path, merged_by_locale.to_yaml)
|
|
215
|
+
total_leaves = merged_by_locale.sum { |_locale, merged| leaf_entries(merged).size }
|
|
216
|
+
puts "配置: #{out_path} (locale #{merged_by_locale.keys.join(',')} / leaf 合計 #{total_leaves} キー)"
|
|
217
|
+
|
|
218
|
+
# YAML ラウンドトリップ(to_yaml → 再読込で各 locale の merged と一致するか)。
|
|
219
|
+
merged_by_locale.each do |locale, merged|
|
|
220
|
+
die("YAML ラウンドトリップ不一致。書き出し結果が壊れている: #{out_path} (locale #{locale})") unless load_locale_tree(out_path, locale) == merged
|
|
221
|
+
end
|
|
222
|
+
|
|
223
|
+
# ---- (3) 移行漏れ検証(削除をメモリ上でシミュレート)----
|
|
224
|
+
# 削除後に Rails がロードするであろう全 locales ツリーを実ロード順で再現する。
|
|
225
|
+
#
|
|
226
|
+
# NOTE: いま書き出した --out は起動時確定の I18n.load_path に含まれない(実機確認済み)。そのため
|
|
227
|
+
# load_path 由来の既存ファイル群(gem の locale 含む)を実順で読みつつ、--out を**末尾に明示追加**して
|
|
228
|
+
# 後勝ちさせ、「削除後+移行分ロード済み」の状態を再現する。
|
|
229
|
+
abs_out = File.expand_path(out_path)
|
|
230
|
+
sim_paths = I18n.load_path.dup
|
|
231
|
+
sim_paths << out_path unless sim_paths.map { |p| File.expand_path(p) }.include?(abs_out)
|
|
232
|
+
original_abs = original_files.map { |f| File.expand_path(f) }
|
|
233
|
+
|
|
234
|
+
sim_tree = {}
|
|
235
|
+
sim_paths.each do |path|
|
|
236
|
+
next unless File.exist?(path)
|
|
237
|
+
next unless path.end_with?('.yml', '.yaml') # .rb ロードパスはこのスキルの範囲外(必要なら別途)
|
|
238
|
+
|
|
239
|
+
content = YAML.safe_load_file(path, permitted_classes: [Symbol], aliases: true) || {}
|
|
240
|
+
next unless content.is_a?(Hash)
|
|
241
|
+
|
|
242
|
+
# オリジナルからは対象 prefix を全 locale で刈った状態にする(実削除後と等価)。
|
|
243
|
+
content = prune_prefix_all_locales(content, LOCALES, prefix_keys) if original_abs.include?(File.expand_path(path))
|
|
244
|
+
deep_merge!(sim_tree, content)
|
|
245
|
+
end
|
|
246
|
+
|
|
247
|
+
sim = I18n::Backend::Simple.new
|
|
248
|
+
sim_tree.each { |loc, data| sim.store_translations(loc, data) }
|
|
249
|
+
|
|
250
|
+
# NOTE: missing 判定は `default:` センチネルで行う。`throw: true` は missing 時に Ruby の throw
|
|
251
|
+
# (catch/throw フロー制御)で MissingTranslation を投げるため rescue では捕まらず UncaughtThrowError に
|
|
252
|
+
# なる(実機確認済み)。default にユニークなオブジェクトを渡せば、missing のときだけそれが返る。
|
|
253
|
+
# 空文字 "" は「存在」扱い(センチネルと equal? でないため missing 扱いしない)。
|
|
254
|
+
missing = Object.new
|
|
255
|
+
|
|
256
|
+
# 母集合は locale ごとに独立に取る(= その locale の merged の全 leaf キー)。locale 横断の和集合に
|
|
257
|
+
# すると、en にしか無いキーを ja で lookup して誤検知する。各 locale はその locale に実在するキーだけ検証する。
|
|
258
|
+
leaks = []
|
|
259
|
+
merged_by_locale.each do |locale, merged|
|
|
260
|
+
leaf_entries(merged).each_key do |key|
|
|
261
|
+
value = sim.translate(locale.to_sym, key, default: missing)
|
|
262
|
+
leaks << [locale, key] if value.equal?(missing)
|
|
263
|
+
end
|
|
264
|
+
end
|
|
265
|
+
|
|
266
|
+
# ---- (4) ゲート ----
|
|
267
|
+
unless leaks.empty?
|
|
268
|
+
warn "移行漏れ検出: 削除すると次の #{leaks.size} キーが未訳になる。オリジナルは変更していない。"
|
|
269
|
+
leaks.sort.each { |locale, key| warn " - #{locale}: #{key}" }
|
|
270
|
+
die('中断。--out の内容・採番・regexp を確認すること。')
|
|
271
|
+
end
|
|
272
|
+
|
|
273
|
+
original_files.each do |f|
|
|
274
|
+
raw = YAML.safe_load_file(f, permitted_classes: [Symbol], aliases: true) || {}
|
|
275
|
+
File.write(f, prune_prefix_all_locales(raw, LOCALES, prefix_keys).to_yaml)
|
|
276
|
+
end
|
|
277
|
+
|
|
278
|
+
puts "削除: prefix '#{PREFIX}' をオリジナル #{original_files.size} ファイルから刈り取った。"
|
|
279
|
+
puts '完了。手順7(local_first_key_regexp 追加)が未済なら次に実施すること。'
|
metadata
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
|
2
2
|
name: copy_tuner_client
|
|
3
3
|
version: !ruby/object:Gem::Version
|
|
4
|
-
version: 1.2.
|
|
4
|
+
version: 1.2.1
|
|
5
5
|
platform: ruby
|
|
6
6
|
authors:
|
|
7
7
|
- SonicGarden
|
|
@@ -228,6 +228,15 @@ files:
|
|
|
228
228
|
- lib/copy_tuner_client/version.rb
|
|
229
229
|
- lib/tasks/copy_tuner_client_tasks.rake
|
|
230
230
|
- package.json
|
|
231
|
+
- skills/copy-tuner-to-locales-cleanup/SKILL.md
|
|
232
|
+
- skills/copy-tuner-to-locales-cleanup/references/example-touchpoints.md
|
|
233
|
+
- skills/copy-tuner-to-locales-cleanup/references/verification-final.md
|
|
234
|
+
- skills/copy-tuner-to-locales-migrate-prefix/SKILL.md
|
|
235
|
+
- skills/copy-tuner-to-locales-migrate-prefix/references/example-touchpoints.md
|
|
236
|
+
- skills/copy-tuner-to-locales-migrate-prefix/references/export-and-split.md
|
|
237
|
+
- skills/copy-tuner-to-locales-migrate-prefix/references/local-first-regexp.md
|
|
238
|
+
- skills/copy-tuner-to-locales-migrate-prefix/references/verification-per-prefix.md
|
|
239
|
+
- skills/copy-tuner-to-locales-migrate-prefix/scripts/migrate_prefix.rb
|
|
231
240
|
- skills/copy-tuner/SKILL.md
|
|
232
241
|
- spec/copy_tuner_client/cache_spec.rb
|
|
233
242
|
- spec/copy_tuner_client/client_spec.rb
|