mirror of
https://github.com/LHY0125/PathEditor.git
synced 2026-05-10 10:19:47 +08:00
feat(i18n): 添加多语言支持功能
- 新增国际化系统,支持中英文切换 - 添加语言选择对话框和语言切换按钮回调 - 扩展配置系统以支持语言设置存储 - 创建语言文件目录结构和占位文件 - 更新主窗口支持UI文本动态刷新
This commit is contained in:
@@ -9,8 +9,10 @@
|
||||
#include "utils/error_code.h"
|
||||
#include "utils/safe_string.h"
|
||||
#include "utils/logger.h"
|
||||
#include "utils/i18n.h"
|
||||
#include "ui/ui_utils.h"
|
||||
#include "ui/dialogs.h"
|
||||
#include "ui/main_window.h"
|
||||
#include <string.h>
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
@@ -574,6 +576,15 @@ void load_all_paths(void)
|
||||
IupSetAttribute(lbl_status, "TITLE", lua_config_get_string("status", "loaded"));
|
||||
}
|
||||
|
||||
// 按钮回调:语言切换
|
||||
int btn_lang_cb(Ihandle *self)
|
||||
{
|
||||
Ihandle *dlg = IupGetDialog(self);
|
||||
language_select_dialog();
|
||||
refresh_main_window_ui(dlg);
|
||||
return IUP_DEFAULT;
|
||||
}
|
||||
|
||||
// 按钮回调:帮助
|
||||
int btn_help_cb(Ihandle *self)
|
||||
{
|
||||
|
||||
@@ -244,4 +244,39 @@ int lua_config_reload(void)
|
||||
int lua_config_is_loaded(void)
|
||||
{
|
||||
return G_loaded;
|
||||
}
|
||||
|
||||
int lua_config_set_string(const char *section, const char *key, const char *value)
|
||||
{
|
||||
if (section == NULL || key == NULL || value == NULL)
|
||||
{
|
||||
return -1;
|
||||
}
|
||||
|
||||
if (G_L == NULL)
|
||||
{
|
||||
return -1;
|
||||
}
|
||||
|
||||
lua_getglobal(G_L, "config");
|
||||
if (!lua_istable(G_L, -1))
|
||||
{
|
||||
lua_settop(G_L, 0);
|
||||
return -1;
|
||||
}
|
||||
|
||||
lua_getfield(G_L, -1, section);
|
||||
if (!lua_istable(G_L, -1))
|
||||
{
|
||||
lua_pop(G_L, 1);
|
||||
lua_createtable(G_L, 0, 4);
|
||||
lua_setfield(G_L, -2, section);
|
||||
lua_getfield(G_L, -1, section);
|
||||
}
|
||||
|
||||
lua_pushstring(G_L, value);
|
||||
lua_setfield(G_L, -2, key);
|
||||
lua_settop(G_L, 0);
|
||||
|
||||
return 0;
|
||||
}
|
||||
+9
-4
@@ -3,11 +3,13 @@
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <wchar.h>
|
||||
#include <libintl.h>
|
||||
#include "core/app_context.h"
|
||||
#include "core/lua_config.h"
|
||||
#include "utils/string_ext.h"
|
||||
#include "utils/os_env.h"
|
||||
#include "utils/logger.h"
|
||||
#include "utils/i18n.h"
|
||||
#include "controller/callbacks.h"
|
||||
#include "ui/main_window.h"
|
||||
|
||||
@@ -46,11 +48,14 @@ int main(int argc, char **argv)
|
||||
|
||||
if (lua_config_init() != 0)
|
||||
{
|
||||
IupMessage("警告", "Lua 配置系统初始化失败,将使用默认值");
|
||||
IupMessage(_("Warning"), "Lua 配置系统初始化失败,将使用默认值");
|
||||
}
|
||||
|
||||
log_info("Lua config initialized");
|
||||
|
||||
// 初始化国际化系统
|
||||
i18n_init(NULL);
|
||||
|
||||
// 在管理员模式下,解决无法拖拽文件到列表框的问题 (UIPI)
|
||||
// 需要加载 User32.dll 获取 ChangeWindowMessageFilter 函数
|
||||
HMODULE hUser32 = LoadLibraryW(L"user32.dll");
|
||||
@@ -76,7 +81,7 @@ int main(int argc, char **argv)
|
||||
AppContext *ctx = create_app_context();
|
||||
if (!ctx)
|
||||
{
|
||||
IupMessage("错误", "无法分配内存创建应用上下文");
|
||||
IupMessage(_("Error"), "无法分配内存创建应用上下文");
|
||||
IupClose();
|
||||
return 1;
|
||||
}
|
||||
@@ -91,11 +96,11 @@ int main(int argc, char **argv)
|
||||
// 检查管理员权限
|
||||
if (!check_admin())
|
||||
{
|
||||
IupMessage("警告", lua_config_get_string("status", "admin_warning"));
|
||||
IupMessage(_("Warning"), _(lua_config_get_string("status", "admin_warning")));
|
||||
|
||||
Ihandle *lbl_status = IupGetDialogChild(dlg, "LBL_STATUS");
|
||||
if (lbl_status)
|
||||
IupSetAttribute(lbl_status, "TITLE", lua_config_get_string("status", "readonly"));
|
||||
IupSetAttribute(lbl_status, "TITLE", _(lua_config_get_string("status", "readonly")));
|
||||
|
||||
Ihandle *btn_new = IupGetDialogChild(dlg, "BTN_NEW");
|
||||
Ihandle *btn_edit = IupGetDialogChild(dlg, "BTN_EDIT");
|
||||
|
||||
+59
-3
@@ -1,6 +1,7 @@
|
||||
#include "ui/dialogs.h"
|
||||
#include "core/lua_config.h"
|
||||
#include "utils/safe_string.h"
|
||||
#include "utils/i18n.h"
|
||||
#include <iup.h>
|
||||
#include <string.h>
|
||||
|
||||
@@ -26,7 +27,7 @@ int custom_input_dialog(const char *title, const char *label_text, char *buffer,
|
||||
Ihandle *text = IupText(NULL);
|
||||
IupSetAttribute(text, "VALUE", buffer);
|
||||
IupSetAttribute(text, "EXPAND", "HORIZONTAL");
|
||||
IupSetAttribute(text, "RASTERSIZE", "500x");
|
||||
IupSetAttribute(text, "RASTERSIZE", lua_config_get_string("input_dialog", "text_size"));
|
||||
IupSetAttribute(text, "NAME", "INPUT_TEXT");
|
||||
|
||||
Ihandle *btn_ok = IupButton(lua_config_get_string("button", "ok"), NULL);
|
||||
@@ -42,8 +43,8 @@ int custom_input_dialog(const char *title, const char *label_text, char *buffer,
|
||||
text,
|
||||
IupHbox(IupFill(), btn_ok, btn_cancel, NULL),
|
||||
NULL);
|
||||
IupSetAttribute(vbox, "MARGIN", "15x15");
|
||||
IupSetAttribute(vbox, "GAP", "10");
|
||||
IupSetAttribute(vbox, "MARGIN", lua_config_get_string("input_dialog", "margin"));
|
||||
IupSetAttribute(vbox, "GAP", lua_config_get_string("input_dialog", "gap"));
|
||||
|
||||
Ihandle *dlg = IupDialog(vbox);
|
||||
IupSetAttribute(dlg, "TITLE", title);
|
||||
@@ -66,6 +67,61 @@ int custom_input_dialog(const char *title, const char *label_text, char *buffer,
|
||||
}
|
||||
}
|
||||
|
||||
IupDestroy(dlg);
|
||||
return result;
|
||||
}
|
||||
|
||||
// 语言选择对话框
|
||||
int language_select_dialog(void)
|
||||
{
|
||||
const char *current_lang = i18n_get_current_language();
|
||||
|
||||
Ihandle *list = IupList(NULL);
|
||||
IupSetAttribute(list, "NAME", "LANG_LIST");
|
||||
IupSetAttribute(list, "DROPDOWN", "YES");
|
||||
IupSetAttribute(list, "VALUE", (strcmp(current_lang, "zh_CN") == 0) ? "1" : "2");
|
||||
IupSetAttribute(list, "1", _("Chinese (Simplified)"));
|
||||
IupSetAttribute(list, "2", _("English"));
|
||||
IupSetAttribute(list, "RASTERSIZE", lua_config_get_string("language", "list_size"));
|
||||
|
||||
Ihandle *btn_ok = IupButton(_("OK"), NULL);
|
||||
IupSetCallback(btn_ok, "ACTION", on_dialog_ok);
|
||||
IupSetAttribute(btn_ok, "RASTERSIZE", lua_config_get_string("button", "rastersize"));
|
||||
|
||||
Ihandle *btn_cancel = IupButton(_("Cancel"), NULL);
|
||||
IupSetCallback(btn_cancel, "ACTION", on_dialog_cancel);
|
||||
IupSetAttribute(btn_cancel, "RASTERSIZE", lua_config_get_string("button", "rastersize"));
|
||||
|
||||
Ihandle *vbox = IupVbox(
|
||||
IupLabel(_("Language")),
|
||||
list,
|
||||
IupHbox(IupFill(), btn_ok, btn_cancel, NULL),
|
||||
NULL);
|
||||
IupSetAttribute(vbox, "MARGIN", lua_config_get_string("language", "margin"));
|
||||
IupSetAttribute(vbox, "GAP", lua_config_get_string("language", "gap"));
|
||||
|
||||
Ihandle *dlg = IupDialog(vbox);
|
||||
IupSetAttribute(dlg, "TITLE", _("Language"));
|
||||
IupSetAttribute(dlg, "MINBOX", "NO");
|
||||
IupSetAttribute(dlg, "MAXBOX", "NO");
|
||||
IupSetAttribute(dlg, "RESIZE", "NO");
|
||||
IupSetAttribute(dlg, "RASTERSIZE", lua_config_get_string("language", "dialog_size"));
|
||||
|
||||
IupSetAttributeHandle(dlg, "DEFAULTENTER", btn_ok);
|
||||
IupSetAttributeHandle(dlg, "DEFAULTESC", btn_cancel);
|
||||
|
||||
IupPopup(dlg, IUP_CENTER, IUP_CENTER);
|
||||
|
||||
int result = IupGetInt(dlg, "MY_STATUS");
|
||||
if (result == 1)
|
||||
{
|
||||
int selected = IupGetInt(list, "VALUE");
|
||||
if (selected == 1)
|
||||
i18n_change_language("zh_CN");
|
||||
else
|
||||
i18n_change_language("en_US");
|
||||
}
|
||||
|
||||
IupDestroy(dlg);
|
||||
return result;
|
||||
}
|
||||
+72
-1
@@ -1,7 +1,9 @@
|
||||
#include "ui/main_window.h"
|
||||
#include "controller/callbacks.h"
|
||||
#include "core/lua_config.h"
|
||||
#include "utils/i18n.h"
|
||||
#include <stddef.h>
|
||||
#include <string.h>
|
||||
|
||||
// 创建路径列表控件
|
||||
static Ihandle *create_path_list(const char *name)
|
||||
@@ -66,6 +68,11 @@ Ihandle *create_main_window(void)
|
||||
Ihandle *btn_export = IupButton(lua_config_get_string("button", "export"), NULL);
|
||||
IupSetAttribute(btn_export, "NAME", "BTN_EXPORT");
|
||||
|
||||
// 创建语言切换按钮
|
||||
Ihandle *btn_lang = IupButton(_("Language"), NULL);
|
||||
IupSetAttribute(btn_lang, "NAME", "BTN_LANG");
|
||||
IupSetCallback(btn_lang, "ACTION", (Icallback)btn_lang_cb);
|
||||
|
||||
// 设置按钮回调
|
||||
IupSetCallback(btn_new, "ACTION", (Icallback)btn_new_cb);
|
||||
IupSetCallback(btn_edit, "ACTION", (Icallback)btn_edit_cb);
|
||||
@@ -88,6 +95,7 @@ Ihandle *create_main_window(void)
|
||||
IupSetAttribute(btn_clean, "RASTERSIZE", btn_size);
|
||||
IupSetAttribute(btn_import, "RASTERSIZE", btn_size);
|
||||
IupSetAttribute(btn_export, "RASTERSIZE", btn_size);
|
||||
IupSetAttribute(btn_lang, "RASTERSIZE", btn_size);
|
||||
|
||||
// 创建操作按钮垂直布局
|
||||
Ihandle *vbox_btns = IupVbox(
|
||||
@@ -130,7 +138,7 @@ Ihandle *create_main_window(void)
|
||||
IupSetAttribute(btn_help, "RASTERSIZE", btn_size);
|
||||
|
||||
// 创建底部按钮水平布局
|
||||
Ihandle *hbox_bottom = IupHbox(lbl_status, IupFill(), btn_help, btn_ok, btn_cancel, NULL);
|
||||
Ihandle *hbox_bottom = IupHbox(lbl_status, IupFill(), btn_help, btn_lang, btn_ok, btn_cancel, NULL);
|
||||
IupSetAttribute(hbox_bottom, "GAP", lua_config_get_string("layout", "hbox_gap"));
|
||||
IupSetAttribute(hbox_bottom, "MARGIN", lua_config_get_string("layout", "hbox_margin"));
|
||||
IupSetAttribute(hbox_bottom, "ALIGNMENT", lua_config_get_string("layout", "hbox_alignment"));
|
||||
@@ -154,4 +162,67 @@ Ihandle *create_main_window(void)
|
||||
IupSetAttribute(dlg, "MAXBOX", "NO");
|
||||
|
||||
return dlg;
|
||||
}
|
||||
|
||||
void refresh_main_window_ui(Ihandle *main_dlg)
|
||||
{
|
||||
if (!main_dlg)
|
||||
return;
|
||||
|
||||
IupSetAttribute(main_dlg, "TITLE", lua_config_get_string("app", "name"));
|
||||
|
||||
IupSetAttribute(main_dlg, "TABTITLE0", lua_config_get_string("label", "tab_sys"));
|
||||
IupSetAttribute(main_dlg, "TABTITLE1", lua_config_get_string("label", "tab_user"));
|
||||
|
||||
Ihandle *btn = IupGetDialogChild(main_dlg, "BTN_NEW");
|
||||
if (btn)
|
||||
IupSetAttribute(btn, "TITLE", lua_config_get_string("button", "new"));
|
||||
|
||||
btn = IupGetDialogChild(main_dlg, "BTN_EDIT");
|
||||
if (btn)
|
||||
IupSetAttribute(btn, "TITLE", lua_config_get_string("button", "edit"));
|
||||
|
||||
btn = IupGetDialogChild(main_dlg, "BTN_BROWSE");
|
||||
if (btn)
|
||||
IupSetAttribute(btn, "TITLE", lua_config_get_string("button", "browse"));
|
||||
|
||||
btn = IupGetDialogChild(main_dlg, "BTN_DEL");
|
||||
if (btn)
|
||||
IupSetAttribute(btn, "TITLE", lua_config_get_string("button", "del"));
|
||||
|
||||
btn = IupGetDialogChild(main_dlg, "BTN_UP");
|
||||
if (btn)
|
||||
IupSetAttribute(btn, "TITLE", lua_config_get_string("button", "up"));
|
||||
|
||||
btn = IupGetDialogChild(main_dlg, "BTN_DOWN");
|
||||
if (btn)
|
||||
IupSetAttribute(btn, "TITLE", lua_config_get_string("button", "down"));
|
||||
|
||||
btn = IupGetDialogChild(main_dlg, "BTN_CLEAN");
|
||||
if (btn)
|
||||
IupSetAttribute(btn, "TITLE", lua_config_get_string("button", "clean"));
|
||||
|
||||
btn = IupGetDialogChild(main_dlg, "BTN_IMPORT");
|
||||
if (btn)
|
||||
IupSetAttribute(btn, "TITLE", lua_config_get_string("button", "import"));
|
||||
|
||||
btn = IupGetDialogChild(main_dlg, "BTN_EXPORT");
|
||||
if (btn)
|
||||
IupSetAttribute(btn, "TITLE", lua_config_get_string("button", "export"));
|
||||
|
||||
btn = IupGetDialogChild(main_dlg, "BTN_LANG");
|
||||
if (btn)
|
||||
IupSetAttribute(btn, "TITLE", _("Language"));
|
||||
|
||||
btn = IupGetDialogChild(main_dlg, "BTN_OK");
|
||||
if (btn)
|
||||
IupSetAttribute(btn, "TITLE", lua_config_get_string("button", "ok"));
|
||||
|
||||
btn = IupGetDialogChild(main_dlg, "BTN_CANCEL");
|
||||
if (btn)
|
||||
IupSetAttribute(btn, "TITLE", lua_config_get_string("button", "cancel"));
|
||||
|
||||
btn = IupGetDialogChild(main_dlg, "BTN_HELP");
|
||||
if (btn)
|
||||
IupSetAttribute(btn, "TITLE", lua_config_get_string("button", "help"));
|
||||
}
|
||||
@@ -0,0 +1,112 @@
|
||||
#include "utils/i18n.h"
|
||||
#include "utils/logger.h"
|
||||
#include "core/lua_config.h"
|
||||
#include <windows.h>
|
||||
#include <stdio.h>
|
||||
#include <string.h>
|
||||
|
||||
static char current_language[16] = {0};
|
||||
static char locale_path[256] = {0};
|
||||
|
||||
static void load_saved_language(void)
|
||||
{
|
||||
FILE *fp = fopen("language.txt", "r");
|
||||
if (fp != NULL)
|
||||
{
|
||||
char lang[16] = {0};
|
||||
if (fgets(lang, sizeof(lang), fp) != NULL)
|
||||
{
|
||||
int len = strlen(lang);
|
||||
if (len > 0 && lang[len - 1] == '\n')
|
||||
lang[len - 1] = '\0';
|
||||
if (strlen(lang) > 0)
|
||||
{
|
||||
size_t copy_len = sizeof(current_language) - 1;
|
||||
if (strlen(lang) < copy_len)
|
||||
copy_len = strlen(lang);
|
||||
memcpy(current_language, lang, copy_len);
|
||||
current_language[copy_len] = '\0';
|
||||
log_info("Loaded saved language: %s", current_language);
|
||||
fclose(fp);
|
||||
return;
|
||||
}
|
||||
}
|
||||
fclose(fp);
|
||||
}
|
||||
}
|
||||
|
||||
void i18n_init(const char *default_lang)
|
||||
{
|
||||
setlocale(LC_ALL, "");
|
||||
|
||||
snprintf(locale_path, sizeof(locale_path), "./locale");
|
||||
bindtextdomain("messages", locale_path);
|
||||
textdomain("messages");
|
||||
|
||||
load_saved_language();
|
||||
|
||||
if (strlen(current_language) == 0)
|
||||
{
|
||||
const char *detected = i18n_detect_system_language();
|
||||
size_t copy_len = sizeof(current_language) - 1;
|
||||
size_t src_len = strlen(detected);
|
||||
if (src_len < copy_len)
|
||||
copy_len = src_len;
|
||||
memcpy(current_language, detected, copy_len);
|
||||
current_language[copy_len] = '\0';
|
||||
}
|
||||
|
||||
char mo_path[512];
|
||||
snprintf(mo_path, sizeof(mo_path), "%s/%s/LC_MESSAGES/%s.mo", locale_path, current_language, current_language);
|
||||
bindtextdomain("messages", mo_path);
|
||||
|
||||
log_info("i18n initialized with language: %s", current_language);
|
||||
}
|
||||
|
||||
const char *i18n_detect_system_language(void)
|
||||
{
|
||||
LANGID langId = GetUserDefaultUILanguage();
|
||||
|
||||
log_info("Detected system language ID: 0x%04X", langId);
|
||||
|
||||
if (langId == 0x0804)
|
||||
{
|
||||
return "zh_CN";
|
||||
}
|
||||
|
||||
return "en_US";
|
||||
}
|
||||
|
||||
void i18n_change_language(const char *lang)
|
||||
{
|
||||
if (!lang || strlen(lang) == 0)
|
||||
return;
|
||||
|
||||
if (strcmp(current_language, lang) == 0)
|
||||
return;
|
||||
|
||||
size_t copy_len = sizeof(current_language) - 1;
|
||||
size_t src_len = strlen(lang);
|
||||
if (src_len < copy_len)
|
||||
copy_len = src_len;
|
||||
memcpy(current_language, lang, copy_len);
|
||||
current_language[copy_len] = '\0';
|
||||
|
||||
char new_lang_path[512];
|
||||
snprintf(new_lang_path, sizeof(new_lang_path), "%s/%s/LC_MESSAGES/%s.mo", locale_path, lang, lang);
|
||||
bindtextdomain("messages", new_lang_path);
|
||||
|
||||
FILE *fp = fopen("language.txt", "w");
|
||||
if (fp != NULL)
|
||||
{
|
||||
fprintf(fp, "%s\n", lang);
|
||||
fclose(fp);
|
||||
}
|
||||
|
||||
log_info("Language changed to: %s", lang);
|
||||
}
|
||||
|
||||
const char *i18n_get_current_language(void)
|
||||
{
|
||||
return current_language;
|
||||
}
|
||||
Reference in New Issue
Block a user