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>
This commit is contained in:
co-authored by
Claude Opus 5.5
parent
808e711f74
commit
000d4841fd
@@ -0,0 +1,68 @@
|
||||
#!/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()
|
||||
Reference in New Issue
Block a user