TH1/Tools/merge_term.py
2026-04-28 21:07:09 +08:00

231 lines
9.5 KiB
Python
Raw Blame History

This file contains invisible Unicode characters

This file contains invisible Unicode characters that are indistinguishable to humans but may be processed differently by a computer. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

#!/usr/bin/env python
# -*- coding: utf-8 -*-
"""Merge Multilingual-ai (post-edit) into term_*.xlsx + apply term-review.md fixes."""
import sys, io, os
sys.stdout = io.TextIOWrapper(sys.stdout.buffer, encoding='utf-8')
from openpyxl import load_workbook
TOOLS = r'C:\TH1\TH1\Tools'
AI_BACKUP = os.path.join(TOOLS, 'Multilingual-ai.backup-2026-04-28.xlsx')
TERM_DIR = os.path.join(TOOLS, '术语表')
# ============================================================
# STEP 1: Multilingual-ai-review.md fixes (rebuild post-edit)
# Format: ID -> {EN/JP/KR: new_value}
# ============================================================
AI_FIXES = {
'17831': {'EN': 'Dharma', 'KR': '정법'},
'17857': {'EN': 'Wago-Araga Bond', 'KR': '화혼과 황혼의 연리'},
'17858': {'EN': 'Cursed Bunrei'},
'17863': {'KR': '바람타기'},
'17865': {'EN': 'Omikuji'},
'17890': {'EN': '[Ability: Leave it to Lord Mishaguji!]',
'JP': '[能力:ミシャグチ様に任せて!]',
'KR': '[능력: 미샤구지님께 맡겨!]'},
'17896': {'EN': 'Chaotic Omikuji Barrage'},
'17897': {'EN': '[Ability: Omikuji]'},
'17908': {'EN': '[Ability: Crimson Leaf Herald]'},
'17916': {'EN': '[Bishop] Class Hero'},
'17939': {'KR': '오니족 호걸'},
'18062': {'EN': 'Gross Body'},
'18127': {'EN': 'Statue of the Queen', 'JP': '后の彫像'},
'18130': {'EN': 'Statue of the Bishop'},
'18133': {'EN': 'Statue of the Rook'},
'18138': {'EN': 'Statue of the Knight'},
'18154': {'EN': 'Karana-sharira', 'JP': '原因身', 'KR': '원인신'},
'18168': {'EN': 'Maha-Vetala', 'JP': 'マハー・ヴェターラ', 'KR': '마하베탈라'},
'18179': {'EN': 'Awe-Strike'},
'18213': {'KR': '바루나함'},
'18217': {'EN': 'Rudra Fire Chariot'},
'18311': {'EN': '[Bishop] Class', 'KR': '[상] 클래스'},
'18314': {'EN': '[Rook] Class'},
'18447': {'KR': '월토끼 환영'},
'18520': {'EN': 'Scarlet Sleepless Castle'},
'18523': {'EN': "The Empire's Blood Sovereign", 'KR': '제국의 피의 군왕'},
'18525': {'EN': 'Perfect & Elegant Maid'},
'18534': {'EN': '[Ability: Yellow Quake Stomp]', 'KR': '[능력: 황진각]'},
'18549': {'EN': 'Sea of Trees of Hourai'},
'18567': {'EN': 'Peerless Elixir of the Realm'},
'18613': {'KR': '마법석{화}'},
'18614': {'KR': '마법석{목}'},
'18615': {'KR': '마법석{금}'},
'18626': {'JP': '----[バグと最適化]----'},
'18717': {'EN': 'Statue of the King'},
'18840': {'EN': 'Statue of the King'},
'19450': {'KR': '중국어'},
}
# ============================================================
# STEP 2: Build {ZH: (EN, JP, KR)} from AI backup + AI_FIXES
# ============================================================
def build_ai_data():
wb = load_workbook(AI_BACKUP, read_only=True)
ws = wb.active
data = {} # ZH -> [EN, JP, KR]
for row in ws.iter_rows(min_row=2, values_only=True):
rid = str(row[0] or '').lstrip('')
zh, en, jp, kr = row[2], row[4], row[5], row[6]
if not zh:
continue
# Apply fixes if any
f = AI_FIXES.get(rid, {})
en2 = f.get('EN', en)
jp2 = f.get('JP', jp)
kr2 = f.get('KR', kr)
data[zh] = [en2, jp2, kr2]
wb.close()
return data
# ============================================================
# STEP 3: term-review.md row-specific fixes by ZH
# Applied after AI merge (so they override anything from AI merge)
# ============================================================
TERM_FIXES = {
# E1
'绝不再把你留在阿斯佩恩': {
'EN': 'Never leave you in Aspern again',
'JP': '二度とアスペルンに置いていかない',
'KR': '다시는 널 아스페른에 두고 가지 않을게'},
# E2 (ZH not changed; per user instruction)
'御住古战场': {
'EN': 'Onbashira Ancient Battlefield',
'KR': '온바시라 고대 전장'},
# E3 拼音 → 英文棋子
'英雄神像[后]': {'EN': 'Hero Statue [Queen]', 'JP': '英雄神像[后]', 'KR': '영웅 신상 [후]'},
'英雄神像[相]': {'EN': 'Hero Statue [Bishop]'},
'英雄神像[王]': {'EN': 'Hero Statue [King]'},
'英雄神像[马]': {'EN': 'Hero Statue [Knight]'},
'英雄神像[车]': {'EN': 'Hero Statue [Rook]'},
# E4 赤口 → Mishaguji
'赤口大人的作祟': {'EN': "Lord Mishaguji's Curse",
'JP': 'ミシャグチ様の祟り',
'KR': '미샤구지님의 저주'},
'交给赤口大人吧!': {'EN': 'Leave it to Lord Mishaguji!',
'JP': 'ミシャグチ様に任せて!',
'KR': '미샤구지님께 맡겨!'},
# E5
'召唤御射宫司大人': {'EN': 'Summon Lord Mishaguji', 'KR': '미샤구지님 소환'},
# E7 挖掘 verb
'挖掘': {'JP': '発掘', 'KR': '발굴'},
# §二 sync (overwrite if AI merge didn't already cover)
'国士无双之药': {'EN': 'Peerless Elixir of the Realm'},
'完美女仆': {'EN': 'Perfect & Elegant Maid'},
'红色不夜城': {'EN': 'Scarlet Sleepless Castle'},
'红叶传令': {'EN': 'Crimson Leaf Herald'},
# §三 C1 (建造英雄神像系列)
'建造英雄神像[马]': {'EN': 'Build Hero Statue [Knight]', 'KR': '영웅 신상 [마] 건설'},
'建造英雄神像[后]': {'EN': 'Build Hero Statue [Queen]', 'KR': '영웅 신상 [후] 건설'},
'建造英雄神像[车]': {'EN': 'Build Hero Statue [Rook]', 'KR': '영웅 신상 [차] 건설'},
'建造英雄神像[相]': {'EN': 'Build Hero Statue [Bishop]', 'JP': '英雄神像[相]', 'KR': '영웅 신상 [상] 건설'},
'建造英雄神像[王]': {'EN': 'Build Hero Statue [King]', 'KR': '영웅 신상 [왕] 건설'},
# §C2 红雾 KR unify (주홍 안개)
'清除红雾': {'KR': '주홍 안개 제거'},
'回收红雾': {'KR': '주홍 안개 회수'},
'红雾攻击': {'KR': '주홍 안개 공격'},
'红雾弥漫': {'KR': '주홍 안개 자욱'},
'红雾领地': {'KR': '주홍 안개 영지'},
'红雾防御': {'KR': '주홍 안개 방어'},
# §C3 风祝 KR (바람 무녀)
'铁血风祝': {'KR': '철혈의 바람 무녀'},
'风祝': {'KR': '바람 무녀'},
# §C4 大团长 → Grand Master
'大团长的将棋时间': {'EN': "Grand Master's Shogi Time"},
# §D3 核能 → 核エネルギー / 핵 에너지
'土豆大王与核能尊神': {'JP': '芋大王と核エネルギーの尊神',
'KR': '감자 대왕과 핵 에너지 존신'},
# §D5 punctuation
'地毯、咖啡与香料': {'JP': '絨毯・コーヒー・香辛料'},
# §D7 미조우
'未遇见': {'KR': '만난 적 없음'},
'未相遇的玩家': {'KR': '만난 적 없는 플레이어'},
# §D10 竹林狼 KR space
'召唤竹林狼': {'KR': '대나무 숲 늑대 소환'},
'竹林狼上校': {'KR': '대나무 숲 늑대 대령'},
# §D11 简体中文 KR
'简体中文': {'KR': '간체 중국어'},
# §D12 血流成河 EN
'我要看到血流成河!': {'EN': 'I want to see rivers of blood!'},
'无聊!我要看到血流成河!': {'EN': 'Boring! I want to see rivers of blood!'},
}
# ============================================================
# STEP 4: Merge into a single term file
# ============================================================
LANG_IDX = {'EN': 0, 'JP': 1, 'KR': 2}
def merge_term(term_path, lang):
"""lang in EN/JP/KR. Loads term_*.xlsx, merges AI data + term fixes, saves."""
ai_data = build_ai_data() # ZH -> [EN, JP, KR]
li = LANG_IDX[lang]
wb = load_workbook(term_path)
ws = wb.active
# Build existing ZH -> row index map
existing = {}
for r in range(2, ws.max_row + 1):
zh = ws.cell(row=r, column=1).value
if zh:
existing[zh] = r
# Counters
overwrote = 0
appended = 0
term_fixed = 0
# Pass 1: Merge AI data
for zh, vals in ai_data.items():
new_val = vals[li]
if new_val is None:
continue
if zh in existing:
row = existing[zh]
old = ws.cell(row=row, column=2).value
if old != new_val:
ws.cell(row=row, column=2).value = new_val
overwrote += 1
else:
new_row = ws.max_row + 1
ws.cell(row=new_row, column=1).value = zh
ws.cell(row=new_row, column=2).value = new_val
existing[zh] = new_row
appended += 1
# Pass 2: Apply term-review fixes (override)
for zh, fix_map in TERM_FIXES.items():
if lang not in fix_map:
continue
new_val = fix_map[lang]
if zh in existing:
row = existing[zh]
old = ws.cell(row=row, column=2).value
if old != new_val:
ws.cell(row=row, column=2).value = new_val
term_fixed += 1
else:
print(f' [WARN] term-fix ZH not found in {lang}: {zh!r}')
wb.save(term_path)
print(f' {os.path.basename(term_path)} ({lang}): overwrote={overwrote} appended={appended} term_fixed={term_fixed} new_total_rows={ws.max_row}')
# ============================================================
# RUN
# ============================================================
if __name__ == '__main__':
print('=== Merging Multilingual-ai post-edit data into term_*.xlsx ===')
merge_term(os.path.join(TERM_DIR, 'term_en.xlsx'), 'EN')
merge_term(os.path.join(TERM_DIR, 'term_jp.xlsx'), 'JP')
merge_term(os.path.join(TERM_DIR, 'term_kr.xlsx'), 'KR')
print('Done.')