diff --git a/docs/CHANGELOG.md b/docs/CHANGELOG.md index 4a139da..0a3204b 100644 --- a/docs/CHANGELOG.md +++ b/docs/CHANGELOG.md @@ -46,6 +46,8 @@ - Language selection is limited to stable codes (`en`, `zh`) and locale-shaped environment values; natural-language labels are not accepted as command arguments. +- Full-screen help now uses `l` to cycle the UI language through the i18n + module instead of hard-coding one key per language. - Documented i18n and user-facing text rules for English-first source text, stable command syntax, concise help copy, and translation-only localization. diff --git a/include/i18n.h b/include/i18n.h index b6c105b..986f99f 100644 --- a/include/i18n.h +++ b/include/i18n.h @@ -58,6 +58,7 @@ typedef enum { bool i18n_try_parse_ui_lang(const char *value, ui_lang_t *lang); ui_lang_t i18n_parse_ui_lang(const char *value, ui_lang_t fallback); ui_lang_t i18n_default_ui_lang(void); +ui_lang_t i18n_next_ui_lang(ui_lang_t lang); const char *i18n_ui_lang_code(ui_lang_t lang); const char *i18n_text(ui_lang_t lang, i18n_text_id_t id); diff --git a/src/help_text.c b/src/help_text.c index 13ec3e1..797f1ae 100644 --- a/src/help_text.c +++ b/src/help_text.c @@ -56,7 +56,7 @@ void help_text_append_full(char *buffer, size_t buf_size, size_t *pos, " Ctrl+D/U - Scroll half page down/up\n" " Ctrl+F/B - Scroll full page down/up\n" " g/G - Jump to top/bottom\n" - " e/z - Switch English/Chinese\n"); + " l - Cycle UI language\n"); return; } @@ -111,5 +111,5 @@ void help_text_append_full(char *buffer, size_t buf_size, size_t *pos, " Ctrl+D/U - 向下/上滚动半页\n" " Ctrl+F/B - 向下/上滚动整页\n" " g/G - 跳到顶部/底部\n" - " e/z - 切换英文/中文\n"); + " l - 切换界面语言\n"); } diff --git a/src/i18n.c b/src/i18n.c index 38b3a3d..2999be8 100644 --- a/src/i18n.c +++ b/src/i18n.c @@ -81,6 +81,10 @@ ui_lang_t i18n_default_ui_lang(void) { return i18n_parse_ui_lang(locale, UI_LANG_EN); } +ui_lang_t i18n_next_ui_lang(ui_lang_t lang) { + return lang == UI_LANG_EN ? UI_LANG_ZH : UI_LANG_EN; +} + const char *i18n_ui_lang_code(ui_lang_t lang) { return lang == UI_LANG_ZH ? "zh" : "en"; } diff --git a/src/i18n_text.c b/src/i18n_text.c index 8568163..cfe5368 100644 --- a/src/i18n_text.c +++ b/src/i18n_text.c @@ -51,8 +51,8 @@ static const i18n_text_entry_t text_catalog[I18N_TEXT_COUNT] = { " 按键 " }, [I18N_HELP_STATUS_FORMAT] = { - "-- KEY REFERENCE -- (%d/%d) j/k:scroll g/G:top/bottom e/z:lang q:close", - "-- 按键参考 -- (%d/%d) j/k:滚动 g/G:首尾 e/z:语言 q:关闭" + "-- KEY REFERENCE -- (%d/%d) j/k:scroll g/G:top/bottom l:lang q:close", + "-- 按键参考 -- (%d/%d) j/k:滚动 g/G:首尾 l:语言 q:关闭" }, [I18N_COMMAND_OUTPUT_TITLE] = { " COMMAND OUTPUT ", diff --git a/src/input.c b/src/input.c index 6172a5f..9468053 100644 --- a/src/input.c +++ b/src/input.c @@ -257,12 +257,8 @@ static bool handle_key(client_t *client, unsigned char key, char *input) { if (key == 'q' || key == 27) { client->show_help = false; tui_render_screen(client); - } else if (key == 'e' || key == 'E') { - client->ui_lang = UI_LANG_EN; - client->help_scroll_pos = 0; - tui_render_help(client); - } else if (key == 'z' || key == 'Z') { - client->ui_lang = UI_LANG_ZH; + } else if (key == 'l' || key == 'L') { + client->ui_lang = i18n_next_ui_lang(client->ui_lang); client->help_scroll_pos = 0; tui_render_help(client); } else if (key == 'j') { diff --git a/tests/test_interactive_input.sh b/tests/test_interactive_input.sh index 54aa175..cc457e4 100755 --- a/tests/test_interactive_input.sh +++ b/tests/test_interactive_input.sh @@ -149,6 +149,14 @@ expect "TNT\\(1\\) 帮助" expect "q:关闭" send -- "q" expect "NORMAL" +send -- "?" +expect "TNT 按键参考" +expect "l:语言" +send -- "l" +expect "TNT KEY REFERENCE" +expect "l:lang" +send -- "q" +expect "NORMAL" send -- ":" expect ":" send -- "lang en\r" diff --git a/tests/unit/test_help_text.c b/tests/unit/test_help_text.c index 7589746..acb4129 100644 --- a/tests/unit/test_help_text.c +++ b/tests/unit/test_help_text.c @@ -31,7 +31,8 @@ TEST(full_help_matches_language) { assert(strstr(en, ":inbox") != NULL); assert(strstr(en, ":support") == NULL); assert(strstr(en, ":commands") == NULL); - assert(strstr(en, "Switch English/Chinese") != NULL); + assert(strstr(en, "Cycle UI language") != NULL); + assert(strstr(en, "Switch English/Chinese") == NULL); assert(strstr(zh, "TNT 按键参考") != NULL); assert(strstr(zh, "可用命令") != NULL); @@ -43,7 +44,8 @@ TEST(full_help_matches_language) { assert(strstr(zh, "@用户名") == NULL); assert(strstr(zh, ":support") == NULL); assert(strstr(zh, ":commands") == NULL); - assert(strstr(zh, "切换英文/中文") != NULL); + assert(strstr(zh, "切换界面语言") != NULL); + assert(strstr(zh, "切换英文/中文") == NULL); assert_ascii_angle_placeholders(zh); } diff --git a/tests/unit/test_i18n.c b/tests/unit/test_i18n.c index 5cd4e78..fa7baef 100644 --- a/tests/unit/test_i18n.c +++ b/tests/unit/test_i18n.c @@ -89,8 +89,12 @@ TEST(text_lookup_matches_language) { "匿名聊天室") != NULL); assert(strstr(i18n_text(UI_LANG_EN, I18N_HELP_STATUS_FORMAT), "KEY REFERENCE") != NULL); + assert(strstr(i18n_text(UI_LANG_EN, I18N_HELP_STATUS_FORMAT), + "l:lang") != NULL); assert(strstr(i18n_text(UI_LANG_ZH, I18N_HELP_STATUS_FORMAT), "按键参考") != NULL); + assert(strstr(i18n_text(UI_LANG_ZH, I18N_HELP_STATUS_FORMAT), + "l:语言") != NULL); assert(strstr(i18n_text(UI_LANG_EN, I18N_COMMAND_OUTPUT_TITLE), "COMMAND") != NULL); assert(strstr(i18n_text(UI_LANG_ZH, I18N_COMMAND_OUTPUT_TITLE), @@ -141,6 +145,8 @@ TEST(text_lookup_matches_language) { "未知命令") != NULL); assert(strcmp(i18n_ui_lang_code(UI_LANG_EN), "en") == 0); assert(strcmp(i18n_ui_lang_code(UI_LANG_ZH), "zh") == 0); + assert(i18n_next_ui_lang(UI_LANG_EN) == UI_LANG_ZH); + assert(i18n_next_ui_lang(UI_LANG_ZH) == UI_LANG_EN); } TEST(text_catalog_is_complete) {