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>
69 lines
2.7 KiB
Python
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()
|