65 lines
2.9 KiB
Python
65 lines
2.9 KiB
Python
#!/usr/bin/env python3
|
||
"""
|
||
fix_i18n_w1.py — 批量修复 W1:给硬编码中文 text 加 otext+i18n 标记
|
||
基于 check_i18n.py --json 报告的 violations(W1 且 git_ignored=False),
|
||
按 pos 从后往前精准插入,保持文件其余部分逐字节不变。
|
||
|
||
.ui: "text": "中文" → "otext": "中文", "text": "中文", "i18n": true
|
||
.dspy: 'text': '中文' → 'otext': '中文', 'text': '中文', 'i18n': True (引号风格跟随原文)
|
||
otext 无 i18n 的: "otext": "中文" → "otext": "中文", "i18n": true
|
||
|
||
用法: python3 scripts/fix_i18n_w1.py /tmp/i18n.json [--dry-run]
|
||
"""
|
||
import json, re, sys
|
||
from collections import defaultdict
|
||
|
||
def main():
|
||
report = json.load(open(sys.argv[1], encoding='utf-8'))
|
||
dry = '--dry-run' in sys.argv
|
||
viols = [v for v in report['violations'] if v['code'] == 'W1' and not v['git_ignored']]
|
||
by_file = defaultdict(list)
|
||
for v in viols:
|
||
by_file[v['file']].append(v)
|
||
|
||
total_fixed = 0
|
||
errors = []
|
||
for fp, vs in sorted(by_file.items()):
|
||
raw = open(fp, encoding='utf-8').read()
|
||
is_ui = fp.endswith('.ui')
|
||
q_t = 'true' if is_ui else 'True'
|
||
# 从后往前改,pos 不漂移
|
||
for v in sorted(vs, key=lambda x: -x['pos']):
|
||
pos = v['pos']
|
||
# 在 pos 处重新匹配完整 key-value 片段
|
||
if v['why'].startswith('dspy otext') or v['why'].startswith('otext'):
|
||
m = re.compile(r'(["\'])otext\1\s*:\s*(["\'])(.*?)\2').match(raw, pos)
|
||
if not m:
|
||
errors.append((fp, pos, 'otext 片段定位失败'))
|
||
continue
|
||
if '"i18n"' in raw[m.end():m.end()+40] or "'i18n'" in raw[m.end():m.end()+40]:
|
||
continue # 已有 i18n 标记(可能重复报告)
|
||
ins = f', {m.group(1)}i18n{m.group(1)}: {q_t}'
|
||
raw = raw[:m.end()] + ins + raw[m.end():]
|
||
total_fixed += 1
|
||
else:
|
||
m = re.compile(r'(["\'])text\1\s*:\s*(["\'])(.*?)\2').match(raw, pos)
|
||
if not m:
|
||
errors.append((fp, pos, 'text 片段定位失败'))
|
||
continue
|
||
q, val = m.group(1), m.group(3)
|
||
ins = f', {q}otext{q}: {q}{val}{q}, {q}i18n{q}: {q_t}'
|
||
# 在 "text": "val" 前插 otext,在其后插 i18n:
|
||
# 结果形如 "otext": "val", "text": "val", "i18n": true
|
||
new_seg = f'{q}otext{q}: {q}{val}{q}, {q}text{q}: {q}{val}{q}, {q}i18n{q}: {q_t}'
|
||
raw = raw[:m.start()] + new_seg + raw[m.end():]
|
||
total_fixed += 1
|
||
if not dry:
|
||
open(fp, 'w', encoding='utf-8').write(raw)
|
||
|
||
print(f'{"DRY-RUN " if dry else ""}fixed={total_fixed} files={len(by_file)} errors={len(errors)}')
|
||
for e in errors[:20]:
|
||
print(' ERR', e)
|
||
|
||
if __name__ == '__main__':
|
||
main()
|