231 lines
9.5 KiB
Python
231 lines
9.5 KiB
Python
#!/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.')
|