From f196bfaf6d4fa358bb663dbbbbd56999823e8581 Mon Sep 17 00:00:00 2001 From: m1ngsama Date: Sun, 24 May 2026 16:10:44 +0800 Subject: [PATCH] cli: use shared localized string helper --- docs/CHANGELOG.md | 2 + src/cli_text.c | 90 ++++++++++++++++++++------------------ tests/unit/test_cli_text.c | 7 +++ 3 files changed, 56 insertions(+), 43 deletions(-) diff --git a/docs/CHANGELOG.md b/docs/CHANGELOG.md index 2d7dad5..056fe94 100644 --- a/docs/CHANGELOG.md +++ b/docs/CHANGELOG.md @@ -58,6 +58,8 @@ manual, and usage text instead of per-field English/Chinese members. - `exec_catalog` now uses the same localized-string helper for exec help summaries. +- Startup CLI help and option error formats now use the shared + localized-string helper and English fallback path. - 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/src/cli_text.c b/src/cli_text.c index 6c2802f..41be3c2 100644 --- a/src/cli_text.c +++ b/src/cli_text.c @@ -1,62 +1,66 @@ #include "cli_text.h" +#include "i18n.h" + void cli_text_append_help(char *buffer, size_t buf_size, size_t *pos, const char *program_name, ui_lang_t lang) { + static const i18n_string_t help_format = I18N_STRING( + "tnt %s - anonymous SSH chat server\n\n" + "Usage: %s [options]\n\n" + "Options:\n" + " -p, --port PORT Listen on PORT (default: %d)\n" + " -d, --state-dir DIR Store host key and logs in DIR\n" + " -V, --version Show version\n" + " -h, --help Show this help\n" + "\n" + "Environment:\n" + " PORT Default listening port\n" + " TNT_STATE_DIR State directory\n" + " TNT_ACCESS_TOKEN Require this password for SSH auth\n" + " TNT_LANG UI language: en or zh (default: locale)\n" + " TNT_MAX_CONNECTIONS Global connection limit (default: 64)\n" + " TNT_RATE_LIMIT Set to 0 to disable rate limiting\n" + " TNT_IDLE_TIMEOUT Idle disconnect timeout in seconds (default: 1800)\n", + "tnt %s - 匿名 SSH 聊天服务器\n\n" + "用法: %s [options]\n\n" + "选项:\n" + " -p, --port PORT 监听 PORT (默认: %d)\n" + " -d, --state-dir DIR 将主机密钥和日志存放在 DIR\n" + " -V, --version 显示版本\n" + " -h, --help 显示此帮助\n" + "\n" + "环境变量:\n" + " PORT 默认监听端口\n" + " TNT_STATE_DIR 状态目录\n" + " TNT_ACCESS_TOKEN 要求 SSH 认证使用此密码\n" + " TNT_LANG UI 语言: en 或 zh (默认跟随 locale)\n" + " TNT_MAX_CONNECTIONS 全局连接数限制 (默认: 64)\n" + " TNT_RATE_LIMIT 设为 0 可禁用速率限制\n" + " TNT_IDLE_TIMEOUT 空闲断开时间,单位秒 (默认: 1800)\n" + ); const char *program = (program_name && program_name[0] != '\0') ? program_name : "tnt"; - if (lang == UI_LANG_ZH) { - buffer_appendf(buffer, buf_size, pos, - "tnt %s - 匿名 SSH 聊天服务器\n\n" - "用法: %s [options]\n\n" - "选项:\n" - " -p, --port PORT 监听 PORT (默认: %d)\n" - " -d, --state-dir DIR 将主机密钥和日志存放在 DIR\n" - " -V, --version 显示版本\n" - " -h, --help 显示此帮助\n" - "\n" - "环境变量:\n" - " PORT 默认监听端口\n" - " TNT_STATE_DIR 状态目录\n" - " TNT_ACCESS_TOKEN 要求 SSH 认证使用此密码\n" - " TNT_LANG UI 语言: en 或 zh (默认跟随 locale)\n" - " TNT_MAX_CONNECTIONS 全局连接数限制 (默认: 64)\n" - " TNT_RATE_LIMIT 设为 0 可禁用速率限制\n" - " TNT_IDLE_TIMEOUT 空闲断开时间,单位秒 (默认: 1800)\n", - TNT_VERSION, program, DEFAULT_PORT); - return; - } - - buffer_appendf(buffer, buf_size, pos, - "tnt %s - anonymous SSH chat server\n\n" - "Usage: %s [options]\n\n" - "Options:\n" - " -p, --port PORT Listen on PORT (default: %d)\n" - " -d, --state-dir DIR Store host key and logs in DIR\n" - " -V, --version Show version\n" - " -h, --help Show this help\n" - "\n" - "Environment:\n" - " PORT Default listening port\n" - " TNT_STATE_DIR State directory\n" - " TNT_ACCESS_TOKEN Require this password for SSH auth\n" - " TNT_LANG UI language: en or zh (default: locale)\n" - " TNT_MAX_CONNECTIONS Global connection limit (default: 64)\n" - " TNT_RATE_LIMIT Set to 0 to disable rate limiting\n" - " TNT_IDLE_TIMEOUT Idle disconnect timeout in seconds (default: 1800)\n", + buffer_appendf(buffer, buf_size, pos, i18n_string(help_format, lang), TNT_VERSION, program, DEFAULT_PORT); } const char *cli_text_invalid_port_format(ui_lang_t lang) { - return lang == UI_LANG_ZH ? "端口无效: %s\n" : "Invalid port: %s\n"; + static const i18n_string_t text = + I18N_STRING("Invalid port: %s\n", "端口无效: %s\n"); + return i18n_string(text, lang); } const char *cli_text_unknown_option_format(ui_lang_t lang) { - return lang == UI_LANG_ZH ? "未知选项: %s\n" : "Unknown option: %s\n"; + static const i18n_string_t text = + I18N_STRING("Unknown option: %s\n", "未知选项: %s\n"); + return i18n_string(text, lang); } const char *cli_text_short_usage_format(ui_lang_t lang) { - return lang == UI_LANG_ZH ? "用法: %s [-p PORT] [-d DIR] [-h]\n" - : "Usage: %s [-p PORT] [-d DIR] [-h]\n"; + static const i18n_string_t text = + I18N_STRING("Usage: %s [-p PORT] [-d DIR] [-h]\n", + "用法: %s [-p PORT] [-d DIR] [-h]\n"); + return i18n_string(text, lang); } diff --git a/tests/unit/test_cli_text.c b/tests/unit/test_cli_text.c index 048f504..2cb708f 100644 --- a/tests/unit/test_cli_text.c +++ b/tests/unit/test_cli_text.c @@ -24,6 +24,11 @@ TEST(help_matches_language) { assert(strstr(output, "Usage: tnt [options]") != NULL); assert(strstr(output, "TNT_LANG") != NULL); + memset(output, 0, sizeof(output)); + pos = 0; + cli_text_append_help(output, sizeof(output), &pos, "", (ui_lang_t)99); + assert(strstr(output, "Usage: tnt [options]") != NULL); + memset(output, 0, sizeof(output)); pos = 0; cli_text_append_help(output, sizeof(output), &pos, "tnt", UI_LANG_ZH); @@ -46,6 +51,8 @@ TEST(error_formats_match_language) { "Usage: %s [-p PORT] [-d DIR] [-h]\n") == 0); assert(strcmp(cli_text_short_usage_format(UI_LANG_ZH), "用法: %s [-p PORT] [-d DIR] [-h]\n") == 0); + assert(strcmp(cli_text_invalid_port_format((ui_lang_t)99), + "Invalid port: %s\n") == 0); } int main(void) {