253 lines
13 KiB
Python
253 lines
13 KiB
Python
# -*- coding: utf-8 -*-
|
||
"""
|
||
为 Multilingual.xlsx 中 8 条新条目填 TW/EN/JP/KR 翻译。
|
||
|
||
目标 ID: 19855, 19857, 19862, 19869, 19872, 19874, 19875, 19876
|
||
跳过: 19871(只填了EN), 19873(已 4 语齐全)
|
||
|
||
规则:
|
||
- 严格保留所有 **<...>** 标签的数量与位置(标签内文本可翻译)
|
||
- 术语沿用项目内已有译文(参考 19871 V1.4.0 公告 + 19873 + Dashboard/techs.json)
|
||
- 韩文权威: 플랑드르(不是 플란드르) / 레밀리아 / 优曇華院 - 鈴仙=레이센 우동게인 이나바
|
||
- 印度地名 "乌甲因" 是误音译, 正确是 Ujjain(乌贾因), 直接翻为正确地名
|
||
"""
|
||
import re
|
||
import shutil
|
||
import sys
|
||
import io
|
||
from openpyxl import load_workbook
|
||
|
||
sys.stdout = io.TextIOWrapper(sys.stdout.buffer, encoding='utf-8')
|
||
|
||
XLSX = r'C:\TH1\TH1\Tools\Multilingual.xlsx'
|
||
|
||
# ---------------- 翻译数据 ----------------
|
||
# 每条: {ID: (TW, EN, JP, KR)}
|
||
TRANSLATIONS = {
|
||
|
||
'19855': (
|
||
'蕾米莉亞斯卡雷特',
|
||
'Remilia Scarlet',
|
||
'レミリア・スカーレット',
|
||
'레밀리아 스칼렛',
|
||
),
|
||
|
||
'19857': (
|
||
'芙蘭朵露斯卡雷特',
|
||
'Flandre Scarlet',
|
||
'フランドール・スカーレット',
|
||
'플랑드르 스칼렛',
|
||
),
|
||
|
||
# 乌甲因 = 印度地名 Ujjain 误音译, 直接翻为正确地名
|
||
'19862': (
|
||
'烏賈因',
|
||
'Ujjain',
|
||
'ウッジャイン',
|
||
'우자인',
|
||
),
|
||
|
||
# 19869 = 铃仙称号. 沿用 19871 V1.4.0 公告同名术语 "The Empire's Eye of Madness"
|
||
# 而非用户提示里的 "Imperial Eye of Madness", 以保持与 19876 英雄技能描述一致
|
||
# (两者指代同一英雄, 不能英文出现两种称号)
|
||
'19869': (
|
||
'帝國的狂氣之瞳 鈴仙・優曇華院・因幡',
|
||
"The Empire's Eye of Madness: Reisen Udongein Inaba",
|
||
'帝国の狂気の瞳 鈴仙・優曇華院・イナバ',
|
||
'제국의 광기의 눈동자: 레이센 우동게인 이나바',
|
||
),
|
||
|
||
# 19872: 含 3 个标签 **<军港>**, **<通用行动点>**, **<军港>**
|
||
# 军港=Naval Port/軍港/軍港/군항
|
||
# 通用行动点=通用行動點/General Action Points/汎用行動ポイント/범용 행동 포인트
|
||
'19872': (
|
||
'為處於**<軍港>**的單位恢復1點**<通用行動點>**,每回合上限一次。提供額外防禦。每座城市僅能建造一座**<軍港>**,且僅能建造在港口附近。',
|
||
'Restore 1 **<General Action Point>** to units stationed in a **<Naval Port>**, up to once per turn. Provides additional defense. Each city can construct only one **<Naval Port>**, and it must be built near a harbor.',
|
||
'**<軍港>**にいるユニットに**<汎用行動ポイント>**を1点回復する(毎ターン1回まで)。追加の防御を提供する。各都市につき**<軍港>**は1つしか建設できず、港の近くにのみ建設できる。',
|
||
'**<군항>**에 있는 유닛에게 **<범용 행동 포인트>**를 1점 회복시킨다(매 턴 1회까지). 추가 방어를 제공한다. 각 도시는 **<군항>**을 하나만 건설할 수 있으며, 항구 근처에만 건설할 수 있다.',
|
||
),
|
||
|
||
# 19874: 北纬27的日晷之王 - 丰聪耳神子相关称号
|
||
# "北纬27" 实际为 "北纬27度" 的简写形式; 翻译时英日韩都补"度"显得自然
|
||
'19874': (
|
||
'北緯27度的日晷之王',
|
||
'Sundial King of the 27th Parallel North',
|
||
'北緯27度の日時計の王',
|
||
'북위 27도의 해시계 왕',
|
||
),
|
||
|
||
# 19875: 含 1 个标签 **<军港>** (注意中文末尾无句号)
|
||
# 沿用 Multilingual_P2 修复后版本: "可以建造**<军港>**。所有单位获得海洋防御"
|
||
'19875': (
|
||
'可以建造**<軍港>**。所有單位獲得海洋防禦。',
|
||
'Can construct **<Naval Port>**. All units gain Naval Defense.',
|
||
'**<軍港>**を建造可能。全ユニットが海洋防御を獲得する。',
|
||
'**<군항>** 건설 가능. 모든 유닛이 해양 방어를 획득한다.',
|
||
),
|
||
|
||
# 19876: 铃仙英雄技能描述. 严格沿用 19871 V1.4.0 公告中铃仙部分的术语
|
||
# 注意中文里 Lv.3 段写的是 **<幻想视差>** 而非 **<幻象视差>** (19871 是幻象视差,
|
||
# 这里"幻想"应是错字, 但既然内部文本可翻译, 我们翻译为 Phantom Parallax 与 19871 一致)
|
||
# 另外最后 **<月兔幻想>** 也是错字应为 **<月兔幻象>** -> Moon Rabbit Phantom
|
||
# 19876 中文标签清单(19个):
|
||
# **<帝国的狂气之瞳:铃仙·优昙华院·因幡>**
|
||
# **<-------- Lv.1 -------->**
|
||
# **<[基础属性]>**
|
||
# **<[能力:战地协同]>**
|
||
# **<协同标的>** x2
|
||
# **<-------- Lv.2 -------->**
|
||
# **<[基础属性]>**
|
||
# **<[能力:幻视调率]>**
|
||
# **<月兔幻象>**
|
||
# **<战地协同>**
|
||
# **<-------- Lv.3 -------->**
|
||
# **<[基础属性]>**
|
||
# **<[能力:幻想视差]>**
|
||
# **<月兔幻象>**
|
||
# **<-------- Lv.4 -------->**
|
||
# **<[基础属性]>**
|
||
# **<[能力:狂视调率]>**
|
||
# **<月兔幻象>** x2
|
||
'19876': (
|
||
# TW
|
||
'**<帝國的狂氣之瞳:鈴仙・優曇華院・因幡>**<br> '
|
||
'**<-------- Lv.1 -------->**<br> '
|
||
'**<[基礎屬性]>**10HP/2攻/1防/2移動力/2射程<br> '
|
||
'**<[能力:戰地協同]>**攻擊單位時將施加一層**<協同標的>**,持續1回合。攻擊帶有**<協同標的>**的目標時,每層使得本次攻擊力提升0.5。<br> '
|
||
'**<-------- Lv.2 -------->**<br> '
|
||
'**<[基礎屬性]>**15HP/2攻/2防/2移動力/2射程<br> '
|
||
'**<[能力:幻視調率]>**擊殺敵方單位時,在其位置生成1個看似與鈴仙完全相同的**<月兔幻象>**。幻象繼承鈴仙的**<戰地協同>**能力,但無法造成傷害,並且受到任意攻擊後立刻陣亡。<br> '
|
||
'**<-------- Lv.3 -------->**<br> '
|
||
'**<[基礎屬性]>**20HP/3攻/2防/2移動力/2射程<br> '
|
||
'**<[能力:幻象視差]>**鈴仙攻擊目標前,附近所有**<月兔幻象>**會對該目標進行一輪齊射。<br> '
|
||
'**<-------- Lv.4 -------->**<br> '
|
||
'**<[基礎屬性]>**30HP/4攻/3防/2移動力/2射程<br> '
|
||
'**<[能力:狂視調率]>**所有**<月兔幻象>**具有本體50%的攻擊力。幻象消滅單位時,也可以創造新的**<月兔幻象>**。<br>',
|
||
|
||
# EN (术语严格沿用 19871)
|
||
"**<The Empire's Eye of Madness: Reisen Udongein Inaba>**<br> "
|
||
"**<-------- Lv.1 -------->**<br> "
|
||
"**<[Base Stats]>**10HP / 2 ATK / 1 DEF / 2 MOV / 2 RNG<br> "
|
||
"**<[Ability: Battlefield Synergy]>**When attacking a unit, applies one stack of **<Synergy Mark>** for 1 turn. When attacking a target that bears **<Synergy Mark>**, each stack increases this attack's damage by 0.5.<br> "
|
||
"**<-------- Lv.2 -------->**<br> "
|
||
"**<[Base Stats]>**15HP / 2 ATK / 2 DEF / 2 MOV / 2 RNG<br> "
|
||
"**<[Ability: Illusion Tuning]>**When killing an enemy unit, generates 1 **<Moon Rabbit Phantom>** identical in appearance to Reisen at its position. The phantom inherits Reisen's **<Battlefield Synergy>** ability but cannot deal damage, and dies instantly upon receiving any attack.<br> "
|
||
"**<-------- Lv.3 -------->**<br> "
|
||
"**<[Base Stats]>**20HP / 3 ATK / 2 DEF / 2 MOV / 2 RNG<br> "
|
||
"**<[Ability: Phantom Parallax]>**Before Reisen attacks a target, all nearby **<Moon Rabbit Phantom>**s fire a salvo at that target.<br> "
|
||
"**<-------- Lv.4 -------->**<br> "
|
||
"**<[Base Stats]>**30HP / 4 ATK / 3 DEF / 2 MOV / 2 RNG<br> "
|
||
"**<[Ability: Mad Tuning]>**All **<Moon Rabbit Phantom>**s have 50% of the main body's attack power. When a phantom destroys a unit, it can also create a new **<Moon Rabbit Phantom>**.<br>",
|
||
|
||
# JP
|
||
'**<帝国の狂気の瞳:鈴仙・優曇華院・イナバ>**<br> '
|
||
'**<-------- Lv.1 -------->**<br> '
|
||
'**<[基本ステータス]>**10HP/攻撃2/防御1/移動2/射程2<br> '
|
||
'**<[能力:戦地連携]>**ユニットを攻撃する際、**<連携対象>**を1層付与し、1ターン持続する。**<連携対象>**を持つ目標を攻撃する時、1層ごとに本攻撃の攻撃力が0.5上昇する。<br> '
|
||
'**<-------- Lv.2 -------->**<br> '
|
||
'**<[基本ステータス]>**15HP/攻撃2/防御2/移動2/射程2<br> '
|
||
'**<[能力:幻視調律]>**敵ユニットを撃破した時、その位置に鈴仙とまったく同じ姿の**<月兎幻影>**を1体生成する。幻影は鈴仙の**<戦地連携>**能力を継承するが、ダメージを与えることはできず、いかなる攻撃を受けても即座に消滅する。<br> '
|
||
'**<-------- Lv.3 -------->**<br> '
|
||
'**<[基本ステータス]>**20HP/攻撃3/防御2/移動2/射程2<br> '
|
||
'**<[能力:幻影視差]>**鈴仙が目標を攻撃する前に、近くの全ての**<月兎幻影>**がその目標へ一斉射撃を行う。<br> '
|
||
'**<-------- Lv.4 -------->**<br> '
|
||
'**<[基本ステータス]>**30HP/攻撃4/防御3/移動2/射程2<br> '
|
||
'**<[能力:狂視調律]>**全ての**<月兎幻影>**は本体の50%の攻撃力を持つ。幻影がユニットを撃破した時、新たな**<月兎幻影>**を生成することもできる。<br>',
|
||
|
||
# KR
|
||
'**<제국의 광기의 눈동자: 레이센 우동게인 이나바>**<br> '
|
||
'**<-------- Lv.1 -------->**<br> '
|
||
'**<[기본 스탯]>**10HP/공격2/방어1/이동2/사거리2<br> '
|
||
'**<[능력: 전장 협동]>**유닛을 공격할 때 **<협동 표적>**을 1중첩 부여하며 1턴간 지속된다. **<협동 표적>**이 부여된 대상을 공격할 때, 중첩 1당 이번 공격력이 0.5 상승한다.<br> '
|
||
'**<-------- Lv.2 -------->**<br> '
|
||
'**<[기본 스탯]>**15HP/공격2/방어2/이동2/사거리2<br> '
|
||
'**<[능력: 환시 조율]>**적 유닛을 처치할 때, 그 위치에 레이센과 완전히 똑같이 보이는 **<달토끼 환영>**을 1개 생성한다. 환영은 레이센의 **<전장 협동>** 능력을 계승하지만, 피해를 줄 수 없으며 어떤 공격이라도 받으면 즉시 사망한다.<br> '
|
||
'**<-------- Lv.3 -------->**<br> '
|
||
'**<[기본 스탯]>**20HP/공격3/방어2/이동2/사거리2<br> '
|
||
'**<[능력: 환영 시차]>**레이센이 목표를 공격하기 전에, 근처의 모든 **<달토끼 환영>**이 그 목표를 향해 일제 사격한다.<br> '
|
||
'**<-------- Lv.4 -------->**<br> '
|
||
'**<[기본 스탯]>**30HP/공격4/방어3/이동2/사거리2<br> '
|
||
'**<[능력: 광시 조율]>**모든 **<달토끼 환영>**은 본체의 50% 공격력을 지닌다. 환영이 유닛을 처치할 때, 새로운 **<달토끼 환영>**을 생성할 수도 있다.<br>',
|
||
),
|
||
}
|
||
|
||
# ---------------- 校验 + 写入 ----------------
|
||
|
||
TAG_PATTERN = re.compile(r'\*\*<[^>]*>\*\*')
|
||
|
||
|
||
def count_tags(s):
|
||
if s is None:
|
||
return 0
|
||
return len(TAG_PATTERN.findall(str(s)))
|
||
|
||
|
||
def main():
|
||
wb = load_workbook(XLSX, read_only=False, data_only=False)
|
||
ws = wb.active
|
||
|
||
# 建立 ID -> row 映射 (注意第一行表头 ID 可能带 BOM)
|
||
id_to_row = {}
|
||
for r in range(2, ws.max_row + 1):
|
||
raw = ws.cell(row=r, column=1).value
|
||
if raw is None:
|
||
continue
|
||
s = str(raw).lstrip('').strip()
|
||
id_to_row[s] = r
|
||
|
||
# 列: 4=TW, 5=EN, 6=JP, 7=KR
|
||
LANG_COLS = [('TW', 4), ('EN', 5), ('JP', 6), ('KR', 7)]
|
||
|
||
print('=' * 70)
|
||
print('校验阶段:')
|
||
print('=' * 70)
|
||
|
||
issues = []
|
||
for tid in TRANSLATIONS:
|
||
if tid not in id_to_row:
|
||
issues.append(f' ID={tid}: row 不存在')
|
||
continue
|
||
r = id_to_row[tid]
|
||
zh = ws.cell(row=r, column=3).value
|
||
zh_tags = count_tags(zh)
|
||
tw, en, jp, kr = TRANSLATIONS[tid]
|
||
tag_counts = {
|
||
'CN': zh_tags,
|
||
'TW': count_tags(tw),
|
||
'EN': count_tags(en),
|
||
'JP': count_tags(jp),
|
||
'KR': count_tags(kr),
|
||
}
|
||
ok = all(v == zh_tags for v in tag_counts.values())
|
||
marker = 'OK' if ok else '!!FAIL!!'
|
||
print(f' ID={tid} row={r} CN={zh_tags} '
|
||
f'TW={tag_counts["TW"]} EN={tag_counts["EN"]} '
|
||
f'JP={tag_counts["JP"]} KR={tag_counts["KR"]} {marker}')
|
||
if not ok:
|
||
issues.append(f' ID={tid} 标签数量不一致: {tag_counts}')
|
||
|
||
if issues:
|
||
print('\n校验失败,中止写入:')
|
||
for x in issues:
|
||
print(x)
|
||
sys.exit(1)
|
||
|
||
print('\n' + '=' * 70)
|
||
print('写入阶段:')
|
||
print('=' * 70)
|
||
|
||
for tid, (tw, en, jp, kr) in TRANSLATIONS.items():
|
||
r = id_to_row[tid]
|
||
ws.cell(row=r, column=4).value = tw
|
||
ws.cell(row=r, column=5).value = en
|
||
ws.cell(row=r, column=6).value = jp
|
||
ws.cell(row=r, column=7).value = kr
|
||
print(f' ID={tid} row={r}: 4 语言已填')
|
||
|
||
wb.save(XLSX)
|
||
print(f'\n保存到: {XLSX}')
|
||
|
||
|
||
if __name__ == '__main__':
|
||
main()
|