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

128 lines
5.2 KiB
Python

#!/usr/bin/env python
# -*- coding: utf-8 -*-
"""Verify term_*.xlsx contains expected post-merge values."""
import sys, io, os
sys.stdout = io.TextIOWrapper(sys.stdout.buffer, encoding='utf-8')
from openpyxl import load_workbook
TERM_DIR = r'C:\TH1\TH1\Tools\术语表'
# Format: (ZH, EN_expected, JP_expected, KR_expected) — None means don't check
EXPECTED = [
# E1
('绝不再把你留在阿斯佩恩',
'Never leave you in Aspern again',
'二度とアスペルンに置いていかない',
'다시는 널 아스페른에 두고 가지 않을게'),
# E2
('御住古战场', 'Onbashira Ancient Battlefield', '御柱古戦場', '온바시라 고대 전장'),
# E3
('英雄神像[后]', 'Hero Statue [Queen]', '英雄神像[后]', '영웅 신상 [후]'),
('英雄神像[相]', 'Hero Statue [Bishop]', None, None),
('英雄神像[王]', 'Hero Statue [King]', None, None),
# E4
('赤口大人的作祟',
"Lord Mishaguji's Curse",
'ミシャグチ様の祟り',
'미샤구지님의 저주'),
('交给赤口大人吧!',
'Leave it to Lord Mishaguji!',
'ミシャグチ様に任せて!',
'미샤구지님께 맡겨!'),
# E5
('召唤御射宫司大人', 'Summon Lord Mishaguji', '御射宮司様を召喚', '미샤구지님 소환'),
# E7
('挖掘', 'Mine', '発掘', '발굴'),
# §二 sync
('国士无双之药', 'Peerless Elixir of the Realm', None, None),
('完美女仆', 'Perfect & Elegant Maid', None, None),
('红色不夜城', 'Scarlet Sleepless Castle', None, None),
('红叶传令', 'Crimson Leaf Herald', None, None),
# §C1
('建造英雄神像[相]', 'Build Hero Statue [Bishop]', '英雄神像[相]', '영웅 신상 [상] 건설'),
('建造英雄神像[王]', 'Build Hero Statue [King]', None, '영웅 신상 [왕] 건설'),
# §C2 红雾 KR
('清除红雾', None, None, '주홍 안개 제거'),
('红雾攻击', None, None, '주홍 안개 공격'),
# §C3 风祝 KR
('铁血风祝', None, None, '철혈의 바람 무녀'),
('风祝', None, None, '바람 무녀'),
# §C4
('大团长的将棋时间', "Grand Master's Shogi Time", None, None),
# §D3
('土豆大王与核能尊神', None, '芋大王と核エネルギーの尊神', '감자 대왕과 핵 에너지 존신'),
# §D5
('地毯、咖啡与香料', None, '絨毯・コーヒー・香辛料', None),
# §D7
('未遇见', None, None, '만난 적 없음'),
('未相遇的玩家', None, None, '만난 적 없는 플레이어'),
# §D10
('召唤竹林狼', None, None, '대나무 숲 늑대 소환'),
# §D11
('简体中文', None, None, '간체 중국어'),
# §D12
('我要看到血流成河!', 'I want to see rivers of blood!', None, None),
('无聊!我要看到血流成河!', 'Boring! I want to see rivers of blood!', None, None),
]
# AI-merge spot checks — these come from Multilingual-ai backup + AI_FIXES
AI_SPOT = [
# ZH, EN, JP, KR (post-edit values)
('正法', 'Dharma', None, '정법'),
('因缘身', 'Karana-sharira', '原因身', '원인신'),
('摩诃毗陀罗', 'Maha-Vetala', 'マハー・ヴェターラ', '마하베탈라'),
('后之雕像', 'Statue of the Queen', '后の彫像', None),
('Chinese', None, None, '중국어'),
('伐楼舰', None, None, '바루나함'),
('[能力:就交给赤口大人吧!]',
'[Ability: Leave it to Lord Mishaguji!]',
'[能力:ミシャグチ様に任せて!]',
'[능력: 미샤구지님께 맡겨!]'),
]
LANG_FILE = {'EN': 'term_en.xlsx', 'JP': 'term_jp.xlsx', 'KR': 'term_kr.xlsx'}
LANG_IDX = {'EN': 0, 'JP': 1, 'KR': 2}
def load_term(path):
wb = load_workbook(path, read_only=True)
ws = wb.active
d = {}
for row in ws.iter_rows(min_row=2, values_only=True):
if row[0]:
d[row[0]] = row[1]
wb.close()
return d
dict_en = load_term(os.path.join(TERM_DIR, 'term_en.xlsx'))
dict_jp = load_term(os.path.join(TERM_DIR, 'term_jp.xlsx'))
dict_kr = load_term(os.path.join(TERM_DIR, 'term_kr.xlsx'))
DICTS = {'EN': dict_en, 'JP': dict_jp, 'KR': dict_kr}
print(f'Row counts: EN={len(dict_en)} JP={len(dict_jp)} KR={len(dict_kr)}')
print()
def check(label, cases):
pass_n = fail_n = 0
for case in cases:
zh, en, jp, kr = case
for lang, exp in (('EN', en), ('JP', jp), ('KR', kr)):
if exp is None:
continue
actual = DICTS[lang].get(zh, '<MISSING>')
if actual == exp:
pass_n += 1
else:
fail_n += 1
print(f' [FAIL] {lang} ZH={zh!r}')
print(f' expected: {exp!r}')
print(f' actual : {actual!r}')
print(f'{label}: {pass_n} pass, {fail_n} fail\n')
return fail_n
f1 = check('term-review fixes', EXPECTED)
f2 = check('AI merge spot-checks', AI_SPOT)
total_fail = f1 + f2
print('=' * 50)
print(f'TOTAL FAIL: {total_fail}')
sys.exit(0 if total_fail == 0 else 1)