From 000d4841fddd767264541b4362dbb6eb179fd963 Mon Sep 17 00:00:00 2001 From: shenlei Date: Wed, 30 Sep 2026 03:32:33 +0900 Subject: [PATCH] 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 --- data/zh_40250/quest_inline_zh.tsv | 133 ++++++++++++++++++++++++++++++ scripts/build_zh_quest_inline.py | 68 +++++++++++++++ 2 files changed, 201 insertions(+) create mode 100644 data/zh_40250/quest_inline_zh.tsv create mode 100644 scripts/build_zh_quest_inline.py diff --git a/data/zh_40250/quest_inline_zh.tsv b/data/zh_40250/quest_inline_zh.tsv new file mode 100644 index 00000000..49cbed03 --- /dev/null +++ b/data/zh_40250/quest_inline_zh.tsv @@ -0,0 +1,133 @@ +# Quest text written inline in the 40250 quest sources (not gameforge.*), UTF-8. +# file line English literal (without quotes) Chinese +# scripts/build_zh_quest_inline.py replaces "" with "" on that line (GBK) before qc. +# Left English on purpose: char_log tags, flag names, GM/test-server debug output (hair, test_att_resist, +# dragon_lair_access, is_yang, event_mystery_box, dragon_soul_daily_gift_mgr, questscroll5 debug). +change_name.quest 5 You cannot change your name if you are married. 已婚角色不能改名。 +change_name.quest 11 You cannot change your name if you are transformed. 变身状态下不能改名。 +change_name.quest 17 You cannot change your name if you are in a guild. 加入帮会的角色不能改名。 +change_name.quest 23 You cannot change your name if you are in a party. 组队状态下不能改名。 +change_name.quest 29 You need level 35 to change your name! 角色达到35级才能改名! +change_name.quest 35 You can not use it now. 现在不能使用。 +change_name.quest 39 Since it's test server, you can go 测试服务器,可以继续 +change_name.quest 46 Please enter the name you want to have 请输入新的角色名 +change_name.quest 51 This name is too long. Please try again. 名字太长,请重新输入。 +change_name.quest 59 You didn't log in after you have changed your name. 改名后你还没有重新登录。 +change_name.quest 60 please re-log in. 请重新登录。 +change_name.quest 65 The problem occured while using the item. 使用物品时出现问题。 +change_name.quest 66 Please use again. 请再使用一次。 +change_name.quest 71 The name is not available. 这个名字不可用。 +change_name.quest 72 Please enter other name. 请输入其他名字。 +change_name.quest 77 The name is not available. 这个名字不可用。 +change_name.quest 78 Please enter other name. 请输入其他名字。 +change_name.quest 83 You have changed your name successfully. 改名成功。 +change_name.quest 84 Please log in again. 请重新登录。 +change_name.quest 93 Unknown error occured. 发生未知错误。 +item_delete.quest 6 Remove item? 要销毁这件物品吗? +item_delete.quest 10 Yes 是 +item_delete.quest 10 No 否 +subquest_24.quest 104 Time left 剩余时间 +heavens_cave_keyquest.quest 743 Stimme von Barah Taraji 巴哈塔拉吉之声 +manwoo.quest 3 GM: Start Fishing Event GM:开始钓鱼活动 +manwoo.quest 4 Manwoo Event 钓鱼活动 +manwoo.quest 5 Which fish should be accepted? 收哪种鱼? +manwoo.quest 6 Between 27802 and 27818 输入27802到27818之间的编号 +manwoo.quest 15 That number isn't accepted 这个编号不可用 +manwoo.quest 18 Manwoo Event 钓鱼活动 +manwoo.quest 19 How many fishes should we accept? 要收多少条鱼? +manwoo.quest 27 That isn't a valid number 这不是有效的数字 +manwoo.quest 30 Manwoo Event 钓鱼活动 +manwoo.quest 31 How many different items should 玩家可以获得 +manwoo.quest 32 the player receive as a reward? Max = 4 几种奖励物品?最多4种 +manwoo.quest 34 cancel 取消 +manwoo.quest 47 Manwoo Event 钓鱼活动 +manwoo.quest 48 Please input the item vnum that will be given (Reward 请输入奖励物品的编号(奖励 +manwoo.quest 50 Manwoo Event 钓鱼活动 +manwoo.quest 52 You did not put a vnum in there 你没有输入编号 +manwoo.quest 53 Again 重新输入 +manwoo.quest 53 no more items 不再添加 +manwoo.quest 53 cancel 取消 +manwoo.quest 61 That vnum does not exist 没有这个编号的物品 +manwoo.quest 66 ok 确定 +manwoo.quest 66 type again 重新输入 +manwoo.quest 66 cancel 取消 +manwoo.quest 80 Manwoo Event 钓鱼活动 +manwoo.quest 81 For how many hours should the event be on? 活动持续多少小时? +manwoo.quest 82 8 hours 8小时 +manwoo.quest 82 16 hours 16小时 +manwoo.quest 82 24 hours 24小时 +manwoo.quest 82 unlimited 不限时 +manwoo.quest 82 input 手动输入 +manwoo.quest 82 cancel 取消 +manwoo.quest 104 GM: Stop Fish event GM:结束钓鱼活动 +manwoo.quest 105 Manwoo Event 钓鱼活动 +manwoo.quest 106 stop the event 结束活动 +manwoo.quest 106 cancel 取消 +manwoo.quest 114 Psst, want to help me out? 嘘,愿意帮我个忙吗? +manwoo.quest 117 Fisherman's Event 渔夫的委托 +manwoo.quest 118 Hi, do you know Octavio in the village over there? 你好,你认识那边村子里的孙老板吗? +manwoo.quest 119 He came to me one day with a very attractive business deal. 有一天他来找我,谈了一笔很诱人的生意。 +manwoo.quest 120 As you know, he is one of the most famous cooks in these regions, 你知道,他是这一带最有名的厨师之一, +manwoo.quest 121 and he strives to be the best there is in every cooking mastery. 在厨艺上样样都想做到最好。 +manwoo.quest 122 He has put his attention to sushi, 他最近迷上了做寿司, +manwoo.quest 123 and he claims he needs live fish to make the tastiest sushi. 说要用活鱼才能做出最好吃的寿司。 +manwoo.quest 125 Fisherman's Event 渔夫的委托 +manwoo.quest 126 Of course he doesn't have any time to catch them himself, 他当然没空自己去钓, +manwoo.quest 127 so he asked me to do it for him, for some items he gets from his customers. 就托我替他钓,用客人给他的一些物品作报酬。 +manwoo.quest 128 But I'm a bit stretched at the moment with the amount he needs from me, 可他要的数量太多,我现在有点忙不过来, +manwoo.quest 129 I cannot possibly do it alone. 一个人根本钓不完。 +manwoo.quest 130 If you help me with Octavio's order, 如果你帮我完成孙老板的订单, +manwoo.quest 131 I will give you a nice reward! 我会给你丰厚的奖励! +manwoo.quest 132 Give me this fish: 请给我这种鱼: +manwoo.quest 133 x: 条: +manwoo.quest 150 About the fish... 关于鱼…… +manwoo.quest 151 Fisherman's Event 渔夫的委托 +manwoo.quest 153 You don't have enough fish! 你的鱼不够! +manwoo.quest 155 Hey! You actually managed to do it! 嘿!你真的做到了! +manwoo.quest 156 Thank you! 谢谢你! +manwoo.quest 157 And now... for the reward 现在……这是你的奖励 +manwoo.quest 159 Fisherman's Event 渔夫的委托 +manwoo.quest 173 You don't have enough space! 你的背包空间不够! +manwoo.quest 174 Please, return when you have enough space! 请腾出空间后再来! +new_quest_lv52.quest 17 Yongan 长安城 +new_quest_lv52.quest 17 Joan 咸阳城 +new_quest_lv52.quest 17 Pyongmoo 洛阳城 +new_quest_lv52.quest 148 Yongan 长安城 +new_quest_lv52.quest 148 Joan 咸阳城 +new_quest_lv52.quest 148 Pyongmoo 洛阳城 +new_quest_lv52.quest 355 There is something wrong with the questflag! 任务状态异常! +new_quest_lv52.quest 483 Questflag got manipulated! You shouldn't be here!!! 任务状态被篡改!你不应该出现在这里!!! +forked_road.quest 115 Shinsoo 盛唐国 +forked_road.quest 115 Chunjo 秦皇国 +forked_road.quest 115 Jinno 汉武国 +forked_road.quest 152 1> min 1> 最低 +forked_road.quest 152 max 最高 +forked_road.quest 153 2> min 2> 最低 +forked_road.quest 153 max 最高 +forked_road.quest 154 3> min 3> 最低 +forked_road.quest 154 max 最高 +forked_road.quest 155 4> min 4> 最低 +forked_road.quest 155 max 最高 +forked_road.quest 156 input number 请输入数字 +forked_road.quest 157 select player's level who will join 选择可以参加的玩家等级 +forked_road.quest 160 Invalid number only 1 - 4 are allowed 数字无效,只能输入1到4 +forked_road.quest 164 max level: 最高等级: +forked_road.quest 192 Event Started !! 活动开始了!! +harvest_festival.quest 251 Harvest Event Commands 丰收节活动管理 +harvest_festival.quest 255 Current Status: ThanksGiving Event Results 当前状态:丰收节活动结果 +harvest_festival.quest 258 Start Event 开始活动 +harvest_festival.quest 258 Cancel 取消 +harvest_festival.quest 264 Current Status: The event is currently active 当前状态:活动进行中 +harvest_festival.quest 266 Stop the Event 结束活动 +harvest_festival.quest 266 Cancel 取消 +pre_event_heavens_cave.quest 11 Pre-Event Helper Script 天界洞预热活动辅助脚本 +pre_event_heavens_cave.quest 15 Warning! 警告! +pre_event_heavens_cave.quest 16 This dialog is not part of the Heavens Cave Pre-Event!!! 此对话不属于天界洞预热活动!!! +pre_event_heavens_cave.quest 17 It's purpose is to help in the testing of the event. Only run the script ONCE PER SERVER because it automaticly starts the event which should only be done 1 time! 它用于协助测试活动。每个服务器只能运行一次,因为它会自动开始活动,而活动只应开始一次! +pre_event_heavens_cave.quest 18 You may use it to resets - using Stop and then Start - every variable to its default value. It only resets variable concerning the event and not your character's variables. 你可以先结束再开始,把所有变量重置为默认值。它只重置与活动相关的变量,不会重置你角色的变量。 +pre_event_heavens_cave.quest 19 The tickets related to this event are: 0030149, 0030150 and 0031479. 与此活动相关的入场券为:0030149、0030150和0031479。 +pre_event_heavens_cave.quest 20 Have Fun! 祝你玩得开心! +pre_event_heavens_cave.quest 23 Start the Event 开始活动 +pre_event_heavens_cave.quest 23 Stop the Event 结束活动 +pre_event_heavens_cave.quest 23 Close 关闭 +questlib.lua 1782 input number 请输入数字 diff --git a/scripts/build_zh_quest_inline.py b/scripts/build_zh_quest_inline.py new file mode 100644 index 00000000..7ad256b1 --- /dev/null +++ b/scripts/build_zh_quest_inline.py @@ -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 "" exactly; it becomes "" 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 +""" + +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()