feat: 添加符文之语中文名称拉取脚本,更新 skill 文档

- 新增 fetch_runeword_names.py 脚本,从中文 Wiki 拉取 RWWeapons/RWChests/RWQuivers/RWShields/RWHelms 五个页面,提取 101 个符文之语的中英文名称保存为 runeword_names.json
- 更新 skill.md:新增 Step 1(拉取名称参考),步骤编号调整为 1-6
- 新增符文之语名称规则章节,要求 {{#lsth:}} 使用中英文名格式

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
This commit is contained in:
wdjwxh 2026-04-12 11:39:01 +08:00
parent 0349be8bcc
commit 8e003dd9c2
3 changed files with 253 additions and 11 deletions

View File

@ -20,7 +20,19 @@ description: 同步英文 MediaWiki 页面变更到中文翻译文档。当用
## 执行步骤 ## 执行步骤
### Step 1: 运行同步脚本 ### Step 1: 更新符文之语名称参考
每次同步前先拉取最新的符文之语中文名称:
```bash
cd /mnt/d/code/sync-pd2-wiki
source venv/bin/activate
python .claude/skills/wiki-sync-translate/scripts/fetch_runeword_names.py
```
此脚本从中文 Wiki 拉取 RWWeapons、RWChests、RWQuivers、RWShields、RWHelms 五个页面,提取所有符文之语的中英文名称,保存到 `references/runeword_names.json`。翻译符文之语相关页面时必须参考此文件。
### Step 2: 运行同步脚本
使用 skill 目录下的专用脚本获取变更: 使用 skill 目录下的专用脚本获取变更:
@ -36,7 +48,7 @@ scripts/wiki_sync.py --title "<页面名称>" --since <上次同步时间> --run
- `--since`: 起始时间,格式如 `2026-01-02T12:07:05Z` - `--since`: 起始时间,格式如 `2026-01-02T12:07:05Z`
- `--run`: 必须提供此参数才会执行 - `--run`: 必须提供此参数才会执行
### Step 2: 读取输出文件 ### Step 3: 读取输出文件
脚本会在 `wiki_sync_output/<时间戳>/changed_pages/` 目录下生成: 脚本会在 `wiki_sync_output/<时间戳>/changed_pages/` 目录下生成:
@ -50,7 +62,7 @@ scripts/wiki_sync.py --title "<页面名称>" --since <上次同步时间> --run
**重要:** 只读取 `comparison.json`,不要读取整个 `*.cn.txt` 文件以节省 token。 **重要:** 只读取 `comparison.json`,不要读取整个 `*.cn.txt` 文件以节省 token。
### Step 3: 解析 comparison.json ### Step 4: 解析 comparison.json
`comparison.json` 格式: `comparison.json` 格式:
```json ```json
@ -88,7 +100,7 @@ scripts/wiki_sync.py --title "<页面名称>" --since <上次同步时间> --run
**注意:** 如果 `old_line``new_line` 差距很大但内容相似如行号从171变到193这通常意味着中间有其他行被插入或删除需要仔细检查变更是否真的相关。 **注意:** 如果 `old_line``new_line` 差距很大但内容相似如行号从171变到193这通常意味着中间有其他行被插入或删除需要仔细检查变更是否真的相关。
### Step 4: 更新中文文档 ### Step 5: 更新中文文档
**核心原则:行号必须完全一致,使用增量修改减少 token 消耗** **核心原则:行号必须完全一致,使用增量修改减少 token 消耗**
@ -117,7 +129,7 @@ cp wiki_sync_output/<时间戳>/changed_pages/*.cn.txt wiki_sync_output/<时间
// 3. 只读取该行附近内容确认,然后用 Edit 修改 // 3. 只读取该行附近内容确认,然后用 Edit 修改
``` ```
### Step 5: 输出结果 ### Step 6: 输出结果
更新后的文档位于 `wiki_sync_output/<时间戳>/result_pages/<页面名>.cn.txt`,用户可直接复制到 Wiki。 更新后的文档位于 `wiki_sync_output/<时间戳>/result_pages/<页面名>.cn.txt`,用户可直接复制到 Wiki。
@ -167,6 +179,11 @@ cp wiki_sync_output/<时间戳>/changed_pages/*.cn.txt wiki_sync_output/<时间
翻译时参考 `references/PD2_glossary.md` 中的标准术语对照表,确保技能名称、灵气名称和通用术语的翻译一致。优先级高于模型自身的翻译选择。 翻译时参考 `references/PD2_glossary.md` 中的标准术语对照表,确保技能名称、灵气名称和通用术语的翻译一致。优先级高于模型自身的翻译选择。
## 翻译术语表 ## 符文之语名称规则
翻译时参考 `references/PD2_glossary.md` 中的标准术语对照表,确保所有技能名称、灵气名称和通用术语的翻译一致。 **`{{#lsth:}}` 模板必须使用中文+英文格式**,因为中文 Wiki 页面中每个符文之语的章节标题是 `=== 中文名 英文名 ===` 格式。例如:
- 正确:`{{#lsth:RWWeapons|力量 Strength}}`
- 错误:`{{#lsth:RWWeapons|Strength}}` (只写英文名无法匹配中文页面的章节)
**名称来源:** 翻译时必须查阅 `references/runeword_names.json`(由 Step 1 的脚本从中文 Wiki 实时拉取生成)。该 JSON 的 key 是英文原名value 是 `中文名 英文名`。不得自行猜测或翻译符文之语名称。

View File

@ -0,0 +1,103 @@
{
"Steel": "钢铁 Steel",
"Malice": "怨恨 Malice",
"Leaf": "叶子 Leaf",
"Pattern": "图纹 Pattern",
"Zephyr": "和风 Zephyr",
"Holy Thunder": "神圣雷击 Holy Thunder",
"Neophyte": "新教徒 Neophyte",
"Strength": "力量 Strength",
"Edge": "边缘 Edge",
"King's Grace": "王者的慈悲 King's Grace",
"Spirit": "精神 Spirit",
"Purity": "纯洁 Purity",
"Insight": "眼光 Insight",
"Honor": "荣耀 Honor",
"Rampage": "狂暴 Rampage",
"Echo": "回响 Echo",
"Black": "黑色 Black",
"White": "白色 White",
"Memory": "记忆 Memory",
"Harmony": "和谐 Harmony",
"Melody": "旋律 Melody",
"Unbending Will": "坚定意志 Unbending Will",
"Obedience": "遵从 Obedience",
"Passion": "热情 Passion",
"Voice of Reason": "思考之声 Voice of Reason",
"Lawbringer": "执法者 Lawbringer",
"Loyalty": "忠诚 Loyalty",
"Crescent Moon": "新月 Crescent Moon",
"Venom": "毒牙 Venom",
"Oath": "誓约 Oath",
"Rift": "裂缝 Rift",
"Kingslayer": "弑王者 Kingslayer",
"Heart of the Oak": "橡树之心 Heart of the Oak",
"Silence": "寂静 Silence",
"Death": "死神 Death",
"Chaos": "混沌 Chaos",
"Call to Arms": "战争召唤 Call to Arms",
"Fortitude": "刚毅 Fortitude",
"Grief": "悔恨 Grief",
"Wind": "轻风 Wind",
"Wrath": "愤怒 Wrath",
"Beast": "野兽 Beast",
"Eternity": "永恒 Eternity",
"Infinity": "无限 Infinity",
"Fury": "狂怒 Fury",
"Famine": "饥荒 Famine",
"Faith": "信心 Faith",
"Ice": "冰冻 Ice",
"Brand": "烙印 Brand",
"Phoenix": "凤凰 Phoenix",
"Destruction": "毁灭 Destruction",
"Last Wish": "最后希望 Last Wish",
"Rapture": "狂喜 Rapture",
"Plague": "瘟疫 Plague",
"Mist": "迷雾 Mist",
"Dominion": "圣域 Dominion",
"Doom": "末日 Doom",
"Hand of Justice": "正义之手 Hand of Justice",
"Pride": "骄傲 Pride",
"Asylum": "庇护 Asylum",
"Obsession": "着魔 Obsession",
"Breath of the Dying": "死亡呼吸 Breath of the Dying",
"Zenith": "天顶 Zenith",
"Stealth": "隐密 Stealth",
"Peace": "和平 Peace",
"Myth": "神话 Myth",
"Smoke": "烟雾 Smoke",
"Hustle": "催促 Hustle",
"Lionheart": "狮子心 Lionheart",
"Treachery": "背信 Treachery",
"Wealth": "财富 Wealth",
"Enlightenment": "教化 Enlightenment",
"Duress": "强制 Duress",
"Stone": "石块 Stone",
"Gloom": "幽暗 Gloom",
"Bone": "白骨 Bone",
"Prudence": "慎重 Prudence",
"Rain": "降雨 Rain",
"Principle": "原理 Principle",
"Bramble": "野蔷薇 Bramble",
"Dragon": "飞龙 Dragon",
"Chains of Honor": "荣耀之链 Chains of Honor",
"Enigma": "谜团 Enigma",
"Innocence": "纯真 Innocence",
"Ancient's Scripture": "远古圣痕 Ancient's Scripture",
"Ancient's Foresight": "远古预兆 Ancient's Foresight",
"Ancients' Pledge": "古代人的契约 Ancients' Pledge",
"Rhyme": "押韵 Rhyme",
"Splendor": "灿烂 Splendor",
"Sanctuary": "圣堂 Sanctuary",
"Exile": "流亡 Exile",
"Epiphany": "顿悟 Epiphany",
"Dream": "梦境 Dream",
"Shattered Wall": "破碎之墙 Shattered Wall",
"Nadir": "天底 Nadir",
"Radiance": "光辉 Radiance",
"Lore": "知识 Lore",
"Wisdom": "智慧 Wisdom",
"Delirium": "迪勒瑞姆 Delirium",
"Flickering Flame": "闪烁火焰 Flickering Flame",
"Ferocity": "残暴 Ferocity"
}

View File

@ -0,0 +1,122 @@
# -*- coding: utf-8 -*-
"""
从中文 Wiki 拉取所有符文之语页面提取符文之语的中英文名称并保存为 JSON
wiki-sync-translate skill 在翻译符文之语相关页面时参考使用
"""
import os
import re
import json
import requests
from pathlib import Path
# ==================== 配置区 ====================
WIKI_API_URL_CN = os.getenv("WIKI_API_URL_CN", "https://wiki.projectdiablo2.cn/w/api.php")
SESSION_CN = requests.Session()
SESSION_CN.headers.update({
"User-Agent": "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36"
})
SESSION_CN.trust_env = False
# 符文之语页面列表(按装备部位)
RUNEWORD_PAGES = [
"RWWeapons",
"RWChests",
"RWQuivers",
"RWShields",
"RWHelms",
]
# 输出路径
SCRIPT_DIR = Path(__file__).resolve().parent
REFERENCES_DIR = SCRIPT_DIR.parent / "references"
OUTPUT_FILE = REFERENCES_DIR / "runeword_names.json"
# ================================================
def get_page_content(title):
"""从中文 Wiki 获取页面完整内容"""
params = {
"action": "query",
"prop": "revisions",
"titles": title,
"rvprop": "content",
"rvslots": "main",
"format": "json"
}
try:
r = SESSION_CN.get(WIKI_API_URL_CN, params=params)
r.raise_for_status()
data = r.json()
pages = data["query"]["pages"]
page = next(iter(pages.values()))
if "revisions" in page:
return page["revisions"][0]["slots"]["main"]["*"]
except Exception as e:
print(f" 获取页面 '{title}' 时出错: {e}")
return None
def extract_runeword_names(wikitext):
"""从 wikitext 中提取所有三级标题作为符文之语名称"""
if not wikitext:
return []
return re.findall(r'===\s*(.+?)\s*===', wikitext)
def split_cn_en(full_name):
"""
分割 "中文名 英文名" 格式的标题
英文名可能包含多个单词 "Flickering Flame", "King's Grace"
所以需要从尾部向前匹配连续的英文单词序列
"""
match = re.search(r'((?:[A-Za-z][A-Za-z\']*(?:\'[A-Za-z]+)*)(?:\s+[A-Za-z][A-Za-z\']*(?:\'[A-Za-z]+)*)*)\s*$', full_name)
if match:
en_name = match.group(1)
cn_part = full_name[:match.start()].strip()
if cn_part:
return cn_part, en_name
# 纯英文或无法分割
return None, full_name
def build_lookup(names):
"""
构建查找表英文原名 -> 完整中英文名称
标题格式为 "中文名 英文名"英文名可含多个单词
"""
lookup = {}
for full_name in names:
cn_name, en_name = split_cn_en(full_name)
lookup[en_name] = full_name
return lookup
def main():
REFERENCES_DIR.mkdir(exist_ok=True)
all_lookup = {}
page_stats = {}
for page_title in RUNEWORD_PAGES:
print(f"拉取: {page_title} ...", end=" ")
wikitext = get_page_content(page_title)
names = extract_runeword_names(wikitext)
lookup = build_lookup(names)
all_lookup.update(lookup)
page_stats[page_title] = len(names)
print(f"找到 {len(names)} 个符文之语")
# 保存 JSON
with open(OUTPUT_FILE, "w", encoding="utf-8") as f:
json.dump(all_lookup, f, ensure_ascii=False, indent=2)
total = len(all_lookup)
print(f"\n总计 {total} 个符文之语名称已保存到 {OUTPUT_FILE}")
for page, count in page_stats.items():
print(f" {page}: {count}")
if __name__ == "__main__":
main()