From 01439507d578dc3d98a6b3172ffc012a0eda5366 Mon Sep 17 00:00:00 2001 From: m1ngsama Date: Sun, 24 May 2026 12:26:16 +0800 Subject: [PATCH] i18n: keep command placeholders locale neutral --- docs/CHANGELOG.md | 2 ++ src/command_catalog.c | 16 ++++++++-------- src/help_text.c | 4 ++-- src/i18n_text.c | 14 +++++++------- tests/test_interactive_input.sh | 6 +++--- tests/unit/test_command_catalog.c | 4 ++++ tests/unit/test_help_text.c | 4 ++++ tests/unit/test_i18n.c | 10 ++++++++-- tests/unit/test_manual_text.c | 2 ++ 9 files changed, 40 insertions(+), 22 deletions(-) diff --git a/docs/CHANGELOG.md b/docs/CHANGELOG.md index 6a5583a..683bd90 100644 --- a/docs/CHANGELOG.md +++ b/docs/CHANGELOG.md @@ -6,6 +6,8 @@ - Split UI-language parsing from localized text lookup: `src/i18n.c` now owns locale/code parsing, while `src/i18n_text.c` owns the table-driven text catalog with coverage checks for every message ID. +- Kept command placeholders stable across localized output: Chinese help and + usage text now uses ASCII metavariables such as `` and ``. - Renamed the internal language state from help-oriented names to UI-language names (`ui_lang_t`, `client->ui_lang`, and `i18n_*_ui_lang`) so future i18n work has a correctly named seam. diff --git a/src/command_catalog.c b/src/command_catalog.c index 8d4cef9..ea316b4 100644 --- a/src/command_catalog.c +++ b/src/command_catalog.c @@ -22,10 +22,10 @@ static const command_catalog_entry_t entries[] = { }, { {TNT_COMMAND_MSG, "msg", {"msg", "w", NULL}, true}, - ":msg , :w ", - ":msg <用户> <文本>, :w <用户> <文本>", - "Whisper to user", "私聊", - ":msg ", ":msg <用户> <文本>", 2 + ":msg , :w ", + ":msg , :w ", + "Send private message", "发送私信", + ":msg ", ":msg ", 2 }, { {TNT_COMMAND_INBOX, "inbox", {"inbox", NULL}, false}, @@ -35,9 +35,9 @@ static const command_catalog_entry_t entries[] = { }, { {TNT_COMMAND_NICK, "nick", {"nick", "name", NULL}, true}, - ":nick , :name ", ":nick <名字>, :name <名字>", + ":nick , :name ", ":nick , :name ", "Change nickname", "更改昵称", - ":nick ", ":nick <名字>", 2 + ":nick ", ":nick ", 2 }, { {TNT_COMMAND_LAST, "last", {"last", NULL}, true}, @@ -47,9 +47,9 @@ static const command_catalog_entry_t entries[] = { }, { {TNT_COMMAND_SEARCH, "search", {"search", NULL}, true}, - ":search ", ":search <关键词>", + ":search ", ":search ", "Search message history", "搜索消息历史", - ":search ", ":search <词>", 1 + ":search ", ":search ", 1 }, { {TNT_COMMAND_MUTE_JOINS, "mute-joins", {"mute-joins", "mute", NULL}, false}, diff --git a/src/help_text.c b/src/help_text.c index 8248aea..13ec3e1 100644 --- a/src/help_text.c +++ b/src/help_text.c @@ -102,8 +102,8 @@ void help_text_append_full(char *buffer, size_t buf_size, size_t *pos, " g/G - 跳到顶部/底部\n" "\n" "特殊消息:\n" - " /me <动作> - 发送动作 (如 /me 挥手)\n" - " @用户名 - 提及用户 (响铃+高亮)\n" + " /me - 发送动作 (如 /me waves)\n" + " @username - 提及用户 (响铃+高亮)\n" "\n" "帮助界面按键:\n" " q, ESC - 关闭帮助\n" diff --git a/src/i18n_text.c b/src/i18n_text.c index 742a969..ed88052 100644 --- a/src/i18n_text.c +++ b/src/i18n_text.c @@ -107,10 +107,10 @@ static const i18n_text_entry_t text_catalog[I18N_TEXT_COUNT] = { "在线用户" }, [I18N_MSG_USAGE] = { - "Usage: msg \n" - " w \n", - "用法: msg <用户名> <消息>\n" - " w <用户名> <消息>\n" + "Usage: msg \n" + " w \n", + "用法: msg \n" + " w \n" }, [I18N_MSG_SENT_FORMAT] = { "Whisper sent to %s\n", @@ -129,8 +129,8 @@ static const i18n_text_entry_t text_catalog[I18N_TEXT_COUNT] = { "(空)" }, [I18N_NICK_USAGE] = { - "Usage: nick \n", - "用法: nick <新用户名>\n" + "Usage: nick \n", + "用法: nick \n" }, [I18N_NICK_INVALID] = { "Invalid username\n", @@ -158,7 +158,7 @@ static const i18n_text_entry_t text_catalog[I18N_TEXT_COUNT] = { }, [I18N_SEARCH_USAGE] = { "Usage: search \n", - "用法: search <关键词>\n" + "用法: search \n" }, [I18N_SEARCH_HEADER_FORMAT] = { "--- Search: \"%s\" (%d match(es)) ---\n", diff --git a/tests/test_interactive_input.sh b/tests/test_interactive_input.sh index 338498e..7ff7d45 100755 --- a/tests/test_interactive_input.sh +++ b/tests/test_interactive_input.sh @@ -266,21 +266,21 @@ expect "NORMAL" send -- ":" expect ":" send -- "search\r" -expect "用法: search <关键词>" +expect "用法: search " expect "q:关闭" send -- "q" expect "NORMAL" send -- ":" expect ":" send -- "msg\r" -expect "用法: msg <用户名> <消息>" +expect "用法: msg " expect "q:关闭" send -- "q" expect "NORMAL" send -- ":" expect ":" send -- "nick\r" -expect "用法: nick <新用户名>" +expect "用法: nick " expect "q:关闭" send -- "q" expect "NORMAL" diff --git a/tests/unit/test_command_catalog.c b/tests/unit/test_command_catalog.c index db05378..3c64e6c 100644 --- a/tests/unit/test_command_catalog.c +++ b/tests/unit/test_command_catalog.c @@ -66,10 +66,14 @@ TEST(generates_localized_help_sections) { assert(strstr(en, ":users, :list, :who") != NULL); assert(strstr(en, "Show online users") != NULL); + assert(strstr(en, ":msg ") != NULL); assert(strstr(en, ":support") == NULL); assert(strstr(zh, ":users, :list, :who") != NULL); assert(strstr(zh, "显示在线用户") != NULL); + assert(strstr(zh, ":msg ") != NULL); + assert(strstr(zh, "<用户>") == NULL); + assert(strstr(zh, "<消息>") == NULL); assert(strstr(zh, ":support") == NULL); } diff --git a/tests/unit/test_help_text.c b/tests/unit/test_help_text.c index af51f6e..1bc3a0d 100644 --- a/tests/unit/test_help_text.c +++ b/tests/unit/test_help_text.c @@ -36,6 +36,10 @@ TEST(full_help_matches_language) { assert(strstr(zh, "可用命令") != NULL); assert(strstr(zh, "命令输出按键") != NULL); assert(strstr(zh, ":inbox") != NULL); + assert(strstr(zh, "/me ") != NULL); + assert(strstr(zh, "@username") != NULL); + assert(strstr(zh, "<动作>") == NULL); + assert(strstr(zh, "@用户名") == NULL); assert(strstr(zh, ":support") == NULL); assert(strstr(zh, ":commands") == NULL); assert(strstr(zh, "切换英文/中文") != NULL); diff --git a/tests/unit/test_i18n.c b/tests/unit/test_i18n.c index b9deecd..90de261 100644 --- a/tests/unit/test_i18n.c +++ b/tests/unit/test_i18n.c @@ -111,13 +111,19 @@ TEST(text_lookup_matches_language) { assert(strstr(i18n_text(UI_LANG_ZH, I18N_IDLE_TIMEOUT_FORMAT), "空闲超时") != NULL); assert(strstr(i18n_text(UI_LANG_EN, I18N_MSG_USAGE), - "msg ") != NULL); + "msg ") != NULL); assert(strstr(i18n_text(UI_LANG_ZH, I18N_MSG_USAGE), - "用户名") != NULL); + "msg ") != NULL); + assert(strstr(i18n_text(UI_LANG_ZH, I18N_MSG_USAGE), + "<用户>") == NULL); + assert(strstr(i18n_text(UI_LANG_ZH, I18N_NICK_USAGE), + "nick ") != NULL); assert(strstr(i18n_text(UI_LANG_EN, I18N_SEARCH_HEADER_FORMAT), "Search") != NULL); assert(strstr(i18n_text(UI_LANG_ZH, I18N_SEARCH_HEADER_FORMAT), "搜索") != NULL); + assert(strstr(i18n_text(UI_LANG_ZH, I18N_SEARCH_USAGE), + "search ") != NULL); assert(strstr(i18n_text(UI_LANG_EN, I18N_LANG_CURRENT_FORMAT), "lang ") != NULL); assert(strstr(i18n_text(UI_LANG_ZH, I18N_LANG_CURRENT_FORMAT), diff --git a/tests/unit/test_manual_text.c b/tests/unit/test_manual_text.c index 4405b77..47b8730 100644 --- a/tests/unit/test_manual_text.c +++ b/tests/unit/test_manual_text.c @@ -52,6 +52,8 @@ TEST(interactive_manual_matches_language) { assert(strstr(zh, "命令") != NULL); assert(strstr(zh, ":lang en|zh") != NULL); assert(strstr(zh, ":mute-joins") != NULL); + assert(strstr(zh, ":msg ") != NULL); + assert(strstr(zh, "<用户>") == NULL); assert(strstr(zh, ":mute-joins, :clear, :q") != NULL); assert(strstr(zh, ":support") == NULL); assert(strstr(zh, ":commands") == NULL);