diff --git a/docs/CHANGELOG.md b/docs/CHANGELOG.md index e3a8fc1..4e7ea16 100644 --- a/docs/CHANGELOG.md +++ b/docs/CHANGELOG.md @@ -18,6 +18,8 @@ - Common command usage errors now stay in the session language, and bare `:search`, `:msg`, and `:nick` show usage instead of falling through to unknown-command guidance. +- Command output text for common interactive commands is now centralized in + the i18n table instead of being scattered through command flow logic. ### Changed - NORMAL mode now opens at the latest visible messages instead of the oldest diff --git a/include/i18n.h b/include/i18n.h index cf072f3..aa7fa15 100644 --- a/include/i18n.h +++ b/include/i18n.h @@ -15,7 +15,26 @@ typedef enum { I18N_HELP_STATUS_FORMAT, I18N_COMMAND_OUTPUT_TITLE, I18N_MOTD_TITLE, - I18N_MOTD_CONTINUE_HINT + I18N_MOTD_CONTINUE_HINT, + I18N_USERS_TITLE, + I18N_MSG_USAGE, + I18N_MSG_SENT_FORMAT, + I18N_MSG_USER_NOT_FOUND_FORMAT, + I18N_INBOX_TITLE, + I18N_INBOX_EMPTY, + I18N_NICK_USAGE, + I18N_NICK_INVALID, + I18N_NICK_TAKEN_FORMAT, + I18N_NICK_UNCHANGED, + I18N_NICK_CHANGED_FORMAT, + I18N_LAST_USAGE, + I18N_LAST_HEADER_FORMAT, + I18N_SEARCH_USAGE, + I18N_SEARCH_HEADER_FORMAT, + I18N_MUTE_JOINS_FORMAT, + I18N_MUTE_JOINS_MUTED, + I18N_MUTE_JOINS_UNMUTED, + I18N_CLEAR_DONE } i18n_text_id_t; bool i18n_try_parse_lang(const char *value, help_lang_t *lang); diff --git a/src/commands.c b/src/commands.c index 41b6f1c..e872b9c 100644 --- a/src/commands.c +++ b/src/commands.c @@ -193,15 +193,9 @@ void commands_dispatch(client_t *client) { strcmp(cmd, "who") == 0) { pthread_rwlock_rdlock(&g_room->lock); int total = g_room->client_count; - if (client->help_lang == LANG_ZH) { - buffer_appendf(output, sizeof(output), &pos, - "\033[1;36m在线用户\033[0m " - "\033[2;37m· %d\033[0m\n", total); - } else { - buffer_appendf(output, sizeof(output), &pos, - "\033[1;36mOnline users\033[0m " - "\033[2;37m· %d\033[0m\n", total); - } + buffer_appendf(output, sizeof(output), &pos, + "\033[1;36m%s\033[0m \033[2;37m· %d\033[0m\n", + i18n_text(client->help_lang, I18N_USERS_TITLE), total); time_t now = time(NULL); for (int i = 0; i < total; i++) { @@ -290,15 +284,8 @@ void commands_dispatch(client_t *client) { while (*rest == ' ') rest++; if (target_name[0] == '\0' || rest[0] == '\0') { - if (client->help_lang == LANG_ZH) { - buffer_appendf(output, sizeof(output), &pos, - "用法: msg <用户名> <消息>\n" - " w <用户名> <消息>\n"); - } else { - buffer_appendf(output, sizeof(output), &pos, - "Usage: msg \n" - " w \n"); - } + buffer_appendf(output, sizeof(output), &pos, "%s", + i18n_text(client->help_lang, I18N_MSG_USAGE)); } else { bool found = false; client_t *target = NULL; @@ -345,21 +332,15 @@ void commands_dispatch(client_t *client) { } if (found) { - if (client->help_lang == LANG_ZH) { - buffer_appendf(output, sizeof(output), &pos, - "悄悄话已发送给 %s\n", target_name); - } else { - buffer_appendf(output, sizeof(output), &pos, - "Whisper sent to %s\n", target_name); - } + buffer_appendf(output, sizeof(output), &pos, + i18n_text(client->help_lang, + I18N_MSG_SENT_FORMAT), + target_name); } else { - if (client->help_lang == LANG_ZH) { - buffer_appendf(output, sizeof(output), &pos, - "未找到用户 '%s'\n", target_name); - } else { - buffer_appendf(output, sizeof(output), &pos, - "User '%s' not found\n", target_name); - } + buffer_appendf(output, sizeof(output), &pos, + i18n_text(client->help_lang, + I18N_MSG_USER_NOT_FOUND_FORMAT), + target_name); } } @@ -375,20 +356,14 @@ void commands_dispatch(client_t *client) { pthread_mutex_unlock(&client->io_lock); client->unread_whispers = 0; - if (client->help_lang == LANG_ZH) { - buffer_appendf(output, sizeof(output), &pos, - "\033[1;36m悄悄话\033[0m " - "\033[2;37m· %d\033[0m\n", snap_count); - } else { - buffer_appendf(output, sizeof(output), &pos, - "\033[1;36mWhispers\033[0m " - "\033[2;37m· %d\033[0m\n", snap_count); - } + buffer_appendf(output, sizeof(output), &pos, + "\033[1;36m%s\033[0m \033[2;37m· %d\033[0m\n", + i18n_text(client->help_lang, I18N_INBOX_TITLE), + snap_count); if (snap_count == 0) { buffer_appendf(output, sizeof(output), &pos, - client->help_lang == LANG_ZH ? - " \033[2;37m(空)\033[0m\n" : - " \033[2;37m(empty)\033[0m\n"); + " \033[2;37m%s\033[0m\n", + i18n_text(client->help_lang, I18N_INBOX_EMPTY)); } for (int i = 0; i < snap_count; i++) { char ts[20]; @@ -406,15 +381,11 @@ void commands_dispatch(client_t *client) { while (*new_name == ' ') new_name++; if (new_name[0] == '\0') { - buffer_appendf(output, sizeof(output), &pos, - client->help_lang == LANG_ZH ? - "用法: nick <新用户名>\n" : - "Usage: nick \n"); + buffer_appendf(output, sizeof(output), &pos, "%s", + i18n_text(client->help_lang, I18N_NICK_USAGE)); } else if (!is_valid_username(new_name)) { - buffer_appendf(output, sizeof(output), &pos, - client->help_lang == LANG_ZH ? - "用户名无效\n" : - "Invalid username\n"); + buffer_appendf(output, sizeof(output), &pos, "%s", + i18n_text(client->help_lang, I18N_NICK_INVALID)); } else { char validated_name[MAX_USERNAME_LEN]; snprintf(validated_name, sizeof(validated_name), "%s", new_name); @@ -445,20 +416,14 @@ void commands_dispatch(client_t *client) { pthread_rwlock_unlock(&g_room->lock); if (taken) { - if (client->help_lang == LANG_ZH) { - buffer_appendf(output, sizeof(output), &pos, - "昵称 '%s' 已被使用\n", - validated_name); - } else { - buffer_appendf(output, sizeof(output), &pos, - "Nickname '%s' is already taken\n", - validated_name); - } - } else if (strcmp(validated_name, old_name) == 0) { buffer_appendf(output, sizeof(output), &pos, - client->help_lang == LANG_ZH ? - "昵称未变化\n" : - "Nickname unchanged\n"); + i18n_text(client->help_lang, + I18N_NICK_TAKEN_FORMAT), + validated_name); + } else if (strcmp(validated_name, old_name) == 0) { + buffer_appendf(output, sizeof(output), &pos, "%s", + i18n_text(client->help_lang, + I18N_NICK_UNCHANGED)); } else { message_t nick_msg = { .timestamp = time(NULL) }; snprintf(nick_msg.username, MAX_USERNAME_LEN, "系统"); @@ -467,15 +432,10 @@ void commands_dispatch(client_t *client) { room_broadcast(g_room, &nick_msg); message_save(&nick_msg); - if (client->help_lang == LANG_ZH) { - buffer_appendf(output, sizeof(output), &pos, - "昵称已修改: %s -> %s\n", - old_name, client->username); - } else { - buffer_appendf(output, sizeof(output), &pos, - "Nickname changed: %s -> %s\n", - old_name, client->username); - } + buffer_appendf(output, sizeof(output), &pos, + i18n_text(client->help_lang, + I18N_NICK_CHANGED_FORMAT), + old_name, client->username); } } @@ -487,10 +447,8 @@ void commands_dispatch(client_t *client) { char *endp; long val = strtol(arg, &endp, 10); if (*endp != '\0' || val < 1 || val > 50) { - buffer_appendf(output, sizeof(output), &pos, - client->help_lang == LANG_ZH ? - "用法: last [N] (N: 1-50,默认 10)\n" : - "Usage: last [N] (N: 1-50, default 10)\n"); + buffer_appendf(output, sizeof(output), &pos, "%s", + i18n_text(client->help_lang, I18N_LAST_USAGE)); goto cmd_done; } n = (int)val; @@ -498,13 +456,9 @@ void commands_dispatch(client_t *client) { message_t *last_msgs = NULL; int last_count = message_load(&last_msgs, n); - if (client->help_lang == LANG_ZH) { - buffer_appendf(output, sizeof(output), &pos, - "--- 最近 %d 条消息 ---\n", last_count); - } else { - buffer_appendf(output, sizeof(output), &pos, - "--- Last %d message(s) ---\n", last_count); - } + buffer_appendf(output, sizeof(output), &pos, + i18n_text(client->help_lang, I18N_LAST_HEADER_FORMAT), + last_count); for (int i = 0; i < last_count; i++) { char ts[20]; struct tm tmi; @@ -519,22 +473,15 @@ void commands_dispatch(client_t *client) { char *query = cmd + 6; while (*query == ' ') query++; if (*query == '\0') { - buffer_appendf(output, sizeof(output), &pos, - client->help_lang == LANG_ZH ? - "用法: search <关键词>\n" : - "Usage: search \n"); + buffer_appendf(output, sizeof(output), &pos, "%s", + i18n_text(client->help_lang, I18N_SEARCH_USAGE)); } else { message_t *found = NULL; int found_count = message_search(query, &found, 15); - if (client->help_lang == LANG_ZH) { - buffer_appendf(output, sizeof(output), &pos, - "--- 搜索: \"%s\" (%d 条匹配) ---\n", - query, found_count); - } else { - buffer_appendf(output, sizeof(output), &pos, - "--- Search: \"%s\" (%d match(es)) ---\n", - query, found_count); - } + buffer_appendf(output, sizeof(output), &pos, + i18n_text(client->help_lang, + I18N_SEARCH_HEADER_FORMAT), + query, found_count); for (int i = 0; i < found_count; i++) { char ts[20]; struct tm tmi; @@ -554,15 +501,12 @@ void commands_dispatch(client_t *client) { } else if (strcmp(cmd, "mute-joins") == 0 || strcmp(cmd, "mute") == 0) { client->mute_joins = !client->mute_joins; - if (client->help_lang == LANG_ZH) { - buffer_appendf(output, sizeof(output), &pos, - "加入/离开提示: %s\n", - client->mute_joins ? "已静音" : "已开启"); - } else { - buffer_appendf(output, sizeof(output), &pos, - "Join/leave notifications: %s\n", - client->mute_joins ? "muted" : "unmuted"); - } + buffer_appendf(output, sizeof(output), &pos, + i18n_text(client->help_lang, I18N_MUTE_JOINS_FORMAT), + i18n_text(client->help_lang, + client->mute_joins ? + I18N_MUTE_JOINS_MUTED : + I18N_MUTE_JOINS_UNMUTED)); } else if (strcmp(cmd, "q") == 0 || strcmp(cmd, "quit") == 0 || strcmp(cmd, "exit") == 0) { @@ -570,10 +514,8 @@ void commands_dispatch(client_t *client) { return; } else if (strcmp(cmd, "clear") == 0 || strcmp(cmd, "cls") == 0) { - buffer_appendf(output, sizeof(output), &pos, - client->help_lang == LANG_ZH ? - "命令输出已清空\n" : - "Command output cleared\n"); + buffer_appendf(output, sizeof(output), &pos, "%s", + i18n_text(client->help_lang, I18N_CLEAR_DONE)); } else if (cmd[0] == '\0') { /* Empty command */ diff --git a/src/i18n.c b/src/i18n.c index e5a1118..961e625 100644 --- a/src/i18n.c +++ b/src/i18n.c @@ -95,6 +95,45 @@ const char *i18n_text(help_lang_t lang, i18n_text_id_t id) { return " 公告 "; case I18N_MOTD_CONTINUE_HINT: return " 按任意键继续 "; + case I18N_USERS_TITLE: + return "在线用户"; + case I18N_MSG_USAGE: + return "用法: msg <用户名> <消息>\n" + " w <用户名> <消息>\n"; + case I18N_MSG_SENT_FORMAT: + return "悄悄话已发送给 %s\n"; + case I18N_MSG_USER_NOT_FOUND_FORMAT: + return "未找到用户 '%s'\n"; + case I18N_INBOX_TITLE: + return "悄悄话"; + case I18N_INBOX_EMPTY: + return "(空)"; + case I18N_NICK_USAGE: + return "用法: nick <新用户名>\n"; + case I18N_NICK_INVALID: + return "用户名无效\n"; + case I18N_NICK_TAKEN_FORMAT: + return "昵称 '%s' 已被使用\n"; + case I18N_NICK_UNCHANGED: + return "昵称未变化\n"; + case I18N_NICK_CHANGED_FORMAT: + return "昵称已修改: %s -> %s\n"; + case I18N_LAST_USAGE: + return "用法: last [N] (N: 1-50,默认 10)\n"; + case I18N_LAST_HEADER_FORMAT: + return "--- 最近 %d 条消息 ---\n"; + case I18N_SEARCH_USAGE: + return "用法: search <关键词>\n"; + case I18N_SEARCH_HEADER_FORMAT: + return "--- 搜索: \"%s\" (%d 条匹配) ---\n"; + case I18N_MUTE_JOINS_FORMAT: + return "加入/离开提示: %s\n"; + case I18N_MUTE_JOINS_MUTED: + return "已静音"; + case I18N_MUTE_JOINS_UNMUTED: + return "已开启"; + case I18N_CLEAR_DONE: + return "命令输出已清空\n"; } } @@ -123,6 +162,45 @@ const char *i18n_text(help_lang_t lang, i18n_text_id_t id) { return " NOTICE "; case I18N_MOTD_CONTINUE_HINT: return " Press any key "; + case I18N_USERS_TITLE: + return "Online users"; + case I18N_MSG_USAGE: + return "Usage: msg \n" + " w \n"; + case I18N_MSG_SENT_FORMAT: + return "Whisper sent to %s\n"; + case I18N_MSG_USER_NOT_FOUND_FORMAT: + return "User '%s' not found\n"; + case I18N_INBOX_TITLE: + return "Whispers"; + case I18N_INBOX_EMPTY: + return "(empty)"; + case I18N_NICK_USAGE: + return "Usage: nick \n"; + case I18N_NICK_INVALID: + return "Invalid username\n"; + case I18N_NICK_TAKEN_FORMAT: + return "Nickname '%s' is already taken\n"; + case I18N_NICK_UNCHANGED: + return "Nickname unchanged\n"; + case I18N_NICK_CHANGED_FORMAT: + return "Nickname changed: %s -> %s\n"; + case I18N_LAST_USAGE: + return "Usage: last [N] (N: 1-50, default 10)\n"; + case I18N_LAST_HEADER_FORMAT: + return "--- Last %d message(s) ---\n"; + case I18N_SEARCH_USAGE: + return "Usage: search \n"; + case I18N_SEARCH_HEADER_FORMAT: + return "--- Search: \"%s\" (%d match(es)) ---\n"; + case I18N_MUTE_JOINS_FORMAT: + return "Join/leave notifications: %s\n"; + case I18N_MUTE_JOINS_MUTED: + return "muted"; + case I18N_MUTE_JOINS_UNMUTED: + return "unmuted"; + case I18N_CLEAR_DONE: + return "Command output cleared\n"; } return ""; diff --git a/tests/unit/test_i18n.c b/tests/unit/test_i18n.c index 4f799b8..9fcab6e 100644 --- a/tests/unit/test_i18n.c +++ b/tests/unit/test_i18n.c @@ -74,6 +74,14 @@ TEST(text_lookup_matches_language) { "Press any key") != NULL); assert(strstr(i18n_text(LANG_ZH, I18N_MOTD_CONTINUE_HINT), "按任意键") != NULL); + assert(strstr(i18n_text(LANG_EN, I18N_MSG_USAGE), + "msg ") != NULL); + assert(strstr(i18n_text(LANG_ZH, I18N_MSG_USAGE), + "用户名") != NULL); + assert(strstr(i18n_text(LANG_EN, I18N_SEARCH_HEADER_FORMAT), + "Search") != NULL); + assert(strstr(i18n_text(LANG_ZH, I18N_SEARCH_HEADER_FORMAT), + "搜索") != NULL); assert(strcmp(i18n_lang_code(LANG_EN), "en") == 0); assert(strcmp(i18n_lang_code(LANG_ZH), "zh") == 0); }