Files
mtgodot-poc/scripts/build_zh_quest_inline.py
T
shenleiandClaude Opus 5.5 000d4841fd quest zh: translate the inline quest text (change_name, item_delete, manwoo, forked_road, ...)
128 literals written directly in the quest sources, outside gameforge.*;
build_zh_quest_inline.py patches them in GBK before make.py (qc) on the server.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-09-30 03:32:33 +09:00

69 lines
2.7 KiB
Python

#!/usr/bin/env python3
"""Put Chinese into the text the 40250 quests write inline, outside gameforge.* (translate.lua).
data/zh_40250/quest_inline_zh.tsv has one `file\\tline\\tEnglish\\tChinese` row per string literal
(UTF-8). The row's line must hold "<English>" exactly; it becomes "<Chinese>" in GBK, the code page
of the newcibn locale. Only changed files are written to the output directory; copy them over the
server's quest directory and run make.py (qc) there. questlib.lua is read at run time, not compiled.
build_zh_quest_inline.py <quest source dir> <out dir>
"""
import argparse
from collections import defaultdict
from pathlib import Path
REPO = Path(__file__).resolve().parents[1]
DEFAULT_TABLE = REPO / "data/zh_40250/quest_inline_zh.tsv"
def table_rows(path: Path):
rows = defaultdict(list)
for number, line in enumerate(path.read_text(encoding="utf-8").splitlines(), 1):
if not line or line.startswith("#"):
continue
parts = line.split("\t")
if len(parts) != 4:
raise ValueError(f"{path}:{number}: want 4 tab-separated columns")
name, line_no, english, chinese = parts
rows[name].append((int(line_no), english, chinese, number))
return rows
def encode(chinese: str, where: str) -> bytes:
data = chinese.encode("gbk")
# A GBK trail byte 0x5C is a backslash to Lua and qc; reword such a translation.
if b"\\" in data or b'"' in data:
raise ValueError(f"{where}: {chinese!r} has a quote or backslash byte in GBK")
return data
def build(source: Path, table: Path, output: Path):
output.mkdir(parents=True, exist_ok=True)
total = 0
for name, rows in sorted(table_rows(table).items()):
lines = (source / name).read_bytes().split(b"\n")
for line_no, english, chinese, number in rows:
where = f"{table.name}:{number} ({name}:{line_no})"
old = b'"' + english.encode("ascii") + b'"'
if old not in lines[line_no - 1]:
raise ValueError(f"{where}: {english!r} not on that line")
lines[line_no - 1] = lines[line_no - 1].replace(old, b'"' + encode(chinese, where) + b'"', 1)
total += 1
(output / name).write_bytes(b"\n".join(lines))
return total
def main():
parser = argparse.ArgumentParser(description=__doc__, formatter_class=argparse.RawDescriptionHelpFormatter)
parser.add_argument("source", type=Path)
parser.add_argument("output", type=Path)
parser.add_argument("--table", type=Path, default=DEFAULT_TABLE)
args = parser.parse_args()
print(f"{build(args.source, args.table, args.output)} strings replaced in {args.output}")
if __name__ == "__main__":
main()