integrate the skills

split the review skills into self- and other-
the self- variant makes informational comments
the other- variant makes nice comments

Google docs is a failure
This commit is contained in:
iacore
2026-06-21 12:44:07 +08:00
parent 1964a7c2e2
commit 90b965a867
16 changed files with 871 additions and 116 deletions
+78
View File
@@ -0,0 +1,78 @@
#!/usr/bin/env python3
"""Reference: reusable detection rules for Chinese→English translation review.
Adapt the rules list for each project's domain vocabulary."""
import csv, re, sys
def review_csv(csv_path):
rows = []
with open(csv_path) as f:
reader = csv.DictReader(f)
for r in reader:
rows.append((r.get('page', '') or '', r['Chinese'] or '', r['English'] or ''))
issues = []
def add(row_idx, cn, en, problem, suggestion):
issues.append({
'row': row_idx + 2,
'page': rows[row_idx][0],
'cn': cn, 'en': en,
'problem': problem,
'suggestion': suggestion
})
for i, (page, cn, en) in enumerate(rows):
if not cn or not en:
continue
# ── Add project-specific detection rules below ──
# Example: "Is we" → machine translation artifact
if re.search(r'\bIs we\b', en):
add(i, cn, en,
"'Is we' — literal MT of 是否/如果. Should be 'if we' or 'whether we'",
re.sub(r'\bIs we\b', 'if we', en))
# Example: Chinese punctuation in English text
if re.search(r'[,。;:!?、]', en):
add(i, cn, en,
"Chinese punctuation in English text",
"[Replace with English punctuation]")
# Example: unbalanced HTML tags
if en.count('<b>') != en.count('</b>'):
add(i, cn, en,
f"Unbalanced <b> tags (open={en.count('<b>')}, close={en.count('</b>')})",
"[Balance tags]")
# Example: unbalanced double quotes
if en.count('"') % 2 != 0:
add(i, cn, en,
f"Unbalanced quotes ({en.count(chr(34))} total)",
"[Balance quotation marks]")
# Example: term inconsistency check
# if re.search(r'TermA', en) and re.search(r'TermB', en) and ...
# ── Sanity checks ──
for i, (page, cn, en) in enumerate(rows):
if cn and not en:
print(f"WARNING row {i+2}: CN present but EN empty: {cn[:80]}")
cn_chars = re.findall(r'[\u4e00-\u9fff]', en)
if cn_chars:
print(f"WARNING row {i+2}: Chinese chars in EN: {cn_chars}")
if cn and en and cn.strip() == en.strip():
print(f"WARNING row {i+2}: CN==EN (untranslated): {cn[:60]}")
return issues
if __name__ == '__main__':
issues = review_csv(sys.argv[1])
print(f"Issues found: {len(issues)}")
for iss in issues:
print(f"\nCSV_ROW_{iss['row']} [{iss['page']}]")
print(f" CN: {iss['cn'][:120]}")
print(f" EN: {iss['en'][:120]}")
print(f" PROBLEM: {iss['problem']}")
print(f" SUGGEST: {iss['suggestion'][:150]}")
+139
View File
@@ -0,0 +1,139 @@
#!/usr/bin/env python3
"""Mechanical sweep for .dj translation review — run after patches or as final verification.
Usage: python3 sweep.py <source.dj> <target.dj> [--stale term1,term2] [--new term1,term2]
Checks:
1. Non-empty line count parity (source == target)
2. Heading count parity
3. Zero Markdown bold (**) in target (djot uses single *)
5. Zero common Chinese punctuation in target
6. Zero [text](#anchor) link artifacts in target TOC area (first 15 lines)
7. Zero unbalanced double-quotes in target
8. --stale: each listed string must appear ZERO times in target
9. --new: each listed string must appear at least once in target
"""
import re
import sys
CN_PUNCT = re.compile(r'[\u3000-\u303f\uff00-\uffef\u201c\u201d\u2018\u2019]')
def read_nonempty(path):
with open(path) as f:
return [l for l in f.read().rstrip('\n').split('\n') if l.strip()]
def main():
if len(sys.argv) < 3:
print("Usage: sweep.py <source.dj> <target.dj> [--stale a,b,c] [--new x,y,z]")
sys.exit(2)
src_path = sys.argv[1]
tgt_path = sys.argv[2]
stale_terms = []
new_terms = []
i = 3
while i < len(sys.argv):
if sys.argv[i] == '--stale' and i + 1 < len(sys.argv):
stale_terms = [t.strip() for t in sys.argv[i+1].split(',') if t.strip()]
i += 2
elif sys.argv[i] == '--new' and i + 1 < len(sys.argv):
new_terms = [t.strip() for t in sys.argv[i+1].split(',') if t.strip()]
i += 2
else:
i += 1
src_lines = read_nonempty(src_path)
tgt_lines = read_nonempty(tgt_path)
tgt_raw = open(tgt_path).read()
errors = 0
# 1. Line count
if len(src_lines) != len(tgt_lines):
print(f"[FAIL] Line count: src={len(src_lines)} tgt={len(tgt_lines)}")
errors += 1
else:
print(f"[OK] Line count: {len(src_lines)}")
# 2. Heading count
src_h = sum(1 for l in src_lines if l.startswith('## '))
tgt_h = sum(1 for l in tgt_lines if l.startswith('## '))
if src_h != tgt_h:
print(f"[FAIL] Headings: src={src_h} tgt={tgt_h}")
errors += 1
else:
print(f"[OK] Headings: {src_h}")
# 3. Unicode em/en-dash
em = tgt_raw.count('\u2014')
en = tgt_raw.count('\u2013')
if em or en:
print(f"[FAIL] Unicode dashes: em-dash={em} en-dash={en}")
errors += 1
else:
print("[OK] No Unicode em/en-dashes")
# 4. Markdown bold
bold = sum(1 for l in tgt_lines if '**' in l)
if bold:
print(f"[FAIL] Markdown bold (**): {bold} lines")
errors += 1
else:
print("[OK] No Markdown bold")
# 5. Chinese punctuation
cn = [(i+1, l[:60]) for i, l in enumerate(tgt_lines) if CN_PUNCT.search(l)]
if cn:
print(f"[FAIL] Chinese/smart punct: {len(cn)} lines")
for ln, snippet in cn[:5]:
print(f" L{ln}: {snippet}")
errors += 1
else:
print("[OK] No Chinese punctuation")
# 6. TOC link artifacts (first 15 lines)
toc_links = sum(1 for l in tgt_lines[:15] if re.search(r'\[.*?\]\(#', l))
if toc_links:
print(f"[FAIL] TOC has [text](#anchor) links: {toc_links}")
errors += 1
else:
print("[OK] TOC clean (no link artifacts)")
# 7. Unbalanced quotes
for i, l in enumerate(tgt_lines):
if l.count('"') % 2 != 0:
print(f"[FAIL] L{i+1}: Unbalanced quotes: {l[:80]}")
errors += 1
if errors == sum(1 for l in tgt_lines if l.count('"') % 2 != 0):
pass # errors already counted above
elif not any(l.count('"') % 2 != 0 for l in tgt_lines):
print("[OK] No unbalanced quotes")
# 8. Stale terms (must be absent)
for term in stale_terms:
count = tgt_raw.count(term)
if count > 0:
print(f"[FAIL] Stale term '{term}' still present: {count}")
errors += 1
else:
print(f"[OK] Stale term '{term}' absent")
# 9. New terms (must be present)
for term in new_terms:
count = tgt_raw.count(term)
if count == 0:
print(f"[FAIL] New term '{term}' not found")
errors += 1
else:
print(f"[OK] New term '{term}' found: {count}")
print(f"\n{'ALL CLEAN' if errors == 0 else f'{errors} ISSUE(S) FOUND'}")
sys.exit(0 if errors == 0 else 1)
if __name__ == '__main__':
main()