i18n: cycle help language with one key

This commit is contained in:
m1ngsama 2026-05-24 15:06:34 +08:00
parent f2942e9c9e
commit 155e535b8a
9 changed files with 31 additions and 12 deletions

View file

@ -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.

View file

@ -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);

View file

@ -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");
}

View file

@ -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";
}

View file

@ -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 ",

View file

@ -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') {

View file

@ -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"

View file

@ -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);
}

View file

@ -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) {