1. 替换所有页面/组件中的硬编码中文提示文案为$lang调用,包括支付、帮助中心、公告等页面 2. 重构diy.js加载失败文案处理逻辑,支持参数化替换 3. 新增多语言混入逻辑,实现导航标题随语种动态切换 4. 重构支付组件初始化逻辑,优化平台适配代码 5. 添加多语言单元测试和硬编码扫描脚本 6. 更新语言包,新增缺失的翻译词条
80 lines
3.4 KiB
Python
80 lines
3.4 KiB
Python
#!/usr/bin/env python3
|
|
# 精筛 v2:剥离 HTML 注释和 JS 注释后,再扫硬编码中文(只关注真实会被渲染的)
|
|
import os, re, json
|
|
from collections import defaultdict
|
|
|
|
ROOT = r'D:\projects\shop-projects\frontend'
|
|
SKIP_DIR = {'node_modules', '.unpackage', 'unpackage', '.git', 'dist', 'stub-app-projects', 'lang', 'tests', 'docs', 'scripts', 'common/mixin'}
|
|
|
|
CN = re.compile(r'[\u4e00-\u9fff]')
|
|
LANG_RE = re.compile(r'\$lang\(')
|
|
|
|
TPL_RE = re.compile(r'<template[^>]*>([\s\S]*?)</template>', re.I)
|
|
TAG_RE = re.compile(r'<([a-zA-Z][\w-]*)\b[^>]*>([^<>\n]+)</\1>')
|
|
HTML_COMMENT_RE = re.compile(r'<!--[\s\S]*?-->')
|
|
|
|
JS_TRIGGERS = [
|
|
re.compile(r'uni\.show(?:Toast|Modal|ActionSheet|Loading)\s*\(\s*\{[\s\S]*?\}\s*\)', re.S),
|
|
re.compile(r'wx\.show(?:Toast|Modal|ActionSheet|Loading)\s*\(\s*\{[\s\S]*?\}\s*\)', re.S),
|
|
re.compile(r'\btitle\s*:\s*[\'"]([^\'"]*?)[\'"]'),
|
|
re.compile(r'\bcontent\s*:\s*[\'"]([^\'"]*?)[\'"]'),
|
|
re.compile(r'\btext\s*:\s*[\'"]([^\'"]*?)[\'"]'),
|
|
re.compile(r'\bplaceholder\s*:\s*[\'"]([^\'"]*?)[\'"]'),
|
|
re.compile(r'\balert\s*\(\s*[\'"]([^\'"]*?)[\'"]'),
|
|
re.compile(r'\bconfirm\s*\(\s*[\'"]([^\'"]*?)[\'"]'),
|
|
]
|
|
|
|
def strip_all_comments(text, is_vue=False):
|
|
text = HTML_COMMENT_RE.sub(lambda m: ' ' * len(m.group()), text)
|
|
text = re.sub(r'/\*[\s\S]*?\*/', lambda m: ' ' * len(m.group()), text)
|
|
text = re.sub(r'//[^\n]*', lambda m: ' ' * len(m.group()), text)
|
|
return text
|
|
|
|
results = defaultdict(list)
|
|
|
|
for dirpath, dirnames, filenames in os.walk(ROOT):
|
|
if any(s in dirpath.replace('\\', '/') for s in SKIP_DIR):
|
|
continue
|
|
for fn in filenames:
|
|
if not fn.endswith(('.vue', '.js')):
|
|
continue
|
|
fp = os.path.join(dirpath, fn)
|
|
rel = os.path.relpath(fp, ROOT).replace('\\', '/')
|
|
try:
|
|
content = open(fp, 'r', encoding='utf-8').read()
|
|
except UnicodeDecodeError:
|
|
continue
|
|
|
|
stripped = strip_all_comments(content)
|
|
|
|
if fn.endswith('.vue'):
|
|
for m in TPL_RE.finditer(stripped):
|
|
tpl = m.group(1)
|
|
for tag in TAG_RE.finditer(tpl):
|
|
inner = tag.group(2).strip()
|
|
if CN.search(inner) and not LANG_RE.search(inner):
|
|
line_no = stripped[:m.start(1) + tpl.find(inner)].count('\n') + 1
|
|
results[rel].append({'kind': 'template', 'tag': tag.group(1), 'text': inner[:160], 'line': line_no})
|
|
|
|
for trig in JS_TRIGGERS:
|
|
for m in trig.finditer(stripped):
|
|
text = (m.group(1) if m.lastindex else m.group(0))
|
|
if not CN.search(text):
|
|
continue
|
|
if LANG_RE.search(text):
|
|
continue
|
|
line_no = stripped[:m.start()].count('\n') + 1
|
|
results[rel].append({'kind': 'js-text', 'match': text[:160], 'line': line_no})
|
|
|
|
ranked = sorted(results.items(), key=lambda kv: -len(kv[1]))
|
|
print(f'total files: {len(ranked)}')
|
|
print(f'total hits: {sum(len(v) for v in ranked)}')
|
|
|
|
out = []
|
|
for f, hits in ranked[:60]:
|
|
out.append({'file': f, 'hits': len(hits), 'samples': hits[:3]})
|
|
print(json.dumps(out, ensure_ascii=False, indent=2))
|
|
|
|
with open(os.path.join(ROOT, 'scripts', 'hardcoded_cn_real.json'), 'w', encoding='utf-8') as f:
|
|
json.dump({k: v for k, v in ranked}, f, ensure_ascii=False, indent=2)
|
|
print('saved hardcoded_cn_real.json') |