$npx -y skills add HoraceLuBFA/en-zh-translation-polish --skill en-zh-translation-polishTranslates English into idiomatic, translationese-free Chinese, optionally as an English-Chinese bilingual version pairing each source paragraph with its translation. Use when the user wants to 翻译成中文 / 英译汉, 去翻译腔/润色译文 (remove translationese, polish a draft), or produce a 中英对照/英中对照
| 1 | # 英译汉翻译润色 (English→Chinese Translate & Polish) |
| 2 | |
| 3 | 把英文译成**地道中文**并产出**英中对照**译文。核心信条(叶子南):英译汉最致命的错误是把英语的“形合”结构迁移进汉语造成翻译腔;好译文 = **以读者为中心、按文本类型调节归化尺度、发挥汉语意合优势、兼顾音韵节奏**。 |
| 4 | |
| 5 | ## 交付物 |
| 6 | |
| 7 | 默认产出**一个**英中对照 Markdown 文件;用户要“全中文版”时再脚本派生。 |
| 8 | |
| 9 | 1. **`<名称> 翻译(中英对照).md`** — 唯一真源。每段**英文原文作为 blockquote (`> `)**,紧跟其下是中文译文。 |
| 10 | 2. (按需)**`<名称> 翻译(全中文).md`** — 脱离对照文件**用脚本机械派生**(删掉 `> ` 行),不要重打中文。 |
| 11 | ```bash |
| 12 | python3 - "<名称> 翻译(中英对照).md" "<名称> 翻译(全中文).md" <<'PY' |
| 13 | import sys, re |
| 14 | src, dst = sys.argv[1], sys.argv[2] |
| 15 | lines = open(src, encoding='utf-8').read().split('\n') |
| 16 | kept = [ln for ln in lines if not ln.lstrip().startswith('>')] |
| 17 | open(dst,'w',encoding='utf-8').write(re.sub(r'\n{3,}','\n\n','\n'.join(kept)).strip()+'\n') |
| 18 | PY |
| 19 | ``` |
| 20 | > 顺序要求:**先跑阶段 6 的标点归一,再派生全中文版**——派生脚本原样继承标点,不会再纠正。 |
| 21 | |
| 22 | 若输入只是聊天里的一小段(几句话),直接在回复里给对照即可,不必落盘;成篇文章或用户指明保存才写文件。命名沿用源文件名,无工具前缀(除非用户要)。目标文件已存在则更新而非新建。 |
| 23 | |
| 24 | ## 工作流(严格按序;每段译文都要走完润色,不是初译就交) |
| 25 | |
| 26 | ### 阶段 0 — 文本分析:定归化档位 ★必做第一步 |
| 27 | 先回答:**这是硬文本还是软文本?属纽马克哪一类?自由度大致几分(1–10)?** 详见 `reference/text-analysis-and-qa.md` 小节 A。 |
| 28 | |
| 29 | - **偏硬(自由度 1–3)**:政治/法律/经贸/科技/合同/说明书。→ 贴原文逻辑,选词精准,**准确 > 流畅**,少介入,术语用固定译法。某些“西化”是为精确付的合理代价。 |
| 30 | - **偏中 (4–6)**:教科书/新闻/一般论述。→ 平衡,默认交际翻译。 |
| 31 | - **偏软 (7–9)**:文学/散文/评论/讲演/广告/宣传/营销。→ 大胆发挥意合与汉语之美,可调结构、可换形象,**流畅/效果优先**。 |
| 32 | - 别忘**文本外因素**:翻译目的、读者是谁。档位一句话写进给用户的说明里。 |
| 33 | |
| 34 | ### 阶段 1 — 理解 → 脱离语言外壳 |
| 35 | 读懂原文后,**抛开英文词句**,在脑中形成意义/图像,再用中文重构(不要在词面上挪移)。遇到结构纠缠的短语用“解包袱法”理清隐含语义关系(见 `reference/techniques.md`)。 |
| 36 | |
| 37 | ### 阶段 2 — 按档位初译 |
| 38 | 以**意合优先**起译:能不用连接词就不用,长句拆成流水短句,被动转主动,定语别堆在名词前。 |
| 39 | |
| 40 | ### 阶段 3 — 润色诊断(核心)逐段过三张表 |
| 41 | 1. **翻译腔病症** — 对照 `reference/translationese-symptoms.md` 逐条排查并修:形合迁移/连接词冗余、长前置定语、“的的不休”、被动滥用、抽象名词作主语、习语硬译、语义关系隐含不清。 |
| 42 | 2. **技巧库** — 用 `reference/techniques.md` 的手段修:词性转换、增/减词、分句/合句、语序移位、定语从句转状语/独立句、正反译、被动转化。 |
| 43 | 3. **隐喻决策** — 基本/图像图式隐喻(旅程、大小、冷热…)可直译;文化专属隐喻糅合或舍弃;直译≠应直译,看档位(`reference/text-analysis-and-qa.md` 小节 B)。 |
| 44 | |
| 45 | ### 阶段 4 — 音韵节奏打磨 |
| 46 | 读出声。利用双音节/四字结构、“偶字易适奇字难平”、对偶排比;并列词组尽量配偶字(“飞机小,便宜”→“体积不大,造价便宜”)。**但软文本才放开;硬文本点到为止。** |
| 47 | |
| 48 | ### 阶段 5 — 准确性质检 |
| 49 | 对照 `reference/text-analysis-and-qa.md` 小节 C 逐项核:擅自改结构/移焦点、漏译情态虚词、擅自添词、搭配、指代、逻辑关系、专名术语数字、语域对齐。 |
| 50 | > 红线:放松准确性 ≠ 理解错误。理解错误没有原谅的余地。 |
| 51 | |
| 52 | ### 阶段 6 — 中文标点规范化 ★(机械执行,落盘后必跑) |
| 53 | 中文译文里的标点必须是中文全角,不能残留英文半角(译者最易忽略,逐字凭眼力一定会漏)。规则: |
| 54 | - `, : ; ? !` → `,:;?!`;句末用 `。`;并列用顿号 `、`;破折号 `——`;省略号 `……`。 |
| 55 | - 圆括号 `( )` → 全角 `( )`:**仅当紧邻中文字符时才转**(包裹中文内容、含人名/术语原文注,如 "道德受体地位(moral patienthood)");纯英文括注(如电影演职 `(Harold D. Schuster, 1937)`)保持半角。 |
| 56 | - 双引号统一为中文全角 `" "`(内层 `' '`);直角引号 `「」`、`『』` 一并归一为 `" "` / `' '`。 |
| 57 | |
| 58 | **以下一律保持半角,绝不转:** ① 英文原文 blockquote(`> ` 行)整段不动;② Markdown 链接 `[文字](url)` 的括号与 URL;③ 中文行内嵌入的整句/词组英文,其内部标点——如被引用的英文原句 `…one nation under God, indivisible, …`;④ 数字/缩写/版本号里的点:`4.3`、`Word 2010`、`A.I.`、`L. M.`;⑤ 代码/公式块。 |
| 59 | |
| 60 | 判定原理:**逗号类与圆括号都只在紧邻中文字符(前或后)时才转**;有方向的引号(“”「」‘’『』)按方向直接映射,只有歧义的直双引号 `"` 才靠交替判定开闭。落盘后跑下面脚本机械归一并自检(`残留` 必须为 0): |
| 61 | |
| 62 | ```bash |
| 63 | python3 - "<名称> 翻译(中英对照).md" <<'PY' |
| 64 | import re, sys |
| 65 | src = sys.argv[1] |
| 66 | lines = open(src, encoding='utf-8').read().split('\n') |
| 67 | CJK_EXTRA = set('“”‘’·—…《》〈〉「」『』【】、。,!?;:()') |
| 68 | def is_cjk(c): |
| 69 | if not c: return False |
| 70 | o = ord(c) |
| 71 | return (0x3400<=o<=0x9fff) or (0x3000<=o<=0x303f) or (0xff00<=o<=0xffef) or (c in CJK_EXTRA) |
| 72 | SMAP = {',':',', ';':';', ':':':', '?':'?', '!':'!', '(':'(', ')':')'} |
| 73 | OPEN2 = '“「'; CLOSE2 = '”」'; OPEN1 = '‘『'; CLOSE1 = '’』' |
| 74 | LINK = re.compile(r'\[[^\]]*\]\([^)]*\)') |
| 75 | def fix(line): |
| 76 | store=[] |
| 77 | line = LINK.sub(lambda m: store.append(m.group(0)) or '\x00%d\x00'%(len(store)-1), line) |
| 78 | out=[]; sop=True # 有方向引号直接映射; 仅歧义直双引号 " 靠交替定开闭 |
| 79 | for c in line: |
| 80 | if c == '"': out.append('“' if sop else '”'); sop = not sop |
| 81 | elif c in OPEN2: out.append('“') |
| 82 | elif c in CLOSE2: out.append('”') |
| 83 | elif c in OPEN1: out.append('‘') |
| 84 | elif c in CLOSE1: out.append('’') |
| 85 | else: out.append(c) |
| 86 | ch=out; n=len(ch) |
| 87 | for i,c in enumerate(ch): # 逗号类 + 圆括号: 紧邻中文才转全角 |
| 88 | if c in SMAP and (is_cjk(ch[i-1] if i else '') or is_cjk(ch[i+1] if i+1<n else '')): |
| 89 | ch[i]=SMAP[c] |
| 90 | line=''.join(ch) |
| 91 | return re.sub('\x00(\\d+)\x00', lambda m: store[int(m.group(1))], line) |
| 92 | def skip(ln): |
| 93 | s=ln.strip(); return s=='' or ln.lstrip().startswith('>') or s=='---' |
| 94 | res=[ln if skip(ln) else fix(ln) for ln in lines] |
| 95 | open(src,'w',encoding='utf-8').write('\n'.join(res)) |
| 96 | def residual(ln): |
| 97 | t = LINK.sub('', ln) # 排除 markdown 链接内的括号/标点, 免误报 |
| 98 | return sum(1 for m in re.finditer(r'[,;:?!()]', t) |
| 99 | if is_cjk(t[m.start()-1] if m.start() else '') or is_cjk(t[m.start()+1] if m.start()+1<l |