From 666310e7b44c44e4c50c2d7f142ee8797475138c Mon Sep 17 00:00:00 2001 From: bridge Date: Sun, 1 Feb 2026 12:41:47 +0800 Subject: [PATCH] feat: enhance hidden domains with additional properties and UI updates - Updated `HiddenDomainInfo` interface to include `cd_years` and `open_prob` properties for better domain management. - Modified `serialize_active_domains` function to serialize new properties. - Enhanced `StatusWidget` to display additional information about hidden domains, including cooldown years and open probability. - Updated localization files for English and Chinese to reflect new status labels for hidden domains. --- .../locales/zh_CN/LC_MESSAGES/game_configs.mo | Bin 60882 -> 61683 bytes .../locales/zh_CN/LC_MESSAGES/game_configs.po | 104 ++++++++++++++---- src/server/main.py | 4 +- tests/test_i18n_integrity.py | 48 ++++++++ web/src/components/layout/StatusWidget.vue | 63 +++++++++-- web/src/locales/en-US.json | 4 +- web/src/locales/zh-CN.json | 4 +- web/src/types/core.ts | 2 + 8 files changed, 198 insertions(+), 31 deletions(-) create mode 100644 tests/test_i18n_integrity.py diff --git a/src/i18n/locales/zh_CN/LC_MESSAGES/game_configs.mo b/src/i18n/locales/zh_CN/LC_MESSAGES/game_configs.mo index 182077a437c839d35fe3166ef8621370b3dff148..98733d0360477d880587d634549e8788f459b78c 100644 GIT binary patch delta 12414 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 delta 11983 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 b2}b;y9-RO6#o+lHn}V{xy%0?PE%ko^7j(e9 diff --git a/src/i18n/locales/zh_CN/LC_MESSAGES/game_configs.po b/src/i18n/locales/zh_CN/LC_MESSAGES/game_configs.po index 2abc0f4..d94e801 100644 --- a/src/i18n/locales/zh_CN/LC_MESSAGES/game_configs.po +++ b/src/i18n/locales/zh_CN/LC_MESSAGES/game_configs.po @@ -2843,7 +2843,7 @@ msgstr "孔雀翎" msgid "WEAPON_1077_DESC" msgstr "虽然只是暗器,但其美艳不可方物。当它绽放时,便是敌人的死期。" -#. world_info.csv: +#. world_info.csv: 简介 msgid "WORLD_INFO_INTRO_NAME" msgstr "简介" @@ -2851,7 +2851,11 @@ msgstr "简介" msgid "WORLD_INFO_INTRO_DESC" msgstr "这是一个诸多修士竞相修行的修仙世界。" -#. world_info.csv: +#. world_info.csv: 简介 +msgid "WORLD_INFO_INTRO_TITLE" +msgstr "简介" + +#. world_info.csv: 境界 msgid "WORLD_INFO_REALM_NAME" msgstr "境界" @@ -2859,15 +2863,23 @@ msgstr "境界" msgid "WORLD_INFO_REALM_DESC" msgstr "修仙的境界从弱到强:练气、筑基、金丹、元婴。每个境界分前期、中期、后期。境界间差距很大。" -#. world_info.csv: +#. world_info.csv: 境界 +msgid "WORLD_INFO_REALM_TITLE" +msgstr "境界" + +#. world_info.csv: 寿元 msgid "WORLD_INFO_LIFESPAN_NAME" msgstr "寿元" -#. world_info.csv: 每个角色均有寿元上限。在大限将至的前20年身体会逐渐衰弱,有几率老死;一旦达到或超过寿元上限,... +#. world_info.csv: 每个角色均有寿元上限。在大限将至的前20年身体会逐渐衰弱,有几率老死;一旦达到或超过寿元上限,则必死无疑。提升境界和某些宝物、丹药能提高寿元上限。 msgid "WORLD_INFO_LIFESPAN_DESC" msgstr "每个角色均有寿元上限。在大限将至的前20年身体会逐渐衰弱,有几率老死;一旦达到或超过寿元上限,则必死无疑。提升境界和某些宝物、丹药能提高寿元上限。" -#. world_info.csv: +#. world_info.csv: 寿元 +msgid "WORLD_INFO_LIFESPAN_TITLE" +msgstr "寿元" + +#. world_info.csv: 死亡 msgid "WORLD_INFO_DEATH_NAME" msgstr "死亡" @@ -2875,7 +2887,11 @@ msgstr "死亡" msgid "WORLD_INFO_DEATH_DESC" msgstr "HP降至0以下也会死亡。" -#. world_info.csv: +#. world_info.csv: 死亡 +msgid "WORLD_INFO_DEATH_TITLE" +msgstr "死亡" + +#. world_info.csv: 区域 msgid "WORLD_INFO_REGION_NAME" msgstr "区域" @@ -2883,7 +2899,11 @@ msgstr "区域" msgid "WORLD_INFO_REGION_DESC" msgstr "不同区域有不同效果,在适当的区域做适当的事情事半功倍。" -#. world_info.csv: +#. world_info.csv: 区域 +msgid "WORLD_INFO_REGION_TITLE" +msgstr "区域" + +#. world_info.csv: 修炼 msgid "WORLD_INFO_CULTIVATION_NAME" msgstr "修炼" @@ -2891,15 +2911,23 @@ msgstr "修炼" msgid "WORLD_INFO_CULTIVATION_DESC" msgstr "修炼可以增加经验,直到到达突破前的瓶颈。突破是概率事件,突破后会进入下一个境界。" -#. world_info.csv: +#. world_info.csv: 修炼 +msgid "WORLD_INFO_CULTIVATION_TITLE" +msgstr "修炼" + +#. world_info.csv: 灵根 msgid "WORLD_INFO_ROOT_NAME" msgstr "灵根" -#. world_info.csv: 灵根由五行元素(金、木、水、火、土)组成,分为单灵根、双灵根和天灵根。五行相克:金克木,木克土... +#. world_info.csv: 灵根由五行元素(金、木、水、火、土)组成,分为单灵根、双灵根和天灵根。五行相克:金克木,木克土,土克水,水克火,火克金。天灵根包含全部五行元素且突破时有额外加成。在与自身灵根属性匹配的区域修炼效率最高。 msgid "WORLD_INFO_ROOT_DESC" msgstr "灵根由五行元素(金、木、水、火、土)组成,分为单灵根、双灵根和天灵根。五行相克:金克木,木克土,土克水,水克火,火克金。天灵根包含全部五行元素且突破时有额外加成。在与自身灵根属性匹配的区域修炼效率最高。" -#. world_info.csv: +#. world_info.csv: 灵根 +msgid "WORLD_INFO_ROOT_TITLE" +msgstr "灵根" + +#. world_info.csv: 天地灵机 msgid "WORLD_INFO_WORLD_QI_NAME" msgstr "天地灵机" @@ -2907,7 +2935,11 @@ msgstr "天地灵机" msgid "WORLD_INFO_WORLD_QI_DESC" msgstr "世界每隔数年会有一次天象变动(如灵气潮汐),影响角色能力。" -#. world_info.csv: +#. world_info.csv: 天地灵机 +msgid "WORLD_INFO_WORLD_QI_TITLE" +msgstr "天地灵机" + +#. world_info.csv: 灵石 msgid "WORLD_INFO_SPIRIT_STONE_NAME" msgstr "灵石" @@ -2915,7 +2947,11 @@ msgstr "灵石" msgid "WORLD_INFO_SPIRIT_STONE_DESC" msgstr "修仙界的通用货币。可用于购买法宝丹药,通过采集、交易或掠夺获取。" -#. world_info.csv: +#. world_info.csv: 灵石 +msgid "WORLD_INFO_SPIRIT_STONE_TITLE" +msgstr "灵石" + +#. world_info.csv: 宗门 msgid "WORLD_INFO_SECT_NAME" msgstr "宗门" @@ -2923,7 +2959,11 @@ msgstr "宗门" msgid "WORLD_INFO_SECT_DESC" msgstr "修士的庇护所。加入宗门可习得独门功法、获同门庇护;散修自由但资源匮乏。" -#. world_info.csv: +#. world_info.csv: 宗门 +msgid "WORLD_INFO_SECT_TITLE" +msgstr "宗门" + +#. world_info.csv: 战斗 msgid "WORLD_INFO_BATTLE_NAME" msgstr "战斗" @@ -2931,7 +2971,11 @@ msgstr "战斗" msgid "WORLD_INFO_BATTLE_DESC" msgstr "弱肉强食,境界压制极大,高境界者对低境界者有绝对优势。若对方死亡,胜者可掠夺败者财物。" -#. world_info.csv: +#. world_info.csv: 战斗 +msgid "WORLD_INFO_BATTLE_TITLE" +msgstr "战斗" + +#. world_info.csv: 动作 msgid "WORLD_INFO_ACTION_NAME" msgstr "动作" @@ -2939,23 +2983,35 @@ msgstr "动作" msgid "WORLD_INFO_ACTION_DESC" msgstr "你有一系列可以执行的动作。要注意动作的效果、限制条件、区域和时间。" -#. world_info.csv: +#. world_info.csv: 动作 +msgid "WORLD_INFO_ACTION_TITLE" +msgstr "动作" + +#. world_info.csv: 装备与丹药 msgid "WORLD_INFO_EQUIPMENT_AND_ELIXIR_NAME" msgstr "装备与丹药" -#. world_info.csv: 通过兵器、辅助装备、丹药等装备,可以获得额外的属性加成,获得或小或大的增益。拥有好的装备或者服... +#. world_info.csv: 通过兵器、辅助装备、丹药等装备,可以获得额外的属性加成,获得或小或大的增益。拥有好的装备或者服用好的丹药,能获得很大好处。 msgid "WORLD_INFO_EQUIPMENT_AND_ELIXIR_DESC" msgstr "通过兵器、辅助装备、丹药等装备,可以获得额外的属性加成,获得或小或大的增益。拥有好的装备或者服用好的丹药,能获得很大好处。" -#. world_info.csv: +#. world_info.csv: 装备与丹药 +msgid "WORLD_INFO_EQUIPMENT_AND_ELIXIR_TITLE" +msgstr "装备与丹药" + +#. world_info.csv: 购物 msgid "WORLD_INFO_SHOPPING_NAME" msgstr "购物" -#. world_info.csv: 在城市区域可以购买练气级别丹药、兵器。购买丹药后会立刻服用强化自身。购买兵器可以帮自己切换兵器... +#. world_info.csv: 在城市区域可以购买练气级别丹药、兵器。购买丹药后会立刻服用强化自身。购买兵器可以帮自己切换兵器类型为顺手的类型。 msgid "WORLD_INFO_SHOPPING_DESC" msgstr "在城市区域可以购买练气级别丹药、兵器。购买丹药后会立刻服用强化自身。购买兵器可以帮自己切换兵器类型为顺手的类型。" -#. world_info.csv: +#. world_info.csv: 购物 +msgid "WORLD_INFO_SHOPPING_TITLE" +msgstr "购物" + +#. world_info.csv: 拍卖会 msgid "WORLD_INFO_AUCTION_NAME" msgstr "拍卖会" @@ -2963,10 +3019,18 @@ msgstr "拍卖会" msgid "WORLD_INFO_AUCTION_DESC" msgstr "每隔一段不确定的时间会有神秘人组织的拍卖会,或许有好货出售。" -#. world_info.csv: +#. world_info.csv: 拍卖会 +msgid "WORLD_INFO_AUCTION_TITLE" +msgstr "拍卖会" + +#. world_info.csv: 秘境 msgid "WORLD_INFO_SECRET_REALM_NAME" msgstr "秘境" #. world_info.csv: 每隔数年会有秘境开启。进入秘境可能遭遇凶险,也可能获得高阶法宝和功法。 msgid "WORLD_INFO_SECRET_REALM_DESC" msgstr "每隔数年会有秘境开启。进入秘境可能遭遇凶险,也可能获得高阶法宝和功法。" + +#. world_info.csv: 秘境 +msgid "WORLD_INFO_SECRET_REALM_TITLE" +msgstr "秘境" diff --git a/src/server/main.py b/src/server/main.py index 945b672..132f8cd 100644 --- a/src/server/main.py +++ b/src/server/main.py @@ -204,7 +204,9 @@ def serialize_active_domains(world: World) -> List[dict]: "max_realm": str(d.max_realm), "danger_prob": d.danger_prob, "drop_prob": d.drop_prob, - "is_open": is_open + "is_open": is_open, + "cd_years": d.cd_years, + "open_prob": d.open_prob }) return domains_data diff --git a/tests/test_i18n_integrity.py b/tests/test_i18n_integrity.py new file mode 100644 index 0000000..2c84e82 --- /dev/null +++ b/tests/test_i18n_integrity.py @@ -0,0 +1,48 @@ +import pytest +from src.utils.df import load_game_configs +from src.i18n import t + +def test_all_csv_ids_have_translations(): + """ + 遍历加载的所有游戏配置 CSV,检查所有以 _id 结尾的字段(如 name_id, desc_id, title_id), + 确保它们在中文环境下都有对应的翻译。 + + 如果 t(key) 返回的结果等于 key 本身,且 key 是全大写(典型的 ID 格式),则视为缺失翻译。 + """ + # 1. 加载配置 (force_chinese_language fixture 已经在 session 级别生效) + configs = load_game_configs() + + missing_keys = [] + + # 需要检查的 ID 后缀 + target_suffixes = ('_id', '_ID') + # 一些已知的例外或不需要翻译的字段可以加在这里 + ignored_keys = set() + + # 2. 遍历所有配置表 + for config_name, rows in configs.items(): + if not rows: + continue + + print(f"Checking config: {config_name}.csv ({len(rows)} rows)") + + for i, row in enumerate(rows): + # 遍历行中的所有键值对 + for key, value in row.items(): + # 检查 Key 是否以 _id 结尾 (例如 title_id) + # 并且 Value 是字符串且非空 + if key.lower().endswith("id") and isinstance(value, str) and value.strip(): + # 也可以进一步过滤,例如只检查全大写的 Value,或者特定前缀 + # 这里假设所有需要翻译的 ID 都是全大写且包含下划线 + if value.isupper() and "_" in value: + translated = t(value) + + # 如果翻译结果和原文一样,且原文不是空的,视为缺失 + # 注意:有些 ID 本身就是英文显示(极少),这里主要针对需要转中文的情况 + if translated == value: + missing_keys.append(f"[{config_name}.csv Row {i+1}] {key}={value}") + + # 3. 断言 + if missing_keys: + error_msg = f"Found {len(missing_keys)} missing translations in zh-CN:\n" + "\n".join(missing_keys) + pytest.fail(error_msg) diff --git a/web/src/components/layout/StatusWidget.vue b/web/src/components/layout/StatusWidget.vue index 6f7498c..59a2391 100644 --- a/web/src/components/layout/StatusWidget.vue +++ b/web/src/components/layout/StatusWidget.vue @@ -1,7 +1,10 @@