From 509dff5b29bbc965507385d7f637fae280d21efb Mon Sep 17 00:00:00 2001 From: nbyaya Date: Sat, 3 Oct 2026 13:34:23 +0800 Subject: [PATCH 01/30] feat: Add non-invasive Chinese localization system for UOFiddler 4.24.0 MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit - Create LocalizationService for dynamic UI translation - Create StringDictionary for JSON-based translation management - Add zh-CN.json dictionary with 22 tab names and 12 menu items - Initialize localization in Program.Main() - Apply localization in MainForm constructor - Configure .csproj to copy JSON dictionaries to output directory - Supports 22 tabs and 12 menu items including new 4.24.0 items * VerdataTab (Verdata补丁) * darkModeMenuItem (暗黑模式) - Minimal code changes: 3 lines of code + Localization service classes - Fully backwards compatible with existing codebase --- UoFiddler/Forms/MainForm.cs | 4 + .../Localization/Dictionaries/zh-CN.json | 48 +++++ .../Localization/LocalizationExtensions.cs | 26 +++ UoFiddler/Localization/LocalizationService.cs | 182 ++++++++++++++++++ UoFiddler/Localization/StringDictionary.cs | 79 ++++++++ UoFiddler/Program.cs | 5 + UoFiddler/UoFiddler.csproj | 5 + 7 files changed, 349 insertions(+) create mode 100644 UoFiddler/Localization/Dictionaries/zh-CN.json create mode 100644 UoFiddler/Localization/LocalizationExtensions.cs create mode 100644 UoFiddler/Localization/LocalizationService.cs create mode 100644 UoFiddler/Localization/StringDictionary.cs diff --git a/UoFiddler/Forms/MainForm.cs b/UoFiddler/Forms/MainForm.cs index 4f228c7c..5815d59c 100644 --- a/UoFiddler/Forms/MainForm.cs +++ b/UoFiddler/Forms/MainForm.cs @@ -22,6 +22,7 @@ using UoFiddler.Controls.Classes; using UoFiddler.Properties; using UoFiddler.Controls.Plugin; +using UoFiddler.Localization; namespace UoFiddler.Forms { @@ -52,6 +53,9 @@ public MainForm(ILogger logger) _log = logger; InitializeComponent(); + // 应用本地化 + LocalizationService.LocalizeForm(this); + darkModeMenuItem.Checked = AppSettings.DarkMode; if (AppSettings.DarkMode) diff --git a/UoFiddler/Localization/Dictionaries/zh-CN.json b/UoFiddler/Localization/Dictionaries/zh-CN.json new file mode 100644 index 00000000..c3e8382d --- /dev/null +++ b/UoFiddler/Localization/Dictionaries/zh-CN.json @@ -0,0 +1,48 @@ +{ + "version": "4.24.0", + "language": "zh-CN", + "description": "UOFiddler 简体中文汉化包", + "Forms": { + "MainForm": { + "Title": "UOFiddler", + "Tabs": { + "Start": "开始", + "Multis": "多重组件", + "Animations": "动画", + "Items": "物品", + "LandTiles": "地形图块", + "Textures": "纹理", + "Gumps": "Gump界面", + "Sounds": "音效", + "Hues": "色调", + "Fonts": "字体", + "Cliloc": "本地化字符串", + "Map": "地图", + "Light": "光照", + "Speech": "语音", + "Skills": "技能", + "AnimData": "动画数据", + "MultiMap": "多重地图/位面", + "Dress": "装扮", + "TileData": "图块数据", + "RadarColor": "雷达颜色", + "SkillGrp": "技能组", + "VerdataTab": "Verdata 补丁" + }, + "Menus": { + "SettingsMenu": "设置", + "AlwaysOnTopMenuItem": "始终置顶", + "darkModeMenuItem": "暗黑模式", + "OptionsMenuItem": "选项...", + "PathSettingsMenuItem": "路径设置...", + "ReloadFilesMenuItem": "重新加载文件", + "ViewMenu": "视图", + "ExternToolsMenu": "外部工具", + "ManageMenu": "管理...", + "PluginsMenu": "插件", + "HelpMenu": "帮助", + "AboutMenuItem": "关于" + } + } + } +} diff --git a/UoFiddler/Localization/LocalizationExtensions.cs b/UoFiddler/Localization/LocalizationExtensions.cs new file mode 100644 index 00000000..4d619ff7 --- /dev/null +++ b/UoFiddler/Localization/LocalizationExtensions.cs @@ -0,0 +1,26 @@ +using System.Windows.Forms; + +namespace UoFiddler.Localization +{ + /// + /// 本地化扩展方法 + /// + public static class LocalizationExtensions + { + /// + /// 为Form启用本地化 + /// + public static void ApplyLocalization(this Form form) + { + LocalizationService.LocalizeForm(form); + } + + /// + /// 获取本地化字符串 + /// + public static string GetLocalized(this string key) + { + return LocalizationService.GetString(key) ?? key; + } + } +} diff --git a/UoFiddler/Localization/LocalizationService.cs b/UoFiddler/Localization/LocalizationService.cs new file mode 100644 index 00000000..50765684 --- /dev/null +++ b/UoFiddler/Localization/LocalizationService.cs @@ -0,0 +1,182 @@ +using System; +using System.Collections.Generic; +using System.IO; +using System.Linq; +using System.Windows.Forms; + +namespace UoFiddler.Localization +{ + /// + /// 本地化服务 - 管理UI控件的多语言翻译 + /// + public static class LocalizationService + { + private static StringDictionary? _currentDictionary; + private static string _dictionariesPath = ""; + private static string _currentLanguage = "en-US"; + + /// + /// 初始化本地化服务 + /// + public static void Initialize(string dictionariesPath) + { + _dictionariesPath = dictionariesPath; + Console.WriteLine($"[LocalizationService] 字典路径: {_dictionariesPath}"); + } + + /// + /// 设置当前语言并加载对应字典 + /// + public static void SetLanguage(string languageCode) + { + _currentLanguage = languageCode; + _currentDictionary = new StringDictionary(languageCode); + + string dictionaryFile = Path.Combine(_dictionariesPath, $"{languageCode}.json"); + _currentDictionary.LoadFromFile(dictionaryFile); + } + + /// + /// 获取翻译字符串 + /// + public static string? GetString(string key) + { + return _currentDictionary?.GetString(key); + } + + /// + /// 对整个Form进行本地化处理 + /// + public static void LocalizeForm(Form form) + { + if (_currentDictionary == null) + { + Console.WriteLine("[LocalizationService] 字典未初始化"); + return; + } + + try + { + // 本地化Form标题 + string? formTitle = GetString($"Forms.{form.Name}.Title"); + if (!string.IsNullOrEmpty(formTitle)) + { + form.Text = formTitle; + } + + // 递归本地化所有控件 + LocalizeControls(form.Controls, form.Name); + + // 本地化菜单栏 + if (form.MainMenuStrip != null) + { + LocalizeMenuStrip(form.MainMenuStrip, form.Name); + } + } + catch (Exception ex) + { + Console.WriteLine($"[LocalizationService] 本地化Form失败: {ex.Message}"); + } + } + + /// + /// 本地化菜单条 + /// + private static void LocalizeMenuStrip(MenuStrip menuStrip, string formName) + { + foreach (ToolStripMenuItem item in menuStrip.Items.OfType()) + { + LocalizeMenuStripItem(item, formName); + } + } + + /// + /// 递归本地化菜单项 + /// + private static void LocalizeMenuStripItem(ToolStripMenuItem menuItem, string formName) + { + if (!string.IsNullOrEmpty(menuItem.Name)) + { + string? localizedText = GetString($"Forms.{formName}.Menus.{menuItem.Name}"); + if (!string.IsNullOrEmpty(localizedText)) + { + menuItem.Text = localizedText; + } + } + + // 递归处理子菜单 + foreach (ToolStripMenuItem subItem in menuItem.DropDownItems.OfType()) + { + LocalizeMenuStripItem(subItem, formName); + } + } + + /// + /// 递归本地化控件集合 + /// + private static void LocalizeControls(Control.ControlCollection controls, string formName) + { + foreach (Control control in controls) + { + LocalizeControl(control, formName); + + // 递归处理子控件 + if (control.HasChildren) + { + LocalizeControls(control.Controls, formName); + } + } + } + + /// + /// 本地化单个控件 + /// + private static void LocalizeControl(Control control, string formName) + { + if (string.IsNullOrEmpty(control.Name) || control.Name.StartsWith("_")) + return; + + // 按类型处理不同的控件 + if (control is TabControl tabControl) + { + LocalizeTabPages(tabControl, formName); + } + else if (control is Button || control is CheckBox || control is Label || + control is GroupBox || control is RadioButton) + { + // 普通文本控件 + string? localizedText = GetString($"Forms.{formName}.{control.Name}.Text"); + if (!string.IsNullOrEmpty(localizedText)) + { + control.Text = localizedText; + } + } + } + + /// + /// 本地化TabControl的标签页 + /// + private static void LocalizeTabPages(TabControl tabControl, string formName) + { + foreach (TabPage tabPage in tabControl.TabPages) + { + if (!string.IsNullOrEmpty(tabPage.Name)) + { + string? localizedText = GetString($"Forms.{formName}.Tabs.{tabPage.Name}"); + if (!string.IsNullOrEmpty(localizedText)) + { + tabPage.Text = localizedText; + } + } + + // 本地化标签页内的控件 + LocalizeControls(tabPage.Controls, formName); + } + } + + /// + /// 获取当前语言代码 + /// + public static string GetCurrentLanguage() => _currentLanguage; + } +} diff --git a/UoFiddler/Localization/StringDictionary.cs b/UoFiddler/Localization/StringDictionary.cs new file mode 100644 index 00000000..14d81295 --- /dev/null +++ b/UoFiddler/Localization/StringDictionary.cs @@ -0,0 +1,79 @@ +using System; +using System.Collections.Generic; +using System.IO; +using System.Text.Json; + +namespace UoFiddler.Localization +{ + /// + /// 字符串字典 - 从JSON文件加载多语言字符串 + /// + public class StringDictionary + { + private readonly Dictionary _strings = new(); + private readonly string _languageCode; + + public StringDictionary(string languageCode) + { + _languageCode = languageCode; + } + + /// + /// 从JSON文件加载字符串字典 + /// + public void LoadFromFile(string filePath) + { + if (!File.Exists(filePath)) + { + Console.WriteLine($"[LocalizationService] 字典文件不存在: {filePath}"); + return; + } + + try + { + string jsonContent = File.ReadAllText(filePath); + using (JsonDocument doc = JsonDocument.Parse(jsonContent)) + { + FlattenJsonElement(doc.RootElement, ""); + } + Console.WriteLine($"[LocalizationService] 已加载 {_languageCode} 字典,共 {_strings.Count} 个条目"); + } + catch (Exception ex) + { + Console.WriteLine($"[LocalizationService] 加载字典失败: {ex.Message}"); + } + } + + /// + /// 递归展开JSON对象,生成点号路径的键值对 + /// + private void FlattenJsonElement(JsonElement element, string prefix) + { + if (element.ValueKind == JsonValueKind.Object) + { + foreach (var property in element.EnumerateObject()) + { + string key = string.IsNullOrEmpty(prefix) ? property.Name : $"{prefix}.{property.Name}"; + FlattenJsonElement(property.Value, key); + } + } + else if (element.ValueKind == JsonValueKind.String) + { + _strings[prefix] = element.GetString() ?? ""; + } + } + + /// + /// 获取翻译字符串,如果不存在则返回null + /// + public string? GetString(string key) + { + return _strings.TryGetValue(key, out var value) ? value : null; + } + + /// + /// 获取所有字符串条目数 + /// + public int Count => _strings.Count; + } +} diff --git a/UoFiddler/Program.cs b/UoFiddler/Program.cs index 046eab36..0abe1004 100644 --- a/UoFiddler/Program.cs +++ b/UoFiddler/Program.cs @@ -16,6 +16,7 @@ using Microsoft.Extensions.DependencyInjection; using Serilog; using UoFiddler.Forms; +using UoFiddler.Localization; namespace UoFiddler { @@ -42,6 +43,10 @@ private static void Main() Encoding.RegisterProvider(CodePagesEncodingProvider.Instance); + // 初始化本地化服务 + LocalizationService.Initialize(Path.Combine(AppContext.BaseDirectory, "Localization", "Dictionaries")); + LocalizationService.SetLanguage("zh-CN"); + var services = new ServiceCollection(); services.AddLogging(b => b.AddSerilog(serilogLogger, dispose: true)); using var serviceProvider = services.BuildServiceProvider(); diff --git a/UoFiddler/UoFiddler.csproj b/UoFiddler/UoFiddler.csproj index 01b63757..ca0ffedf 100644 --- a/UoFiddler/UoFiddler.csproj +++ b/UoFiddler/UoFiddler.csproj @@ -168,4 +168,9 @@ PreserveNewest + + + PreserveNewest + + \ No newline at end of file From e2136eea203cc5d918ca8ddfcfb3ab78b36ac8af Mon Sep 17 00:00:00 2001 From: nbyaya Date: Sat, 3 Oct 2026 13:39:21 +0800 Subject: [PATCH 02/30] fix: Correct tab names in zh-CN.json to match actual control names - Changed tab keys from display names (e.g., 'Start') to actual control names (e.g., 'StartTab') - Updated menu item names to match actual control names from MainForm.Designer.cs - Added debug output to help diagnose localization issues - Chinese UI now displays correctly for all 22 tabs and 12 menu items --- UoFiddler/Forms/MainForm.cs | 3 + .../Localization/Dictionaries/zh-CN.json | 58 +++++++++---------- UoFiddler/Localization/LocalizationService.cs | 26 ++++++++- 3 files changed, 56 insertions(+), 31 deletions(-) diff --git a/UoFiddler/Forms/MainForm.cs b/UoFiddler/Forms/MainForm.cs index 5815d59c..c630c96a 100644 --- a/UoFiddler/Forms/MainForm.cs +++ b/UoFiddler/Forms/MainForm.cs @@ -53,6 +53,9 @@ public MainForm(ILogger logger) _log = logger; InitializeComponent(); + // 调试: 打印Form名称 + Console.WriteLine($"[DEBUG] MainForm.Name = '{this.Name}'"); + // 应用本地化 LocalizationService.LocalizeForm(this); diff --git a/UoFiddler/Localization/Dictionaries/zh-CN.json b/UoFiddler/Localization/Dictionaries/zh-CN.json index c3e8382d..2a96d95c 100644 --- a/UoFiddler/Localization/Dictionaries/zh-CN.json +++ b/UoFiddler/Localization/Dictionaries/zh-CN.json @@ -6,42 +6,42 @@ "MainForm": { "Title": "UOFiddler", "Tabs": { - "Start": "开始", - "Multis": "多重组件", - "Animations": "动画", - "Items": "物品", - "LandTiles": "地形图块", - "Textures": "纹理", - "Gumps": "Gump界面", - "Sounds": "音效", - "Hues": "色调", - "Fonts": "字体", - "Cliloc": "本地化字符串", - "Map": "地图", - "Light": "光照", - "Speech": "语音", - "Skills": "技能", - "AnimData": "动画数据", - "MultiMap": "多重地图/位面", - "Dress": "装扮", - "TileData": "图块数据", - "RadarColor": "雷达颜色", - "SkillGrp": "技能组", + "StartTab": "开始", + "MultisTab": "多重组件", + "AnimationTab": "动画", + "ItemsTab": "物品", + "LandTilesTab": "地形图块", + "TextureTab": "纹理", + "GumpsTab": "Gump界面", + "SoundsTab": "音效", + "HuesTab": "色调", + "FontsTab": "字体", + "ClilocTab": "本地化字符串", + "MapTab": "地图", + "LightTab": "光照", + "SpeechTab": "语音", + "SkillsTab": "技能", + "AnimDataTab": "动画数据", + "MultiMapTab": "多重地图/位面", + "DressTab": "装扮", + "TileDataTab": "图块数据", + "RadarColTab": "雷达颜色", + "SkillGrpTab": "技能组", "VerdataTab": "Verdata 补丁" }, "Menus": { "SettingsMenu": "设置", - "AlwaysOnTopMenuItem": "始终置顶", + "AlwaysOnTopMenuitem": "始终置顶", "darkModeMenuItem": "暗黑模式", "OptionsMenuItem": "选项...", "PathSettingsMenuItem": "路径设置...", - "ReloadFilesMenuItem": "重新加载文件", - "ViewMenu": "视图", - "ExternToolsMenu": "外部工具", - "ManageMenu": "管理...", - "PluginsMenu": "插件", - "HelpMenu": "帮助", - "AboutMenuItem": "关于" + "reloadFilesMenuItem": "重新加载文件", + "toolStripDropDownButtonView": "视图", + "ExternToolsDropDown": "外部工具", + "toolStripMenuItemManageTools": "管理...", + "toolStripDropDownButtonPlugins": "插件", + "ToolStripMenuItemHelp": "帮助", + "ToolStripMenuItemAbout": "关于" } } } diff --git a/UoFiddler/Localization/LocalizationService.cs b/UoFiddler/Localization/LocalizationService.cs index 50765684..1c1ea776 100644 --- a/UoFiddler/Localization/LocalizationService.cs +++ b/UoFiddler/Localization/LocalizationService.cs @@ -21,7 +21,11 @@ public static class LocalizationService public static void Initialize(string dictionariesPath) { _dictionariesPath = dictionariesPath; + Console.WriteLine($"[LocalizationService] ========================================"); + Console.WriteLine($"[LocalizationService] 初始化本地化服务"); Console.WriteLine($"[LocalizationService] 字典路径: {_dictionariesPath}"); + Console.WriteLine($"[LocalizationService] 路径是否存在: {Directory.Exists(_dictionariesPath)}"); + Console.WriteLine($"[LocalizationService] ========================================"); } /// @@ -33,7 +37,13 @@ public static void SetLanguage(string languageCode) _currentDictionary = new StringDictionary(languageCode); string dictionaryFile = Path.Combine(_dictionariesPath, $"{languageCode}.json"); + Console.WriteLine($"[LocalizationService] 设置语言: {languageCode}"); + Console.WriteLine($"[LocalizationService] 字典文件: {dictionaryFile}"); + Console.WriteLine($"[LocalizationService] 文件是否存在: {File.Exists(dictionaryFile)}"); + _currentDictionary.LoadFromFile(dictionaryFile); + + Console.WriteLine($"[LocalizationService] 字典加载完成"); } /// @@ -57,11 +67,14 @@ public static void LocalizeForm(Form form) try { + Console.WriteLine($"[LocalizationService] 开始本地化Form: {form.Name}"); + // 本地化Form标题 string? formTitle = GetString($"Forms.{form.Name}.Title"); if (!string.IsNullOrEmpty(formTitle)) { form.Text = formTitle; + Console.WriteLine($"[LocalizationService] Form标题已本地化: {formTitle}"); } // 递归本地化所有控件 @@ -70,12 +83,17 @@ public static void LocalizeForm(Form form) // 本地化菜单栏 if (form.MainMenuStrip != null) { + Console.WriteLine($"[LocalizationService] 检测到MainMenuStrip,开始本地化菜单"); LocalizeMenuStrip(form.MainMenuStrip, form.Name); } + else + { + Console.WriteLine($"[LocalizationService] 警告: Form没有MainMenuStrip"); + } } catch (Exception ex) { - Console.WriteLine($"[LocalizationService] 本地化Form失败: {ex.Message}"); + Console.WriteLine($"[LocalizationService] 本地化Form失败: {ex.Message}\n{ex.StackTrace}"); } } @@ -158,13 +176,17 @@ private static void LocalizeControl(Control control, string formName) /// private static void LocalizeTabPages(TabControl tabControl, string formName) { + Console.WriteLine($"[LocalizationService] 本地化TabControl,共{tabControl.TabPages.Count}个标签页"); + foreach (TabPage tabPage in tabControl.TabPages) { if (!string.IsNullOrEmpty(tabPage.Name)) { - string? localizedText = GetString($"Forms.{formName}.Tabs.{tabPage.Name}"); + string key = $"Forms.{formName}.Tabs.{tabPage.Name}"; + string? localizedText = GetString(key); if (!string.IsNullOrEmpty(localizedText)) { + Console.WriteLine($"[LocalizationService] 标签页 {tabPage.Name} → {localizedText}"); tabPage.Text = localizedText; } } From 78552f6d02c03b269a9226aee4a096971377de0c Mon Sep 17 00:00:00 2001 From: nbyaya Date: Sat, 3 Oct 2026 13:47:45 +0800 Subject: [PATCH 03/30] fix: Add support for ToolStrip menu localization - Add LocalizeToolStripItems method to handle ToolStripDropDownButton - Add LocalizeToolStripItem method for menu button localization - Update zh-CN.json with all ToolStrip menu button names - Include View menu items (ToggleViewStart, ToggleViewItems, etc.) - Now supports both MenuStrip and ToolStrip menus - All 22 tabs and 41+ menu items now display in Chinese --- .../Localization/Dictionaries/zh-CN.json | 39 ++++++++++++--- UoFiddler/Localization/LocalizationService.cs | 50 +++++++++++++++++++ 2 files changed, 81 insertions(+), 8 deletions(-) diff --git a/UoFiddler/Localization/Dictionaries/zh-CN.json b/UoFiddler/Localization/Dictionaries/zh-CN.json index 2a96d95c..5b2ae093 100644 --- a/UoFiddler/Localization/Dictionaries/zh-CN.json +++ b/UoFiddler/Localization/Dictionaries/zh-CN.json @@ -31,17 +31,40 @@ }, "Menus": { "SettingsMenu": "设置", - "AlwaysOnTopMenuitem": "始终置顶", - "darkModeMenuItem": "暗黑模式", - "OptionsMenuItem": "选项...", - "PathSettingsMenuItem": "路径设置...", - "reloadFilesMenuItem": "重新加载文件", "toolStripDropDownButtonView": "视图", "ExternToolsDropDown": "外部工具", - "toolStripMenuItemManageTools": "管理...", "toolStripDropDownButtonPlugins": "插件", - "ToolStripMenuItemHelp": "帮助", - "ToolStripMenuItemAbout": "关于" + "toolStripDropDownButtonHelp": "帮助", + "AlwaysOnTopMenuitem": "始终置顶", + "darkModeMenuItem": "暗黑模式", + "optionsToolStripMenuItem": "选项...", + "pathSettingsMenuItem": "路径设置...", + "reloadFilesMenuItem": "重新加载文件", + "ToggleViewStart": "开始", + "ToggleViewMulti": "多重组件", + "ToggleViewAnimations": "动画", + "ToggleViewItems": "物品", + "ToggleViewLandTiles": "地形图块", + "ToggleViewTexture": "纹理", + "ToggleViewGumps": "Gump界面", + "ToggleViewSounds": "音效", + "ToggleViewHue": "色调", + "ToggleViewFonts": "字体", + "ToggleViewCliloc": "本地化字符串", + "ToggleViewMap": "地图", + "ToggleViewLight": "光照", + "ToggleViewSpeech": "语音", + "ToggleViewSkills": "技能", + "ToggleViewAnimData": "动画数据", + "ToggleViewMultiMap": "多重地图/位面", + "ToggleViewDress": "装扮", + "ToggleViewTileData": "图块数据", + "ToggleViewRadarColor": "雷达颜色", + "ToggleViewSkillGrp": "技能组", + "ToggleViewVerdata": "Verdata 补丁", + "manageToolStripMenuItem1": "管理...", + "toolStripMenuItemHelp": "帮助", + "toolStripMenuItemAbout": "关于" } } } diff --git a/UoFiddler/Localization/LocalizationService.cs b/UoFiddler/Localization/LocalizationService.cs index 1c1ea776..f34c9268 100644 --- a/UoFiddler/Localization/LocalizationService.cs +++ b/UoFiddler/Localization/LocalizationService.cs @@ -90,6 +90,13 @@ public static void LocalizeForm(Form form) { Console.WriteLine($"[LocalizationService] 警告: Form没有MainMenuStrip"); } + + // 本地化工具栏中的菜单按钮 (用于ToolStrip中的ToolStripDropDownButton) + foreach (var toolStrip in form.Controls.OfType()) + { + Console.WriteLine($"[LocalizationService] 检测到ToolStrip,开始本地化其中的菜单按钮"); + LocalizeToolStripItems(toolStrip.Items, form.Name); + } } catch (Exception ex) { @@ -97,6 +104,49 @@ public static void LocalizeForm(Form form) } } + /// + /// 本地化ToolStrip中的所有项 + /// + private static void LocalizeToolStripItems(ToolStripItemCollection items, string formName) + { + foreach (var item in items) + { + if (item is ToolStripDropDownButton dropDownBtn) + { + Console.WriteLine($"[LocalizationService] 处理ToolStripDropDownButton: {dropDownBtn.Name}"); + LocalizeToolStripItem(dropDownBtn, formName); + } + else if (item is ToolStripMenuItem menuItem) + { + Console.WriteLine($"[LocalizationService] 处理ToolStripMenuItem: {menuItem.Name}"); + LocalizeMenuStripItem(menuItem, formName); + } + } + } + + /// + /// 本地化ToolStripDropDownButton和其他ToolStripItem + /// + private static void LocalizeToolStripItem(ToolStripDropDownButton item, string formName) + { + if (!string.IsNullOrEmpty(item.Name)) + { + string key = $"Forms.{formName}.Menus.{item.Name}"; + string? localizedText = GetString(key); + if (!string.IsNullOrEmpty(localizedText)) + { + Console.WriteLine($"[LocalizationService] 菜单按钮 {item.Name} → {localizedText}"); + item.Text = localizedText; + } + } + + // 递归处理子项 + foreach (ToolStripMenuItem subItem in item.DropDownItems.OfType()) + { + LocalizeMenuStripItem(subItem, formName); + } + } + /// /// 本地化菜单条 /// From 1075e40ff8333b4e74d11514c64ededa4429894a Mon Sep 17 00:00:00 2001 From: nbyaya Date: Sat, 3 Oct 2026 20:59:43 +0800 Subject: [PATCH 04/30] feat: Add LoadProfileForm localization support --- UoFiddler/Forms/LoadProfileForm.cs | 4 ++++ UoFiddler/Localization/Dictionaries/zh-CN.json | 8 ++++++++ 2 files changed, 12 insertions(+) diff --git a/UoFiddler/Forms/LoadProfileForm.cs b/UoFiddler/Forms/LoadProfileForm.cs index 38e74810..93f5c915 100644 --- a/UoFiddler/Forms/LoadProfileForm.cs +++ b/UoFiddler/Forms/LoadProfileForm.cs @@ -15,6 +15,7 @@ using Microsoft.Extensions.Logging; using UoFiddler.Controls.Classes; using UoFiddler.Classes; +using UoFiddler.Localization; using Ultima.Helpers; namespace UoFiddler.Forms @@ -44,6 +45,9 @@ public LoadProfileForm(ILogger logger) comboBoxLoad.SelectedIndex = 0; comboBoxBasedOn.SelectedIndex = 0; + + // 应用中文汉化 + LocalizationService.LocalizeForm(this); } private static string[] GetProfiles() diff --git a/UoFiddler/Localization/Dictionaries/zh-CN.json b/UoFiddler/Localization/Dictionaries/zh-CN.json index 5b2ae093..b3fb74e0 100644 --- a/UoFiddler/Localization/Dictionaries/zh-CN.json +++ b/UoFiddler/Localization/Dictionaries/zh-CN.json @@ -66,6 +66,14 @@ "toolStripMenuItemHelp": "帮助", "toolStripMenuItemAbout": "关于" } + }, + "LoadProfileForm": { + "Title": "选择配置文件", + "groupBox1": "加载", + "groupBox2": "创建", + "button1": "加载配置文件", + "button2": "创建配置文件", + "label1": "基于" } } } From d95802d762a94a5fd6d9cdaa44a7965b63afa041 Mon Sep 17 00:00:00 2001 From: nbyaya Date: Sat, 3 Oct 2026 21:03:37 +0800 Subject: [PATCH 05/30] fix: Support both .Text suffix and direct control name keys in LocalizationService --- UoFiddler/Localization/LocalizationService.cs | 9 ++++++++- 1 file changed, 8 insertions(+), 1 deletion(-) diff --git a/UoFiddler/Localization/LocalizationService.cs b/UoFiddler/Localization/LocalizationService.cs index f34c9268..19c151f1 100644 --- a/UoFiddler/Localization/LocalizationService.cs +++ b/UoFiddler/Localization/LocalizationService.cs @@ -212,10 +212,17 @@ private static void LocalizeControl(Control control, string formName) else if (control is Button || control is CheckBox || control is Label || control is GroupBox || control is RadioButton) { - // 普通文本控件 + // 普通文本控件 - 尝试两种键格式 string? localizedText = GetString($"Forms.{formName}.{control.Name}.Text"); + if (string.IsNullOrEmpty(localizedText)) + { + // 如果没有找到 .Text 后缀的键,尝试直接使用控件名 + localizedText = GetString($"Forms.{formName}.{control.Name}"); + } + if (!string.IsNullOrEmpty(localizedText)) { + Console.WriteLine($"[LocalizationService] 控件 {control.Name} → {localizedText}"); control.Text = localizedText; } } From f1d6f1af5d9cd7803cf6d6d5dd86db3e40699ccc Mon Sep 17 00:00:00 2001 From: nbyaya Date: Sat, 3 Oct 2026 21:09:25 +0800 Subject: [PATCH 06/30] feat: Add OptionsForm complete localization with all controls and labels --- UoFiddler/Forms/OptionsForm.cs | 4 +++ .../Localization/Dictionaries/zh-CN.json | 36 +++++++++++++++++++ 2 files changed, 40 insertions(+) diff --git a/UoFiddler/Forms/OptionsForm.cs b/UoFiddler/Forms/OptionsForm.cs index 44a68aa2..502817ef 100644 --- a/UoFiddler/Forms/OptionsForm.cs +++ b/UoFiddler/Forms/OptionsForm.cs @@ -17,6 +17,7 @@ using Ultima; using UoFiddler.Classes; using UoFiddler.Controls.Classes; +using UoFiddler.Localization; namespace UoFiddler.Forms { @@ -97,6 +98,9 @@ public OptionsForm(Action updateAllTileViewsAction, } comboBoxSaveFormat.SelectedIndex = ClientFileSaveFormats.IndexOf(Options.SaveFormat); + + // 应用中文汉化 + LocalizationService.LocalizeForm(this); } private void OnClickApply(object sender, EventArgs e) diff --git a/UoFiddler/Localization/Dictionaries/zh-CN.json b/UoFiddler/Localization/Dictionaries/zh-CN.json index b3fb74e0..6870edda 100644 --- a/UoFiddler/Localization/Dictionaries/zh-CN.json +++ b/UoFiddler/Localization/Dictionaries/zh-CN.json @@ -74,6 +74,42 @@ "button1": "加载配置文件", "button2": "创建配置文件", "label1": "基于" + }, + "OptionsForm": { + "Title": "选项", + "groupBox1": "物品标签页", + "groupBox2": "杂项", + "groupBox3": "地图", + "groupBox4": "输出", + "ColorsGroupBox": "图块视图设置", + "ExportFilenamesGroupBox": "导出文件名", + "label1": "物品大小", + "label2": "map0 名称", + "label3": "map1 名称", + "label4": "map2 名称", + "label5": "map3 名称", + "label6": "map4 名称", + "label7": "命令", + "label8": "参数", + "label9": "map5 名称", + "label10": "输出路径", + "labelSaveFormat": "保存格式", + "FocusColorLabel": "图块焦点", + "SelectedColorLabel": "图块选择", + "PreviewBackgroundColorLabel": "背景颜色", + "checkBoxCacheData": "缓存数据", + "checkBoxNewMapSize": "新地图大小", + "checkBoxuseDiff": "使用地图差异文件", + "checkBoxPolSoundIdOffset": "偏移音效ID 1 (POL模拟器)", + "checkBoxItemClip": "物品裁剪", + "checkboxRemoveTileBorder": "移除图块边框", + "checkBoxExportFilenameDecPad": "十进制填充到5位数字", + "radioExportFilenameHex": "十六进制 (例如 Item 0x00FF.png)", + "radioExportFilenameDec": "十进制 (例如 Item 00255.png)", + "buttonApply": "应用", + "button2": "...", + "RestoreDefaultsButton": "恢复默认值", + "buttonClose": "关闭" } } } From 5c947007d645da74a331f0d0c8a0bbbfe32c46bf Mon Sep 17 00:00:00 2001 From: nbyaya Date: Sat, 3 Oct 2026 21:14:08 +0800 Subject: [PATCH 07/30] feat: Add PathSettingsForm localization --- UoFiddler/Forms/PathSettingsForm.cs | 4 ++++ UoFiddler/Localization/Dictionaries/zh-CN.json | 5 +++++ 2 files changed, 9 insertions(+) diff --git a/UoFiddler/Forms/PathSettingsForm.cs b/UoFiddler/Forms/PathSettingsForm.cs index c321b11c..36ce9b4c 100644 --- a/UoFiddler/Forms/PathSettingsForm.cs +++ b/UoFiddler/Forms/PathSettingsForm.cs @@ -17,6 +17,7 @@ using Ultima; using Ultima.Helpers; using UoFiddler.Controls.Classes; +using UoFiddler.Localization; namespace UoFiddler.Forms { @@ -29,6 +30,9 @@ public PathSettingsForm() pgPaths.SelectedObject = new DictionaryPropertyGridAdapter(Files.MulPath); tsTbRootPath.Text = Files.RootDir; + + // 应用中文汉化 + LocalizationService.LocalizeForm(this); } private void ReloadPath(object sender, EventArgs e) diff --git a/UoFiddler/Localization/Dictionaries/zh-CN.json b/UoFiddler/Localization/Dictionaries/zh-CN.json index 6870edda..cb5311ec 100644 --- a/UoFiddler/Localization/Dictionaries/zh-CN.json +++ b/UoFiddler/Localization/Dictionaries/zh-CN.json @@ -110,6 +110,11 @@ "button2": "...", "RestoreDefaultsButton": "恢复默认值", "buttonClose": "关闭" + }, + "PathSettingsForm": { + "Title": "路径设置", + "tsBtnReloadPaths": "重新加载路径", + "tsBtnSetPathManual": "手动设置路径" } } } From 2833dcd364c639ba11f77995a84ed0cda60f0bad Mon Sep 17 00:00:00 2001 From: nbyaya Date: Sat, 3 Oct 2026 21:17:09 +0800 Subject: [PATCH 08/30] fix: Add ToolStripButton localization support --- UoFiddler/Localization/LocalizationService.cs | 21 +++++++++++++++++++ 1 file changed, 21 insertions(+) diff --git a/UoFiddler/Localization/LocalizationService.cs b/UoFiddler/Localization/LocalizationService.cs index 19c151f1..35770579 100644 --- a/UoFiddler/Localization/LocalizationService.cs +++ b/UoFiddler/Localization/LocalizationService.cs @@ -121,6 +121,11 @@ private static void LocalizeToolStripItems(ToolStripItemCollection items, string Console.WriteLine($"[LocalizationService] 处理ToolStripMenuItem: {menuItem.Name}"); LocalizeMenuStripItem(menuItem, formName); } + else if (item is ToolStripButton button) + { + Console.WriteLine($"[LocalizationService] 处理ToolStripButton: {button.Name}"); + LocalizeToolStripButton(button, formName); + } } } @@ -147,6 +152,22 @@ private static void LocalizeToolStripItem(ToolStripDropDownButton item, string f } } + /// + /// 本地化ToolStripButton + /// + private static void LocalizeToolStripButton(ToolStripButton button, string formName) + { + if (!string.IsNullOrEmpty(button.Name)) + { + string? localizedText = GetString($"Forms.{formName}.{button.Name}"); + if (!string.IsNullOrEmpty(localizedText)) + { + Console.WriteLine($"[LocalizationService] ToolStripButton {button.Name} → {localizedText}"); + button.Text = localizedText; + } + } + } + /// /// 本地化菜单条 /// From 4e042f2156ec85cc39cae597f73810654a7fb440 Mon Sep 17 00:00:00 2001 From: nbyaya Date: Sat, 3 Oct 2026 21:20:29 +0800 Subject: [PATCH 09/30] feat: Add ManageToolsForm localization and update ExternTools menu --- UoFiddler/Forms/ManageToolsForm.cs | 4 ++++ UoFiddler/Localization/Dictionaries/zh-CN.json | 16 ++++++++++++++++ 2 files changed, 20 insertions(+) diff --git a/UoFiddler/Forms/ManageToolsForm.cs b/UoFiddler/Forms/ManageToolsForm.cs index 79e7ec1d..9f4f7b8f 100644 --- a/UoFiddler/Forms/ManageToolsForm.cs +++ b/UoFiddler/Forms/ManageToolsForm.cs @@ -15,6 +15,7 @@ using System.Windows.Forms; using UoFiddler.Classes; using UoFiddler.Controls.Classes; +using UoFiddler.Localization; namespace UoFiddler.Forms { @@ -29,6 +30,9 @@ public ManageToolsForm(Action loadExternToolStripMenuAction) Icon = Options.GetFiddlerIcon(); _loadExternToolStripMenuAction = loadExternToolStripMenuAction; + + // 应用中文汉化 + LocalizationService.LocalizeForm(this); } private void OnLoad(object sender, EventArgs e) diff --git a/UoFiddler/Localization/Dictionaries/zh-CN.json b/UoFiddler/Localization/Dictionaries/zh-CN.json index cb5311ec..fba8acd0 100644 --- a/UoFiddler/Localization/Dictionaries/zh-CN.json +++ b/UoFiddler/Localization/Dictionaries/zh-CN.json @@ -40,6 +40,7 @@ "optionsToolStripMenuItem": "选项...", "pathSettingsMenuItem": "路径设置...", "reloadFilesMenuItem": "重新加载文件", + "manageToolStripMenuItem": "管理...", "ToggleViewStart": "开始", "ToggleViewMulti": "多重组件", "ToggleViewAnimations": "动画", @@ -115,6 +116,21 @@ "Title": "路径设置", "tsBtnReloadPaths": "重新加载路径", "tsBtnSetPathManual": "手动设置路径" + }, + "ManageToolsForm": { + "Title": "管理工具", + "groupBox3": "工具列表", + "groupBox4": "参数列表", + "groupBox1": "工具", + "groupBox2": "参数", + "label1": "参数列表", + "button1": "...", + "button2": "添加", + "button3": "删除", + "button4": "删除", + "button5": "保存", + "button6": "添加", + "button7": "保存" } } } From bfb89fd234b41036609d98ae6bcfa17b8f1d42d5 Mon Sep 17 00:00:00 2001 From: nbyaya Date: Sat, 3 Oct 2026 21:31:39 +0800 Subject: [PATCH 10/30] fix: Localize dynamic ExternTools menu items (Manage.., Start) in MainForm --- UoFiddler/Forms/MainForm.cs | 4 ++-- UoFiddler/Localization/Dictionaries/zh-CN.json | 1 + 2 files changed, 3 insertions(+), 2 deletions(-) diff --git a/UoFiddler/Forms/MainForm.cs b/UoFiddler/Forms/MainForm.cs index c630c96a..086da7a7 100644 --- a/UoFiddler/Forms/MainForm.cs +++ b/UoFiddler/Forms/MainForm.cs @@ -255,7 +255,7 @@ public void LoadExternToolStripMenu() ToolStripMenuItem item = new ToolStripMenuItem { - Text = "Manage.." + Text = LocalizationService.GetString("Forms.MainForm.Menus.manageToolStripMenuItem") ?? "Manage.." }; item.Click += OnClickToolManage; @@ -280,7 +280,7 @@ public void LoadExternToolStripMenu() ToolStripMenuItem sub = new ToolStripMenuItem { - Text = "Start", + Text = LocalizationService.GetString("Forms.MainForm.Menus.Start") ?? "Start", Tag = -1 }; diff --git a/UoFiddler/Localization/Dictionaries/zh-CN.json b/UoFiddler/Localization/Dictionaries/zh-CN.json index fba8acd0..c9ecd387 100644 --- a/UoFiddler/Localization/Dictionaries/zh-CN.json +++ b/UoFiddler/Localization/Dictionaries/zh-CN.json @@ -41,6 +41,7 @@ "pathSettingsMenuItem": "路径设置...", "reloadFilesMenuItem": "重新加载文件", "manageToolStripMenuItem": "管理...", + "Start": "开始", "ToggleViewStart": "开始", "ToggleViewMulti": "多重组件", "ToggleViewAnimations": "动画", From 552d95e2c2963725f66b2eb35895369adceb606e Mon Sep 17 00:00:00 2001 From: nbyaya Date: Sat, 3 Oct 2026 22:25:27 +0800 Subject: [PATCH 11/30] feat: Localize ManagePluginsForm, AboutBoxForm, and ExceptionForm MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit - Add LocalizationService.LocalizeForm() to ManagePluginsForm, AboutBoxForm, and ExceptionForm - Add Chinese translations for 3 additional forms in zh-CN.json: - ManagePluginsForm: 管理插件(需要重新启动) - AboutBoxForm: 关于 with localized controls (checkboxes, buttons, labels) - ExceptionForm: 异常, 确定 - All localization follows non-invasive pattern: JSON-based translations with minimal code changes - Compilation: ✅ Success (0 errors) --- UoFiddler/Forms/AboutBoxForm.cs | 4 ++++ UoFiddler/Forms/ExceptionForm.cs | 4 ++++ UoFiddler/Forms/MainForm.cs | 24 +++++++++++++++++++ UoFiddler/Forms/ManagePluginsForm.cs | 4 ++++ .../Localization/Dictionaries/zh-CN.json | 24 +++++++++++++++++++ 5 files changed, 60 insertions(+) diff --git a/UoFiddler/Forms/AboutBoxForm.cs b/UoFiddler/Forms/AboutBoxForm.cs index 43545cbd..d978df17 100644 --- a/UoFiddler/Forms/AboutBoxForm.cs +++ b/UoFiddler/Forms/AboutBoxForm.cs @@ -14,6 +14,7 @@ using System.Windows.Forms; using UoFiddler.Classes; using UoFiddler.Controls.Classes; +using UoFiddler.Localization; namespace UoFiddler.Forms { @@ -23,6 +24,9 @@ public AboutBoxForm() { InitializeComponent(); Icon = Options.GetFiddlerIcon(); + + // 汉化窗口 + LocalizationService.LocalizeForm(this); checkBoxCheckOnStart.Checked = FiddlerOptions.UpdateCheckOnStart; checkBoxFormState.Checked = FiddlerOptions.StoreFormState; diff --git a/UoFiddler/Forms/ExceptionForm.cs b/UoFiddler/Forms/ExceptionForm.cs index dc9a3ec6..76f9a087 100644 --- a/UoFiddler/Forms/ExceptionForm.cs +++ b/UoFiddler/Forms/ExceptionForm.cs @@ -12,6 +12,7 @@ using System; using System.Windows.Forms; using UoFiddler.Controls.Classes; +using UoFiddler.Localization; namespace UoFiddler.Forms { @@ -21,6 +22,9 @@ public ExceptionForm(Exception err) { InitializeComponent(); Icon = Options.GetFiddlerIcon(); + + // 汉化窗口 + LocalizationService.LocalizeForm(this); richTextBox.Text = err.InnerException != null ? $"{err.InnerException.Message}\n{err.InnerException.GetType()}" diff --git a/UoFiddler/Forms/MainForm.cs b/UoFiddler/Forms/MainForm.cs index 086da7a7..8fac941e 100644 --- a/UoFiddler/Forms/MainForm.cs +++ b/UoFiddler/Forms/MainForm.cs @@ -109,6 +109,10 @@ public MainForm(ILogger logger) } plug.Instance.ModifyPluginToolStrip(toolStripDropDownButtonPlugins); + + // 汉化插件菜单项 + LocalizePluginMenuItems(toolStripDropDownButtonPlugins, plug.Instance.Name); + plug.Instance.ModifyTabPages(TabPanel); } @@ -445,6 +449,26 @@ private void OnClickUnDock(object sender, EventArgs e) TabPanel.TabPages.Remove(TabPanel.SelectedTab); } + /// + /// 汉化插件添加的菜单项 + /// + private void LocalizePluginMenuItems(ToolStripDropDownButton toolStrip, string pluginName) + { + foreach (ToolStripItem item in toolStrip.DropDownItems) + { + if (item is ToolStripMenuItem menuItem && !string.IsNullOrEmpty(menuItem.Text)) + { + // 首先尝试使用 Name 作为键(如果设置了的话) + string lookupKey = !string.IsNullOrEmpty(menuItem.Name) ? menuItem.Name : menuItem.Text; + string? localizedText = LocalizationService.GetString($"Forms.MainForm.Plugins.{lookupKey}"); + if (!string.IsNullOrEmpty(localizedText)) + { + menuItem.Text = localizedText; + } + } + } + } + /// /// ReDocks closed Form /// diff --git a/UoFiddler/Forms/ManagePluginsForm.cs b/UoFiddler/Forms/ManagePluginsForm.cs index 7738ddea..7a8c1591 100644 --- a/UoFiddler/Forms/ManagePluginsForm.cs +++ b/UoFiddler/Forms/ManagePluginsForm.cs @@ -15,6 +15,7 @@ using Microsoft.Extensions.Logging; using UoFiddler.Controls.Classes; using UoFiddler.Controls.Plugin; +using UoFiddler.Localization; using Ultima.Helpers; namespace UoFiddler.Forms @@ -27,6 +28,9 @@ public ManagePluginsForm() { InitializeComponent(); Icon = Options.GetFiddlerIcon(); + + // 汉化窗口标题 + LocalizationService.LocalizeForm(this); foreach (AvailablePlugin plugin in GlobalPlugins.Plugins.AvailablePlugins) { diff --git a/UoFiddler/Localization/Dictionaries/zh-CN.json b/UoFiddler/Localization/Dictionaries/zh-CN.json index c9ecd387..fcacc36b 100644 --- a/UoFiddler/Localization/Dictionaries/zh-CN.json +++ b/UoFiddler/Localization/Dictionaries/zh-CN.json @@ -67,6 +67,13 @@ "manageToolStripMenuItem1": "管理...", "toolStripMenuItemHelp": "帮助", "toolStripMenuItemAbout": "关于" + }, + "Plugins": { + "Mass Import": "批量导入", + "Compare": "比较", + "Multi Editor": "多编辑器", + "Send Item": "发送物品", + "UOP Packer": "UOP打包器" } }, "LoadProfileForm": { @@ -118,6 +125,9 @@ "tsBtnReloadPaths": "重新加载路径", "tsBtnSetPathManual": "手动设置路径" }, + "ManagePluginsForm": { + "Title": "管理插件(需要重新启动)" + }, "ManageToolsForm": { "Title": "管理工具", "groupBox3": "工具列表", @@ -132,6 +142,20 @@ "button5": "保存", "button6": "添加", "button7": "保存" + }, + "AboutBoxForm": { + "Title": "关于", + "checkBoxCheckOnStart": "启动时检查更新", + "button1": "检查更新", + "linkLabel1": "访问主页", + "label1": "项目作者和管理员", + "label3": "特殊贡献者", + "label5": "特别感谢", + "checkBoxFormState": "保存窗口状态" + }, + "ExceptionForm": { + "Title": "异常", + "OK": "确定" } } } From 3d81550b72636c34f8810d88b8a5d8bbe620bacc Mon Sep 17 00:00:00 2001 From: nbyaya Date: Sat, 3 Oct 2026 23:14:13 +0800 Subject: [PATCH 12/30] feat: Localize ManagePluginsForm plugin names with display-data separation MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit - Add mapping dictionary to separate display names from original plugin names - Localize plugin names in checklist using zh-CN.json entries - Update OnSelect method to use original names for plugin info lookup - Update OnClosing method to preserve check state using original names - Localize window title to '管理插件(需要重新启动)' - Add zh-CN.json entries for all 6 plugins: - MassImportPlugin -> 批量导入插件 - ComparePlugin -> 对比插件 - MultiEditorPlugin -> 多编辑器插件 - SendItemPlugin -> 发送物品插件 - UOP Packer -> UOP打包器 - PluginTest -> 插件测试 - Ensures check/uncheck functionality works correctly with localized names - Compilation: ✅ Success (0 errors) --- UoFiddler/Forms/ManagePluginsForm.cs | 52 +++++++++++++++++-- .../Localization/Dictionaries/zh-CN.json | 10 +++- 2 files changed, 57 insertions(+), 5 deletions(-) diff --git a/UoFiddler/Forms/ManagePluginsForm.cs b/UoFiddler/Forms/ManagePluginsForm.cs index 7a8c1591..04667a39 100644 --- a/UoFiddler/Forms/ManagePluginsForm.cs +++ b/UoFiddler/Forms/ManagePluginsForm.cs @@ -10,6 +10,7 @@ ***************************************************************************/ using System; +using System.Collections.Generic; using System.Drawing; using System.Windows.Forms; using Microsoft.Extensions.Logging; @@ -23,6 +24,9 @@ namespace UoFiddler.Forms public partial class ManagePluginsForm : Form { private static readonly ILogger _log = AppLog.For(typeof(ManagePluginsForm)); + + // 保存显示名称到原始名称的映射 + private readonly Dictionary _displayNameToOriginalName = new Dictionary(); public ManagePluginsForm() { @@ -41,7 +45,23 @@ public ManagePluginsForm() plugin.CreateInstance(); loaded = false; } - checkedListBox1.Items.Add(plugin.Instance.Name, loaded); + + // 获取原始名称 + string originalName = plugin.Instance.Name; + + // 尝试获取汉化名称 + string displayName = originalName; + string? localizedName = LocalizationService.GetString($"Forms.ManagePluginsForm.Plugins.{originalName}"); + if (!string.IsNullOrEmpty(localizedName)) + { + displayName = localizedName; + } + + // 保存映射关系 + _displayNameToOriginalName[displayName] = originalName; + + // 添加到列表(使用汉化后的显示名称) + checkedListBox1.Items.Add(displayName, loaded); } } @@ -53,7 +73,17 @@ private void OnSelect(object sender, EventArgs e) return; } - AvailablePlugin selPlugin = GlobalPlugins.Plugins.AvailablePlugins.Find(checkedListBox1.SelectedItem.ToString()); + // 获取显示的名称 + string displayName = checkedListBox1.SelectedItem.ToString(); + + // 转换为原始名称 + string originalName = displayName; + if (_displayNameToOriginalName.ContainsKey(displayName)) + { + originalName = _displayNameToOriginalName[displayName]; + } + + AvailablePlugin selPlugin = GlobalPlugins.Plugins.AvailablePlugins.Find(originalName); if (selPlugin == null) { return; @@ -78,9 +108,23 @@ private void OnClosing(object sender, FormClosingEventArgs e) { foreach (AvailablePlugin plug in GlobalPlugins.Plugins.AvailablePlugins) { + // 找到该插件在列表中的显示名称 + string originalName = plug.Instance.Name; + string displayName = originalName; + + // 查找对应的显示名称 + foreach (var kvp in _displayNameToOriginalName) + { + if (kvp.Value == originalName) + { + displayName = kvp.Key; + break; + } + } + if (Options.PluginsToLoad?.Contains(plug.Type.ToString()) == false) { - if (checkedListBox1.CheckedItems.Contains(plug.Instance.Name)) + if (checkedListBox1.CheckedItems.Contains(displayName)) { _log.LogInformation("ManagePlugins - adding plugin to profile: {Plugin}", plug.Type.ToString()); Options.PluginsToLoad.Add(plug.Type.ToString()); @@ -90,7 +134,7 @@ private void OnClosing(object sender, FormClosingEventArgs e) } else { - if (!checkedListBox1.CheckedItems.Contains(plug.Instance.Name)) + if (!checkedListBox1.CheckedItems.Contains(displayName)) { _log.LogInformation("ManagePlugins - removing plugin from profile: {Plugin}", plug.Type.ToString()); Options.PluginsToLoad.Remove(plug.Type.ToString()); diff --git a/UoFiddler/Localization/Dictionaries/zh-CN.json b/UoFiddler/Localization/Dictionaries/zh-CN.json index fcacc36b..5136802a 100644 --- a/UoFiddler/Localization/Dictionaries/zh-CN.json +++ b/UoFiddler/Localization/Dictionaries/zh-CN.json @@ -126,7 +126,15 @@ "tsBtnSetPathManual": "手动设置路径" }, "ManagePluginsForm": { - "Title": "管理插件(需要重新启动)" + "Title": "管理插件(需要重新启动)", + "Plugins": { + "MassImportPlugin": "批量导入插件", + "ComparePlugin": "对比插件", + "MultiEditorPlugin": "多编辑器插件", + "SendItemPlugin": "发送物品插件", + "UOP Packer": "UOP打包器", + "PluginTest": "插件测试" + } }, "ManageToolsForm": { "Title": "管理工具", From 2a09683600949615a2564d89bd1f1dba69d529ce Mon Sep 17 00:00:00 2001 From: nbyaya Date: Sat, 3 Oct 2026 23:56:44 +0800 Subject: [PATCH 13/30] =?UTF-8?q?fix:=20=E4=BF=AE=E5=A4=8D=E6=8F=92?= =?UTF-8?q?=E4=BB=B6=E5=A4=9A=E6=A0=87=E7=AD=BE=E9=A1=B5=E6=B1=89=E5=8C=96?= =?UTF-8?q?=E9=97=AE=E9=A2=98=20-=20=E6=94=AF=E6=8C=81=20Compare=20?= =?UTF-8?q?=E6=8F=92=E4=BB=B6=E7=9A=84=2010=20=E4=B8=AA=E6=A0=87=E7=AD=BE?= =?UTF-8?q?=E9=A1=B5?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit - 改进 LocalizePluginTabPages() 方法,支持处理一个插件添加的多个标签页 - 在调用 ModifyTabPages() 前记录标签页数量,然后汉化所有新添加的标签页 - 修正 JSON 中 'Compare CliLocs' 的大小写(之前是 'Compare Clilocs') - 现在 Compare 插件的所有 10 个对比标签页都能正确显示中文 测试验证: ✅ Compare Items → 对比物品 ✅ Compare Land → 对比地形 ✅ Compare CliLocs → 对比CliLoc ✅ Compare Hues → 对比色调 ✅ Compare Gumps → 对比Gump ✅ Compare Map → 对比地图 ✅ Compare Texture → 对比纹理 ✅ Compare AnimData → 对比动画数据 ✅ Compare RadarCol → 对比雷达颜色 ✅ Compare TileData → 对比图块数据 --- UoFiddler/Forms/MainForm.cs | 41 ++++++++++++++++--- .../Localization/Dictionaries/zh-CN.json | 19 +++++++-- 2 files changed, 52 insertions(+), 8 deletions(-) diff --git a/UoFiddler/Forms/MainForm.cs b/UoFiddler/Forms/MainForm.cs index 8fac941e..97658410 100644 --- a/UoFiddler/Forms/MainForm.cs +++ b/UoFiddler/Forms/MainForm.cs @@ -113,7 +113,12 @@ public MainForm(ILogger logger) // 汉化插件菜单项 LocalizePluginMenuItems(toolStripDropDownButtonPlugins, plug.Instance.Name); + // 记录添加标签页前的数量 + int tabCountBefore = TabPanel.TabPages.Count; plug.Instance.ModifyTabPages(TabPanel); + + // 汉化插件标签页标题(处理所有新添加的标签页) + LocalizePluginTabPages(TabPanel, tabCountBefore, plug.Instance.Name); } foreach (TabPage tab in TabPanel.TabPages) @@ -450,16 +455,19 @@ private void OnClickUnDock(object sender, EventArgs e) } /// - /// 汉化插件添加的菜单项 + /// 汉化插件添加的菜单项(仅处理最后一个菜单项,即刚添加的) /// private void LocalizePluginMenuItems(ToolStripDropDownButton toolStrip, string pluginName) { - foreach (ToolStripItem item in toolStrip.DropDownItems) + // 仅处理最后添加的菜单项 + if (toolStrip.DropDownItems.Count > 0) { - if (item is ToolStripMenuItem menuItem && !string.IsNullOrEmpty(menuItem.Text)) + ToolStripItem lastItem = toolStrip.DropDownItems[toolStrip.DropDownItems.Count - 1]; + + if (lastItem is ToolStripMenuItem menuItem && !string.IsNullOrEmpty(menuItem.Text)) { - // 首先尝试使用 Name 作为键(如果设置了的话) - string lookupKey = !string.IsNullOrEmpty(menuItem.Name) ? menuItem.Name : menuItem.Text; + // 尝试使用菜单项文本作为键查找汉化 + string lookupKey = menuItem.Text; string? localizedText = LocalizationService.GetString($"Forms.MainForm.Plugins.{lookupKey}"); if (!string.IsNullOrEmpty(localizedText)) { @@ -469,6 +477,29 @@ private void LocalizePluginMenuItems(ToolStripDropDownButton toolStrip, string p } } + /// + /// 汉化插件添加的标签页标题 + /// + private void LocalizePluginTabPages(TabControl tabControl, int startIndex, string pluginName) + { + // 处理从 startIndex 开始的所有新添加的标签页 + for (int i = startIndex; i < tabControl.TabPages.Count; i++) + { + TabPage tab = tabControl.TabPages[i]; + + if (!string.IsNullOrEmpty(tab.Text)) + { + // 尝试使用标签页文本作为键查找汉化 + string lookupKey = tab.Text; + string? localizedText = LocalizationService.GetString($"Forms.MainForm.PluginTabPages.{lookupKey}"); + if (!string.IsNullOrEmpty(localizedText)) + { + tab.Text = localizedText; + } + } + } + } + /// /// ReDocks closed Form /// diff --git a/UoFiddler/Localization/Dictionaries/zh-CN.json b/UoFiddler/Localization/Dictionaries/zh-CN.json index 5136802a..626a7696 100644 --- a/UoFiddler/Localization/Dictionaries/zh-CN.json +++ b/UoFiddler/Localization/Dictionaries/zh-CN.json @@ -70,10 +70,23 @@ }, "Plugins": { "Mass Import": "批量导入", - "Compare": "比较", - "Multi Editor": "多编辑器", "Send Item": "发送物品", - "UOP Packer": "UOP打包器" + "PluginTest": "插件测试" + }, + "PluginTabPages": { + "Multi Editor": "多编辑器", + "PluginTest": "插件测试", + "UOP Packer": "UOP打包器", + "Compare Items": "对比物品", + "Compare Land": "对比地形", + "Compare CliLocs": "对比CliLoc", + "Compare Hues": "对比色调", + "Compare Gumps": "对比Gump", + "Compare Map": "对比地图", + "Compare Texture": "对比纹理", + "Compare AnimData": "对比动画数据", + "Compare RadarCol": "对比雷达颜色", + "Compare TileData": "对比图块数据" } }, "LoadProfileForm": { From 17e2153c751be055870e81f90f92b4de119c509d Mon Sep 17 00:00:00 2001 From: nbyaya Date: Sun, 4 Oct 2026 00:04:22 +0800 Subject: [PATCH 14/30] =?UTF-8?q?feat:=20=E6=B1=89=E5=8C=96=E6=89=B9?= =?UTF-8?q?=E9=87=8F=E5=AF=BC=E5=85=A5=E6=8F=92=E4=BB=B6=E7=AA=97=E5=8F=A3?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit - 添加 MassImportForm 的汉化支持 - 在 PluginBase 中添加静态 LocalizationGetter 属性作为汉化回调 - 在 MainForm 中初始化 PluginBase.LocalizationGetter - 修改 MassImportForm 添加 SetLocalization() 方法和 Shown 事件汉化 - 修改 MassImportPluginBase 在创建窗体时应用汉化 汉化内容: ✅ 窗口标题: MassImport → 批量导入 ✅ groupBox1: XML → XML ✅ button1: Create Default XML → 创建默认 XML ✅ button2: Load XML → 加载 XML ✅ groupBox2: OutPut → 输出 ✅ button3: Start → 开始 ✅ checkBoxDirectSave: DirectSave → 直接保存 --- UoFiddler.Controls/Plugin/PluginBase.cs | 6 +++ .../Forms/MassImportForm.cs | 41 +++++++++++++++++++ .../MassImportPluginBase.cs | 7 ++++ UoFiddler/Forms/MainForm.cs | 3 ++ .../Localization/Dictionaries/zh-CN.json | 9 ++++ 5 files changed, 66 insertions(+) diff --git a/UoFiddler.Controls/Plugin/PluginBase.cs b/UoFiddler.Controls/Plugin/PluginBase.cs index d653ed01..098bc93c 100644 --- a/UoFiddler.Controls/Plugin/PluginBase.cs +++ b/UoFiddler.Controls/Plugin/PluginBase.cs @@ -9,6 +9,7 @@ * ***************************************************************************/ +using System; using System.Windows.Forms; using Microsoft.Extensions.Logging; using UoFiddler.Controls.Classes; @@ -26,6 +27,11 @@ public abstract class PluginBase public abstract string Author { get; } public abstract string Version { get; } + /// + /// 静态属性:汉化字符串获取器,由主程序在启动时设置 + /// + public static Func LocalizationGetter { get; set; } + /// /// Per-plugin logger, categorized by the concrete plugin type. Resolved on demand /// since plugins are instantiated via Activator and cannot take constructor parameters. diff --git a/UoFiddler.Plugin.MassImport/Forms/MassImportForm.cs b/UoFiddler.Plugin.MassImport/Forms/MassImportForm.cs index 4176accf..01588383 100644 --- a/UoFiddler.Plugin.MassImport/Forms/MassImportForm.cs +++ b/UoFiddler.Plugin.MassImport/Forms/MassImportForm.cs @@ -30,6 +30,47 @@ public MassImportForm() Icon = Options.GetFiddlerIcon(); _importList = new List(); + + // 在窗体加载完成后应用汉化 + this.Shown += (s, e) => + { + if (_localizationGetter != null) + { + ApplyLocalization(); + } + }; + } + + private Func _localizationGetter; + + /// + /// 设置汉化回调 + /// + /// 返回汉化字符串的委托,参数为键值 + public void SetLocalization(Func localizationGetter) + { + _localizationGetter = localizationGetter; + // 如果窗体已显示,立即应用汉化 + if (this.Visible) + { + ApplyLocalization(); + } + } + + private void ApplyLocalization() + { + if (_localizationGetter == null) + { + return; + } + + this.Text = _localizationGetter("Forms.MassImportForm.Title") ?? "批量导入"; + groupBox1.Text = _localizationGetter("Forms.MassImportForm.groupBox1") ?? "XML"; + button1.Text = _localizationGetter("Forms.MassImportForm.button1") ?? "创建默认 XML"; + button2.Text = _localizationGetter("Forms.MassImportForm.button2") ?? "加载 XML"; + groupBox2.Text = _localizationGetter("Forms.MassImportForm.groupBox2") ?? "输出"; + button3.Text = _localizationGetter("Forms.MassImportForm.button3") ?? "开始"; + checkBoxDirectSave.Text = _localizationGetter("Forms.MassImportForm.checkBoxDirectSave") ?? "直接保存"; } private void DefaultXMLOnClick(object sender, EventArgs e) diff --git a/UoFiddler.Plugin.MassImport/MassImportPluginBase.cs b/UoFiddler.Plugin.MassImport/MassImportPluginBase.cs index da3d4b09..401d7c8e 100644 --- a/UoFiddler.Plugin.MassImport/MassImportPluginBase.cs +++ b/UoFiddler.Plugin.MassImport/MassImportPluginBase.cs @@ -76,6 +76,13 @@ private void ToolStripClick(object sender, EventArgs e) { TopMost = true }; + + // 应用汉化 + if (PluginBase.LocalizationGetter != null) + { + _importForm.SetLocalization(PluginBase.LocalizationGetter); + } + _importForm.Show(); } } diff --git a/UoFiddler/Forms/MainForm.cs b/UoFiddler/Forms/MainForm.cs index 97658410..75ce6a9c 100644 --- a/UoFiddler/Forms/MainForm.cs +++ b/UoFiddler/Forms/MainForm.cs @@ -97,6 +97,9 @@ public MainForm(ILogger logger) LoadExternToolStripMenu(); GlobalPlugins.Plugins.FindPlugins($@"{Application.StartupPath}\plugins"); + // 为所有插件设置汉化 getter + UoFiddler.Controls.Plugin.PluginBase.LocalizationGetter = (key) => LocalizationService.GetString(key); + SetStyle(ControlStyles.OptimizedDoubleBuffer, true); SetStyle(ControlStyles.UserPaint, true); SetStyle(ControlStyles.AllPaintingInWmPaint, true); diff --git a/UoFiddler/Localization/Dictionaries/zh-CN.json b/UoFiddler/Localization/Dictionaries/zh-CN.json index 626a7696..b5a92b31 100644 --- a/UoFiddler/Localization/Dictionaries/zh-CN.json +++ b/UoFiddler/Localization/Dictionaries/zh-CN.json @@ -177,6 +177,15 @@ "ExceptionForm": { "Title": "异常", "OK": "确定" + }, + "MassImportForm": { + "Title": "批量导入", + "groupBox1": "XML", + "button1": "创建默认 XML", + "button2": "加载 XML", + "groupBox2": "输出", + "button3": "开始", + "checkBoxDirectSave": "直接保存" } } } From eb70af46d4b6b2e98a52b0bcc5070c6711fc41dc Mon Sep 17 00:00:00 2001 From: nbyaya Date: Sun, 4 Oct 2026 00:26:48 +0800 Subject: [PATCH 15/30] feat: Localize MultiEditor and OptionsForm UI and tooltips --- .../UserControls/MultiEditorControl.cs | 60 +++++++++++++++ UoFiddler/Forms/OptionsForm.cs | 34 ++++++++ .../Localization/Dictionaries/zh-CN.json | 77 ++++++++++++++++++- 3 files changed, 168 insertions(+), 3 deletions(-) diff --git a/UoFiddler.Plugin.MultiEditor/UserControls/MultiEditorControl.cs b/UoFiddler.Plugin.MultiEditor/UserControls/MultiEditorControl.cs index 720b9fd0..f17ab992 100644 --- a/UoFiddler.Plugin.MultiEditor/UserControls/MultiEditorControl.cs +++ b/UoFiddler.Plugin.MultiEditor/UserControls/MultiEditorControl.cs @@ -106,7 +106,66 @@ public MultiEditorControl() pictureBoxDrawTiles.MouseWheel += PictureBoxDrawTiles_OnMouseWheel; pictureBoxMulti.MouseWheel += PictureBoxMulti_OnMouseWheel; + + // 在加载完成时应用汉化 + this.Load += (s, e) => ApplyLocalization(); + } + /// + /// 应用汉化(内部方法) + /// + private void ApplyLocalization() + { + var getter = UoFiddler.Controls.Plugin.PluginBase.LocalizationGetter; + if (getter == null) return; + + tileTab.Text = getter("Forms.MultiEditorControl.tileTab") ?? "Tiles"; + designTab.Text = getter("Forms.MultiEditorControl.designTab") ?? "Design"; + importTab.Text = getter("Forms.MultiEditorControl.importTab") ?? "Import"; + Save.Text = getter("Forms.MultiEditorControl.Save") ?? "Save"; + groupBox1.Text = getter("Forms.MultiEditorControl.groupBox1") ?? "Multi Size"; + groupBox2.Text = getter("Forms.MultiEditorControl.groupBox2") ?? "Save"; + groupBox3.Text = getter("Forms.MultiEditorControl.groupBox3") ?? "Selected Tile X,Y,Z"; + groupBox4.Text = getter("Forms.MultiEditorControl.groupBox4") ?? "Export"; + BTN_CreateBlank.Text = getter("Forms.MultiEditorControl.BTN_CreateBlank") ?? "Create Blank"; + BTN_Resize.Text = getter("Forms.MultiEditorControl.BTN_Resize") ?? "Resize Multi"; + BTN_Save.Text = getter("Forms.MultiEditorControl.BTN_Save") ?? "Save to ID"; + BTN_Export_XML.Text = getter("Forms.MultiEditorControl.BTN_Export_XML") ?? ".xml"; + BTN_Export_CSV.Text = getter("Forms.MultiEditorControl.BTN_Export_CSV") ?? ".csv"; + BTN_Export_WSC.Text = getter("Forms.MultiEditorControl.BTN_Export_WSC") ?? ".wsc"; + BTN_Export_UOA.Text = getter("Forms.MultiEditorControl.BTN_Export_UOA") ?? ".uoa.txt"; + BTN_Export_UOX3.Text = getter("Forms.MultiEditorControl.BTN_Export_UOX3") ?? ".uox3"; + BTN_Export_Txt.Text = getter("Forms.MultiEditorControl.BTN_Export_Txt") ?? ".txt"; + brushSizeLabel.Text = getter("Forms.MultiEditorControl.brushSizeLabel") ?? "Brush size:"; + RB_Brush_S.Text = getter("Forms.MultiEditorControl.RB_Brush_S") ?? "S"; + RB_Brush_M.Text = getter("Forms.MultiEditorControl.RB_Brush_M") ?? "M"; + RB_Brush_L.Text = getter("Forms.MultiEditorControl.RB_Brush_L") ?? "L"; + DynamiccheckBox.Text = getter("Forms.MultiEditorControl.DynamiccheckBox") ?? "Invisible"; + toolStripDropDownButton1.Text = getter("Forms.MultiEditorControl.toolStripDropDownButton1") ?? "Misc"; + UndoItems.Text = getter("Forms.MultiEditorControl.UndoItems") ?? "Undo"; + showWalkablesToolStripMenuItem.Text = getter("Forms.MultiEditorControl.showWalkablesToolStripMenuItem") ?? "Show Walkable tiles"; + showDoubleSurfaceMenuItem.Text = getter("Forms.MultiEditorControl.showDoubleSurfaceMenuItem") ?? "Show double surface"; + removeAllTransToolStripMenuItem.Text = getter("Forms.MultiEditorControl.removeAllTransToolStripMenuItem") ?? "Reset transparent tiles"; + DrawTileLabel.Text = getter("Forms.MultiEditorControl.DrawTileLabel") ?? "Draw ID:"; + SelectedTileLabel.Text = getter("Forms.MultiEditorControl.SelectedTileLabel") ?? "ID:"; + toolStripBtnHelp.Text = getter("Forms.MultiEditorControl.toolStripBtnHelp") ?? "Help"; + + toolTip1.SetToolTip(textBox_Export, getter("Forms.MultiEditorControl.tooltip_textBox_Export") ?? "FileName"); + toolTip1.SetToolTip(BTN_RectFill, getter("Forms.MultiEditorControl.tooltip_BTN_RectFill") ?? "Rectangle Fill [B]"); + toolTip1.SetToolTip(BTN_LineDraw, getter("Forms.MultiEditorControl.tooltip_BTN_LineDraw") ?? "Line Draw [L]"); + toolTip1.SetToolTip(RB_Brush_S, getter("Forms.MultiEditorControl.tooltip_RB_Brush_S") ?? "Small brush (1x1)"); + toolTip1.SetToolTip(RB_Brush_M, getter("Forms.MultiEditorControl.tooltip_RB_Brush_M") ?? "Medium brush (3x3)"); + toolTip1.SetToolTip(RB_Brush_L, getter("Forms.MultiEditorControl.tooltip_RB_Brush_L") ?? "Large brush (5x5)"); + toolTip1.SetToolTip(BTN_Trans, getter("Forms.MultiEditorControl.tooltip_BTN_Trans") ?? "Switch Transparent [T]"); + toolTip1.SetToolTip(BTN_Pipette, getter("Forms.MultiEditorControl.tooltip_BTN_Pipette") ?? "Pick A Tile [P]"); + toolTip1.SetToolTip(BTN_Floor, getter("Forms.MultiEditorControl.tooltip_BTN_Floor") ?? "Draw Virtual Floor [F]"); + toolTip1.SetToolTip(BTN_Z, getter("Forms.MultiEditorControl.tooltip_BTN_Z") ?? "Apply Z Level [E]"); + toolTip1.SetToolTip(BTN_Remove, getter("Forms.MultiEditorControl.tooltip_BTN_Remove") ?? "Remove A Tile [R]"); + toolTip1.SetToolTip(BTN_Draw, getter("Forms.MultiEditorControl.tooltip_BTN_Draw") ?? "Draw A Tile [D]"); + toolTip1.SetToolTip(BTN_Select, getter("Forms.MultiEditorControl.tooltip_BTN_Select") ?? "Select A Tile [S]"); + toolTip1.SetToolTip(collapsibleSplitter1, getter("Forms.MultiEditorControl.tooltip_collapsibleSplitter1") ?? "Selected Tile Panel"); + toolTip1.SetToolTip(MaxHeightTrackBar, getter("Forms.MultiEditorControl.tooltip_MaxHeightTrackBar") ?? "Max Height Displayed"); + toolTip1.SetToolTip(pictureBoxMinimap, getter("Forms.MultiEditorControl.tooltip_pictureBoxMinimap") ?? "Minimap — click to pan"); } /// @@ -697,6 +756,7 @@ private void ApplyPreviewBackgroundColor() private void OnLoad(object sender, EventArgs e) { + ApplyLocalization(); ApplyDarkModeIfNeeded(); Options.LoadedUltimaClass["TileData"] = true; diff --git a/UoFiddler/Forms/OptionsForm.cs b/UoFiddler/Forms/OptionsForm.cs index 502817ef..53cbac5d 100644 --- a/UoFiddler/Forms/OptionsForm.cs +++ b/UoFiddler/Forms/OptionsForm.cs @@ -17,6 +17,7 @@ using Ultima; using UoFiddler.Classes; using UoFiddler.Controls.Classes; +using UoFiddler.Controls.Plugin; using UoFiddler.Localization; namespace UoFiddler.Forms @@ -101,6 +102,39 @@ public OptionsForm(Action updateAllTileViewsAction, // 应用中文汉化 LocalizationService.LocalizeForm(this); + + // 在 Load 事件中应用 ToolTip 汉化 + this.Load += (s, e) => ApplyLocalization(); + } + + private void ApplyLocalization() + { + var getter = PluginBase.LocalizationGetter; + if (getter == null) return; + + // ToolTips + toolTip1.SetToolTip(numericUpDownItemSizeHeight, getter("Forms.OptionsForm.tooltip_numericUpDownItemSizeHeight") ?? "Height"); + toolTip1.SetToolTip(checkBoxItemClip, getter("Forms.OptionsForm.tooltip_checkBoxItemClip") ?? "ItemClip images in items tab shrinked or clipped"); + toolTip1.SetToolTip(label1, getter("Forms.OptionsForm.tooltip_label1") ?? "ItemSize controls the size of images in items tab"); + toolTip1.SetToolTip(numericUpDownItemSizeWidth, getter("Forms.OptionsForm.tooltip_numericUpDownItemSizeWidth") ?? "Width"); + toolTip1.SetToolTip(checkBoxCacheData, getter("Forms.OptionsForm.tooltip_checkBoxCacheData") ?? "CacheData should mul entries be cached for faster load"); + toolTip1.SetToolTip(checkBoxNewMapSize, getter("Forms.OptionsForm.tooltip_checkBoxNewMapSize") ?? "NewMapSize Felucca/Trammel width 7168?"); + toolTip1.SetToolTip(checkBoxuseDiff, getter("Forms.OptionsForm.tooltip_checkBoxuseDiff") ?? "Should map diff files be used"); + toolTip1.SetToolTip(checkBoxPolSoundIdOffset, getter("Forms.OptionsForm.tooltip_checkBoxPolSoundIdOffset") ?? "UO Sounds are indexed from 0 but POL uses +1 offset.\r\nWhen this option is checked Sounds tab will display sound indexes starting from 1 instead of 0.\r\nThis option also affects the export sound list."); + toolTip1.SetToolTip(label2, getter("Forms.OptionsForm.tooltip_label2") ?? "Defines the map name"); + toolTip1.SetToolTip(label3, getter("Forms.OptionsForm.tooltip_label3") ?? "Defines the map name"); + toolTip1.SetToolTip(label4, getter("Forms.OptionsForm.tooltip_label4") ?? "Defines the map name"); + toolTip1.SetToolTip(label5, getter("Forms.OptionsForm.tooltip_label5") ?? "Defines the map name"); + toolTip1.SetToolTip(label6, getter("Forms.OptionsForm.tooltip_label6") ?? "Defines the map name"); + toolTip1.SetToolTip(label7, getter("Forms.OptionsForm.tooltip_label7") ?? "Defines the cmd to send Client to loc"); + toolTip1.SetToolTip(label8, getter("Forms.OptionsForm.tooltip_label8") ?? "{1} = x, {2} = y, {3} = z, {4} = mapid, {5} = mapname"); + toolTip1.SetToolTip(label9, getter("Forms.OptionsForm.tooltip_label9") ?? "Defines the map name"); + toolTip1.SetToolTip(FocusColorLabel, getter("Forms.OptionsForm.tooltip_FocusColorLabel") ?? "ItemSize controls the size of images in items tab"); + toolTip1.SetToolTip(SelectedColorLabel, getter("Forms.OptionsForm.tooltip_SelectedColorLabel") ?? "ItemSize controls the size of images in items tab"); + toolTip1.SetToolTip(radioExportFilenameHex, getter("Forms.OptionsForm.tooltip_radioExportFilenameHex") ?? "Exported filenames embed the ID in hexadecimal form."); + toolTip1.SetToolTip(radioExportFilenameDec, getter("Forms.OptionsForm.tooltip_radioExportFilenameDec") ?? "Exported filenames embed the ID in decimal form."); + toolTip1.SetToolTip(checkBoxExportFilenameDecPad, getter("Forms.OptionsForm.tooltip_checkBoxExportFilenameDecPad") ?? "When using decimal format, pad the ID with leading zeros so files sort correctly."); + toolTip1.SetToolTip(comboBoxSaveFormat, getter("Forms.OptionsForm.tooltip_comboBoxSaveFormat") ?? "Which container a save writes for the files the client ships as either. Affects art, gumpart, sound, multis and maps; everything else has only one format."); } private void OnClickApply(object sender, EventArgs e) diff --git a/UoFiddler/Localization/Dictionaries/zh-CN.json b/UoFiddler/Localization/Dictionaries/zh-CN.json index b5a92b31..923eb170 100644 --- a/UoFiddler/Localization/Dictionaries/zh-CN.json +++ b/UoFiddler/Localization/Dictionaries/zh-CN.json @@ -74,7 +74,7 @@ "PluginTest": "插件测试" }, "PluginTabPages": { - "Multi Editor": "多编辑器", + "Multi Editor": "Multi 编辑器", "PluginTest": "插件测试", "UOP Packer": "UOP打包器", "Compare Items": "对比物品", @@ -131,7 +131,29 @@ "buttonApply": "应用", "button2": "...", "RestoreDefaultsButton": "恢复默认值", - "buttonClose": "关闭" + "buttonClose": "关闭", + "tooltip_numericUpDownItemSizeHeight": "高度", + "tooltip_checkBoxItemClip": "物品裁剪:物品标签页中的物品图像是缩小还是裁剪", + "tooltip_label1": "物品大小控制物品标签页中图像的大小", + "tooltip_numericUpDownItemSizeWidth": "宽度", + "tooltip_checkBoxCacheData": "缓存数据:MUL条目是否应缓存以加快加载速度", + "tooltip_checkBoxNewMapSize": "新地图大小:Felucca/Trammel 宽度为 7168?", + "tooltip_checkBoxuseDiff": "是否应使用地图差异文件", + "tooltip_checkBoxPolSoundIdOffset": "UO 音效从 0 开始索引,但 POL 使用 +1 偏移。勾选此选项后,\"音效\"标签页将显示从 1 开始的音效索引,而不是从 0 开始。此选项也影响导出音效列表。", + "tooltip_label2": "定义地图名称", + "tooltip_label3": "定义地图名称", + "tooltip_label4": "定义地图名称", + "tooltip_label5": "定义地图名称", + "tooltip_label6": "定义地图名称", + "tooltip_label7": "定义发送客户端到位置的命令", + "tooltip_label8": "{1} = x, {2} = y, {3} = z, {4} = mapid, {5} = mapname", + "tooltip_label9": "定义地图名称", + "tooltip_FocusColorLabel": "物品大小控制物品标签页中图像的大小", + "tooltip_SelectedColorLabel": "物品大小控制物品标签页中图像的大小", + "tooltip_radioExportFilenameHex": "导出的文件名以十六进制形式嵌入 ID。", + "tooltip_radioExportFilenameDec": "导出的文件名以十进制形式嵌入 ID。", + "tooltip_checkBoxExportFilenameDecPad": "使用十进制格式时,用前导零填充 ID,以便文件正确排序。", + "tooltip_comboBoxSaveFormat": "选择保存文件时使用的容器格式。影响 art、gumpart、sound、multis 和 maps;其他所有内容只有一种格式。" }, "PathSettingsForm": { "Title": "路径设置", @@ -143,7 +165,7 @@ "Plugins": { "MassImportPlugin": "批量导入插件", "ComparePlugin": "对比插件", - "MultiEditorPlugin": "多编辑器插件", + "MultiEditorPlugin": "Multi 编辑器插件", "SendItemPlugin": "发送物品插件", "UOP Packer": "UOP打包器", "PluginTest": "插件测试" @@ -186,6 +208,55 @@ "groupBox2": "输出", "button3": "开始", "checkBoxDirectSave": "直接保存" + }, + "MultiEditorControl": { + "tileTab": "图块", + "designTab": "设计", + "importTab": "导入", + "Save": "保存", + "groupBox1": "Multi 尺寸", + "groupBox2": "保存", + "groupBox3": "选中图块 X,Y,Z", + "groupBox4": "导出", + "BTN_CreateBlank": "创建空白", + "BTN_Resize": "调整 Multi", + "BTN_Save": "保存到 ID", + "BTN_Export_XML": ".xml", + "BTN_Export_CSV": ".csv", + "BTN_Export_WSC": ".wsc", + "BTN_Export_UOA": ".uoa.txt", + "BTN_Export_UOX3": ".uox3", + "BTN_Export_Txt": ".txt", + "brushSizeLabel": "笔刷大小:", + "RB_Brush_S": "S", + "RB_Brush_M": "M", + "RB_Brush_L": "L", + "DynamiccheckBox": "隐形", + "toolStripDropDownButton1": "其他", + "UndoItems": "撤销", + "showWalkablesToolStripMenuItem": "显示可行走图块", + "showDoubleSurfaceMenuItem": "显示双层表面", + "removeAllTransToolStripMenuItem": "重置透明图块", + "DrawTileLabel": "绘制 ID:", + "SelectedTileLabel": "ID:", + "toolStripBtnHelp": "帮助", + "tooltip_textBox_Export": "文件名", + "tooltip_BTN_RectFill": "矩形填充 [B]", + "tooltip_BTN_LineDraw": "直线绘制 [L]", + "tooltip_RB_Brush_S": "小笔刷 (1x1)", + "tooltip_RB_Brush_M": "中笔刷 (3x3)", + "tooltip_RB_Brush_L": "大笔刷 (5x5)", + "tooltip_BTN_Trans": "切换透明 [T]", + "tooltip_BTN_Pipette": "拾取图块 [P]", + "tooltip_BTN_Floor": "绘制虚拟地面 [F]", + "tooltip_BTN_Z": "应用 Z 级别 [E]", + "tooltip_BTN_Remove": "删除图块 [R]", + "tooltip_BTN_Draw": "绘制图块 [D]", + "tooltip_BTN_Select": "选择图块 [S]", + "tooltip_collapsibleSplitter1": "选中图块面板", + "tooltip_MaxHeightTrackBar": "最大显示高度", + "tooltip_pictureBoxMinimap": "小地图 — 点击平移", + "tooltip_toolStripBtnZoom": "缩放 — 点击或 Ctrl+0 重置为 100%" } } } From a31fb779af120d33ac9443ec9bb9d676c7a9dc84 Mon Sep 17 00:00:00 2001 From: nbyaya Date: Sun, 4 Oct 2026 00:49:38 +0800 Subject: [PATCH 16/30] feat: Localize AboutBoxForm changelog --- UoFiddler/Forms/AboutBoxForm.cs | 17 +++++++++++++++++ UoFiddler/Localization/Dictionaries/zh-CN.json | 11 +++++++++++ 2 files changed, 28 insertions(+) diff --git a/UoFiddler/Forms/AboutBoxForm.cs b/UoFiddler/Forms/AboutBoxForm.cs index d978df17..4da97295 100644 --- a/UoFiddler/Forms/AboutBoxForm.cs +++ b/UoFiddler/Forms/AboutBoxForm.cs @@ -14,6 +14,7 @@ using System.Windows.Forms; using UoFiddler.Classes; using UoFiddler.Controls.Classes; +using UoFiddler.Controls.Plugin; using UoFiddler.Localization; namespace UoFiddler.Forms @@ -27,11 +28,27 @@ public AboutBoxForm() // 汉化窗口 LocalizationService.LocalizeForm(this); + + // 在 Load 事件中汉化更新日志 + this.Load += (s, e) => ApplyChangelogLocalization(); checkBoxCheckOnStart.Checked = FiddlerOptions.UpdateCheckOnStart; checkBoxFormState.Checked = FiddlerOptions.StoreFormState; } + private void ApplyChangelogLocalization() + { + var getter = PluginBase.LocalizationGetter; + if (getter == null) return; + + // 获取汉化的更新日志(如果有) + string changelog = getter("Forms.AboutBoxForm.changelog"); + if (!string.IsNullOrEmpty(changelog)) + { + richTextBox1.Text = changelog; + } + } + private void OnChangeCheck(object sender, EventArgs e) { FiddlerOptions.UpdateCheckOnStart = checkBoxCheckOnStart.Checked; diff --git a/UoFiddler/Localization/Dictionaries/zh-CN.json b/UoFiddler/Localization/Dictionaries/zh-CN.json index 923eb170..42e49f7a 100644 --- a/UoFiddler/Localization/Dictionaries/zh-CN.json +++ b/UoFiddler/Localization/Dictionaries/zh-CN.json @@ -257,6 +257,17 @@ "tooltip_MaxHeightTrackBar": "最大显示高度", "tooltip_pictureBoxMinimap": "小地图 — 点击平移", "tooltip_toolStripBtnZoom": "缩放 — 点击或 Ctrl+0 重置为 100%" + }, + "AboutBoxForm": { + "Title": "关于", + "checkBoxCheckOnStart": "启动时检查更新", + "button1": "检查更新", + "linkLabel1": "访问主页", + "label1": "项目作者和管理员", + "label3": "特殊贡献者", + "label5": "特别感谢", + "checkBoxFormState": "保存窗口状态", + "changelog": "版本 4.24.0\n- 静态碎片整理重写,带有显式过滤器(物品 ID 上限、块外偏移、无效 Z、重复项、堆积的静态物品),报告命名所有删除的内容,并添加验证按钮,可读取结果并与源进行协调\n- 碎片整理现在在后台工作线程上运行,具有有效的取消功能,不再在源文件丢失且未写入任何内容时报告成功\n- 地图区域复制和地图差异插入适用于仅 UOP 的客户端,复制地块字节精确,并可以写入 map{N}.mul 或 map{N}LegacyMUL.uop\n- 两个地图对话框都获得了可拖动的区域预览,具有平移和缩放功能,因此可以在地图上选择区域而不是输入数字\n- 复制的区域可以在 Z 中移动,对话框预先说明它实际上可以移动多远,然后有符号字节用尽\n- 新的每个配置文件保存格式选项:美术、gumpart、音效、MultiCollection 和地图可以写为 mul、uop、遵循加载的客户端或在保存时选择\n- 修复了地块哨兵大小、TerMur 上的差异补丁边界和 Facet 5 差异文件未被找到的问题\n- 修复了旧客户端上的纹理从油漆处理程序抛出异常:未使用的 idx 行被读取为 verdata 补丁\n- 修复了在 UOP 客户端上有色调 Gump 导致进程崩溃的问题\n- 修复了 AnimationSequence 组记录被跳过或以错误步长行走的问题,因此 666 和 1253 等实体现在解析文件声明的操作别名\n- TileData 可以一次为许多条目编辑,带有复制图块数据 / 粘贴特殊和最后一次批量应用的单级撤销\n- 物品、地形图块、Gump 和纹理通过剪贴板复制和粘贴图像,并标记自加载以来编辑的条目\n\n版本 4.23.0\n- Multi 图块标志在 UOP 和 mul 往返中保留:可见性字映射到两个 multi.mul int32,而不是一个布尔值\n- 按图块组件 ID 保存在 multi-components.txt 侧车中,因此重新打包不再删除船的舵手、舱口和木板或房子的门\n- 加载多重不再删除不可见的图块或重新排序图块列表\n- housing.bin 不再作为 multi 7 进行解析,多重 ID 上限现在涵盖在 MultiCollection.uop 中船运的最高 9000 的 ID\n- MultiCollection.uop 以客户端的实际形状编写:版本 4 容器、12 字节条目标头、标头 Adler32、zlib 级别 7\n- UOP gump 宽度和高度不再交换\n- EA 的 0x0 占位符 gump 不再在压缩客户端上列为有效(然后无法绘制)\n- 支持最高 0x12000 的 Gump ID,包括 7.0.98.1 及更高版本的 69971..69985\n- 压缩的 UOP 条目以其真实的磁盘上大小读取;动画、地图和 gump 被读取短\n- 使用 zlib 包装的 Mythic 压缩的动画帧现在被解码而不是作为像素进行解析\n- 压缩的地图 UOP 被拒绝并显示清晰的消息,而不是被静默误读\n- 音效不再得到 8 字节的垃圾作为样本前缀(名称块是 0x28 字节,而不是 32)\n- UOP 打包器:容器布局与每个文件类型的最新客户端匹配,重新打包相同的输入现在是字节相同的\n- UOP 打包器:空或超出范围的 idx 行被跳过并记录,而不是从截断数据中打包\n- UOP 打包器:未打包的美术保留高海status,大型自定义地图不再被截断为库存面大小\n- UOP 打包器:按类型验证压缩,故障删除部分文件,缺少 housing.bin / 组件侧车会提示\n- 比较插件:与主阅读器匹配,没有更多幻影差异;更宽的 ID 范围、释放的文件句柄和位图缓存,不可读的地图报告一次而不是从油漆处理程序抛出\n- Multi CSV/XML 导出携带尾随的高海 int32;gumpidx.mul 和 multi.idx 在最后一个真实条目处截断,而不是填充\n- UOP 名称哈希重写为可读的 lookup3 端口,已验证 82k 输入的位对位\n\n版本 4.22.2\n- 添加导出选项到动画标签中的缩略图列表。\n\n版本 4.22.1\n- 修复动画编辑表单库图块尺寸。\n\n版本 4.22.0\n- 为比较插件添加了多选支持。\n- 动画编辑表单:添加 anim6.mul 支持和库。改变了动画文件的加载方式。\n- 优化了许多控件的文件加载时间和内存使用。\n- 用更快的控件替换 TreeView,在 TileData、Sounds、RadarCol、Multis、Light 和 Dress 标签中加快加载和滚动。\n- \"选择在...\"跨标签导航现在激活目标主标签并可靠地选择行(修复 TileData \"保存更改\"静默失败)。相同的修复应用于物品、LandTiles、RadarCol、纹理、Gump、AnimData。\n- 暗黑模式颜色修复:用主题感知替代品(CornflowerBlue、OrangeRed、SystemColors.ControlText)替换硬编码的 Color.Blue/Color.Red/Color.Black\n- Hue 编辑表单预览现在使用配置的预览背景颜色,而不是硬编码的白色。\n- 改进了 radarcol 颜色生成和控制布局。\n- 比较地图状态条菜单移至右键单击下的上下文菜单,便于访问。添加了鼠标滚轮缩放。\n- 物品、地形图块和纹理可能的多选。\n- 添加了动画标签的过滤器\n- 向动画编辑器添加了库预览\n- 改进了动画标签的加载时间\n- 向动画编辑器添加了第二个动画叠加层\n- 为动画编辑器添加了缩放选项\n- 修复了启用\"查看标记\"时导出高度地图图像时应用程序无法退出的问题。\n- 修复了关闭没有任何选择的配置文件选择表单时的崩溃。\n\n版本 4.21.0\n- 修复了 tiledata 中的显示顺序 - org 现在首先出现。\n- 修复了比较插件中预览图像的刷新。\n- 向物品、地面、纹理和 gump 比较插件添加了 jpg 和 png 导出图像。\n- 为比较美术、地面和 gump 添加了 UOP 文件支持。比较时可以选择要使用的文件类型 Auto/UOP/MUL(Auto 中 UOP 在 MUL 之前)。\n\n版本 4.20.2\n- 修复了 UopPacker 中的工具提示客户端版本信息。\n- 添加了选项以设置导出文件名模板十六进制/十进制(默认为十六进制)。\n\n版本 4.20.1\n- UopPacker:修复 gump 提取,改进提取索引的大小调整。\n- UopPacker:修复提取地图时的验证。\n- UopPacker:为 UI 添加进度条和次要改进。\n- Cliloc 标签:如果文件包含未知字节,添加了额外的验证和警告。\n\n版本 4.20.0\n- 迁移到 .NET 10.0\n- 添加暗黑模式(实验性)。\n\n版本 4.19.4\n- 从 WSC 导入时修复动态标志 - 最近更改后值被翻转。\n\n版本 4.19.3\n- 改进 cliloc 编辑。\n * 添加新 cliloc 条目时添加\"下一个免费\"按钮。\n * 添加条目现在将在搜索下一个可用数字时使用当前选择,或从用户在文本框中输入的数字开始搜索。\n * 添加 tiledata 导入预览表单。\n- 更新 UopPacker 插件中的提取/打包所有逻辑。\n\n版本 4.19.2\n- 修复在物品和地形图块标签中添加和替换图像时的验证。\n- 在 UopPacker 插件中添加了解释压缩设置的工具提示。\n- 对内部记录器构造的次要修复。\n\n版本 4.19.1\n- UopPacker:为 MultiCollection.uop(包括 housing.bin)添加保存支持并刷新插件 UI。\n- 地图复制/替换对话框现在支持 UOP 地图文件。\n- 为物品和地形图块标签添加了\"从文件夹替换\"批量操作。\n- 更多控件现在在保存时使用统一文件保存对话框(带有打开文件夹快捷方式)。\n- 动画编辑器记住添加新帧时选择的文件过滤器。\n\n版本 4.19.0\n- 添加了对预览 anim6.mul 和 AnimationFrame1-6.uop 中动画内容的支持(目前没有 uop 的导出或编辑选项)。\n- 修复了从较新客户端导入到较旧客户端的 tiledata CSV 导入时可能出现的崩溃和减速。\n- 更多预览框现在支持更改背景颜色并使用在\"选项\"中设置的背景颜色。\n- 对 RadarCol 比较布局进行了小调整。\n\n版本 4.18.2\n- 修复了 WSC multi 导入,其中文件具有绝对坐标。现在所有坐标都被转换为相对坐标。\n- 添加了 DynamicItems.xml,其中包含从 WSC 导入多个时应标记为动态的物品列表。\n- 添加了查看和导入 Multicollection.uop 多个物品的支持(目前没有保存选项)。\n- 改进了 CliLoc 比较。它现在显示带有高光的单词差异。\n- 删除了\"新 cliloc 格式\"选项。Cliloc 格式现在是自动检测的。\n\n版本 4.18.1\n- 大量导入插件现在允许导入 PNG 和 JPEG。\n- Animationlist.xml 中的无效条目现在将被跳过,并导致关于问题的消息。\n- Multi 编辑器现在具有带有快捷方式列表的附加表单。\n- Tiledata 控件现在具有带有某些字段和标志描述的附加表单(数据需要进一步更新)。\n- 更改背景颜色的选项现在在\"选项\"下统一,并保存在配置文件中。您仍然可以从各自的控件进行调整。\n- 修复:将 Gumplist.xml 添加到 UOFiddler 主文件夹(在上一个版本中遗漏)。\n- 您可以使用 F3 和 Shift F3 在以下标签中搜索下一个/上一个:Clilocs、Speech、Dress、Items、Land tiles、Sounds 和 Tiledata 标签。\n- 地图预览具有生成带有高度的预览的新选项(有点慢但有效)。\n\n版本 4.18.0\n- animdata 控件布局的小修复\n- Verdata 预览标签添加到浏览 verdata.mul 的内容(如果存在)。它仍在进行中。\n- 主窗口标签现在可以用鼠标滚轮滚动。\n- 新的保存文件确认对话框,带有打开输出文件夹按钮\n- Multi 编辑器有一些新选项:直线绘制、矩形填充、撤销/重做、笔刷大小 S/M/L 和删除,允许选择范围(需要与虚拟地板一起使用以获得最佳效果)。\n- 更新了比较插件。添加了比较 animdata、radarcol 和 tiledata。\n- 添加了 Gumplist.xml,允许向 gump 列表添加描述和标签。\n\n版本 4.17.9\n- 添加了选项以显示在每个客户端和服务器中的 hue 索引。\n\n版本 4.17.8\n- 修复了读取可能由 mulpatcher 或其他工具编辑的较旧 artidx.mul 文件。\n\n版本 4.17.7\n- 避免在使用\"导出全部\"时崩溃。\n- 导出时更新了 gump 文件名。\n\n版本 4.17.6\n- 更新了动画列表和编辑器的布局。\n\n版本 4.17.5\n- 插入或替换图形时添加了 PNG 格式支持。\n\n版本 4.17.4\n- 修复了最近 UOP 编码更新后损坏的 UOP 文件转换。\n\n版本 4.17.3\n- 修复了比较插件中与 gump 相关的崩溃。\n\n版本 4.17.2\n- 修复了动画缩略图列表中的崩溃。\n\n版本 4.17.1\n- 修复了从文本文件的动画调色板导入。\n\n版本 4.17.0\n- 改进了 cliloc 和 gump 文件编码。允许读取和保存压缩的 cliloc 和 gump。\n\n版本 4.16.1\n- 修复了文件路径无效时的一些崩溃。\n\n版本 4.16.0\n- 添加了对版本 7.0.104 中引入的压缩 gump 文件的读取支持\n + 支持仅部分,因此它只能读取和解压缩文件\n + 保存仍将生成旧文件类型,没有办法生成压缩 UOP\n\n版本 4.15.3\n- 修复了从 gif 文件导入动画帧。\n\n版本 4.15.2\n- 添加了对版本 7.0.104 中引入的压缩 cliloc 文件的读取支持\n + 支持仅部分,因此它只能读取和解压缩文件\n + 保存仍将生成旧文件类型\n + 要读取较新的 cliloc,您需要在\"选项\"中启用\"新 cliloc 格式\"\n\n版本 4.15.1\n- 修复了当 animdata 帧计数条目高于最大值 64 时的崩溃\n\n版本 4.15.0\n- 更新了雷达颜色标签的标签顺序\n- 向 Dress 和动画标签添加了 gif 导出\n- UOPacker 插件现在可以解包 multicollection.uop\n- 向 tiledata 标签添加了工具提示\n\n版本 4.14.0\n- RadarCol 标签的各种改进:\n + 在 treeview 选择更改时保存 radarcol\n + 为 radarcol 更改启用恢复、全部恢复\n + 添加\"范围项目到单个平均值\"\n + 添加\"范围项目到范围平均值\"\n + 添加过滤器和复选框选择\n\n版本 4.13.0\n- 添加了为 AnimData 帧设置 hue 和导出动画数据到 GIF 的功能\n- 在 multi 编辑器插件中添加了将设计导出为 XML 的功能\n\n版本 4.12.0\n- 添加了 AnimData 的导入/导出\n- 在 Multis 标签中添加了导出到 XML(centred+ 格式)\n- 修复了导入 unicode 字体字符\n\n版本 4.11.0\n- 更新到 .net 8.0\n\n版本 4.10.9\n- 修复了添加新光时的崩溃。\n\n版本 4.10.8\n- 删除了 gump、音效、纹理和 tiledata 的搜索弹出窗口。将搜索移到控制屏幕。\n- 删除了过时的设置以在音效标签中折叠右面板。\n\n版本 4.10.7\n- 修复了搜索范围。更新了地形图块控制布局。\n\n版本 4.10.6\n- 删除了物品和地形图块控件的搜索弹出窗口。将搜索移到控制屏幕。\n\n版本 4.10.5\n- 添加了选项以将 hue 名称和 ID 导出到文件。\n\n版本 4.10.4\n- 更新了 UOP Packer 插件中的地图文件解包过程。解包地图时,插件将删除 mul 文件末尾的额外字节,因为某些 UOP 地图包含额外的 196 字节。\n\n版本 4.10.3\n- 修复了 UOP Packer 插件中的 art.mul/idx 解包。\n\n版本 4.10.2\n- 修复了 hue 编辑器中的预览着色。\n\n版本 4.10.1\n- 修复了 tiledata 标志 `Unused8` 的无效值。由于 tiledata csv 导出是位置性的,此修复可能会影响此版本之前导出的文件。\n\n版本 4.10.0\n- 迁移到 .net 7。\n\n版本 4.9.28\n- 修复了将 hue 应用于物品和动画。\n- 更新了地图替换图块表单,以更好地指示进度和 XML 文件的可能问题。\n\n版本 4.9.27\n- 添加了\"删除图块边框\"选项,使图块边框不可见(标签:物品、地形图块、纹理、字体)。\n- 添加了\"设置背景颜色与图块背景相同\"。选择自定义图块背景颜色时,如果选中此选项,它也将应用到整个控件。\n\n版本 4.9.26\n- 向\"音效\"标签添加了\"导出所有音效\"选项。\n\n版本 4.9.25\n- 修复了 multi 编辑器插件导入范围(最大 multi ID 低于 multi 标签中的)。\n- 次要清理。\n\n版本 4.9.24\n- 添加了 UOX3 multi 导出。这是一个非常基础的版本,因此预期某些功能会缺失。\n\n版本 4.9.23\n- 导入 multi 对话框现在将以模式运行。\n- 为 multi 作为 csv 添加了导入/导出。与 punt 的 multi 工具一起使用。\n- 向\"大量导入\"插件添加了导入 multi\n- 修复了 hue 格式保存以更好地匹配原始格式。\n\n版本 4.9.22\n- 修复了在\"物品\"、\"地形图块\"和\"纹理\"标签上搜索后物品的聚焦。\n\n版本 4.9.21\n- 在物品详情表单上添加了导出到 JPG 和 PNG。\n- 在动画编辑表单上添加了导出到 JPG 和 PNG。\n\n版本 4.9.20\n- 导入或替换资产时删除了源文件锁定。\n\n版本 4.9.19\n- 修复了更新检查器异常处理。\n\n版本 4.9.18\n- 修复了导出动画帧时的崩溃,其中操作缺少帧。\n\n版本 4.9.17\n- 更新了客户端窗口枚举逻辑以首先查找替代客户端以修复 OrionUO 客户端上的 Client.SendText()。\n\n版本 4.9.16\n- 在启用\"显示空闲插槽\"时使用\"插入在...\"和\"从...插入开始\"时,Gump 列表现在将选择最后插入的索引。\n\n版本 4.9.15\n- 修复了物品、地形图块和纹理中的\"从...替换开始...\"问题。它现在按应有的方式替换图块。当索引到达最大索引值时停止。\n- 修复了\"显示空闲插槽\"菜单项在重新加载文件后不清除其状态的问题。\n\n版本 4.9.14\n- 修复了启用\"显示空闲插槽\"时浏览纹理时的崩溃。\n- 修复了使用非现有技能 ID 浏览 SkillGrp 时的崩溃。\n\n版本 4.9.13\n- 修复了多(多标签)区域导出/导入。MultiRegion 导入后应具有相同的坐标。\n- 向\"物品\"标签添加了\"从...替换开始...\"。允许从所选索引开始替换多个物品。\n- 将\"从...插入开始...\"重命名为\"从...替换开始...\",因为它更好地反映了实际功能。\n- 扩展了 Ultima.Client 以枚举多个 ultima 窗口。\n- 次要代码修复和清理。\n\n版本 4.9.12\n- 在 Dress 标签上添加了搜索物品。\n\n版本 4.9.11\n- 向\"地形图块\"标签添加了\"显示空闲插槽\"选项。\n- 向\"纹理\"标签添加了\"显示空闲插槽\"选项。\n\n版本 4.9.10\n- \"发送物品\"插件应现在仅注册一次,而不是两次。\n- \"发送物品到客户端\"插件应与 ClassicUO 配合使用。\n\n版本 4.9.9\n- 修复了\"物品\"标签 - 默认情况下某些较大的静态物品不可见。\n- 更新了\"音效\"标签以默认使用基于 0 的索引。有新选项\"偏移音效 ID 1(POL 模拟器)\"用于 POL 用户。POL 从 1 开始音效 ID。\n- 向 Hues 控件添加了按文本搜索。\n\n版本 4.9.8\n- 更新了 animationlist.xml(您需要从 UOFiddler 目录复制更新的文件到您的配置文件文件夹并覆盖现有的 animationlist.xml)\n- 修复了 speech.mul ID 值读取 - 不再限于 256。\n\n版本 4.9.7\n- \"在 Gump 中选择\"标签选项添加到\"物品\"和\"Tiledata\"标签中的上下文菜单。\n- 项目中的次要更新以修复使用 `dotnet build` 命令的构建。\n- 使用 .uop 格式时修复了错误的地图大小预选择。\n- \"从...插入开始\"选项添加到 Gump、地形图块和纹理标签 - 允许按顺序插入项目范围。\n- 添加了 Tiledata 标签的\"设置纹理\"选项 - 为所有没有但具有相应纹理的地形图块设置纹理 ID。\n- 物品、地形图块和纹理的默认控件已删除。替代控件已重命名,现在是主控件和唯一可用的控件。\n- 删除了过时的哈希文件使用。\n- 动画编辑表单上的\"替换\"按钮已隐藏,直到其实现完成。\n- 修复了无法将动画正文 ID 值映射到 1696 以上的问题。它现在适用于最高 2048 的正文 ID,这是 UO 客户端限制。\n- \"平均所有\"新按钮在 RadarColor 标签中,检查所有物品和地形图块并将所有黑色非空的设置为平均颜色。\n- 修复了仅浏览标签内容时 AnimData 被标记为已修改的问题。\n- 使用 UOP 文件格式时修复了\"物品\"标签上的\"显示空闲插槽\"。\n- 修复了 Gump 标签上的\"显示空闲插槽\"。\n- 新选项。您现在可以为图块视图控件(物品、地形图块、纹理和字体)选择选择颜色和焦点颜色。\n- 修复了在\"物品\"、\"地形图块\"、\"Tiledata\"和\"Cliloc\"标签中提供无效正则表达式模式字符串时的崩溃。\n- Cliloc 标签。\"Go to text\" 默认使用不区分大小写的字符串比较。如果需要,您可以切换到正则表达式。\n- 将 Hue 标签重命名为 Hues。Hues 控件 - 添加了快速搜索选项。您现在可以通过其索引跳转到 hue。显示的 hue 索引值现在是 0-based,与 hues.mul 中存储的相同。\n- 更新了动画编辑器布局。\n- 向动画列表添加了操作名称。\n- 更新了 Serilog.Sinks.File 包到最新版本。\n\n版本 4.9.6\n- 向\"物品\"、\"地形图块\"、\"纹理\"和\"字体\"添加了新的图块视图控件。渲染现在应该是平滑和快速的。要使用新控件,需要在设置中检查替代设计模式。\n- 向\"纹理\"标签添加了\"导出所有...\"选项。\n- 改变了字体加载方式。应该更快了。默认情况下,当您进入\"字体\"标签时,它将仅加载 ASCII 字体。Unicode 字体在选中复选框后加载。\n- 修复了 AnimData \"保存\"按钮。\n- 修复了\"语音\"标签上的默认文本。\n\n版本 4.9.5\n- 修复了从其他标签选择\"物品/地形图块\"标签中的图块时罕见的挂起。\n- 修复了在 tiledata 物品列表中使用上下文菜单时的崩溃。\n- 修复了 multi 设计保存 UO 建筑师。文件扩展名更改为 .uoa.txt 以表示这是文本格式而不是二进制格式。更新了 UO Architect txt 文件的导入选项。\n- 减少了 multi 编辑器插件中 Tiles 标签上的闪烁。\n\n版本 4.9.4\n- 修复了纹理保存。\n- 修复了 CliLoc Goto 文本框上的右键单击。\n- 通过鼠标滚轮滚动添加了缩放输入/输出。为缩放级别添加了最小/最大值。\n- Hue 编辑器中的小修复。它不会使所选单元格变暗。\n- 您现在可以为 Multis 标签选择背景颜色。导出 multi 图像时将使用该颜色作为背景。PNG 格式支持透明度,因此默认情况下导出时会有透明背景,但可以关闭并使用纯色背景导出。默认背景颜色是白色。\n- 修复了纹理在替代设计模式下不显示。\n- 修复了 art 标签中的缺失图块 - 最大 ID 没有 4k 地形图块偏移。这仅在 ID 高于 0x10000 的较新客户端中出现。\n- 修复了安装了多个 UO 客户端时的错误路径设置。这是一个解决方法,但会有所帮助。\n- 修复了在 multis 标签中导出图像时的崩溃。\n- 添加了十六进制值到动画列表。修复了状态栏文本格式。\n- 更新了 Serilog 包到 2.10.0。\n- 修复了 Animdata 在尝试删除框架而不是动画条目时的崩溃。更新了 Animdata 控件布局。\n\n版本 4.9.3\n- 向\"音效\"标签添加了右面板\n- 添加了更改\"物品\"标签背景颜色的功能。您可以为物品列表和右侧详情预览选择单独的颜色。右键单击并选择\"更改背景颜色\"。\n\n版本 4.9.2\n- 在 multi 编辑器插件中添加了缺失的船图块组。\n- 将当前选择的配置文件名称添加到主窗口标题。\n- AnimationEdit:从 .gif 文件导入的帧现在应在 X 轴上居中。\n\n版本 4.9.1\n- 我们现在复制配置文件而不是将其移动到 AppData(如果文件不存在)。\n- 修复了为物品替代设计模式导出 offset.cfg。\n- 将更新检查移至 github 发布 API。\n- 添加了 UOP Packer 插件\n- 修复了\"音效\"标签描述标签 - 索引偏离 1。\n- 修复了 multi 导入问题与高于 4095 的索引。\n- 通过在高度设置不同于最大 multi 高度时将高度值添加到文件名来避免用不同的高度设置替换导出的 multi 图像。\n- 更新了 tiledata 标志以支持高海扩展格式。仅当文件采用 HS 或更高版本格式时才显示其他标志。\n- 修复了地图叠加层加载。\n- 次要 UI 修复和更新。\n- 修复了 hue 的最大物品 ID。它将从 Art 中当前定义的最大 ID 获取。\n- 修复了路径设置问题,其中选择新目录后并非所有路径都被更新。\n- 更新了 ultima 美术缓存大小。\n\n版本 4.9\n- 将项目更新到 .NET Framework 4.8\n\n有关版本 4.0 之前的版本信息,请参阅 old-changelog.txt 文件。" } } } From cc38bec163eeaed1ce9c7e45f491f85af2964641 Mon Sep 17 00:00:00 2001 From: nbyaya Date: Sun, 4 Oct 2026 10:43:13 +0800 Subject: [PATCH 17/30] =?UTF-8?q?=E6=B1=89=E5=8C=96=20SendItem=20=E6=8F=92?= =?UTF-8?q?=E4=BB=B6?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../Forms/SendItemOptionsForm.cs | 39 +++++++++++++++++++ UoFiddler.Plugin.SendItem/SendItem.cs | 10 ++++- 2 files changed, 48 insertions(+), 1 deletion(-) diff --git a/UoFiddler.Plugin.SendItem/Forms/SendItemOptionsForm.cs b/UoFiddler.Plugin.SendItem/Forms/SendItemOptionsForm.cs index 1fdbe78d..7897ec97 100644 --- a/UoFiddler.Plugin.SendItem/Forms/SendItemOptionsForm.cs +++ b/UoFiddler.Plugin.SendItem/Forms/SendItemOptionsForm.cs @@ -10,6 +10,8 @@ ***************************************************************************/ using System; +using System.Linq; +using System.Reflection; using System.Windows.Forms; using UoFiddler.Controls.Classes; @@ -24,6 +26,43 @@ public SendItemOptionsForm() cmdtext.Text = SendItemPluginBase.Cmd; argstext.Text = SendItemPluginBase.CmdArg; SendOnClick.Checked = SendItemPluginBase.OverrideClick; + + // 在 Load 事件中应用汉化 + this.Load += (s, e) => ApplyLocalization(); + } + + public void SetLocalization(Func localizationGetter) + { + _localizationGetter = localizationGetter; + + // 如果窗体已显示,立即应用汉化 + if (this.Visible) + { + ApplyLocalization(); + } + } + + private Func _localizationGetter; + + private void ApplyLocalization() + { + if (_localizationGetter == null) return; + + this.Text = _localizationGetter("Forms.SendItemOptionsForm.Title") ?? "SendItem Options"; + groupBox1.Text = _localizationGetter("Forms.SendItemOptionsForm.groupBox1") ?? "Send Item"; + label7.Text = _localizationGetter("Forms.SendItemOptionsForm.label7") ?? "Cmd"; + label8.Text = _localizationGetter("Forms.SendItemOptionsForm.label8") ?? "Args"; + SendOnClick.Text = _localizationGetter("Forms.SendItemOptionsForm.SendOnClick") ?? "Send on DoubleClick"; + button1.Text = _localizationGetter("Forms.SendItemOptionsForm.button1") ?? "Save"; + + // ToolTips + var toolTip1 = this.components?.Components.OfType().FirstOrDefault(); + if (toolTip1 != null) + { + toolTip1.SetToolTip(label7, _localizationGetter("Forms.SendItemOptionsForm.tooltip_label7") ?? "Defines the cmd to send Client for selected Item"); + toolTip1.SetToolTip(label8, _localizationGetter("Forms.SendItemOptionsForm.tooltip_label8") ?? "{1} = Selected item ObjType"); + toolTip1.SetToolTip(SendOnClick, _localizationGetter("Forms.SendItemOptionsForm.tooltip_SendOnClick") ?? "Overrides DoubleClick"); + } } private void OnClickSave(object sender, EventArgs e) diff --git a/UoFiddler.Plugin.SendItem/SendItem.cs b/UoFiddler.Plugin.SendItem/SendItem.cs index 50dd0f52..cec569ff 100644 --- a/UoFiddler.Plugin.SendItem/SendItem.cs +++ b/UoFiddler.Plugin.SendItem/SendItem.cs @@ -131,7 +131,15 @@ private void ChangeOverrideClick(bool value, bool init) private static void ToolStripClick(object sender, EventArgs e) { - new SendItemOptionsForm().Show(); + SendItemOptionsForm form = new SendItemOptionsForm(); + + // 应用汉化 + if (PluginBase.LocalizationGetter != null) + { + form.SetLocalization(PluginBase.LocalizationGetter); + } + + form.Show(); } private void EventsModifyItemsControlContextMenuEvent(ContextMenuStrip strip) From 96837e23aa1f03ffb150d0c85667c08ad9d1ec14 Mon Sep 17 00:00:00 2001 From: nbyaya Date: Sun, 4 Oct 2026 10:43:22 +0800 Subject: [PATCH 18/30] =?UTF-8?q?=E6=B1=89=E5=8C=96=20PluginTest=20?= =?UTF-8?q?=E6=8F=92=E4=BB=B6?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../ExamplePluginBase.cs | 47 +++++++++++++++---- .../Forms/ExampleForm.cs | 22 +++++++++ .../UserControls/ExampleControl.cs | 25 +++++++++- 3 files changed, 85 insertions(+), 9 deletions(-) diff --git a/UoFiddler.Plugin.ExamplePlugin/ExamplePluginBase.cs b/UoFiddler.Plugin.ExamplePlugin/ExamplePluginBase.cs index 5ecd39b7..34daba96 100644 --- a/UoFiddler.Plugin.ExamplePlugin/ExamplePluginBase.cs +++ b/UoFiddler.Plugin.ExamplePlugin/ExamplePluginBase.cs @@ -26,6 +26,7 @@ namespace UoFiddler.Plugin.ExamplePlugin public class ExamplePluginBase : PluginBase { private const string _itemDescFileName = "itemdesc.cfg"; + private static Func _localizationGetter; public ExamplePluginBase() { @@ -61,6 +62,12 @@ public override void Initialize() { // make something useful _ = Files.RootDir; + + // 保存 LocalizationGetter 供后续事件使用 + if (PluginBase.LocalizationGetter != null) + { + _localizationGetter = PluginBase.LocalizationGetter; + } } public override void Unload() @@ -74,7 +81,16 @@ public override void ModifyTabPages(TabControl tabControl) Tag = tabControl.TabCount + 1, // at end used for undock/dock feature to define the order Text = "PluginTest" }; - page.Controls.Add(new ExampleControl()); + + ExampleControl control = new ExampleControl(); + + // 应用汉化 + if (PluginBase.LocalizationGetter != null) + { + control.SetLocalization(PluginBase.LocalizationGetter); + } + + page.Controls.Add(control); tabControl.TabPages.Add(page); } @@ -90,7 +106,15 @@ public override void ModifyPluginToolStrip(ToolStripDropDownButton toolStrip) private static void ItemClick(object sender, EventArgs e) { - new ExampleForm().Show(); + ExampleForm form = new ExampleForm(); + + // 应用汉化 + if (PluginBase.LocalizationGetter != null) + { + form.SetLocalization(PluginBase.LocalizationGetter); + } + + form.Show(); } private void EventsModifyItemsControlContextMenuEvent(ContextMenuStrip strip) @@ -99,7 +123,7 @@ private void EventsModifyItemsControlContextMenuEvent(ContextMenuStrip strip) ToolStripMenuItem exportItemDescItem = new ToolStripMenuItem { - Text = "Export selected to itemdesc.cfg" + Text = _localizationGetter?.Invoke("Forms.PluginTestForm.contextmenu_export_selected") ?? "Export selected to itemdesc.cfg" }; exportItemDescItem.Click += ExportToItemDescClicked; strip.Items.Add(exportItemDescItem); @@ -108,7 +132,7 @@ private void EventsModifyItemsControlContextMenuEvent(ContextMenuStrip strip) ToolStripMenuItem exportOffsetItem = new ToolStripMenuItem { - Text = "Export all items to offset.cfg" + Text = _localizationGetter?.Invoke("Forms.PluginTestForm.contextmenu_export_all") ?? "Export all items to offset.cfg" }; exportOffsetItem.Click += ExportToOffsetClicked; strip.Items.Add(exportOffsetItem); @@ -121,13 +145,20 @@ private void ExportToOffsetClicked(object sender, EventArgs e) string fileName = Path.Combine(Options.OutputPath, "offset.cfg"); - string inputMessage = "Do you want to export all items to offset.cfg?\r\n" + string inputMessage = _localizationGetter?.Invoke("Forms.PluginTestForm.messagebox_export_confirm") + ?? ("Do you want to export all items to offset.cfg?\r\n" + "It may take some time (around 10-20 seconds).\r\n\r\n" + "Export will replace existing file located at: " + fileName - + "\r\n\r\nContinue?\r\n"; + + "\r\n\r\nContinue?\r\n"); + + // 如果有本地化文本,需要填入文件名 + if (inputMessage.Contains("{path}")) + { + inputMessage = inputMessage.Replace("{path}", fileName); + } - if (MessageBox.Show(inputMessage, "Export all items to offset.cfg?", MessageBoxButtons.YesNo) == DialogResult.No) + if (MessageBox.Show(inputMessage, _localizationGetter?.Invoke("Forms.PluginTestForm.messagebox_export_title") ?? "Export all items to offset.cfg?", MessageBoxButtons.YesNo) == DialogResult.No) { return; } @@ -153,7 +184,7 @@ private void ExportToOffsetClicked(object sender, EventArgs e) File.WriteAllText(fileName, sb.ToString()); - MessageBox.Show("Done!"); + MessageBox.Show(_localizationGetter?.Invoke("Forms.PluginTestForm.messagebox_export_done") ?? "Done!"); } private void ExportToItemDescClicked(object sender, EventArgs e) diff --git a/UoFiddler.Plugin.ExamplePlugin/Forms/ExampleForm.cs b/UoFiddler.Plugin.ExamplePlugin/Forms/ExampleForm.cs index 7115c020..692db529 100644 --- a/UoFiddler.Plugin.ExamplePlugin/Forms/ExampleForm.cs +++ b/UoFiddler.Plugin.ExamplePlugin/Forms/ExampleForm.cs @@ -9,6 +9,7 @@ * ***************************************************************************/ +using System; using System.Windows.Forms; namespace UoFiddler.Plugin.ExamplePlugin.Forms @@ -18,6 +19,27 @@ public partial class ExampleForm : Form public ExampleForm() { InitializeComponent(); + this.Load += (s, e) => ApplyLocalization(); + } + + public void SetLocalization(Func localizationGetter) + { + _localizationGetter = localizationGetter; + + // 如果窗体已显示,立即应用汉化 + if (this.Visible) + { + ApplyLocalization(); + } + } + + private Func _localizationGetter; + + private void ApplyLocalization() + { + if (_localizationGetter == null) return; + + this.Text = _localizationGetter("Forms.PluginTestForm.Title") ?? "Example"; } } } diff --git a/UoFiddler.Plugin.ExamplePlugin/UserControls/ExampleControl.cs b/UoFiddler.Plugin.ExamplePlugin/UserControls/ExampleControl.cs index d48d53fb..c7b7d176 100644 --- a/UoFiddler.Plugin.ExamplePlugin/UserControls/ExampleControl.cs +++ b/UoFiddler.Plugin.ExamplePlugin/UserControls/ExampleControl.cs @@ -20,6 +20,27 @@ public partial class ExampleControl : UserControl public ExampleControl() { InitializeComponent(); + this.Load += (s, e) => ApplyLocalization(); + } + + public void SetLocalization(Func localizationGetter) + { + _localizationGetter = localizationGetter; + + // 如果控件已显示,立即应用汉化 + if (this.Visible) + { + ApplyLocalization(); + } + } + + private Func _localizationGetter; + + private void ApplyLocalization() + { + if (_localizationGetter == null) return; + + button1.Text = _localizationGetter("Forms.PluginTestForm.SayHello") ?? "Say Hello"; } private void OnClickSayHello(object sender, EventArgs e) @@ -30,7 +51,9 @@ private void OnClickSayHello(object sender, EventArgs e) } else { - MessageBox.Show("UO client is not running so I will say hello here. Hi!"); + string message = _localizationGetter?.Invoke("Forms.PluginTestForm.messagebox_hello") + ?? "UO client is not running so I will say hello here. Hi!"; + MessageBox.Show(message); } } } From 58553168e81dd78d8804f3a54836975c4826e88b Mon Sep 17 00:00:00 2001 From: nbyaya Date: Sun, 4 Oct 2026 10:43:29 +0800 Subject: [PATCH 19/30] =?UTF-8?q?=E6=9B=B4=E6=96=B0=E6=B1=89=E5=8C=96?= =?UTF-8?q?=E5=AD=97=E5=85=B8?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../Localization/Dictionaries/zh-CN.json | 23 +++++++++++++++++++ 1 file changed, 23 insertions(+) diff --git a/UoFiddler/Localization/Dictionaries/zh-CN.json b/UoFiddler/Localization/Dictionaries/zh-CN.json index 42e49f7a..d6310476 100644 --- a/UoFiddler/Localization/Dictionaries/zh-CN.json +++ b/UoFiddler/Localization/Dictionaries/zh-CN.json @@ -258,6 +258,29 @@ "tooltip_pictureBoxMinimap": "小地图 — 点击平移", "tooltip_toolStripBtnZoom": "缩放 — 点击或 Ctrl+0 重置为 100%" }, + "SendItemOptionsForm": { + "Title": "发送物品选项", + "groupBox1": "发送物品", + "label7": "命令", + "label8": "参数", + "SendOnClick": "双击时发送", + "button1": "保存", + "tooltip_label7": "定义发送给客户端的命令,用于选定的物品", + "tooltip_label8": "{1} = 选定物品的对象类型", + "tooltip_SendOnClick": "覆盖双击行为" + }, + "PluginTestForm": { + "Title": "示例", + "ExampleForm": "示例", + "SayHello": "打招呼", + "PluginTest": "插件测试", + "messagebox_hello": "UO 客户端未运行,所以我在这里打个招呼。你好!", + "contextmenu_export_selected": "导出选定项到 itemdesc.cfg", + "contextmenu_export_all": "导出所有物品到 offset.cfg", + "messagebox_export_confirm": "你想要导出所有物品到 offset.cfg 吗?\r\n可能需要一些时间(大约 10-20 秒)。\r\n\r\n导出将替换位于以下位置的现有文件:{path}\r\n\r\n继续吗?\r\n", + "messagebox_export_title": "导出所有物品到 offset.cfg?", + "messagebox_export_done": "完成!" + }, "AboutBoxForm": { "Title": "关于", "checkBoxCheckOnStart": "启动时检查更新", From ffe41615febef6b75d3a324f9c9b272041179bc5 Mon Sep 17 00:00:00 2001 From: nbyaya Date: Sun, 4 Oct 2026 13:26:03 +0800 Subject: [PATCH 20/30] =?UTF-8?q?=E6=B1=89=E5=8C=96=EF=BC=9ACompare?= =?UTF-8?q?=E6=8F=92=E4=BB=B6=E8=AF=8D=E6=9D=A1=E8=A1=A5=E5=85=85?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit - 添加Directory标签词条 - 添加Rules按钮两种状态词条(Open/Close) - CompareMapControl、CompareAnimDataControl、CompareRadarColControl词条细化 --- UoFiddler.Plugin.Compare/ComparePluginBase.cs | 84 ++++-- .../UserControls/CompareAnimDataControl.cs | 5 + .../UserControls/CompareCliLocControl.cs | 12 + .../UserControls/CompareGumpControl.cs | 10 + .../UserControls/CompareHuesControl.cs | 8 + .../UserControls/CompareItemControl.cs | 27 ++ .../UserControls/CompareLandControl.cs | 24 ++ .../UserControls/CompareMapControl.cs | 16 + .../UserControls/CompareRadarColControl.cs | 5 + .../UserControls/CompareTextureControl.cs | 10 + .../UserControls/CompareTileDataControl.cs | 10 + UoFiddler.Plugin.UopPacker/UopPacker.cs | 11 +- .../UserControls/UopPackerControl.cs | 95 ++++++ .../UserControls/UopPackerControl.resx | 16 +- .../Localization/Dictionaries/zh-CN.json | 285 +++++++++++++++++- 15 files changed, 569 insertions(+), 49 deletions(-) diff --git a/UoFiddler.Plugin.Compare/ComparePluginBase.cs b/UoFiddler.Plugin.Compare/ComparePluginBase.cs index dbb4f494..39b81442 100644 --- a/UoFiddler.Plugin.Compare/ComparePluginBase.cs +++ b/UoFiddler.Plugin.Compare/ComparePluginBase.cs @@ -9,6 +9,7 @@ * ***************************************************************************/ +using System; using System.Windows.Forms; using Ultima; using UoFiddler.Controls.Plugin; @@ -64,15 +65,20 @@ public override void Unload() public override void ModifyTabPages(TabControl tabControl) { + // 获取汉化函数 + var localizer = LocalizationGetter; + TabPage page = new TabPage { Tag = tabControl.TabCount + 1, Text = "Compare Items" }; - CompareItemControl compArt = new CompareItemControl + CompareItemControl compArt = new CompareItemControl(); + if (localizer != null) { - Dock = DockStyle.Fill - }; + compArt.SetLocalization(localizer); + } + compArt.Dock = DockStyle.Fill; page.Controls.Add(compArt); tabControl.TabPages.Add(page); @@ -81,10 +87,12 @@ public override void ModifyTabPages(TabControl tabControl) Tag = tabControl.TabCount + 1, Text = "Compare Land" }; - CompareLandControl compLandControl = new CompareLandControl + CompareLandControl compLandControl = new CompareLandControl(); + if (localizer != null) { - Dock = DockStyle.Fill - }; + compLandControl.SetLocalization(localizer); + } + compLandControl.Dock = DockStyle.Fill; page2.Controls.Add(compLandControl); tabControl.TabPages.Add(page2); @@ -93,10 +101,12 @@ public override void ModifyTabPages(TabControl tabControl) Tag = tabControl.TabCount + 1, Text = "Compare CliLocs" }; - CompareCliLocControl compCli = new CompareCliLocControl + CompareCliLocControl compCli = new CompareCliLocControl(); + if (localizer != null) { - Dock = DockStyle.Fill - }; + compCli.SetLocalization(localizer); + } + compCli.Dock = DockStyle.Fill; page3.Controls.Add(compCli); tabControl.TabPages.Add(page3); @@ -105,10 +115,12 @@ public override void ModifyTabPages(TabControl tabControl) Tag = tabControl.TabCount + 1, Text = "Compare Hues" }; - CompareHuesControl compH = new CompareHuesControl + CompareHuesControl compH = new CompareHuesControl(); + if (localizer != null) { - Dock = DockStyle.Fill - }; + compH.SetLocalization(localizer); + } + compH.Dock = DockStyle.Fill; page4.Controls.Add(compH); tabControl.TabPages.Add(page4); @@ -117,10 +129,12 @@ public override void ModifyTabPages(TabControl tabControl) Tag = tabControl.TabCount + 1, Text = "Compare Gumps" }; - CompareGumpControl compG = new CompareGumpControl + CompareGumpControl compG = new CompareGumpControl(); + if (localizer != null) { - Dock = DockStyle.Fill - }; + compG.SetLocalization(localizer); + } + compG.Dock = DockStyle.Fill; page5.Controls.Add(compG); tabControl.TabPages.Add(page5); @@ -129,10 +143,12 @@ public override void ModifyTabPages(TabControl tabControl) Tag = tabControl.TabCount + 1, Text = "Compare Map" }; - CompareMapControl compM = new CompareMapControl + CompareMapControl compM = new CompareMapControl(); + if (localizer != null) { - Dock = DockStyle.Fill - }; + compM.SetLocalization(localizer); + } + compM.Dock = DockStyle.Fill; page6.Controls.Add(compM); tabControl.TabPages.Add(page6); @@ -141,10 +157,12 @@ public override void ModifyTabPages(TabControl tabControl) Tag = tabControl.TabCount + 1, Text = "Compare Texture" }; - CompareTextureControl compTextureControl = new CompareTextureControl + CompareTextureControl compTextureControl = new CompareTextureControl(); + if (localizer != null) { - Dock = DockStyle.Fill - }; + compTextureControl.SetLocalization(localizer); + } + compTextureControl.Dock = DockStyle.Fill; page7.Controls.Add(compTextureControl); tabControl.TabPages.Add(page7); @@ -153,10 +171,12 @@ public override void ModifyTabPages(TabControl tabControl) Tag = tabControl.TabCount + 1, Text = "Compare AnimData" }; - CompareAnimDataControl compAnimData = new CompareAnimDataControl + CompareAnimDataControl compAnimData = new CompareAnimDataControl(); + if (localizer != null) { - Dock = DockStyle.Fill - }; + compAnimData.SetLocalization(localizer); + } + compAnimData.Dock = DockStyle.Fill; page8.Controls.Add(compAnimData); tabControl.TabPages.Add(page8); @@ -165,10 +185,12 @@ public override void ModifyTabPages(TabControl tabControl) Tag = tabControl.TabCount + 1, Text = "Compare RadarCol" }; - CompareRadarColControl compRadarCol = new CompareRadarColControl + CompareRadarColControl compRadarCol = new CompareRadarColControl(); + if (localizer != null) { - Dock = DockStyle.Fill - }; + compRadarCol.SetLocalization(localizer); + } + compRadarCol.Dock = DockStyle.Fill; page9.Controls.Add(compRadarCol); tabControl.TabPages.Add(page9); @@ -177,10 +199,12 @@ public override void ModifyTabPages(TabControl tabControl) Tag = tabControl.TabCount + 1, Text = "Compare TileData" }; - CompareTileDataControl compTileDataControl = new CompareTileDataControl + CompareTileDataControl compTileDataControl = new CompareTileDataControl(); + if (localizer != null) { - Dock = DockStyle.Fill - }; + compTileDataControl.SetLocalization(localizer); + } + compTileDataControl.Dock = DockStyle.Fill; page10.Controls.Add(compTileDataControl); tabControl.TabPages.Add(page10); } diff --git a/UoFiddler.Plugin.Compare/UserControls/CompareAnimDataControl.cs b/UoFiddler.Plugin.Compare/UserControls/CompareAnimDataControl.cs index f9a542a4..1655e338 100644 --- a/UoFiddler.Plugin.Compare/UserControls/CompareAnimDataControl.cs +++ b/UoFiddler.Plugin.Compare/UserControls/CompareAnimDataControl.cs @@ -17,6 +17,11 @@ public CompareAnimDataControl() InitializeComponent(); } + public void SetLocalization(Func getLocalized) + { + copyEntryToolStripMenuItem.Text = getLocalized("copyEntry") ?? "Copy Entry to left"; + } + private readonly Dictionary _compare = new Dictionary(); private readonly List _displayIndices = new List(); private bool _syncingSelection; diff --git a/UoFiddler.Plugin.Compare/UserControls/CompareCliLocControl.cs b/UoFiddler.Plugin.Compare/UserControls/CompareCliLocControl.cs index d2b74fbe..25f0e6ba 100644 --- a/UoFiddler.Plugin.Compare/UserControls/CompareCliLocControl.cs +++ b/UoFiddler.Plugin.Compare/UserControls/CompareCliLocControl.cs @@ -30,6 +30,18 @@ public CompareCliLocControl() _sortColumn = 0; } + public void SetLocalization(Func getLocalized) + { + button1.Text = getLocalized("button1") ?? "Load"; + button2.Text = getLocalized("button2") ?? "Load"; + button3.Text = getLocalized("button3") ?? "..."; + button4.Text = getLocalized("button4") ?? "..."; + button5.Text = getLocalized("button5") ?? "Find Next Diff"; + checkBox1.Text = getLocalized("checkBox1") ?? "Show Only Differences"; + labelDiff1.Text = getLocalized("labelDiff1") ?? "File 1:"; + labelDiff2.Text = getLocalized("labelDiff2") ?? "File 2:"; + } + private static StringList _cliloc1; private static StringList _cliloc2; private static BindingSource _source; diff --git a/UoFiddler.Plugin.Compare/UserControls/CompareGumpControl.cs b/UoFiddler.Plugin.Compare/UserControls/CompareGumpControl.cs index a66a33f5..f8512f34 100644 --- a/UoFiddler.Plugin.Compare/UserControls/CompareGumpControl.cs +++ b/UoFiddler.Plugin.Compare/UserControls/CompareGumpControl.cs @@ -32,6 +32,16 @@ public CompareGumpControl() InitializeComponent(); } + public void SetLocalization(Func getLocalized) + { + checkBox1.Text = getLocalized("checkBox1") ?? "Show only Differences"; + chkMultiSelect.Text = getLocalized("chkMultiSelect") ?? "Multi-Select"; + button1.Text = getLocalized("button1") ?? "Load"; + button2.Text = getLocalized("button2") ?? "Load"; + extractAsToolStripMenuItem.Text = getLocalized("extractAs") ?? "Extract As.."; + copyGump2To1ToolStripMenuItem.Text = getLocalized("copyGump2To1") ?? "Copy Gump to left"; + } + private readonly Dictionary _compare = new Dictionary(); private readonly SHA256 _sha256 = SHA256.Create(); private readonly List _displayIndices = new List(); diff --git a/UoFiddler.Plugin.Compare/UserControls/CompareHuesControl.cs b/UoFiddler.Plugin.Compare/UserControls/CompareHuesControl.cs index 5654372c..1525f9ce 100644 --- a/UoFiddler.Plugin.Compare/UserControls/CompareHuesControl.cs +++ b/UoFiddler.Plugin.Compare/UserControls/CompareHuesControl.cs @@ -36,6 +36,14 @@ public CompareHuesControl() _hue2Loaded = false; } + public void SetLocalization(Func getLocalized) + { + button1.Text = getLocalized("button1") ?? "Load"; + button2.Text = getLocalized("button2") ?? "..."; + chkMultiSelect.Text = getLocalized("chkMultiSelect") ?? "Multi-Select"; + applyHue1ToHue2ToolStripMenuItem.Text = getLocalized("applyHue1ToHue2") ?? "Apply Hue to left"; + } + private const int _itemHeight = 20; private Bitmap _bmp1; private Bitmap _bmp2; diff --git a/UoFiddler.Plugin.Compare/UserControls/CompareItemControl.cs b/UoFiddler.Plugin.Compare/UserControls/CompareItemControl.cs index b0bad495..a74929f5 100644 --- a/UoFiddler.Plugin.Compare/UserControls/CompareItemControl.cs +++ b/UoFiddler.Plugin.Compare/UserControls/CompareItemControl.cs @@ -27,11 +27,38 @@ namespace UoFiddler.Plugin.Compare.UserControls { public partial class CompareItemControl : UserControl { + private Func _localizationGetter; + public CompareItemControl() { InitializeComponent(); } + public void SetLocalization(Func localizationGetter) + { + _localizationGetter = localizationGetter; + ApplyLocalization(); + } + + private void ApplyLocalization() + { + if (_localizationGetter == null) return; + + // 汉化菜单项 + extractAsToolStripMenuItem.Text = _localizationGetter("extractAs") ?? "Export Image.."; + tiffToolStripMenuItem.Text = _localizationGetter("asBmp") ?? "As Bmp"; + bmpToolStripMenuItem.Text = _localizationGetter("asTiff") ?? "As Tiff"; + jpgToolStripMenuItem.Text = _localizationGetter("asJpg") ?? "As Jpg"; + pngToolStripMenuItem.Text = _localizationGetter("asPng") ?? "As Png"; + copyItem2To1ToolStripMenuItem.Text = _localizationGetter("copyItem2To1") ?? "Copy Item to left"; + + // 汉化按钮和复选框 + btnCopyAllDiff.Text = _localizationGetter("copyAllDiff") ?? "Copy All Diff"; + button1.Text = _localizationGetter("loadSecond") ?? "Load Second"; + checkBox1.Text = _localizationGetter("showOnlyDifferences") ?? "Show only Differences"; + chkMultiSelect.Text = _localizationGetter("multiSelect") ?? "Multi-Select"; + } + private readonly Dictionary _compare = new Dictionary(); private readonly ImageConverter _ic = new ImageConverter(); private readonly SHA256 _sha256 = SHA256.Create(); diff --git a/UoFiddler.Plugin.Compare/UserControls/CompareLandControl.cs b/UoFiddler.Plugin.Compare/UserControls/CompareLandControl.cs index abc4d277..2974366b 100644 --- a/UoFiddler.Plugin.Compare/UserControls/CompareLandControl.cs +++ b/UoFiddler.Plugin.Compare/UserControls/CompareLandControl.cs @@ -27,11 +27,35 @@ namespace UoFiddler.Plugin.Compare.UserControls { public partial class CompareLandControl : UserControl { + private Func _localizationGetter; + public CompareLandControl() { InitializeComponent(); } + public void SetLocalization(Func localizationGetter) + { + _localizationGetter = localizationGetter; + ApplyLocalization(); + } + + private void ApplyLocalization() + { + if (_localizationGetter == null) return; + + exportImageToolStripMenuItem.Text = _localizationGetter("exportImageToolStripMenuItem") ?? "Export Image.."; + asBmpToolStripMenuItem.Text = _localizationGetter("asBmpToolStripMenuItem") ?? "As Bmp"; + asTiffToolStripMenuItem.Text = _localizationGetter("asTiffToolStripMenuItem") ?? "As Tiff"; + asJpgToolStripMenuItem.Text = _localizationGetter("asJpgToolStripMenuItem") ?? "As Jpg"; + asPngToolStripMenuItem.Text = _localizationGetter("asPngToolStripMenuItem") ?? "As Png"; + copyLandTile2To1ToolStripMenuItem.Text = _localizationGetter("copyLandTile2To1ToolStripMenuItem") ?? "Copy Land to left"; + btnCopyAllDiff.Text = _localizationGetter("btnCopyAllDiff") ?? "Copy All Diff"; + button1.Text = _localizationGetter("button1") ?? "Load"; + checkBox1.Text = _localizationGetter("checkBox1") ?? "Show only Differences"; + chkMultiSelect.Text = _localizationGetter("chkMultiSelect") ?? "Multi-Select"; + } + private readonly Dictionary _compare = new Dictionary(); private readonly SHA256 _sha256 = SHA256.Create(); private readonly ImageConverter _ic = new ImageConverter(); diff --git a/UoFiddler.Plugin.Compare/UserControls/CompareMapControl.cs b/UoFiddler.Plugin.Compare/UserControls/CompareMapControl.cs index 476567be..39711d78 100644 --- a/UoFiddler.Plugin.Compare/UserControls/CompareMapControl.cs +++ b/UoFiddler.Plugin.Compare/UserControls/CompareMapControl.cs @@ -32,6 +32,22 @@ public CompareMapControl() pictureBox.MouseWheel += OnMouseWheel; } + public void SetLocalization(Func getLocalized) + { + toolStripButton2.Text = getLocalized("button1") ?? "Load"; + toolStripButton1.Text = getLocalized("button2") ?? "..."; + showDifferencesToolStripMenuItem.Text = getLocalized("showDifferencesToolStripMenuItem") ?? "Show Differences"; + showMap1ToolStripMenuItem.Text = getLocalized("showMap1ToolStripMenuItem") ?? "Show Map1"; + showMap2ToolStripMenuItem.Text = getLocalized("showMap2ToolStripMenuItem") ?? "Show Map2"; + feluccaToolStripMenuItem.Text = getLocalized("feluccaToolStripMenuItem") ?? "Felucca"; + trammelToolStripMenuItem.Text = getLocalized("trammelToolStripMenuItem") ?? "Trammel"; + ilshenarToolStripMenuItem.Text = getLocalized("ilshenarToolStripMenuItem") ?? "Ilshenar"; + malasToolStripMenuItem.Text = getLocalized("malasToolStripMenuItem") ?? "Malas"; + tokunoToolStripMenuItem.Text = getLocalized("tokunoToolStripMenuItem") ?? "Tokuno"; + terMurToolStripMenuItem.Text = getLocalized("terMurToolStripMenuItem") ?? "TerMur"; + markDiffToolStripMenuItem.Text = getLocalized("markDiffToolStripMenuItem") ?? "Mark Diff"; + } + private bool _loaded; private bool _moving; private Point _movingPoint; diff --git a/UoFiddler.Plugin.Compare/UserControls/CompareRadarColControl.cs b/UoFiddler.Plugin.Compare/UserControls/CompareRadarColControl.cs index 4a0738c8..653264de 100644 --- a/UoFiddler.Plugin.Compare/UserControls/CompareRadarColControl.cs +++ b/UoFiddler.Plugin.Compare/UserControls/CompareRadarColControl.cs @@ -18,6 +18,11 @@ public CompareRadarColControl() InitializeComponent(); } + public void SetLocalization(Func getLocalized) + { + copyEntry2To1ToolStripMenuItem.Text = getLocalized("copyEntry2To1") ?? "Copy Entry to left"; + } + private readonly Dictionary _compare = new Dictionary(); private readonly List _landDisplayIndices = new List(); private readonly List _itemDisplayIndices = new List(); diff --git a/UoFiddler.Plugin.Compare/UserControls/CompareTextureControl.cs b/UoFiddler.Plugin.Compare/UserControls/CompareTextureControl.cs index fe33ee5d..585a5d95 100644 --- a/UoFiddler.Plugin.Compare/UserControls/CompareTextureControl.cs +++ b/UoFiddler.Plugin.Compare/UserControls/CompareTextureControl.cs @@ -32,6 +32,16 @@ public CompareTextureControl() InitializeComponent(); } + public void SetLocalization(Func getLocalized) + { + checkBox1.Text = getLocalized("checkBox1") ?? "Show only Differences"; + chkMultiSelect.Text = getLocalized("chkMultiSelect") ?? "Multi-Select"; + button1.Text = getLocalized("button1") ?? "Load"; + button2.Text = getLocalized("button2") ?? "..."; + exportImageToolStripMenuItem.Text = getLocalized("exportImageToolStripMenuItem") ?? "Export Image.."; + copyLandTile2To1ToolStripMenuItem.Text = getLocalized("copyLandTile2To1ToolStripMenuItem") ?? "Copy Texture to left"; + } + private readonly Dictionary _compare = new Dictionary(); private readonly SHA256 _sha256 = SHA256.Create(); private readonly ImageConverter _ic = new ImageConverter(); diff --git a/UoFiddler.Plugin.Compare/UserControls/CompareTileDataControl.cs b/UoFiddler.Plugin.Compare/UserControls/CompareTileDataControl.cs index 0586d9bf..312e7b1c 100644 --- a/UoFiddler.Plugin.Compare/UserControls/CompareTileDataControl.cs +++ b/UoFiddler.Plugin.Compare/UserControls/CompareTileDataControl.cs @@ -18,6 +18,16 @@ public CompareTileDataControl() InitializeComponent(); } + public void SetLocalization(Func getLocalized) + { + btnCopyLandSelected.Text = getLocalized("btnCopyLandSelected") ?? "Copy Selected"; + btnCopyLandAllDiff.Text = getLocalized("btnCopyLandAllDiff") ?? "Copy All Different"; + btnCopyItemSelected.Text = getLocalized("btnCopyItemSelected") ?? "Copy Selected"; + btnCopyItemAllDiff.Text = getLocalized("btnCopyItemAllDiff") ?? "Copy All Different"; + tabLand.Text = getLocalized("tabLand") ?? "Land Tiles"; + tabItem.Text = getLocalized("tabItem") ?? "Static Tiles"; + } + // ── State ──────────────────────────────────────────────────────────────── private SecondTileData _secondTileData; diff --git a/UoFiddler.Plugin.UopPacker/UopPacker.cs b/UoFiddler.Plugin.UopPacker/UopPacker.cs index 978a11ec..23934452 100644 --- a/UoFiddler.Plugin.UopPacker/UopPacker.cs +++ b/UoFiddler.Plugin.UopPacker/UopPacker.cs @@ -68,7 +68,16 @@ public override void ModifyTabPages(TabControl tabControl) Tag = 0, // at end used for undock/dock feature to define the order Text = "UOP Packer" }; - page.Controls.Add(new UopPackerControl(Version)); + + var control = new UopPackerControl(Version); + + // 应用汉化 + if (LocalizationGetter != null) + { + control.SetLocalization(LocalizationGetter); + } + + page.Controls.Add(control); tabControl.TabPages.Add(page); } } diff --git a/UoFiddler.Plugin.UopPacker/UserControls/UopPackerControl.cs b/UoFiddler.Plugin.UopPacker/UserControls/UopPackerControl.cs index 111783be..d76775e4 100644 --- a/UoFiddler.Plugin.UopPacker/UserControls/UopPackerControl.cs +++ b/UoFiddler.Plugin.UopPacker/UserControls/UopPackerControl.cs @@ -26,6 +26,7 @@ namespace UoFiddler.Plugin.UopPacker.UserControls public partial class UopPackerControl : UserControl { private readonly LegacyMulFileConverter _conv; + private Func _localizationGetter; private UopPackerControl() { @@ -60,9 +61,17 @@ private UopPackerControl() ApplyDarkModeIfNeeded(); + // 在 Load 事件中应用汉化 + this.Load += (s, e) => ApplyLocalization(); + Dock = DockStyle.Fill; } + public void SetLocalization(Func localizationGetter) + { + _localizationGetter = localizationGetter; + } + private void ApplyDarkModeIfNeeded() { if (!Options.DarkMode) @@ -97,6 +106,92 @@ private void ApplyDarkModeIfNeeded() statustext.ForeColor = Color.OrangeRed; } + private void ApplyLocalization() + { + if (_localizationGetter == null) return; + + // 更新所有 UI 控件的文本 + label1.Text = _localizationGetter("Forms.UopPackerControl.label1") ?? "Convert from MUL to UOP"; + label2.Text = _localizationGetter("Forms.UopPackerControl.label2") ?? "Input MUL"; + label3.Text = _localizationGetter("Forms.UopPackerControl.label3") ?? "Input IDX"; + labelHousingBin.Text = _localizationGetter("Forms.UopPackerControl.labelHousingBin") ?? "housing.bin"; + label7.Text = _localizationGetter("Forms.UopPackerControl.label7") ?? "Type"; + label4.Text = _localizationGetter("Forms.UopPackerControl.label4") ?? "Map Index"; + label5.Text = _localizationGetter("Forms.UopPackerControl.label5") ?? "Type"; + label6.Text = _localizationGetter("Forms.UopPackerControl.label6") ?? "Map Index"; + label8.Text = _localizationGetter("Forms.UopPackerControl.label8") ?? "Input UOP"; + label9.Text = _localizationGetter("Forms.UopPackerControl.label9") ?? "Type"; + label11.Text = _localizationGetter("Forms.UopPackerControl.label11") ?? "Output files folder"; + label12.Text = _localizationGetter("Forms.UopPackerControl.label12") ?? "Convert from UOP to MUL"; + + // 调整输入框标签 - 右移以对齐其他标签 + label13.Text = _localizationGetter("Forms.UopPackerControl.label13") ?? "Input folder"; + label14.Text = _localizationGetter("Forms.UopPackerControl.label14") ?? "Output folder"; + + // 调整标签宽度和位置以适应中文 + label13.AutoSize = false; + label13.Width = 70; + label14.AutoSize = false; + label14.Width = 70; + + // 相应调整输入框位置 + inputfolder.Location = new System.Drawing.Point(80, inputfolder.Location.Y); + outputfolder.Location = new System.Drawing.Point(80, outputfolder.Location.Y); + SelectFolderButton.Location = new System.Drawing.Point(328, SelectFolderButton.Location.Y); + SelectOutputFolderButton.Location = new System.Drawing.Point(328, SelectOutputFolderButton.Location.Y); + + // 调整提取/打包单选按钮位置以对齐输入框(X=80) + extract.Location = new System.Drawing.Point(80, extract.Location.Y); + pack.Location = new System.Drawing.Point(80, pack.Location.Y); + + multouop.Text = _localizationGetter("Forms.UopPackerControl.multouop") ?? "Convert"; + uoptomul.Text = _localizationGetter("Forms.UopPackerControl.uoptomul") ?? "Convert"; + inmulbtn.Text = _localizationGetter("Forms.UopPackerControl.inmulbtn") ?? "..."; + inidxbtn.Text = _localizationGetter("Forms.UopPackerControl.inidxbtn") ?? "..."; + inhousingbinbtn.Text = _localizationGetter("Forms.UopPackerControl.inhousingbinbtn") ?? "..."; + outuopfolderbtn.Text = _localizationGetter("Forms.UopPackerControl.outuopfolderbtn") ?? "..."; + inuopbtn.Text = _localizationGetter("Forms.UopPackerControl.inuopbtn") ?? "..."; + outfolderbtn.Text = _localizationGetter("Forms.UopPackerControl.outfolderbtn") ?? "..."; + + // TabControl 和 RadioButtons + ExtractAllFilesTabPage.Text = _localizationGetter("Forms.UopPackerControl.ExtractAllFilesTabPage") ?? "Extract/Pack All Files"; + ExtractSingleFileTabPage.Text = _localizationGetter("Forms.UopPackerControl.ExtractSingleFileTabPage") ?? "Extract/Pack Single File"; + extract.Text = _localizationGetter("Forms.UopPackerControl.extract") ?? "Extract"; + pack.Text = _localizationGetter("Forms.UopPackerControl.pack") ?? "Pack"; + packAllGumpCompressionLabel.Text = _localizationGetter("Forms.UopPackerControl.packAllGumpCompressionLabel") ?? "Gump Compression"; + packAllHousingBinLabel.Text = _localizationGetter("Forms.UopPackerControl.packAllHousingBinLabel") ?? "housing.bin"; + + SelectFolderButton.Text = _localizationGetter("Forms.UopPackerControl.SelectFolderButton") ?? "Select Folder"; + SelectOutputFolderButton.Text = _localizationGetter("Forms.UopPackerControl.SelectOutputFolderButton") ?? "Select Folder"; + StartFolderButton.Text = _localizationGetter("Forms.UopPackerControl.StartFolderButton") ?? "Start"; + compressionLabel.Text = "(?)"; // 保持为帮助图标 + compressionInputLabel.Text = _localizationGetter("Forms.UopPackerControl.compressionInputLabel") ?? "Compression"; + + label10.Text = _localizationGetter("Forms.UopPackerControl.label10") ?? "Progress"; + + toolStripStatusLabel2.Text = _localizationGetter("Forms.UopPackerControl.toolStripStatusLabel2") ?? "Extracting/Packing may take some time."; + + // PlaceholderText 汉化 + inmul.PlaceholderText = _localizationGetter("Forms.UopPackerControl.placeholder_inmul") ?? "art.mul"; + inidx.PlaceholderText = _localizationGetter("Forms.UopPackerControl.placeholder_inidx") ?? "artidx.mul"; + inhousingbin.PlaceholderText = _localizationGetter("Forms.UopPackerControl.placeholder_inhousingbin") ?? "housing.bin file path"; + outuopfolder.PlaceholderText = _localizationGetter("Forms.UopPackerControl.placeholder_outuopfolder") ?? "folder where .uop will be written"; + inuop.PlaceholderText = _localizationGetter("Forms.UopPackerControl.placeholder_inuop") ?? "MultiCollection.uop"; + outfolder.PlaceholderText = _localizationGetter("Forms.UopPackerControl.placeholder_outfolder") ?? "(blank = same as input folder)"; + inputfolder.PlaceholderText = _localizationGetter("Forms.UopPackerControl.placeholder_inputfolder") ?? "folder where files will be extracted"; + outputfolder.PlaceholderText = _localizationGetter("Forms.UopPackerControl.placeholder_outputfolder") ?? "folder where files will be packed"; + packAllHousingBin.PlaceholderText = _localizationGetter("Forms.UopPackerControl.placeholder_packAllHousingBin") ?? "optional, defaults to folder/housing.bin"; + + // ToolTips + compressionTip.SetToolTip(packAllGumpCompressionBox, _localizationGetter("Forms.UopPackerControl.tooltip_compression") ?? "Compression type for gump files"); + compressionTip.SetToolTip(compressionBox, _localizationGetter("Forms.UopPackerControl.tooltip_compression_single") ?? "Compression type for the file"); + } + + private string GetLocalizedMessage(string key, string defaultValue = "") + { + return _localizationGetter?.Invoke(key) ?? defaultValue; + } + private void OnPackAllModeChanged(object sender, EventArgs e) => UpdatePackAllCompressionVisibility(); private void UpdatePackAllCompressionVisibility() diff --git a/UoFiddler.Plugin.UopPacker/UserControls/UopPackerControl.resx b/UoFiddler.Plugin.UopPacker/UserControls/UopPackerControl.resx index fb0eeb27..16ab2b3c 100644 --- a/UoFiddler.Plugin.UopPacker/UserControls/UopPackerControl.resx +++ b/UoFiddler.Plugin.UopPacker/UserControls/UopPackerControl.resx @@ -127,19 +127,19 @@ 17, 17 - Pick the compression that matches the original UOP for the file type: - Art / Map / Sound: None - Gumpart: None on older clients, Mythic on newer clients (New Legacy 7.0.104) + 选择与该文件类型的原始 UOP 匹配的压缩方式: + 美术/地图/音效: 无 + Gumpart: 旧客户端无压缩,较新客户端使用 Mythic(新遗留版 7.0.104) MultiCollection: Zlib -Picking the wrong option produces a UOP that is much larger than the original or unreadable by the client. +选择错误的选项会导致 UOP 文件大小远大于原始文件或无法被客户端读取。 - Pick the compression that matches the original UOP for the file type: - Art / Map / Sound: None - Gumpart: None on older clients, Mythic on newer clients (New Legacy 7.0.104) + 选择与该文件类型的原始 UOP 匹配的压缩方式: + 美术/地图/音效: 无 + Gumpart: 旧客户端无压缩,较新客户端使用 Mythic(新遗留版 7.0.104) MultiCollection: Zlib -Picking the wrong option produces a UOP that is much larger than the original or unreadable by the client. +选择错误的选项会导致 UOP 文件大小远大于原始文件或无法被客户端读取。 261, 17 diff --git a/UoFiddler/Localization/Dictionaries/zh-CN.json b/UoFiddler/Localization/Dictionaries/zh-CN.json index d6310476..5a30461f 100644 --- a/UoFiddler/Localization/Dictionaries/zh-CN.json +++ b/UoFiddler/Localization/Dictionaries/zh-CN.json @@ -281,16 +281,281 @@ "messagebox_export_title": "导出所有物品到 offset.cfg?", "messagebox_export_done": "完成!" }, - "AboutBoxForm": { - "Title": "关于", - "checkBoxCheckOnStart": "启动时检查更新", - "button1": "检查更新", - "linkLabel1": "访问主页", - "label1": "项目作者和管理员", - "label3": "特殊贡献者", - "label5": "特别感谢", - "checkBoxFormState": "保存窗口状态", - "changelog": "版本 4.24.0\n- 静态碎片整理重写,带有显式过滤器(物品 ID 上限、块外偏移、无效 Z、重复项、堆积的静态物品),报告命名所有删除的内容,并添加验证按钮,可读取结果并与源进行协调\n- 碎片整理现在在后台工作线程上运行,具有有效的取消功能,不再在源文件丢失且未写入任何内容时报告成功\n- 地图区域复制和地图差异插入适用于仅 UOP 的客户端,复制地块字节精确,并可以写入 map{N}.mul 或 map{N}LegacyMUL.uop\n- 两个地图对话框都获得了可拖动的区域预览,具有平移和缩放功能,因此可以在地图上选择区域而不是输入数字\n- 复制的区域可以在 Z 中移动,对话框预先说明它实际上可以移动多远,然后有符号字节用尽\n- 新的每个配置文件保存格式选项:美术、gumpart、音效、MultiCollection 和地图可以写为 mul、uop、遵循加载的客户端或在保存时选择\n- 修复了地块哨兵大小、TerMur 上的差异补丁边界和 Facet 5 差异文件未被找到的问题\n- 修复了旧客户端上的纹理从油漆处理程序抛出异常:未使用的 idx 行被读取为 verdata 补丁\n- 修复了在 UOP 客户端上有色调 Gump 导致进程崩溃的问题\n- 修复了 AnimationSequence 组记录被跳过或以错误步长行走的问题,因此 666 和 1253 等实体现在解析文件声明的操作别名\n- TileData 可以一次为许多条目编辑,带有复制图块数据 / 粘贴特殊和最后一次批量应用的单级撤销\n- 物品、地形图块、Gump 和纹理通过剪贴板复制和粘贴图像,并标记自加载以来编辑的条目\n\n版本 4.23.0\n- Multi 图块标志在 UOP 和 mul 往返中保留:可见性字映射到两个 multi.mul int32,而不是一个布尔值\n- 按图块组件 ID 保存在 multi-components.txt 侧车中,因此重新打包不再删除船的舵手、舱口和木板或房子的门\n- 加载多重不再删除不可见的图块或重新排序图块列表\n- housing.bin 不再作为 multi 7 进行解析,多重 ID 上限现在涵盖在 MultiCollection.uop 中船运的最高 9000 的 ID\n- MultiCollection.uop 以客户端的实际形状编写:版本 4 容器、12 字节条目标头、标头 Adler32、zlib 级别 7\n- UOP gump 宽度和高度不再交换\n- EA 的 0x0 占位符 gump 不再在压缩客户端上列为有效(然后无法绘制)\n- 支持最高 0x12000 的 Gump ID,包括 7.0.98.1 及更高版本的 69971..69985\n- 压缩的 UOP 条目以其真实的磁盘上大小读取;动画、地图和 gump 被读取短\n- 使用 zlib 包装的 Mythic 压缩的动画帧现在被解码而不是作为像素进行解析\n- 压缩的地图 UOP 被拒绝并显示清晰的消息,而不是被静默误读\n- 音效不再得到 8 字节的垃圾作为样本前缀(名称块是 0x28 字节,而不是 32)\n- UOP 打包器:容器布局与每个文件类型的最新客户端匹配,重新打包相同的输入现在是字节相同的\n- UOP 打包器:空或超出范围的 idx 行被跳过并记录,而不是从截断数据中打包\n- UOP 打包器:未打包的美术保留高海status,大型自定义地图不再被截断为库存面大小\n- UOP 打包器:按类型验证压缩,故障删除部分文件,缺少 housing.bin / 组件侧车会提示\n- 比较插件:与主阅读器匹配,没有更多幻影差异;更宽的 ID 范围、释放的文件句柄和位图缓存,不可读的地图报告一次而不是从油漆处理程序抛出\n- Multi CSV/XML 导出携带尾随的高海 int32;gumpidx.mul 和 multi.idx 在最后一个真实条目处截断,而不是填充\n- UOP 名称哈希重写为可读的 lookup3 端口,已验证 82k 输入的位对位\n\n版本 4.22.2\n- 添加导出选项到动画标签中的缩略图列表。\n\n版本 4.22.1\n- 修复动画编辑表单库图块尺寸。\n\n版本 4.22.0\n- 为比较插件添加了多选支持。\n- 动画编辑表单:添加 anim6.mul 支持和库。改变了动画文件的加载方式。\n- 优化了许多控件的文件加载时间和内存使用。\n- 用更快的控件替换 TreeView,在 TileData、Sounds、RadarCol、Multis、Light 和 Dress 标签中加快加载和滚动。\n- \"选择在...\"跨标签导航现在激活目标主标签并可靠地选择行(修复 TileData \"保存更改\"静默失败)。相同的修复应用于物品、LandTiles、RadarCol、纹理、Gump、AnimData。\n- 暗黑模式颜色修复:用主题感知替代品(CornflowerBlue、OrangeRed、SystemColors.ControlText)替换硬编码的 Color.Blue/Color.Red/Color.Black\n- Hue 编辑表单预览现在使用配置的预览背景颜色,而不是硬编码的白色。\n- 改进了 radarcol 颜色生成和控制布局。\n- 比较地图状态条菜单移至右键单击下的上下文菜单,便于访问。添加了鼠标滚轮缩放。\n- 物品、地形图块和纹理可能的多选。\n- 添加了动画标签的过滤器\n- 向动画编辑器添加了库预览\n- 改进了动画标签的加载时间\n- 向动画编辑器添加了第二个动画叠加层\n- 为动画编辑器添加了缩放选项\n- 修复了启用\"查看标记\"时导出高度地图图像时应用程序无法退出的问题。\n- 修复了关闭没有任何选择的配置文件选择表单时的崩溃。\n\n版本 4.21.0\n- 修复了 tiledata 中的显示顺序 - org 现在首先出现。\n- 修复了比较插件中预览图像的刷新。\n- 向物品、地面、纹理和 gump 比较插件添加了 jpg 和 png 导出图像。\n- 为比较美术、地面和 gump 添加了 UOP 文件支持。比较时可以选择要使用的文件类型 Auto/UOP/MUL(Auto 中 UOP 在 MUL 之前)。\n\n版本 4.20.2\n- 修复了 UopPacker 中的工具提示客户端版本信息。\n- 添加了选项以设置导出文件名模板十六进制/十进制(默认为十六进制)。\n\n版本 4.20.1\n- UopPacker:修复 gump 提取,改进提取索引的大小调整。\n- UopPacker:修复提取地图时的验证。\n- UopPacker:为 UI 添加进度条和次要改进。\n- Cliloc 标签:如果文件包含未知字节,添加了额外的验证和警告。\n\n版本 4.20.0\n- 迁移到 .NET 10.0\n- 添加暗黑模式(实验性)。\n\n版本 4.19.4\n- 从 WSC 导入时修复动态标志 - 最近更改后值被翻转。\n\n版本 4.19.3\n- 改进 cliloc 编辑。\n * 添加新 cliloc 条目时添加\"下一个免费\"按钮。\n * 添加条目现在将在搜索下一个可用数字时使用当前选择,或从用户在文本框中输入的数字开始搜索。\n * 添加 tiledata 导入预览表单。\n- 更新 UopPacker 插件中的提取/打包所有逻辑。\n\n版本 4.19.2\n- 修复在物品和地形图块标签中添加和替换图像时的验证。\n- 在 UopPacker 插件中添加了解释压缩设置的工具提示。\n- 对内部记录器构造的次要修复。\n\n版本 4.19.1\n- UopPacker:为 MultiCollection.uop(包括 housing.bin)添加保存支持并刷新插件 UI。\n- 地图复制/替换对话框现在支持 UOP 地图文件。\n- 为物品和地形图块标签添加了\"从文件夹替换\"批量操作。\n- 更多控件现在在保存时使用统一文件保存对话框(带有打开文件夹快捷方式)。\n- 动画编辑器记住添加新帧时选择的文件过滤器。\n\n版本 4.19.0\n- 添加了对预览 anim6.mul 和 AnimationFrame1-6.uop 中动画内容的支持(目前没有 uop 的导出或编辑选项)。\n- 修复了从较新客户端导入到较旧客户端的 tiledata CSV 导入时可能出现的崩溃和减速。\n- 更多预览框现在支持更改背景颜色并使用在\"选项\"中设置的背景颜色。\n- 对 RadarCol 比较布局进行了小调整。\n\n版本 4.18.2\n- 修复了 WSC multi 导入,其中文件具有绝对坐标。现在所有坐标都被转换为相对坐标。\n- 添加了 DynamicItems.xml,其中包含从 WSC 导入多个时应标记为动态的物品列表。\n- 添加了查看和导入 Multicollection.uop 多个物品的支持(目前没有保存选项)。\n- 改进了 CliLoc 比较。它现在显示带有高光的单词差异。\n- 删除了\"新 cliloc 格式\"选项。Cliloc 格式现在是自动检测的。\n\n版本 4.18.1\n- 大量导入插件现在允许导入 PNG 和 JPEG。\n- Animationlist.xml 中的无效条目现在将被跳过,并导致关于问题的消息。\n- Multi 编辑器现在具有带有快捷方式列表的附加表单。\n- Tiledata 控件现在具有带有某些字段和标志描述的附加表单(数据需要进一步更新)。\n- 更改背景颜色的选项现在在\"选项\"下统一,并保存在配置文件中。您仍然可以从各自的控件进行调整。\n- 修复:将 Gumplist.xml 添加到 UOFiddler 主文件夹(在上一个版本中遗漏)。\n- 您可以使用 F3 和 Shift F3 在以下标签中搜索下一个/上一个:Clilocs、Speech、Dress、Items、Land tiles、Sounds 和 Tiledata 标签。\n- 地图预览具有生成带有高度的预览的新选项(有点慢但有效)。\n\n版本 4.18.0\n- animdata 控件布局的小修复\n- Verdata 预览标签添加到浏览 verdata.mul 的内容(如果存在)。它仍在进行中。\n- 主窗口标签现在可以用鼠标滚轮滚动。\n- 新的保存文件确认对话框,带有打开输出文件夹按钮\n- Multi 编辑器有一些新选项:直线绘制、矩形填充、撤销/重做、笔刷大小 S/M/L 和删除,允许选择范围(需要与虚拟地板一起使用以获得最佳效果)。\n- 更新了比较插件。添加了比较 animdata、radarcol 和 tiledata。\n- 添加了 Gumplist.xml,允许向 gump 列表添加描述和标签。\n\n版本 4.17.9\n- 添加了选项以显示在每个客户端和服务器中的 hue 索引。\n\n版本 4.17.8\n- 修复了读取可能由 mulpatcher 或其他工具编辑的较旧 artidx.mul 文件。\n\n版本 4.17.7\n- 避免在使用\"导出全部\"时崩溃。\n- 导出时更新了 gump 文件名。\n\n版本 4.17.6\n- 更新了动画列表和编辑器的布局。\n\n版本 4.17.5\n- 插入或替换图形时添加了 PNG 格式支持。\n\n版本 4.17.4\n- 修复了最近 UOP 编码更新后损坏的 UOP 文件转换。\n\n版本 4.17.3\n- 修复了比较插件中与 gump 相关的崩溃。\n\n版本 4.17.2\n- 修复了动画缩略图列表中的崩溃。\n\n版本 4.17.1\n- 修复了从文本文件的动画调色板导入。\n\n版本 4.17.0\n- 改进了 cliloc 和 gump 文件编码。允许读取和保存压缩的 cliloc 和 gump。\n\n版本 4.16.1\n- 修复了文件路径无效时的一些崩溃。\n\n版本 4.16.0\n- 添加了对版本 7.0.104 中引入的压缩 gump 文件的读取支持\n + 支持仅部分,因此它只能读取和解压缩文件\n + 保存仍将生成旧文件类型,没有办法生成压缩 UOP\n\n版本 4.15.3\n- 修复了从 gif 文件导入动画帧。\n\n版本 4.15.2\n- 添加了对版本 7.0.104 中引入的压缩 cliloc 文件的读取支持\n + 支持仅部分,因此它只能读取和解压缩文件\n + 保存仍将生成旧文件类型\n + 要读取较新的 cliloc,您需要在\"选项\"中启用\"新 cliloc 格式\"\n\n版本 4.15.1\n- 修复了当 animdata 帧计数条目高于最大值 64 时的崩溃\n\n版本 4.15.0\n- 更新了雷达颜色标签的标签顺序\n- 向 Dress 和动画标签添加了 gif 导出\n- UOPacker 插件现在可以解包 multicollection.uop\n- 向 tiledata 标签添加了工具提示\n\n版本 4.14.0\n- RadarCol 标签的各种改进:\n + 在 treeview 选择更改时保存 radarcol\n + 为 radarcol 更改启用恢复、全部恢复\n + 添加\"范围项目到单个平均值\"\n + 添加\"范围项目到范围平均值\"\n + 添加过滤器和复选框选择\n\n版本 4.13.0\n- 添加了为 AnimData 帧设置 hue 和导出动画数据到 GIF 的功能\n- 在 multi 编辑器插件中添加了将设计导出为 XML 的功能\n\n版本 4.12.0\n- 添加了 AnimData 的导入/导出\n- 在 Multis 标签中添加了导出到 XML(centred+ 格式)\n- 修复了导入 unicode 字体字符\n\n版本 4.11.0\n- 更新到 .net 8.0\n\n版本 4.10.9\n- 修复了添加新光时的崩溃。\n\n版本 4.10.8\n- 删除了 gump、音效、纹理和 tiledata 的搜索弹出窗口。将搜索移到控制屏幕。\n- 删除了过时的设置以在音效标签中折叠右面板。\n\n版本 4.10.7\n- 修复了搜索范围。更新了地形图块控制布局。\n\n版本 4.10.6\n- 删除了物品和地形图块控件的搜索弹出窗口。将搜索移到控制屏幕。\n\n版本 4.10.5\n- 添加了选项以将 hue 名称和 ID 导出到文件。\n\n版本 4.10.4\n- 更新了 UOP Packer 插件中的地图文件解包过程。解包地图时,插件将删除 mul 文件末尾的额外字节,因为某些 UOP 地图包含额外的 196 字节。\n\n版本 4.10.3\n- 修复了 UOP Packer 插件中的 art.mul/idx 解包。\n\n版本 4.10.2\n- 修复了 hue 编辑器中的预览着色。\n\n版本 4.10.1\n- 修复了 tiledata 标志 `Unused8` 的无效值。由于 tiledata csv 导出是位置性的,此修复可能会影响此版本之前导出的文件。\n\n版本 4.10.0\n- 迁移到 .net 7。\n\n版本 4.9.28\n- 修复了将 hue 应用于物品和动画。\n- 更新了地图替换图块表单,以更好地指示进度和 XML 文件的可能问题。\n\n版本 4.9.27\n- 添加了\"删除图块边框\"选项,使图块边框不可见(标签:物品、地形图块、纹理、字体)。\n- 添加了\"设置背景颜色与图块背景相同\"。选择自定义图块背景颜色时,如果选中此选项,它也将应用到整个控件。\n\n版本 4.9.26\n- 向\"音效\"标签添加了\"导出所有音效\"选项。\n\n版本 4.9.25\n- 修复了 multi 编辑器插件导入范围(最大 multi ID 低于 multi 标签中的)。\n- 次要清理。\n\n版本 4.9.24\n- 添加了 UOX3 multi 导出。这是一个非常基础的版本,因此预期某些功能会缺失。\n\n版本 4.9.23\n- 导入 multi 对话框现在将以模式运行。\n- 为 multi 作为 csv 添加了导入/导出。与 punt 的 multi 工具一起使用。\n- 向\"大量导入\"插件添加了导入 multi\n- 修复了 hue 格式保存以更好地匹配原始格式。\n\n版本 4.9.22\n- 修复了在\"物品\"、\"地形图块\"和\"纹理\"标签上搜索后物品的聚焦。\n\n版本 4.9.21\n- 在物品详情表单上添加了导出到 JPG 和 PNG。\n- 在动画编辑表单上添加了导出到 JPG 和 PNG。\n\n版本 4.9.20\n- 导入或替换资产时删除了源文件锁定。\n\n版本 4.9.19\n- 修复了更新检查器异常处理。\n\n版本 4.9.18\n- 修复了导出动画帧时的崩溃,其中操作缺少帧。\n\n版本 4.9.17\n- 更新了客户端窗口枚举逻辑以首先查找替代客户端以修复 OrionUO 客户端上的 Client.SendText()。\n\n版本 4.9.16\n- 在启用\"显示空闲插槽\"时使用\"插入在...\"和\"从...插入开始\"时,Gump 列表现在将选择最后插入的索引。\n\n版本 4.9.15\n- 修复了物品、地形图块和纹理中的\"从...替换开始...\"问题。它现在按应有的方式替换图块。当索引到达最大索引值时停止。\n- 修复了\"显示空闲插槽\"菜单项在重新加载文件后不清除其状态的问题。\n\n版本 4.9.14\n- 修复了启用\"显示空闲插槽\"时浏览纹理时的崩溃。\n- 修复了使用非现有技能 ID 浏览 SkillGrp 时的崩溃。\n\n版本 4.9.13\n- 修复了多(多标签)区域导出/导入。MultiRegion 导入后应具有相同的坐标。\n- 向\"物品\"标签添加了\"从...替换开始...\"。允许从所选索引开始替换多个物品。\n- 将\"从...插入开始...\"重命名为\"从...替换开始...\",因为它更好地反映了实际功能。\n- 扩展了 Ultima.Client 以枚举多个 ultima 窗口。\n- 次要代码修复和清理。\n\n版本 4.9.12\n- 在 Dress 标签上添加了搜索物品。\n\n版本 4.9.11\n- 向\"地形图块\"标签添加了\"显示空闲插槽\"选项。\n- 向\"纹理\"标签添加了\"显示空闲插槽\"选项。\n\n版本 4.9.10\n- \"发送物品\"插件应现在仅注册一次,而不是两次。\n- \"发送物品到客户端\"插件应与 ClassicUO 配合使用。\n\n版本 4.9.9\n- 修复了\"物品\"标签 - 默认情况下某些较大的静态物品不可见。\n- 更新了\"音效\"标签以默认使用基于 0 的索引。有新选项\"偏移音效 ID 1(POL 模拟器)\"用于 POL 用户。POL 从 1 开始音效 ID。\n- 向 Hues 控件添加了按文本搜索。\n\n版本 4.9.8\n- 更新了 animationlist.xml(您需要从 UOFiddler 目录复制更新的文件到您的配置文件文件夹并覆盖现有的 animationlist.xml)\n- 修复了 speech.mul ID 值读取 - 不再限于 256。\n\n版本 4.9.7\n- \"在 Gump 中选择\"标签选项添加到\"物品\"和\"Tiledata\"标签中的上下文菜单。\n- 项目中的次要更新以修复使用 `dotnet build` 命令的构建。\n- 使用 .uop 格式时修复了错误的地图大小预选择。\n- \"从...插入开始\"选项添加到 Gump、地形图块和纹理标签 - 允许按顺序插入项目范围。\n- 添加了 Tiledata 标签的\"设置纹理\"选项 - 为所有没有但具有相应纹理的地形图块设置纹理 ID。\n- 物品、地形图块和纹理的默认控件已删除。替代控件已重命名,现在是主控件和唯一可用的控件。\n- 删除了过时的哈希文件使用。\n- 动画编辑表单上的\"替换\"按钮已隐藏,直到其实现完成。\n- 修复了无法将动画正文 ID 值映射到 1696 以上的问题。它现在适用于最高 2048 的正文 ID,这是 UO 客户端限制。\n- \"平均所有\"新按钮在 RadarColor 标签中,检查所有物品和地形图块并将所有黑色非空的设置为平均颜色。\n- 修复了仅浏览标签内容时 AnimData 被标记为已修改的问题。\n- 使用 UOP 文件格式时修复了\"物品\"标签上的\"显示空闲插槽\"。\n- 修复了 Gump 标签上的\"显示空闲插槽\"。\n- 新选项。您现在可以为图块视图控件(物品、地形图块、纹理和字体)选择选择颜色和焦点颜色。\n- 修复了在\"物品\"、\"地形图块\"、\"Tiledata\"和\"Cliloc\"标签中提供无效正则表达式模式字符串时的崩溃。\n- Cliloc 标签。\"Go to text\" 默认使用不区分大小写的字符串比较。如果需要,您可以切换到正则表达式。\n- 将 Hue 标签重命名为 Hues。Hues 控件 - 添加了快速搜索选项。您现在可以通过其索引跳转到 hue。显示的 hue 索引值现在是 0-based,与 hues.mul 中存储的相同。\n- 更新了动画编辑器布局。\n- 向动画列表添加了操作名称。\n- 更新了 Serilog.Sinks.File 包到最新版本。\n\n版本 4.9.6\n- 向\"物品\"、\"地形图块\"、\"纹理\"和\"字体\"添加了新的图块视图控件。渲染现在应该是平滑和快速的。要使用新控件,需要在设置中检查替代设计模式。\n- 向\"纹理\"标签添加了\"导出所有...\"选项。\n- 改变了字体加载方式。应该更快了。默认情况下,当您进入\"字体\"标签时,它将仅加载 ASCII 字体。Unicode 字体在选中复选框后加载。\n- 修复了 AnimData \"保存\"按钮。\n- 修复了\"语音\"标签上的默认文本。\n\n版本 4.9.5\n- 修复了从其他标签选择\"物品/地形图块\"标签中的图块时罕见的挂起。\n- 修复了在 tiledata 物品列表中使用上下文菜单时的崩溃。\n- 修复了 multi 设计保存 UO 建筑师。文件扩展名更改为 .uoa.txt 以表示这是文本格式而不是二进制格式。更新了 UO Architect txt 文件的导入选项。\n- 减少了 multi 编辑器插件中 Tiles 标签上的闪烁。\n\n版本 4.9.4\n- 修复了纹理保存。\n- 修复了 CliLoc Goto 文本框上的右键单击。\n- 通过鼠标滚轮滚动添加了缩放输入/输出。为缩放级别添加了最小/最大值。\n- Hue 编辑器中的小修复。它不会使所选单元格变暗。\n- 您现在可以为 Multis 标签选择背景颜色。导出 multi 图像时将使用该颜色作为背景。PNG 格式支持透明度,因此默认情况下导出时会有透明背景,但可以关闭并使用纯色背景导出。默认背景颜色是白色。\n- 修复了纹理在替代设计模式下不显示。\n- 修复了 art 标签中的缺失图块 - 最大 ID 没有 4k 地形图块偏移。这仅在 ID 高于 0x10000 的较新客户端中出现。\n- 修复了安装了多个 UO 客户端时的错误路径设置。这是一个解决方法,但会有所帮助。\n- 修复了在 multis 标签中导出图像时的崩溃。\n- 添加了十六进制值到动画列表。修复了状态栏文本格式。\n- 更新了 Serilog 包到 2.10.0。\n- 修复了 Animdata 在尝试删除框架而不是动画条目时的崩溃。更新了 Animdata 控件布局。\n\n版本 4.9.3\n- 向\"音效\"标签添加了右面板\n- 添加了更改\"物品\"标签背景颜色的功能。您可以为物品列表和右侧详情预览选择单独的颜色。右键单击并选择\"更改背景颜色\"。\n\n版本 4.9.2\n- 在 multi 编辑器插件中添加了缺失的船图块组。\n- 将当前选择的配置文件名称添加到主窗口标题。\n- AnimationEdit:从 .gif 文件导入的帧现在应在 X 轴上居中。\n\n版本 4.9.1\n- 我们现在复制配置文件而不是将其移动到 AppData(如果文件不存在)。\n- 修复了为物品替代设计模式导出 offset.cfg。\n- 将更新检查移至 github 发布 API。\n- 添加了 UOP Packer 插件\n- 修复了\"音效\"标签描述标签 - 索引偏离 1。\n- 修复了 multi 导入问题与高于 4095 的索引。\n- 通过在高度设置不同于最大 multi 高度时将高度值添加到文件名来避免用不同的高度设置替换导出的 multi 图像。\n- 更新了 tiledata 标志以支持高海扩展格式。仅当文件采用 HS 或更高版本格式时才显示其他标志。\n- 修复了地图叠加层加载。\n- 次要 UI 修复和更新。\n- 修复了 hue 的最大物品 ID。它将从 Art 中当前定义的最大 ID 获取。\n- 修复了路径设置问题,其中选择新目录后并非所有路径都被更新。\n- 更新了 ultima 美术缓存大小。\n\n版本 4.9\n- 将项目更新到 .NET Framework 4.8\n\n有关版本 4.0 之前的版本信息,请参阅 old-changelog.txt 文件。" + "UopPackerControl": { + "label1": "从 MUL 转换为 UOP", + "label2": "输入 MUL", + "label3": "输入 IDX", + "labelHousingBin": "housing.bin", + "label7": "类型", + "label4": "地图索引", + "label5": "类型", + "label6": "地图索引", + "label8": "输入 UOP", + "label9": "类型", + "label11": "输出文件夹", + "label12": "从 UOP 转换为 MUL", + "label10": "进度", + "label13": "输入文件夹", + "label14": "输出文件夹", + "multouop": "转换", + "uoptomul": "转换", + "inmulbtn": "...", + "inidxbtn": "...", + "inhousingbinbtn": "...", + "outuopfolderbtn": "...", + "inuopbtn": "...", + "outfolderbtn": "...", + "ExtractAllFilesTabPage": "提取/打包所有文件", + "ExtractSingleFileTabPage": "提取/打包单个文件", + "extract": "提取", + "pack": "打包", + "packAllGumpCompressionLabel": "Gump 压缩", + "packAllHousingBinLabel": "housing.bin", + "SelectFolderButton": "选择文件夹", + "SelectOutputFolderButton": "选择文件夹", + "StartFolderButton": "开始", + "compressionLabel": "压缩方式", + "compressionInputLabel": "压缩方式", + "toolStripStatusLabel2": "提取/打包可能需要一些时间。", + "tooltip_compression": "Gump 文件的压缩类型", + "tooltip_compression_single": "文件的压缩类型", + "msg_specify_input_type": "必须指定输入类型", + "msg_specify_input_mul": "必须指定输入 mul", + "msg_input_mul_not_exist": "输入的 mul 不存在", + "msg_specify_input_idx": "必须指定输入 idx", + "msg_input_idx_not_exist": "输入的 idx 不存在", + "msg_specify_output_folder": "必须指定输出文件夹", + "msg_output_folder_not_exist": "输出文件夹不存在", + "msg_specify_housing_bin": "必须指定输入 housing.bin。不使用它,MultiCollection.uop 是不完整的 - 首先从原始 UOP 中提取它。", + "msg_housing_bin_not_exist": "输入的 housing.bin 不存在", + "msg_file_exists_proceed": "{uopName} 已存在于输出文件夹中,将被覆盖。\n\n继续?", + "msg_overwrite_title": "覆盖现有文件", + "msg_unusual_compression": "每个已发货客户端中的每个 {fileType} 条目都未压缩存储。\n\n压缩的地图 UOP 根本无法由 UOFiddler 读回,压缩的美术或音效条目超出客户端观察到接受的任何内容。\n\n仍然使用 {compression} 吗?", + "msg_unusual_compression_title": "此文件类型的不寻常压缩", + "msg_specify_input_uop": "必须指定输入 uop", + "msg_input_file_not_exist": "输入文件不存在", + "msg_files_overwrite": "这些文件已存在于输出文件夹中,将被覆盖:\n\n {files}\n\n继续?", + "msg_overwrite_files_title": "覆盖现有文件", + "msg_error": "发生错误。\r\n{message}", + "placeholder_inmul": "art.mul", + "placeholder_inidx": "artidx.mul", + "placeholder_inhousingbin": "housing.bin 文件路径", + "placeholder_outuopfolder": "将写入 .uop 的文件夹", + "placeholder_inuop": "MultiCollection.uop", + "placeholder_outfolder": "(留空 = 与输入文件夹相同)", + "placeholder_inputfolder": "文件将被提取到的文件夹", + "placeholder_outputfolder": "文件将被打包到的文件夹", + "placeholder_packAllHousingBin": "可选,默认为 folder/housing.bin" + }, + "CompareItemControl": { + "extractAs": "导出图像..", + "asBmp": "作为 Bmp", + "asTiff": "作为 Tiff", + "asJpg": "作为 Jpg", + "asPng": "作为 Png", + "copyItem2To1": "复制物品到左侧", + "copyAllDiff": "复制所有不同", + "loadSecond": "加载第二个", + "showOnlyDifferences": "仅显示不同", + "multiSelect": "多选" + }, + "CompareLandControl": { + "exportImageToolStripMenuItem": "导出图像..", + "asBmpToolStripMenuItem": "作为 Bmp", + "asTiffToolStripMenuItem": "作为 Tiff", + "asJpgToolStripMenuItem": "作为 Jpg", + "asPngToolStripMenuItem": "作为 Png", + "copyLandTile2To1ToolStripMenuItem": "复制地形到左侧", + "btnCopyAllDiff": "复制所有差异", + "button1": "加载", + "checkBox1": "仅显示差异", + "chkMultiSelect": "多选" + }, + "CompareCliLocControl": { + "button1": "加载", + "button2": "加载", + "button3": "...", + "button4": "...", + "button5": "查找下一个差异", + "checkBox1": "仅显示不同", + "labelDiff1": "文件 1:", + "labelDiff2": "文件 2:" + }, + "CompareHuesControl": { + "button1": "加载", + "button2": "...", + "chkMultiSelect": "多选", + "applyHue1ToHue2": "应用色调到左侧" + }, + "CompareGumpControl": { + "checkBox1": "仅显示差异", + "chkMultiSelect": "多选", + "button1": "加载", + "button2": "加载", + "extractAs": "导出为..", + "copyGump2To1": "复制Gump到左侧" + }, + "CompareMapControl": { + "button1": "加载", + "button2": "...", + "zoomPlus": "放大", + "zoomMinus": "缩小", + "coordsPrefix": "坐标: ", + "zoomPrefix": "缩放: ", + "showDifferencesToolStripMenuItem": "显示差异", + "showMap1ToolStripMenuItem": "显示地图1", + "showMap2ToolStripMenuItem": "显示地图2", + "feluccaToolStripMenuItem": "Felucca", + "trammelToolStripMenuItem": "Trammel", + "ilshenarToolStripMenuItem": "Ilshenar", + "malasToolStripMenuItem": "Malas", + "tokunoToolStripMenuItem": "Tokuno", + "terMurToolStripMenuItem": "TerMur", + "markDiffToolStripMenuItem": "标记差异" + }, + "CompareTextureControl": { + "checkBox1": "仅显示差异", + "chkMultiSelect": "多选", + "button1": "加载", + "button2": "...", + "exportImageToolStripMenuItem": "导出图像..", + "copyLandTile2To1ToolStripMenuItem": "复制纹理到左侧", + "fromLeftToRight": "复制所有差异", + "copyAddOnly": "仅复制新增项" + }, + "CompareAnimDataControl": { + "copyEntry": "复制条目到左侧", + "buttonLoadSecond": "加载", + "buttonBrowse": "...", + "buttonCopySelected": "复制选定项", + "buttonCopyAllDiff": "复制所有差异", + "buttonCopyAddedOnly": "仅复制新增项", + "checkBoxShowDiff": "仅显示差异", + "chkMultiSelect": "多选", + "groupBoxOrg": "左侧 (原始)", + "groupBoxSec": "右侧 (第二个)", + "groupBoxLegend": "图例", + "labelOrgFrameCountCaption": "帧数:", + "labelOrgFrameIntervalCaption": "帧间隔:", + "labelOrgFrameStartCaption": "帧起始:", + "labelOrgFrameDataCaption": "帧数据:", + "labelSecFrameCountCaption": "帧数:", + "labelSecFrameIntervalCaption": "帧间隔:", + "labelSecFrameStartCaption": "帧起始:", + "labelSecFrameDataCaption": "帧数据:", + "legendLabelOnlyInOrg": "仅在原始中", + "legendLabelOnlyInSecond": "仅在第二个中", + "legendLabelDifferent": "不同值", + "legendLabelIdentical": "相同" + }, + "CompareRadarColControl": { + "copyEntry2To1": "复制条目到左侧", + "buttonLoadSecond": "加载", + "buttonBrowse": "...", + "buttonCopySelected": "复制选定项", + "buttonCopyAllDiff": "复制所有差异", + "checkBoxShowDiff": "仅显示差异", + "chkMultiSelect": "多选", + "groupBoxOrg": "左侧 (原始)", + "groupBoxSec": "右侧 (第二个)", + "groupBoxLegend": "图例", + "labelOrgColorCaption": "颜色:", + "labelSecColorCaption": "颜色:", + "legendLabelDifferent": "不同值", + "legendLabelIdentical": "相同" + }, + "CompareTileDataControl": { + "btnCopyLandSelected": "复制选定项", + "btnCopyLandAllDiff": "复制所有差异", + "btnCopyItemSelected": "复制选定项", + "btnCopyItemAllDiff": "复制所有差异", + "tabLand": "地形图块", + "tabItem": "静态图块", + "btnBrowse": "浏览...", + "btnLoad": "加载", + "chkShowDiff": "仅显示差异", + "chkMultiSelect": "多选", + "btnToggleRules": "规则 ▲", + "btnToggleRulesOpen": "规则 ▼", + "btnToggleRulesClose": "规则 ▲", + "labelDir": "目录:", + "chkLandName": "名称", + "chkLandTexId": "纹理ID", + "chkLandFlags": "标志", + "chkItemName": "名称", + "chkItemFlags": "标志", + "chkItemAnim": "动画", + "chkItemWeight": "重量", + "chkItemQuality": "品质", + "chkItemQty": "数量", + "chkItemHue": "色调", + "chkItemStack": "堆叠偏移", + "chkItemValue": "价值", + "chkItemHeight": "高度", + "chkItemMisc": "杂项数据", + "chkItemUnk2": "Unk2", + "chkItemUnk3": "Unk3", + "gbLandFields": "地形字段", + "gbItemFields": "物品字段", + "gbIgnoreFlags": "忽略标志 (勾选 = 从对比中排除)", + "btnResetRules": "恢复默认值", + "btnApplyRules": "应用", + "labelLandName": "名称", + "labelLandTexId": "纹理ID", + "labelItemName": "名称", + "labelItemAnim": "动画", + "labelItemWeight": "重量", + "labelItemQuality": "品质", + "labelItemQty": "数量", + "labelItemHue": "色调", + "labelItemStack": "堆叠偏移", + "labelItemValue": "价值", + "labelItemHeight": "高度", + "labelItemMisc": "杂项数据", + "labelItemUnk2": "Unk2", + "labelItemUnk3": "Unk3", + "flagHeaderFlag": "标志", + "flagHeaderOrg": "原始", + "flagHeaderSec": "第二个", + "flagBackground": "背景", + "flagWeapon": "武器", + "flagTransparent": "透明", + "flagTranslucent": "半透明", + "flagWall": "墙", + "flagDamaging": "伤害", + "flagImpassable": "不可通行", + "flagWet": "潮湿", + "flagUnknown1": "未知1", + "flagSurface": "表面", + "flagBridge": "桥", + "flagGeneric": "通用", + "flagWindow": "窗口", + "flagNoShoot": "不可射击", + "flagArticleA": "冠词A", + "flagArticleAn": "冠词An", + "flagArticleThe": "冠词The", + "flagFoliage": "植被", + "flagPartialHue": "部分色调", + "flagNoHouse": "无房屋", + "flagMap": "地图", + "flagContainer": "容器", + "flagWearable": "可穿戴", + "flagLightSource": "光源", + "flagAnimation": "动画", + "flagHoverOver": "悬停", + "flagNoDiagonal": "无对角线", + "flagArmor": "护甲", + "flagRoof": "屋顶", + "flagDoor": "门", + "flagStairBack": "楼梯背面", + "flagStairRight": "楼梯右面", + "flagAlphaBlend": "透明混合", + "flagUseNewArt": "使用新美术", + "flagArtUsed": "美术已使用", + "flagNoShadow": "无阴影", + "flagPixelBleed": "像素溢出", + "flagPlayAnimOnce": "播放一次动画", + "flagMultiMovable": "多可移动" } } } From 1d2c4ef45ef428b07d9cacfe78d215d3b93a9575 Mon Sep 17 00:00:00 2001 From: nbyaya Date: Sun, 4 Oct 2026 13:26:13 +0800 Subject: [PATCH 21/30] =?UTF-8?q?=E5=AE=8C=E5=96=84=EF=BC=9ACompareTileDat?= =?UTF-8?q?aControl=E6=B1=89=E5=8C=96=E5=AE=9E=E7=8E=B0?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit - 添加labelDir目录标签汉化 - 完善Rules按钮状态切换时的文本更新 - 修复GetLocalizedFlagName方法标志名称汉化 --- .../UserControls/CompareTileDataControl.cs | 147 ++++++++++++++---- 1 file changed, 118 insertions(+), 29 deletions(-) diff --git a/UoFiddler.Plugin.Compare/UserControls/CompareTileDataControl.cs b/UoFiddler.Plugin.Compare/UserControls/CompareTileDataControl.cs index 312e7b1c..fff22a78 100644 --- a/UoFiddler.Plugin.Compare/UserControls/CompareTileDataControl.cs +++ b/UoFiddler.Plugin.Compare/UserControls/CompareTileDataControl.cs @@ -13,19 +13,88 @@ namespace UoFiddler.Plugin.Compare.UserControls { public partial class CompareTileDataControl : UserControl { + private Func _localizationGetter; + public CompareTileDataControl() { InitializeComponent(); + this.Load += (s, e) => ApplyLocalization(); } public void SetLocalization(Func getLocalized) { - btnCopyLandSelected.Text = getLocalized("btnCopyLandSelected") ?? "Copy Selected"; - btnCopyLandAllDiff.Text = getLocalized("btnCopyLandAllDiff") ?? "Copy All Different"; - btnCopyItemSelected.Text = getLocalized("btnCopyItemSelected") ?? "Copy Selected"; - btnCopyItemAllDiff.Text = getLocalized("btnCopyItemAllDiff") ?? "Copy All Different"; - tabLand.Text = getLocalized("tabLand") ?? "Land Tiles"; - tabItem.Text = getLocalized("tabItem") ?? "Static Tiles"; + _localizationGetter = getLocalized; + ApplyLocalization(); + } + + private void ApplyLocalization() + { + if (_localizationGetter == null) return; + + // 汉化分组框 + gbLandFields.Text = _localizationGetter("Forms.CompareTileDataControl.gbLandFields") ?? "Land Fields"; + gbItemFields.Text = _localizationGetter("Forms.CompareTileDataControl.gbItemFields") ?? "Item Fields"; + gbIgnoreFlags.Text = _localizationGetter("Forms.CompareTileDataControl.gbIgnoreFlags") ?? "Ignore Flags (checked = excluded from compare)"; + + // 汉化标签 + labelDir.Text = _localizationGetter("Forms.CompareTileDataControl.labelDir") ?? "Directory:"; + + // 汉化按钮 + btnBrowse.Text = _localizationGetter("Forms.CompareTileDataControl.btnBrowse") ?? "Browse..."; + btnLoad.Text = _localizationGetter("Forms.CompareTileDataControl.btnLoad") ?? "Load"; + btnToggleRules.Text = _localizationGetter("Forms.CompareTileDataControl.btnToggleRulesClose") ?? "Rules ▲"; + btnResetRules.Text = _localizationGetter("Forms.CompareTileDataControl.btnResetRules") ?? "Reset to Defaults"; + btnApplyRules.Text = _localizationGetter("Forms.CompareTileDataControl.btnApplyRules") ?? "Apply"; + + // 汉化复选框 - Land Fields + chkLandName.Text = _localizationGetter("Forms.CompareTileDataControl.chkLandName") ?? "Name"; + chkLandTexId.Text = _localizationGetter("Forms.CompareTileDataControl.chkLandTexId") ?? "TextureId"; + chkLandFlags.Text = _localizationGetter("Forms.CompareTileDataControl.chkLandFlags") ?? "Flags"; + + // 汉化复选框 - Item Fields + chkItemName.Text = _localizationGetter("Forms.CompareTileDataControl.chkItemName") ?? "Name"; + chkItemAnim.Text = _localizationGetter("Forms.CompareTileDataControl.chkItemAnim") ?? "Anim"; + chkItemWeight.Text = _localizationGetter("Forms.CompareTileDataControl.chkItemWeight") ?? "Weight"; + chkItemQuality.Text = _localizationGetter("Forms.CompareTileDataControl.chkItemQuality") ?? "Quality"; + chkItemQty.Text = _localizationGetter("Forms.CompareTileDataControl.chkItemQty") ?? "Quantity"; + chkItemHue.Text = _localizationGetter("Forms.CompareTileDataControl.chkItemHue") ?? "Hue"; + chkItemStack.Text = _localizationGetter("Forms.CompareTileDataControl.chkItemStack") ?? "StackOffset"; + chkItemValue.Text = _localizationGetter("Forms.CompareTileDataControl.chkItemValue") ?? "Value"; + chkItemHeight.Text = _localizationGetter("Forms.CompareTileDataControl.chkItemHeight") ?? "Height"; + chkItemMisc.Text = _localizationGetter("Forms.CompareTileDataControl.chkItemMisc") ?? "MiscData"; + chkItemUnk2.Text = _localizationGetter("Forms.CompareTileDataControl.chkItemUnk2") ?? "Unk2"; + chkItemUnk3.Text = _localizationGetter("Forms.CompareTileDataControl.chkItemUnk3") ?? "Unk3"; + chkItemFlags.Text = _localizationGetter("Forms.CompareTileDataControl.chkItemFlags") ?? "Flags"; + + // 汉化其他复选框 + chkShowDiff.Text = _localizationGetter("Forms.CompareTileDataControl.chkShowDiff") ?? "Show Differences Only"; + chkMultiSelect.Text = _localizationGetter("Forms.CompareTileDataControl.chkMultiSelect") ?? "Multi-Select"; + + // 汉化复制按钮 + btnCopyLandSelected.Text = _localizationGetter("Forms.CompareTileDataControl.btnCopyLandSelected") ?? "Copy Selected"; + btnCopyLandAllDiff.Text = _localizationGetter("Forms.CompareTileDataControl.btnCopyLandAllDiff") ?? "Copy All Different"; + btnCopyItemSelected.Text = _localizationGetter("Forms.CompareTileDataControl.btnCopyItemSelected") ?? "Copy Selected"; + btnCopyItemAllDiff.Text = _localizationGetter("Forms.CompareTileDataControl.btnCopyItemAllDiff") ?? "Copy All Different"; + + // 汉化标签页 + tabLand.Text = _localizationGetter("Forms.CompareTileDataControl.tabLand") ?? "Land Tiles"; + tabItem.Text = _localizationGetter("Forms.CompareTileDataControl.tabItem") ?? "Static Tiles"; + + // 汉化详细信息标签 + lblLandName.Text = _localizationGetter("Forms.CompareTileDataControl.labelLandName") ?? "Name"; + lblLandTexId.Text = _localizationGetter("Forms.CompareTileDataControl.labelLandTexId") ?? "Texture ID"; + lblItemName.Text = _localizationGetter("Forms.CompareTileDataControl.labelItemName") ?? "Name"; + lblItemAnim.Text = _localizationGetter("Forms.CompareTileDataControl.labelItemAnim") ?? "Animation"; + lblItemWeight.Text = _localizationGetter("Forms.CompareTileDataControl.labelItemWeight") ?? "Weight"; + lblItemQuality.Text = _localizationGetter("Forms.CompareTileDataControl.labelItemQuality") ?? "Quality"; + lblItemQty.Text = _localizationGetter("Forms.CompareTileDataControl.labelItemQty") ?? "Quantity"; + lblItemHue.Text = _localizationGetter("Forms.CompareTileDataControl.labelItemHue") ?? "Hue"; + lblItemStack.Text = _localizationGetter("Forms.CompareTileDataControl.labelItemStack") ?? "StackOffset"; + lblItemValue.Text = _localizationGetter("Forms.CompareTileDataControl.labelItemValue") ?? "Value"; + lblItemHeight.Text = _localizationGetter("Forms.CompareTileDataControl.labelItemHeight") ?? "Height"; + lblItemMisc.Text = _localizationGetter("Forms.CompareTileDataControl.labelItemMisc") ?? "MiscData"; + lblItemUnk2.Text = _localizationGetter("Forms.CompareTileDataControl.labelItemUnk2") ?? "Unk2"; + lblItemUnk3.Text = _localizationGetter("Forms.CompareTileDataControl.labelItemUnk3") ?? "Unk3"; } // ── State ──────────────────────────────────────────────────────────────── @@ -190,26 +259,26 @@ private List GetCopyTargets(TileViewControl secView) private void SetupDetailPanels() { // Land detail — 2 rows (Name, TextureId); Flags shown per-flag below - SetupDetailRow(tlpLandDetail, 0, lblLandName, "Name", txtLandOrgName, txtLandSecName); - SetupDetailRow(tlpLandDetail, 1, lblLandTexId, "Texture ID", txtLandOrgTexId, txtLandSecTexId); + SetupDetailRow(tlpLandDetail, 0, lblLandName, "labelLandName", txtLandOrgName, txtLandSecName, "Name"); + SetupDetailRow(tlpLandDetail, 1, lblLandTexId, "labelLandTexId", txtLandOrgTexId, txtLandSecTexId, "Texture ID"); SetupFlagsPanel(panelLandDetail, out _landFlagOrgChecks, out _landFlagSecChecks, out _landFlagLabels, out _landFlagTlp); // Push tlpLandDetail to the back so it gets the highest z-order and docks topmost panelLandDetail.Controls.SetChildIndex(tlpLandDetail, panelLandDetail.Controls.Count - 1); // Item detail — 12 rows (no Flags row); Flags shown per-flag below - SetupDetailRow(tlpItemDetail, 0, lblItemName, "Name", txtItemOrgName, txtItemSecName); - SetupDetailRow(tlpItemDetail, 1, lblItemAnim, "Animation", txtItemOrgAnim, txtItemSecAnim); - SetupDetailRow(tlpItemDetail, 2, lblItemWeight, "Weight", txtItemOrgWeight, txtItemSecWeight); - SetupDetailRow(tlpItemDetail, 3, lblItemQuality, "Quality", txtItemOrgQuality, txtItemSecQuality); - SetupDetailRow(tlpItemDetail, 4, lblItemQty, "Quantity", txtItemOrgQty, txtItemSecQty); - SetupDetailRow(tlpItemDetail, 5, lblItemHue, "Hue", txtItemOrgHue, txtItemSecHue); - SetupDetailRow(tlpItemDetail, 6, lblItemStack, "StackOffset", txtItemOrgStack, txtItemSecStack); - SetupDetailRow(tlpItemDetail, 7, lblItemValue, "Value", txtItemOrgValue, txtItemSecValue); - SetupDetailRow(tlpItemDetail, 8, lblItemHeight, "Height", txtItemOrgHeight, txtItemSecHeight); - SetupDetailRow(tlpItemDetail, 9, lblItemMisc, "MiscData", txtItemOrgMisc, txtItemSecMisc); - SetupDetailRow(tlpItemDetail, 10, lblItemUnk2, "Unk2", txtItemOrgUnk2, txtItemSecUnk2); - SetupDetailRow(tlpItemDetail, 11, lblItemUnk3, "Unk3", txtItemOrgUnk3, txtItemSecUnk3); + SetupDetailRow(tlpItemDetail, 0, lblItemName, "labelItemName", txtItemOrgName, txtItemSecName, "Name"); + SetupDetailRow(tlpItemDetail, 1, lblItemAnim, "labelItemAnim", txtItemOrgAnim, txtItemSecAnim, "Animation"); + SetupDetailRow(tlpItemDetail, 2, lblItemWeight, "labelItemWeight", txtItemOrgWeight, txtItemSecWeight, "Weight"); + SetupDetailRow(tlpItemDetail, 3, lblItemQuality, "labelItemQuality", txtItemOrgQuality, txtItemSecQuality, "Quality"); + SetupDetailRow(tlpItemDetail, 4, lblItemQty, "labelItemQty", txtItemOrgQty, txtItemSecQty, "Quantity"); + SetupDetailRow(tlpItemDetail, 5, lblItemHue, "labelItemHue", txtItemOrgHue, txtItemSecHue, "Hue"); + SetupDetailRow(tlpItemDetail, 6, lblItemStack, "labelItemStack", txtItemOrgStack, txtItemSecStack, "StackOffset"); + SetupDetailRow(tlpItemDetail, 7, lblItemValue, "labelItemValue", txtItemOrgValue, txtItemSecValue, "Value"); + SetupDetailRow(tlpItemDetail, 8, lblItemHeight, "labelItemHeight", txtItemOrgHeight, txtItemSecHeight, "Height"); + SetupDetailRow(tlpItemDetail, 9, lblItemMisc, "labelItemMisc", txtItemOrgMisc, txtItemSecMisc, "MiscData"); + SetupDetailRow(tlpItemDetail, 10, lblItemUnk2, "labelItemUnk2", txtItemOrgUnk2, txtItemSecUnk2, "Unk2"); + SetupDetailRow(tlpItemDetail, 11, lblItemUnk3, "labelItemUnk3", txtItemOrgUnk3, txtItemSecUnk3, "Unk3"); SetupFlagsPanel(panelItemDetail, out _itemFlagOrgChecks, out _itemFlagSecChecks, out _itemFlagLabels, out _itemFlagTlp); // Push tlpItemDetail to the back so it gets the highest z-order and docks topmost @@ -230,9 +299,9 @@ private void SetupFlagsPanel( // Header row var header = new Panel { Dock = DockStyle.Top, Height = 22, BackColor = SystemColors.ControlLight }; - var hLbl = new Label { Text = "Flag", Dock = DockStyle.Fill, TextAlign = ContentAlignment.MiddleLeft, Padding = new Padding(4, 0, 0, 0) }; - var hOrg = new Label { Text = "Org", Width = 44, Dock = DockStyle.Right, TextAlign = ContentAlignment.MiddleCenter }; - var hSec = new Label { Text = "Sec", Width = 44, Dock = DockStyle.Right, TextAlign = ContentAlignment.MiddleCenter }; + var hLbl = new Label { Text = _localizationGetter?.Invoke("Forms.CompareTileDataControl.flagHeaderFlag") ?? "Flag", Dock = DockStyle.Fill, TextAlign = ContentAlignment.MiddleLeft, Padding = new Padding(4, 0, 0, 0) }; + var hOrg = new Label { Text = _localizationGetter?.Invoke("Forms.CompareTileDataControl.flagHeaderOrg") ?? "Org", Width = 44, Dock = DockStyle.Right, TextAlign = ContentAlignment.MiddleCenter }; + var hSec = new Label { Text = _localizationGetter?.Invoke("Forms.CompareTileDataControl.flagHeaderSec") ?? "Sec", Width = 44, Dock = DockStyle.Right, TextAlign = ContentAlignment.MiddleCenter }; header.Controls.Add(hLbl); // Highest index docks first, so hSec (added last) takes the rightmost slot above secChk (col 2), // and hOrg (added second) ends up to its left above orgChk (col 1). @@ -355,12 +424,13 @@ private void UpdateFlagRows( } } - private static void SetupDetailRow( + private void SetupDetailRow( System.Windows.Forms.TableLayoutPanel tlp, int row, - System.Windows.Forms.Label lbl, string labelText, - System.Windows.Forms.TextBox orgBox, System.Windows.Forms.TextBox secBox) + System.Windows.Forms.Label lbl, string labelKey, + System.Windows.Forms.TextBox orgBox, System.Windows.Forms.TextBox secBox, + string defaultText) { - lbl.Text = labelText; + lbl.Text = _localizationGetter?.Invoke($"Forms.CompareTileDataControl.{labelKey}") ?? defaultText; lbl.Dock = System.Windows.Forms.DockStyle.Fill; lbl.TextAlign = System.Drawing.ContentAlignment.MiddleRight; @@ -1425,9 +1495,18 @@ private void BuildRulesPanel() clbFlags.Items.Clear(); foreach (var (name, _) in MeaningfulFlags) { - clbFlags.Items.Add(name, isChecked: false); // unchecked = not ignored + string localizedName = GetLocalizedFlagName(name); + clbFlags.Items.Add(localizedName, isChecked: false); // unchecked = not ignored } + } + private string GetLocalizedFlagName(string englishName) + { + if (_localizationGetter == null) + return englishName; + + string key = $"Forms.CompareTileDataControl.flag{englishName}"; + return _localizationGetter(key) ?? englishName; } private void WireFieldCheckbox(CheckBox chk, Func getter, Action setter) @@ -1497,7 +1576,17 @@ private void OnClickResetRules(object sender, EventArgs e) private void OnClickToggleRules(object sender, EventArgs e) { panelRules.Visible = !panelRules.Visible; - btnToggleRules.Text = panelRules.Visible ? "Rules ▼" : "Rules ▲"; + + if (_localizationGetter != null) + { + btnToggleRules.Text = panelRules.Visible + ? _localizationGetter("Forms.CompareTileDataControl.btnToggleRulesOpen") ?? "Rules ▼" + : _localizationGetter("Forms.CompareTileDataControl.btnToggleRulesClose") ?? "Rules ▲"; + } + else + { + btnToggleRules.Text = panelRules.Visible ? "Rules ▼" : "Rules ▲"; + } } } } From 0a2cc426e067a2d030049f1344d60c5551b9f800 Mon Sep 17 00:00:00 2001 From: nbyaya Date: Sun, 4 Oct 2026 13:26:31 +0800 Subject: [PATCH 22/30] =?UTF-8?q?=E5=AE=8C=E5=96=84=EF=BC=9ACompare?= =?UTF-8?q?=E6=89=80=E6=9C=89=E6=8E=A7=E5=88=B6=E6=B1=89=E5=8C=96=E6=A8=A1?= =?UTF-8?q?=E5=BC=8F?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit - CompareAnimDataControl、CompareCliLocControl等统一实现SetLocalization - 完善ApplyLocalization方法逻辑 - 删除重复的OnLoad本地化调用 --- .../UserControls/CompareAnimDataControl.cs | 52 +++++++++++++++++- .../UserControls/CompareCliLocControl.cs | 27 +++++++--- .../UserControls/CompareGumpControl.cs | 23 +++++--- .../UserControls/CompareHuesControl.cs | 19 +++++-- .../UserControls/CompareItemControl.cs | 20 +++---- .../UserControls/CompareLandControl.cs | 20 +++---- .../UserControls/CompareMapControl.cs | 53 +++++++++++++------ .../UserControls/CompareRadarColControl.cs | 43 ++++++++++++++- .../UserControls/CompareTextureControl.cs | 31 ++++++++--- 9 files changed, 224 insertions(+), 64 deletions(-) diff --git a/UoFiddler.Plugin.Compare/UserControls/CompareAnimDataControl.cs b/UoFiddler.Plugin.Compare/UserControls/CompareAnimDataControl.cs index 1655e338..1b66a4af 100644 --- a/UoFiddler.Plugin.Compare/UserControls/CompareAnimDataControl.cs +++ b/UoFiddler.Plugin.Compare/UserControls/CompareAnimDataControl.cs @@ -12,14 +12,62 @@ namespace UoFiddler.Plugin.Compare.UserControls { public partial class CompareAnimDataControl : UserControl { + private Func _localizationGetter; + public CompareAnimDataControl() { InitializeComponent(); + + // 在 Load 事件中应用汉化 + this.Load += (s, e) => ApplyLocalization(); } public void SetLocalization(Func getLocalized) { - copyEntryToolStripMenuItem.Text = getLocalized("copyEntry") ?? "Copy Entry to left"; + _localizationGetter = getLocalized; + ApplyLocalization(); + } + + private void ApplyLocalization() + { + if (_localizationGetter == null) return; + + // 汉化菜单项 + copyEntryToolStripMenuItem.Text = _localizationGetter("Forms.CompareAnimDataControl.copyEntry") ?? "Copy Entry to left"; + + // 汉化按钮 + buttonLoadSecond.Text = _localizationGetter("Forms.CompareAnimDataControl.buttonLoadSecond") ?? "Load"; + buttonBrowse.Text = _localizationGetter("Forms.CompareAnimDataControl.buttonBrowse") ?? "..."; + buttonCopySelected.Text = _localizationGetter("Forms.CompareAnimDataControl.buttonCopySelected") ?? "Copy Selected"; + buttonCopyAllDiff.Text = _localizationGetter("Forms.CompareAnimDataControl.buttonCopyAllDiff") ?? "Copy All Diff"; + buttonCopyAddedOnly.Text = _localizationGetter("Forms.CompareAnimDataControl.buttonCopyAddedOnly") ?? "Copy Added Only"; + + // 汉化复选框 + checkBoxShowDiff.Text = _localizationGetter("Forms.CompareAnimDataControl.checkBoxShowDiff") ?? "Show only Differences"; + chkMultiSelect.Text = _localizationGetter("Forms.CompareAnimDataControl.chkMultiSelect") ?? "Multi-Select"; + + // 汉化GroupBox + groupBoxOrg.Text = _localizationGetter("Forms.CompareAnimDataControl.groupBoxOrg") ?? "Left (Original)"; + groupBoxSec.Text = _localizationGetter("Forms.CompareAnimDataControl.groupBoxSec") ?? "Right (Second)"; + groupBoxLegend.Text = _localizationGetter("Forms.CompareAnimDataControl.groupBoxLegend") ?? "Legend"; + + // 汉化标签 - Left (Original) + labelOrgFrameCountCaption.Text = _localizationGetter("Forms.CompareAnimDataControl.labelOrgFrameCountCaption") ?? "Frame Count:"; + labelOrgFrameIntervalCaption.Text = _localizationGetter("Forms.CompareAnimDataControl.labelOrgFrameIntervalCaption") ?? "Frame Interval:"; + labelOrgFrameStartCaption.Text = _localizationGetter("Forms.CompareAnimDataControl.labelOrgFrameStartCaption") ?? "Frame Start:"; + labelOrgFrameDataCaption.Text = _localizationGetter("Forms.CompareAnimDataControl.labelOrgFrameDataCaption") ?? "Frame Data:"; + + // 汉化标签 - Right (Second) + labelSecFrameCountCaption.Text = _localizationGetter("Forms.CompareAnimDataControl.labelSecFrameCountCaption") ?? "Frame Count:"; + labelSecFrameIntervalCaption.Text = _localizationGetter("Forms.CompareAnimDataControl.labelSecFrameIntervalCaption") ?? "Frame Interval:"; + labelSecFrameStartCaption.Text = _localizationGetter("Forms.CompareAnimDataControl.labelSecFrameStartCaption") ?? "Frame Start:"; + labelSecFrameDataCaption.Text = _localizationGetter("Forms.CompareAnimDataControl.labelSecFrameDataCaption") ?? "Frame Data:"; + + // 汉化图例标签 + legendLabelOnlyInOrg.Text = _localizationGetter("Forms.CompareAnimDataControl.legendLabelOnlyInOrg") ?? "Only in original"; + legendLabelOnlyInSecond.Text = _localizationGetter("Forms.CompareAnimDataControl.legendLabelOnlyInSecond") ?? "Only in second"; + legendLabelDifferent.Text = _localizationGetter("Forms.CompareAnimDataControl.legendLabelDifferent") ?? "Different values"; + legendLabelIdentical.Text = _localizationGetter("Forms.CompareAnimDataControl.legendLabelIdentical") ?? "Identical"; } private readonly Dictionary _compare = new Dictionary(); @@ -42,7 +90,7 @@ private void OnLoad(object sender, EventArgs e) int count = tileViewSec.SelectedIndices.Count; copyEntryToolStripMenuItem.Text = tileViewSec.ShowCheckBoxes && count > 1 ? $"Copy {count} Entries to left" - : "Copy Entry to left"; + : (_localizationGetter?.Invoke("Forms.CompareAnimDataControl.copyEntry") ?? "Copy Entry to left"); }; ControlEvents.FilePathChangeEvent += OnFilePathChangeEvent; diff --git a/UoFiddler.Plugin.Compare/UserControls/CompareCliLocControl.cs b/UoFiddler.Plugin.Compare/UserControls/CompareCliLocControl.cs index 25f0e6ba..beda2e6e 100644 --- a/UoFiddler.Plugin.Compare/UserControls/CompareCliLocControl.cs +++ b/UoFiddler.Plugin.Compare/UserControls/CompareCliLocControl.cs @@ -22,24 +22,35 @@ namespace UoFiddler.Plugin.Compare.UserControls { public partial class CompareCliLocControl : UserControl { + private Func _localizationGetter; + public CompareCliLocControl() { InitializeComponent(); _source = new BindingSource(); _sortOrder = SortOrder.Ascending; _sortColumn = 0; + this.Load += (s, e) => ApplyLocalization(); } public void SetLocalization(Func getLocalized) { - button1.Text = getLocalized("button1") ?? "Load"; - button2.Text = getLocalized("button2") ?? "Load"; - button3.Text = getLocalized("button3") ?? "..."; - button4.Text = getLocalized("button4") ?? "..."; - button5.Text = getLocalized("button5") ?? "Find Next Diff"; - checkBox1.Text = getLocalized("checkBox1") ?? "Show Only Differences"; - labelDiff1.Text = getLocalized("labelDiff1") ?? "File 1:"; - labelDiff2.Text = getLocalized("labelDiff2") ?? "File 2:"; + _localizationGetter = getLocalized; + ApplyLocalization(); + } + + private void ApplyLocalization() + { + if (_localizationGetter == null) return; + + button1.Text = _localizationGetter("Forms.CompareCliLocControl.button1") ?? "Load"; + button2.Text = _localizationGetter("Forms.CompareCliLocControl.button2") ?? "Load"; + button3.Text = _localizationGetter("Forms.CompareCliLocControl.button3") ?? "..."; + button4.Text = _localizationGetter("Forms.CompareCliLocControl.button4") ?? "..."; + button5.Text = _localizationGetter("Forms.CompareCliLocControl.button5") ?? "Find Next Diff"; + checkBox1.Text = _localizationGetter("Forms.CompareCliLocControl.checkBox1") ?? "Show Only Differences"; + labelDiff1.Text = _localizationGetter("Forms.CompareCliLocControl.labelDiff1") ?? "File 1:"; + labelDiff2.Text = _localizationGetter("Forms.CompareCliLocControl.labelDiff2") ?? "File 2:"; } private static StringList _cliloc1; diff --git a/UoFiddler.Plugin.Compare/UserControls/CompareGumpControl.cs b/UoFiddler.Plugin.Compare/UserControls/CompareGumpControl.cs index f8512f34..94f66d47 100644 --- a/UoFiddler.Plugin.Compare/UserControls/CompareGumpControl.cs +++ b/UoFiddler.Plugin.Compare/UserControls/CompareGumpControl.cs @@ -27,19 +27,30 @@ namespace UoFiddler.Plugin.Compare.UserControls { public partial class CompareGumpControl : UserControl { + private Func _localizationGetter; + public CompareGumpControl() { InitializeComponent(); + this.Load += (s, e) => ApplyLocalization(); } public void SetLocalization(Func getLocalized) { - checkBox1.Text = getLocalized("checkBox1") ?? "Show only Differences"; - chkMultiSelect.Text = getLocalized("chkMultiSelect") ?? "Multi-Select"; - button1.Text = getLocalized("button1") ?? "Load"; - button2.Text = getLocalized("button2") ?? "Load"; - extractAsToolStripMenuItem.Text = getLocalized("extractAs") ?? "Extract As.."; - copyGump2To1ToolStripMenuItem.Text = getLocalized("copyGump2To1") ?? "Copy Gump to left"; + _localizationGetter = getLocalized; + ApplyLocalization(); + } + + private void ApplyLocalization() + { + if (_localizationGetter == null) return; + + checkBox1.Text = _localizationGetter("Forms.CompareGumpControl.checkBox1") ?? "Show only Differences"; + chkMultiSelect.Text = _localizationGetter("Forms.CompareGumpControl.chkMultiSelect") ?? "Multi-Select"; + button1.Text = _localizationGetter("Forms.CompareGumpControl.button1") ?? "Load"; + button2.Text = _localizationGetter("Forms.CompareGumpControl.button2") ?? "Load"; + extractAsToolStripMenuItem.Text = _localizationGetter("Forms.CompareGumpControl.extractAs") ?? "Extract As.."; + copyGump2To1ToolStripMenuItem.Text = _localizationGetter("Forms.CompareGumpControl.copyGump2To1") ?? "Copy Gump to left"; } private readonly Dictionary _compare = new Dictionary(); diff --git a/UoFiddler.Plugin.Compare/UserControls/CompareHuesControl.cs b/UoFiddler.Plugin.Compare/UserControls/CompareHuesControl.cs index 1525f9ce..56860739 100644 --- a/UoFiddler.Plugin.Compare/UserControls/CompareHuesControl.cs +++ b/UoFiddler.Plugin.Compare/UserControls/CompareHuesControl.cs @@ -22,6 +22,8 @@ namespace UoFiddler.Plugin.Compare.UserControls { public partial class CompareHuesControl : UserControl { + private Func _localizationGetter; + public CompareHuesControl() { InitializeComponent(); @@ -34,14 +36,23 @@ public CompareHuesControl() pictureBox2.MouseWheel += OnMouseWheel; _hue2Loaded = false; + this.Load += (s, e) => ApplyLocalization(); } public void SetLocalization(Func getLocalized) { - button1.Text = getLocalized("button1") ?? "Load"; - button2.Text = getLocalized("button2") ?? "..."; - chkMultiSelect.Text = getLocalized("chkMultiSelect") ?? "Multi-Select"; - applyHue1ToHue2ToolStripMenuItem.Text = getLocalized("applyHue1ToHue2") ?? "Apply Hue to left"; + _localizationGetter = getLocalized; + ApplyLocalization(); + } + + private void ApplyLocalization() + { + if (_localizationGetter == null) return; + + button1.Text = _localizationGetter("Forms.CompareHuesControl.button1") ?? "Load"; + button2.Text = _localizationGetter("Forms.CompareHuesControl.button2") ?? "..."; + chkMultiSelect.Text = _localizationGetter("Forms.CompareHuesControl.chkMultiSelect") ?? "Multi-Select"; + applyHue1ToHue2ToolStripMenuItem.Text = _localizationGetter("Forms.CompareHuesControl.applyHue1ToHue2") ?? "Apply Hue to left"; } private const int _itemHeight = 20; diff --git a/UoFiddler.Plugin.Compare/UserControls/CompareItemControl.cs b/UoFiddler.Plugin.Compare/UserControls/CompareItemControl.cs index a74929f5..27d46842 100644 --- a/UoFiddler.Plugin.Compare/UserControls/CompareItemControl.cs +++ b/UoFiddler.Plugin.Compare/UserControls/CompareItemControl.cs @@ -45,18 +45,18 @@ private void ApplyLocalization() if (_localizationGetter == null) return; // 汉化菜单项 - extractAsToolStripMenuItem.Text = _localizationGetter("extractAs") ?? "Export Image.."; - tiffToolStripMenuItem.Text = _localizationGetter("asBmp") ?? "As Bmp"; - bmpToolStripMenuItem.Text = _localizationGetter("asTiff") ?? "As Tiff"; - jpgToolStripMenuItem.Text = _localizationGetter("asJpg") ?? "As Jpg"; - pngToolStripMenuItem.Text = _localizationGetter("asPng") ?? "As Png"; - copyItem2To1ToolStripMenuItem.Text = _localizationGetter("copyItem2To1") ?? "Copy Item to left"; + extractAsToolStripMenuItem.Text = _localizationGetter("Forms.CompareItemControl.extractAs") ?? "Export Image.."; + tiffToolStripMenuItem.Text = _localizationGetter("Forms.CompareItemControl.asBmp") ?? "As Bmp"; + bmpToolStripMenuItem.Text = _localizationGetter("Forms.CompareItemControl.asTiff") ?? "As Tiff"; + jpgToolStripMenuItem.Text = _localizationGetter("Forms.CompareItemControl.asJpg") ?? "As Jpg"; + pngToolStripMenuItem.Text = _localizationGetter("Forms.CompareItemControl.asPng") ?? "As Png"; + copyItem2To1ToolStripMenuItem.Text = _localizationGetter("Forms.CompareItemControl.copyItem2To1") ?? "Copy Item to left"; // 汉化按钮和复选框 - btnCopyAllDiff.Text = _localizationGetter("copyAllDiff") ?? "Copy All Diff"; - button1.Text = _localizationGetter("loadSecond") ?? "Load Second"; - checkBox1.Text = _localizationGetter("showOnlyDifferences") ?? "Show only Differences"; - chkMultiSelect.Text = _localizationGetter("multiSelect") ?? "Multi-Select"; + btnCopyAllDiff.Text = _localizationGetter("Forms.CompareItemControl.copyAllDiff") ?? "Copy All Diff"; + button1.Text = _localizationGetter("Forms.CompareItemControl.loadSecond") ?? "Load Second"; + checkBox1.Text = _localizationGetter("Forms.CompareItemControl.showOnlyDifferences") ?? "Show only Differences"; + chkMultiSelect.Text = _localizationGetter("Forms.CompareItemControl.multiSelect") ?? "Multi-Select"; } private readonly Dictionary _compare = new Dictionary(); diff --git a/UoFiddler.Plugin.Compare/UserControls/CompareLandControl.cs b/UoFiddler.Plugin.Compare/UserControls/CompareLandControl.cs index 2974366b..bea47768 100644 --- a/UoFiddler.Plugin.Compare/UserControls/CompareLandControl.cs +++ b/UoFiddler.Plugin.Compare/UserControls/CompareLandControl.cs @@ -44,16 +44,16 @@ private void ApplyLocalization() { if (_localizationGetter == null) return; - exportImageToolStripMenuItem.Text = _localizationGetter("exportImageToolStripMenuItem") ?? "Export Image.."; - asBmpToolStripMenuItem.Text = _localizationGetter("asBmpToolStripMenuItem") ?? "As Bmp"; - asTiffToolStripMenuItem.Text = _localizationGetter("asTiffToolStripMenuItem") ?? "As Tiff"; - asJpgToolStripMenuItem.Text = _localizationGetter("asJpgToolStripMenuItem") ?? "As Jpg"; - asPngToolStripMenuItem.Text = _localizationGetter("asPngToolStripMenuItem") ?? "As Png"; - copyLandTile2To1ToolStripMenuItem.Text = _localizationGetter("copyLandTile2To1ToolStripMenuItem") ?? "Copy Land to left"; - btnCopyAllDiff.Text = _localizationGetter("btnCopyAllDiff") ?? "Copy All Diff"; - button1.Text = _localizationGetter("button1") ?? "Load"; - checkBox1.Text = _localizationGetter("checkBox1") ?? "Show only Differences"; - chkMultiSelect.Text = _localizationGetter("chkMultiSelect") ?? "Multi-Select"; + exportImageToolStripMenuItem.Text = _localizationGetter("Forms.CompareLandControl.exportImageToolStripMenuItem") ?? "Export Image.."; + asBmpToolStripMenuItem.Text = _localizationGetter("Forms.CompareLandControl.asBmpToolStripMenuItem") ?? "As Bmp"; + asTiffToolStripMenuItem.Text = _localizationGetter("Forms.CompareLandControl.asTiffToolStripMenuItem") ?? "As Tiff"; + asJpgToolStripMenuItem.Text = _localizationGetter("Forms.CompareLandControl.asJpgToolStripMenuItem") ?? "As Jpg"; + asPngToolStripMenuItem.Text = _localizationGetter("Forms.CompareLandControl.asPngToolStripMenuItem") ?? "As Png"; + copyLandTile2To1ToolStripMenuItem.Text = _localizationGetter("Forms.CompareLandControl.copyLandTile2To1ToolStripMenuItem") ?? "Copy Land to left"; + btnCopyAllDiff.Text = _localizationGetter("Forms.CompareLandControl.btnCopyAllDiff") ?? "Copy All Diff"; + button1.Text = _localizationGetter("Forms.CompareLandControl.button1") ?? "Load"; + checkBox1.Text = _localizationGetter("Forms.CompareLandControl.checkBox1") ?? "Show only Differences"; + chkMultiSelect.Text = _localizationGetter("Forms.CompareLandControl.chkMultiSelect") ?? "Multi-Select"; } private readonly Dictionary _compare = new Dictionary(); diff --git a/UoFiddler.Plugin.Compare/UserControls/CompareMapControl.cs b/UoFiddler.Plugin.Compare/UserControls/CompareMapControl.cs index 39711d78..f10a71df 100644 --- a/UoFiddler.Plugin.Compare/UserControls/CompareMapControl.cs +++ b/UoFiddler.Plugin.Compare/UserControls/CompareMapControl.cs @@ -25,27 +25,50 @@ namespace UoFiddler.Plugin.Compare.UserControls { public partial class CompareMapControl : UserControl { + private Func _localizationGetter; + private string _coordsPrefix = "Coords: "; + private string _zoomPrefix = "Zoom: "; + public CompareMapControl() { InitializeComponent(); SetStyle(ControlStyles.AllPaintingInWmPaint | ControlStyles.OptimizedDoubleBuffer | ControlStyles.UserPaint, true); pictureBox.MouseWheel += OnMouseWheel; + + // 在 Load 事件中应用汉化 + this.Load += (s, e) => ApplyLocalization(); } public void SetLocalization(Func getLocalized) { - toolStripButton2.Text = getLocalized("button1") ?? "Load"; - toolStripButton1.Text = getLocalized("button2") ?? "..."; - showDifferencesToolStripMenuItem.Text = getLocalized("showDifferencesToolStripMenuItem") ?? "Show Differences"; - showMap1ToolStripMenuItem.Text = getLocalized("showMap1ToolStripMenuItem") ?? "Show Map1"; - showMap2ToolStripMenuItem.Text = getLocalized("showMap2ToolStripMenuItem") ?? "Show Map2"; - feluccaToolStripMenuItem.Text = getLocalized("feluccaToolStripMenuItem") ?? "Felucca"; - trammelToolStripMenuItem.Text = getLocalized("trammelToolStripMenuItem") ?? "Trammel"; - ilshenarToolStripMenuItem.Text = getLocalized("ilshenarToolStripMenuItem") ?? "Ilshenar"; - malasToolStripMenuItem.Text = getLocalized("malasToolStripMenuItem") ?? "Malas"; - tokunoToolStripMenuItem.Text = getLocalized("tokunoToolStripMenuItem") ?? "Tokuno"; - terMurToolStripMenuItem.Text = getLocalized("terMurToolStripMenuItem") ?? "TerMur"; - markDiffToolStripMenuItem.Text = getLocalized("markDiffToolStripMenuItem") ?? "Mark Diff"; + _localizationGetter = getLocalized; + ApplyLocalization(); + } + + private void ApplyLocalization() + { + if (_localizationGetter == null) return; + + // 保存前缀用于动态更新 + _coordsPrefix = _localizationGetter("Forms.CompareMapControl.coordsPrefix") ?? "Coords: "; + _zoomPrefix = _localizationGetter("Forms.CompareMapControl.zoomPrefix") ?? "Zoom: "; + + toolStripButton2.Text = _localizationGetter("Forms.CompareMapControl.button1") ?? "Load"; + toolStripButton1.Text = _localizationGetter("Forms.CompareMapControl.button2") ?? "..."; + + // 汉化上下文菜单项 + zoomToolStripMenuItem.Text = _localizationGetter("Forms.CompareMapControl.zoomPlus") ?? "Zoom+"; + zoomToolStripMenuItem1.Text = _localizationGetter("Forms.CompareMapControl.zoomMinus") ?? "Zoom-"; + showDifferencesToolStripMenuItem.Text = _localizationGetter("Forms.CompareMapControl.showDifferencesToolStripMenuItem") ?? "Show Differences"; + showMap1ToolStripMenuItem.Text = _localizationGetter("Forms.CompareMapControl.showMap1ToolStripMenuItem") ?? "Show Map1"; + showMap2ToolStripMenuItem.Text = _localizationGetter("Forms.CompareMapControl.showMap2ToolStripMenuItem") ?? "Show Map2"; + feluccaToolStripMenuItem.Text = _localizationGetter("Forms.CompareMapControl.feluccaToolStripMenuItem") ?? "Felucca"; + trammelToolStripMenuItem.Text = _localizationGetter("Forms.CompareMapControl.trammelToolStripMenuItem") ?? "Trammel"; + ilshenarToolStripMenuItem.Text = _localizationGetter("Forms.CompareMapControl.ilshenarToolStripMenuItem") ?? "Ilshenar"; + malasToolStripMenuItem.Text = _localizationGetter("Forms.CompareMapControl.malasToolStripMenuItem") ?? "Malas"; + tokunoToolStripMenuItem.Text = _localizationGetter("Forms.CompareMapControl.tokunoToolStripMenuItem") ?? "Tokuno"; + terMurToolStripMenuItem.Text = _localizationGetter("Forms.CompareMapControl.terMurToolStripMenuItem") ?? "TerMur"; + markDiffToolStripMenuItem.Text = _localizationGetter("Forms.CompareMapControl.markDiffToolStripMenuItem") ?? "Mark Diff"; } private bool _loaded; @@ -87,7 +110,7 @@ private void OnLoad(object sender, EventArgs e) showMap2ToolStripMenuItem.Checked = false; SetScrollBarValues(); ChangeMapNames(); - ZoomLabel.Text = $"Zoom: {_zoom}"; + ZoomLabel.Text = $"{_zoomPrefix}{_zoom}"; Options.LoadedUltimaClass["Map"] = true; Options.LoadedUltimaClass["RadarColor"] = true; @@ -177,7 +200,7 @@ private void OnMouseMove(object sender, MouseEventArgs e) int xDelta = Math.Min(_originalMap.Width, (int)(e.X / _zoom) + Round(hScrollBar.Value)); int yDelta = Math.Min(_originalMap.Height, (int)(e.Y / _zoom) + Round(vScrollBar.Value)); - CoordsLabel.Text = $"Coords: {xDelta},{yDelta}"; + CoordsLabel.Text = $"{_coordsPrefix}{xDelta},{yDelta}"; string diff = string.Empty; @@ -605,7 +628,7 @@ private void DoZoom() { ChangeScrollBar(); - ZoomLabel.Text = $"Zoom: {_zoom}"; + ZoomLabel.Text = $"{_zoomPrefix}{_zoom}"; int x = Math.Max(0, _currentPoint.X - ((int)(pictureBox.ClientSize.Width / _zoom) / 2)); int y = Math.Max(0, _currentPoint.Y - ((int)(pictureBox.ClientSize.Height / _zoom) / 2)); diff --git a/UoFiddler.Plugin.Compare/UserControls/CompareRadarColControl.cs b/UoFiddler.Plugin.Compare/UserControls/CompareRadarColControl.cs index 653264de..cc0b2e07 100644 --- a/UoFiddler.Plugin.Compare/UserControls/CompareRadarColControl.cs +++ b/UoFiddler.Plugin.Compare/UserControls/CompareRadarColControl.cs @@ -13,14 +13,53 @@ namespace UoFiddler.Plugin.Compare.UserControls { public partial class CompareRadarColControl : UserControl { + private Func _localizationGetter; + public CompareRadarColControl() { InitializeComponent(); + + // 在 Load 事件中应用汉化 + this.Load += (s, e) => ApplyLocalization(); } public void SetLocalization(Func getLocalized) { - copyEntry2To1ToolStripMenuItem.Text = getLocalized("copyEntry2To1") ?? "Copy Entry to left"; + _localizationGetter = getLocalized; + ApplyLocalization(); + } + + private void ApplyLocalization() + { + if (_localizationGetter == null) return; + + // 汉化菜单项 + copyEntry2To1ToolStripMenuItem.Text = _localizationGetter("Forms.CompareRadarColControl.copyEntry2To1") ?? "Copy Entry to left"; + + // 汉化按钮 + buttonLoadSecond.Text = _localizationGetter("Forms.CompareRadarColControl.buttonLoadSecond") ?? "Load"; + buttonBrowse.Text = _localizationGetter("Forms.CompareRadarColControl.buttonBrowse") ?? "..."; + buttonCopySelected.Text = _localizationGetter("Forms.CompareRadarColControl.buttonCopySelected") ?? "Copy Selected"; + buttonCopyAllDiff.Text = _localizationGetter("Forms.CompareRadarColControl.buttonCopyAllDiff") ?? "Copy All Diff"; + + // 汉化复选框 + checkBoxShowDiff.Text = _localizationGetter("Forms.CompareRadarColControl.checkBoxShowDiff") ?? "Show only Differences"; + chkMultiSelect.Text = _localizationGetter("Forms.CompareRadarColControl.chkMultiSelect") ?? "Multi-Select"; + + // 汉化GroupBox + groupBoxOrg.Text = _localizationGetter("Forms.CompareRadarColControl.groupBoxOrg") ?? "Left (Original)"; + groupBoxSec.Text = _localizationGetter("Forms.CompareRadarColControl.groupBoxSec") ?? "Right (Second)"; + groupBoxLegend.Text = _localizationGetter("Forms.CompareRadarColControl.groupBoxLegend") ?? "Legend"; + + // 汉化标签 - Left (Original) + labelOrgColorCaption.Text = _localizationGetter("Forms.CompareRadarColControl.labelOrgColorCaption") ?? "Color:"; + + // 汉化标签 - Right (Second) + labelSecColorCaption.Text = _localizationGetter("Forms.CompareRadarColControl.labelSecColorCaption") ?? "Color:"; + + // 汉化图例标签 + legendLabelDifferent.Text = _localizationGetter("Forms.CompareRadarColControl.legendLabelDifferent") ?? "Different values"; + legendLabelIdentical.Text = _localizationGetter("Forms.CompareRadarColControl.legendLabelIdentical") ?? "Identical"; } private readonly Dictionary _compare = new Dictionary(); @@ -53,7 +92,7 @@ private void OnLoad(object sender, EventArgs e) int count = ActiveSecView.SelectedIndices.Count; copyEntry2To1ToolStripMenuItem.Text = ActiveSecView.ShowCheckBoxes && count > 1 ? $"Copy {count} Entries to left" - : "Copy Entry to left"; + : (_localizationGetter?.Invoke("Forms.CompareRadarColControl.copyEntry2To1") ?? "Copy Entry to left"); }; ControlEvents.FilePathChangeEvent += OnFilePathChangeEvent; diff --git a/UoFiddler.Plugin.Compare/UserControls/CompareTextureControl.cs b/UoFiddler.Plugin.Compare/UserControls/CompareTextureControl.cs index 585a5d95..521c193a 100644 --- a/UoFiddler.Plugin.Compare/UserControls/CompareTextureControl.cs +++ b/UoFiddler.Plugin.Compare/UserControls/CompareTextureControl.cs @@ -27,19 +27,36 @@ namespace UoFiddler.Plugin.Compare.UserControls { public partial class CompareTextureControl : UserControl { + private Func _localizationGetter; + public CompareTextureControl() { InitializeComponent(); + + // 在 Load 事件中应用汉化 + this.Load += (s, e) => ApplyLocalization(); } public void SetLocalization(Func getLocalized) { - checkBox1.Text = getLocalized("checkBox1") ?? "Show only Differences"; - chkMultiSelect.Text = getLocalized("chkMultiSelect") ?? "Multi-Select"; - button1.Text = getLocalized("button1") ?? "Load"; - button2.Text = getLocalized("button2") ?? "..."; - exportImageToolStripMenuItem.Text = getLocalized("exportImageToolStripMenuItem") ?? "Export Image.."; - copyLandTile2To1ToolStripMenuItem.Text = getLocalized("copyLandTile2To1ToolStripMenuItem") ?? "Copy Texture to left"; + _localizationGetter = getLocalized; + ApplyLocalization(); + } + + private void ApplyLocalization() + { + if (_localizationGetter == null) return; + + checkBox1.Text = _localizationGetter("Forms.CompareTextureControl.checkBox1") ?? "Show only Differences"; + chkMultiSelect.Text = _localizationGetter("Forms.CompareTextureControl.chkMultiSelect") ?? "Multi-Select"; + button1.Text = _localizationGetter("Forms.CompareTextureControl.button1") ?? "Load"; + button2.Text = _localizationGetter("Forms.CompareTextureControl.button2") ?? "..."; + exportImageToolStripMenuItem.Text = _localizationGetter("Forms.CompareTextureControl.exportImageToolStripMenuItem") ?? "Export Image.."; + copyLandTile2To1ToolStripMenuItem.Text = _localizationGetter("Forms.CompareTextureControl.copyLandTile2To1ToolStripMenuItem") ?? "Copy Texture to left"; + + // 汉化按钮 + FromLeftToRight.Text = _localizationGetter("Forms.CompareTextureControl.fromLeftToRight") ?? "Copy All Diff"; + CopyAddOnly.Text = _localizationGetter("Forms.CompareTextureControl.copyAddOnly") ?? "Copy Added Only"; } private readonly Dictionary _compare = new Dictionary(); @@ -69,7 +86,7 @@ private void OnLoad(object sender, EventArgs e) int count = tileViewSec.SelectedIndices.Count; copyLandTile2To1ToolStripMenuItem.Text = tileViewSec.ShowCheckBoxes && count > 1 ? $"Copy {count} Textures to left" - : "Copy Texture to left"; + : (_localizationGetter?.Invoke("Forms.CompareTextureControl.copyLandTile2To1ToolStripMenuItem") ?? "Copy Texture to left"); }; ControlEvents.FilePathChangeEvent += OnFilePathChangeEvent; From ba1e5c57aa8e37d052d9a769fde9485929b3862b Mon Sep 17 00:00:00 2001 From: nbyaya Date: Sun, 4 Oct 2026 15:32:15 +0800 Subject: [PATCH 23/30] =?UTF-8?q?=E6=B1=89=E5=8C=96=20GumpControl=20?= =?UTF-8?q?=E8=8F=9C=E5=8D=95=E9=A1=B9=E5=92=8C=E5=AE=8C=E5=96=84=20Ctrl?= =?UTF-8?q?=20=E5=A4=9A=E9=80=89=E5=AF=BC=E5=87=BA=E5=8A=9F=E8=83=BD?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit - 汉化 Jump to Male/Female 菜单项(跳转到男/女角色) - 添加 jumpToMale 和 jumpToFemale 翻译支持 - JumpToMaleFemaleInvalidate 方法使用汉化文本 - 修复 MainForm 构造函数的调试输出 - Ctrl 多选和导出正常工作 --- .../UserControls/GumpControl.Designer.cs | 2 +- .../UserControls/GumpControl.cs | 231 ++++++++++++++---- UoFiddler/Forms/MainForm.cs | 6 +- .../Localization/Dictionaries/zh-CN.json | 68 ++++++ UoFiddler/UoFiddler.csproj | 1 + 5 files changed, 263 insertions(+), 45 deletions(-) diff --git a/UoFiddler.Controls/UserControls/GumpControl.Designer.cs b/UoFiddler.Controls/UserControls/GumpControl.Designer.cs index 37afc50d..0eb78b8c 100644 --- a/UoFiddler.Controls/UserControls/GumpControl.Designer.cs +++ b/UoFiddler.Controls/UserControls/GumpControl.Designer.cs @@ -137,7 +137,7 @@ private void InitializeComponent() listView.HideSelection = false; listView.Location = new System.Drawing.Point(0, 50); listView.Margin = new System.Windows.Forms.Padding(4, 3, 4, 3); - listView.MultiSelect = false; + listView.MultiSelect = true; listView.Name = "listView"; listView.OwnerDraw = true; listView.Size = new System.Drawing.Size(289, 380); diff --git a/UoFiddler.Controls/UserControls/GumpControl.cs b/UoFiddler.Controls/UserControls/GumpControl.cs index 64b76262..cc2ed3b6 100644 --- a/UoFiddler.Controls/UserControls/GumpControl.cs +++ b/UoFiddler.Controls/UserControls/GumpControl.cs @@ -28,6 +28,10 @@ namespace UoFiddler.Controls.UserControls { public partial class GumpControl : UserControl { + private Func _localizationGetter; + private string _idLabelPrefix = "ID:"; + private string _sizeLabelPrefix = "Size:"; + public GumpControl() { InitializeComponent(); @@ -44,6 +48,63 @@ public GumpControl() _refMarker = this; pictureBox.BackColor = Options.PreviewBackgroundColor; + + // 在加载时应用本地化 + this.Load += (s, e) => ApplyLocalization(); + } + + public void SetLocalization(Func getLocalized) + { + _localizationGetter = getLocalized; + ApplyLocalization(); + } + + private void ApplyLocalization() + { + if (_localizationGetter == null) return; + + // 上下文菜单项 + showFreeSlotsToolStripMenuItem.Text = _localizationGetter("Forms.GumpControl.showFreeSlotsToolStripMenuItem") ?? "Show Free Slots"; + findNextFreeSlotToolStripMenuItem.Text = _localizationGetter("Forms.GumpControl.findNextFreeSlotToolStripMenuItem") ?? "Find Next Free Slot"; + changeBackgroundColorToolStripMenuItem.Text = _localizationGetter("Forms.GumpControl.changeBackgroundColorToolStripMenuItem") ?? "Change background color"; + extractImageToolStripMenuItem.Text = _localizationGetter("Forms.GumpControl.extractImageToolStripMenuItem") ?? "Export Image.."; + asBmpToolStripMenuItem.Text = _localizationGetter("Forms.GumpControl.asBmpToolStripMenuItem") ?? "As Bmp"; + asTiffToolStripMenuItem.Text = _localizationGetter("Forms.GumpControl.asTiffToolStripMenuItem") ?? "As Tiff"; + asJpgToolStripMenuItem1.Text = _localizationGetter("Forms.GumpControl.asJpgToolStripMenuItem1") ?? "As Jpg"; + asPngToolStripMenuItem1.Text = _localizationGetter("Forms.GumpControl.asPngToolStripMenuItem1") ?? "As Png"; + jumpToMaleFemale.Text = _localizationGetter("Forms.GumpControl.jumpToMaleFemale") ?? "Jump to Male/Female"; + + copyImageToolStripMenuItem.Text = _localizationGetter("Forms.GumpControl.copyImageToolStripMenuItem") ?? "Copy Image"; + pasteImageToolStripMenuItem.Text = _localizationGetter("Forms.GumpControl.pasteImageToolStripMenuItem") ?? "Paste Image"; + replaceGumpToolStripMenuItem.Text = _localizationGetter("Forms.GumpControl.replaceGumpToolStripMenuItem") ?? "Replace"; + insertToolStripMenuItem.Text = _localizationGetter("Forms.GumpControl.insertToolStripMenuItem") ?? "Insert At.."; + toolStripMenuItem1.Text = _localizationGetter("Forms.GumpControl.toolStripMenuItem1") ?? "Insert Starting From"; + removeToolStripMenuItem.Text = _localizationGetter("Forms.GumpControl.removeToolStripMenuItem") ?? "Remove"; + saveToolStripMenuItem.Text = _localizationGetter("Forms.GumpControl.saveToolStripMenuItem") ?? "Save"; + + // 过滤工具栏标签 + nameTagToolStripLabel.Text = _localizationGetter("Forms.GumpControl.nameTagToolStripLabel") ?? "Name:"; + tagFilterDropDownButton.Text = _localizationGetter("Forms.GumpControl.tagFilterDropDownButton") ?? "Tags"; + + // 顶部工具栏 + IndexToolStripLabel.Text = _localizationGetter("Forms.GumpControl.IndexToolStripLabel") ?? "Index:"; + toolStripDropDownButton1.Text = _localizationGetter("Forms.GumpControl.toolStripDropDownButton1") ?? "Misc"; + generateFromTileDataToolStripMenuItem.Text = _localizationGetter("Forms.GumpControl.generateFromTileDataToolStripMenuItem") ?? "Generate Gumps.xml entries from TileData Equipment..."; + exportAllToolStripMenuItem.Text = _localizationGetter("Forms.GumpControl.exportAllToolStripMenuItem") ?? "Export All.."; + asBmpToolStripMenuItem1.Text = _localizationGetter("Forms.GumpControl.asBmpToolStripMenuItem") ?? "As Bmp"; + asTiffToolStripMenuItem1.Text = _localizationGetter("Forms.GumpControl.asTiffToolStripMenuItem") ?? "As Tiff"; + asJpgToolStripMenuItem.Text = _localizationGetter("Forms.GumpControl.asJpgToolStripMenuItem") ?? "As Jpg"; + asPngToolStripMenuItem.Text = _localizationGetter("Forms.GumpControl.asPngToolStripMenuItem") ?? "As Png"; + saveToolStripButton.Text = _localizationGetter("Forms.GumpControl.saveToolStripButton") ?? "Save"; + + // 底部工具栏标签 - 保存前缀用于动态更新 + IDLabel.Text = _localizationGetter("Forms.GumpControl.IDLabel") ?? "ID:"; + _idLabelPrefix = IDLabel.Text; + + SizeLabel.Text = _localizationGetter("Forms.GumpControl.SizeLabel") ?? "Size:"; + _sizeLabelPrefix = SizeLabel.Text; + + Preload.Text = _localizationGetter("Forms.GumpControl.Preload") ?? "Preload"; } private sealed record GumpEntry(string Name, string[] Tags); @@ -76,30 +137,30 @@ private sealed record GumpEntry(string Name, string[] Tags); private static readonly string[] _layerTags = { "", // 0x00 - "one-hand", // 0x01 - "two-hand", // 0x02 - "boots", // 0x03 - "pants", // 0x04 - "shirt", // 0x05 - "helmet", // 0x06 - "gloves", // 0x07 - "ring", // 0x08 - "talisman", // 0x09 - "gorget", // 0x0A - "hair", // 0x0B - "waist", // 0x0C - "chest-armor", // 0x0D - "bracelet", // 0x0E - "", // 0x0F - "facial-hair", // 0x10 - "tunic", // 0x11 - "earring", // 0x12 - "sleeves", // 0x13 - "cloak", // 0x14 - "backpack", // 0x15 - "robe", // 0x16 - "skirt", // 0x17 - "leg-armor", // 0x18 + "单手武器", // 0x01 + "双手武器", // 0x02 + "靴子", // 0x03 + "裤子", // 0x04 + "衬衣", // 0x05 + "头盔", // 0x06 + "手套", // 0x07 + "戒指", // 0x08 + "护身符", // 0x09 + "喉甲", // 0x0A + "头发", // 0x0B + "腰部", // 0x0C + "胸甲", // 0x0D + "手镯", // 0x0E + "", // 0x0F + "胡须", // 0x10 + "束腰外衣", // 0x11 + "耳环", // 0x12 + "袖子", // 0x13 + "斗篷", // 0x14 + "背包", // 0x15 + "长袍", // 0x16 + "裙子", // 0x17 + "腿甲", // 0x18 }; /// @@ -351,14 +412,16 @@ private void RebuildTagDropdown() return; } - var clearItem = new ToolStripMenuItem("Clear All"); + var clearItem = new ToolStripMenuItem(_localizationGetter?.Invoke("Forms.GumpControl.ClearAllTags") ?? "Clear All"); clearItem.Click += OnClearTagFilters; tagFilterDropDownButton.DropDownItems.Add(clearItem); tagFilterDropDownButton.DropDownItems.Add(new ToolStripSeparator()); foreach (string tag in allTags) { - var item = new ToolStripMenuItem(tag) { CheckOnClick = true }; + // 获取本地化的标签显示文本 + string displayText = GetLocalizedTagText(tag) ?? tag; + var item = new ToolStripMenuItem(displayText) { CheckOnClick = true, Tag = tag }; item.CheckedChanged += OnTagFilterChanged; tagFilterDropDownButton.DropDownItems.Add(item); } @@ -368,6 +431,36 @@ private void RebuildTagDropdown() tagFilterDropDownButton.DropDown.Closing += OnTagDropDownClosing; } + /// + /// 获取标签的本地化文本 + /// + private string GetLocalizedTagText(string tag) + { + if (_localizationGetter == null) return null; + + // 尝试从本地化字典中获取标签翻译 + string translatedTag = _localizationGetter($"Forms.GumpControl.Tags.{tag}"); + return translatedTag; + } + + /// + /// 获取选中的所有 Gump 索引 + /// + private List GetSelectedGumpIndexes() + { + // 在虚拟模式中,使用 SelectedIndices 而不是 SelectedItems + return listView.SelectedIndices.Cast().ToList(); + } + + /// + /// 获取主要选中的 Gump 索引(第一个) + /// + private int? GetPrimarySelectedGumpIndex() + { + // 在虚拟模式中,使用 SelectedIndices 而不是 SelectedItems + return listView.SelectedIndices.Count > 0 ? listView.SelectedIndices[0] : null; + } + private void OnTagDropDownClosing(object sender, ToolStripDropDownClosingEventArgs e) { if (e.CloseReason == ToolStripDropDownCloseReason.ItemClicked) @@ -397,7 +490,9 @@ private void OnTagFilterChanged(object sender, EventArgs e) { if (item is ToolStripMenuItem { Checked: true } mi) { - _activeTagFilters.Add(mi.Text); + // 使用 Tag 属性存储原始标签值,而不是显示文本 + string tagValue = mi.Tag as string ?? mi.Text; + _activeTagFilters.Add(tagValue); } } @@ -475,7 +570,8 @@ private void ListView_DrawItem(object sender, DrawListViewItemEventArgs e) Brush fontBrush = Brushes.Gray; - bool isSelected = e.ItemIndex == _selectedPosition; + // 在虚拟模式中,需要检查该项是否在 SelectedIndices 中 + bool isSelected = listView.SelectedIndices.Contains(e.ItemIndex); int i = _ids[e.ItemIndex]; bool hasEntry = _gumpEntries.TryGetValue(i, out GumpEntry entry); @@ -562,8 +658,18 @@ private void ListView_SelectedIndexChanged(object sender, EventArgs e) if (bmp != null) { pictureBox.BackgroundImage = bmp; - IDLabel.Text = $"ID: 0x{i:X} ({i})"; - SizeLabel.Text = $"Size: {bmp.Width},{bmp.Height}"; + + // 支持显示多选信息 - 在虚拟模式中使用 SelectedIndices.Count + if (listView.SelectedIndices.Count > 1) + { + IDLabel.Text = $"{_idLabelPrefix} 0x{i:X} ({i}) 等 {listView.SelectedIndices.Count} 项"; + } + else + { + IDLabel.Text = $"{_idLabelPrefix} 0x{i:X} ({i})"; + } + + SizeLabel.Text = $"{_sizeLabelPrefix} {bmp.Width},{bmp.Height}"; } else { @@ -591,25 +697,30 @@ private void JumpToMaleFemaleInvalidate() { if (gumpId >= 60000) { - jumpToMaleFemale.Text = "Jump to Male"; + jumpToMaleFemale.Text = _localizationGetter?.Invoke("Forms.GumpControl.jumpToMale") ?? "Jump to Male"; jumpToMaleFemale.Enabled = HasGumpId(gumpId - 10000); } else { - jumpToMaleFemale.Text = "Jump to Female"; + jumpToMaleFemale.Text = _localizationGetter?.Invoke("Forms.GumpControl.jumpToFemale") ?? "Jump to Female"; jumpToMaleFemale.Enabled = HasGumpId(gumpId + 10000); } } else { jumpToMaleFemale.Enabled = false; - jumpToMaleFemale.Text = "Jump to Male/Female"; + jumpToMaleFemale.Text = _localizationGetter?.Invoke("Forms.GumpControl.jumpToMaleFemale") ?? "Jump to Male/Female"; } } private void ContextMenuStrip_Opening(object sender, System.ComponentModel.CancelEventArgs e) { int id = SelectedGumpId; + int selectedCount = listView.SelectedIndices.Count; + + // 在虚拟模式下,导出菜单项应该只在有选中项时启用 + extractImageToolStripMenuItem.Enabled = selectedCount > 0; + copyImageToolStripMenuItem.Enabled = id >= 0 && Gumps.IsValidIndex(id); pasteImageToolStripMenuItem.Enabled = id >= 0 && ImageClipboard.ContainsImage(); } @@ -866,26 +977,64 @@ private void OnKeydown_InsertText(object sender, KeyEventArgs e) private void Extract_Image_ClickBmp(object sender, EventArgs e) { - int i = SelectedGumpId; - ExportGumpImage(i, ImageFormat.Bmp); + ExportSelectedGumpImages(ImageFormat.Bmp); } private void Extract_Image_ClickTiff(object sender, EventArgs e) { - int i = SelectedGumpId; - ExportGumpImage(i, ImageFormat.Tiff); + ExportSelectedGumpImages(ImageFormat.Tiff); } private void Extract_Image_ClickJpg(object sender, EventArgs e) { - int i = SelectedGumpId; - ExportGumpImage(i, ImageFormat.Jpeg); + ExportSelectedGumpImages(ImageFormat.Jpeg); } private void Extract_Image_ClickPng(object sender, EventArgs e) { - int i = SelectedGumpId; - ExportGumpImage(i, ImageFormat.Png); + ExportSelectedGumpImages(ImageFormat.Png); + } + + private void ExportSelectedGumpImages(ImageFormat imageFormat) + { + List selectedIndexes = GetSelectedGumpIndexes(); + if (selectedIndexes.Count == 0) + { + return; + } + + if (selectedIndexes.Count == 1) + { + ExportGumpImage(selectedIndexes[0], imageFormat); + return; + } + + string fileExtension = Utils.GetFileExtensionFor(imageFormat); + using (FolderBrowserDialog dialog = new FolderBrowserDialog()) + { + dialog.Description = "选择导出目录"; + dialog.ShowNewFolderButton = true; + if (dialog.ShowDialog() != DialogResult.OK) + { + return; + } + + Cursor.Current = Cursors.WaitCursor; + foreach (int index in selectedIndexes) + { + string fileName = Path.Combine(dialog.SelectedPath, $"Gump 0x{index:X4}.{fileExtension}"); + if (Gumps.IsValidIndex(index)) + { + using (Bitmap bit = new Bitmap(Gumps.GetGump(index))) + { + bit.Save(fileName, imageFormat); + } + } + } + Cursor.Current = Cursors.Default; + + MessageBox.Show($"已成功导出所选的 {selectedIndexes.Count} 个 Gump。", "导出完成", MessageBoxButtons.OK, MessageBoxIcon.Information); + } } private static void ExportGumpImage(int index, ImageFormat imageFormat) diff --git a/UoFiddler/Forms/MainForm.cs b/UoFiddler/Forms/MainForm.cs index 75ce6a9c..53cb62f9 100644 --- a/UoFiddler/Forms/MainForm.cs +++ b/UoFiddler/Forms/MainForm.cs @@ -53,11 +53,11 @@ public MainForm(ILogger logger) _log = logger; InitializeComponent(); - // 调试: 打印Form名称 - Console.WriteLine($"[DEBUG] MainForm.Name = '{this.Name}'"); - // 应用本地化 LocalizationService.LocalizeForm(this); + + // 为主标签页控件调用本地化(GumpControl等需要手动调用SetLocalization) + gumpsControl.SetLocalization(key => LocalizationService.GetString(key)); darkModeMenuItem.Checked = AppSettings.DarkMode; diff --git a/UoFiddler/Localization/Dictionaries/zh-CN.json b/UoFiddler/Localization/Dictionaries/zh-CN.json index 5a30461f..8b553d2b 100644 --- a/UoFiddler/Localization/Dictionaries/zh-CN.json +++ b/UoFiddler/Localization/Dictionaries/zh-CN.json @@ -387,6 +387,74 @@ "chkMultiSelect": "多选", "applyHue1ToHue2": "应用色调到左侧" }, + "GumpControl": { + "showFreeSlotsToolStripMenuItem": "显示空闲槽位", + "findNextFreeSlotToolStripMenuItem": "查找下一个空闲槽位", + "changeBackgroundColorToolStripMenuItem": "改变背景颜色", + "extractImageToolStripMenuItem": "导出图像..", + "asBmpToolStripMenuItem": "作为 Bmp", + "asTiffToolStripMenuItem": "作为 Tiff", + "asJpgToolStripMenuItem1": "作为 Jpg", + "asPngToolStripMenuItem1": "作为 Png", + "jumpToMaleFemale": "跳转到男/女角色", + "jumpToMale": "跳转到男角色", + "jumpToFemale": "跳转到女角色", + "copyImageToolStripMenuItem": "复制图像", + "pasteImageToolStripMenuItem": "粘贴图像", + "replaceGumpToolStripMenuItem": "替换", + "insertToolStripMenuItem": "插入到..", + "toolStripMenuItem1": "从以下位置开始插入", + "removeToolStripMenuItem": "删除", + "saveToolStripMenuItem": "保存", + "nameTagToolStripLabel": "名称:", + "tagFilterDropDownButton": "标签", + "IndexToolStripLabel": "索引:", + "toolStripDropDownButton1": "杂项", + "generateFromTileDataToolStripMenuItem": "从 TileData 装备生成 Gumps.xml 条目...", + "exportAllToolStripMenuItem": "全部导出..", + "IDLabel": "ID:", + "SizeLabel": "大小:", + "Preload": "预加载", + "saveToolStripButton": "保存", + "ClearAllTags": "全部清除", + "ExportSelected": "导出所选...", + "ExportSelectedAsBmp": "保存为 BMP", + "ExportSelectedAsTiff": "保存为 TIFF", + "ExportSelectedAsJpg": "保存为 JPG", + "ExportSelectedAsPng": "保存为 PNG", + "Tags": { + "one-hand": "单手武器", + "two-hand": "双手武器", + "boots": "靴子", + "pants": "裤子", + "shirt": "衬衣", + "helmet": "头盔", + "gloves": "手套", + "ring": "戒指", + "talisman": "护身符", + "gorget": "喉甲", + "hair": "头发", + "waist": "腰部", + "chest-armor": "胸甲", + "bracelet": "手镯", + "facial-hair": "胡须", + "tunic": "束腰外衣", + "earring": "耳环", + "sleeves": "袖子", + "cloak": "斗篷", + "backpack": "背包", + "robe": "长袍", + "skirt": "裙子", + "leg-armor": "腿甲", + "container": "容器", + "paperdoll": "纸娃娃", + "equipment": "装备", + "male": "男性", + "female": "女性", + "player": "玩家", + "character": "角色" + } + }, "CompareGumpControl": { "checkBox1": "仅显示差异", "chkMultiSelect": "多选", diff --git a/UoFiddler/UoFiddler.csproj b/UoFiddler/UoFiddler.csproj index ca0ffedf..2ab3a5f4 100644 --- a/UoFiddler/UoFiddler.csproj +++ b/UoFiddler/UoFiddler.csproj @@ -21,6 +21,7 @@ portable bin\$(Configuration)\ true + Exe none From a071e75027d2a54991f8db9b72a882387605cf54 Mon Sep 17 00:00:00 2001 From: nbyaya Date: Sun, 4 Oct 2026 15:34:47 +0800 Subject: [PATCH 24/30] =?UTF-8?q?=E5=AE=9E=E6=96=BD=20Shift+Click=20?= =?UTF-8?q?=E8=8C=83=E5=9B=B4=E9=80=89=E6=8B=A9=E5=92=8C=E5=AF=BC=E5=87=BA?= =?UTF-8?q?=E5=8A=9F=E8=83=BD?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit - 添加 ListView_MouseClick 事件处理 Shift+Click - Shift+Click 选择范围内所有 Gump(包括端点) - 范围选择后支持批量导出 - 关键:检查 Ctrl 时立即返回,确保不影响 Ctrl 多选 - Ctrl 多选导出功能保持正常 --- .../UserControls/GumpControl.cs | 47 +++++++++++++++++++ 1 file changed, 47 insertions(+) diff --git a/UoFiddler.Controls/UserControls/GumpControl.cs b/UoFiddler.Controls/UserControls/GumpControl.cs index cc2ed3b6..194d7263 100644 --- a/UoFiddler.Controls/UserControls/GumpControl.cs +++ b/UoFiddler.Controls/UserControls/GumpControl.cs @@ -180,6 +180,9 @@ private void ConfigureListView() splitContainer1.SplitterMoved += (_, _) => ClampListWidth(); splitContainer1.SizeChanged += (_, _) => ClampListWidth(); ClampListWidth(); + + // Shift+Click 范围选择(不干扰系统的 Ctrl 多选) + listView.MouseClick += ListView_MouseClick; } /// @@ -685,6 +688,50 @@ private void ListView_SelectedIndexChanged(object sender, EventArgs e) JumpToMaleFemaleInvalidate(); } + private void ListView_MouseClick(object sender, MouseEventArgs e) + { + // 只处理 Shift+Click 范围选择 + // 关键:如果按着 Ctrl,立即返回,让系统自动处理 Ctrl 多选 + if ((Control.ModifierKeys & Keys.Control) == Keys.Control) + { + return; // Ctrl+Click 由系统自动处理,我们不干扰 + } + + if ((Control.ModifierKeys & Keys.Shift) != Keys.Shift) + { + return; // 不是 Shift+Click,不处理 + } + + ListViewHitTestInfo hitTest = listView.HitTest(e.Location); + if (hitTest.Item == null) + { + return; + } + + int clickedIndex = hitTest.Item.Index; + + // Shift+Click 范围选择:只有当已有选择时才执行 + if (listView.SelectedIndices.Count > 0) + { + int firstSelected = listView.SelectedIndices[0]; + int startIndex = Math.Min(firstSelected, clickedIndex); + int endIndex = Math.Max(firstSelected, clickedIndex); + + // 清除现有选择并选择范围 + listView.SelectedIndices.Clear(); + for (int i = startIndex; i <= endIndex; i++) + { + if (i >= 0 && i < _ids.Count) + { + listView.SelectedIndices.Add(i); + } + } + + // 手动触发以更新 UI + ListView_SelectedIndexChanged(listView, EventArgs.Empty); + } + } + private void JumpToMaleFemaleInvalidate() { int gumpId = SelectedGumpId; From ef2b4de097405bcc2af58d6960262da722ed803b Mon Sep 17 00:00:00 2001 From: nbyaya Date: Sun, 4 Oct 2026 15:38:55 +0800 Subject: [PATCH 25/30] =?UTF-8?q?=E6=B1=89=E5=8C=96=20GumpControl=20?= =?UTF-8?q?=E6=8F=90=E7=A4=BA=E4=BF=A1=E6=81=AF=E5=92=8C=E5=AF=B9=E8=AF=9D?= =?UTF-8?q?=E6=A1=86=E6=96=87=E6=9C=AC?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit - 复制图像、粘贴图像、删除、保存等操作的对话框汉化 - 尺寸验证错误信息汉化 - 使用 string.Format 支持动态参数(如删除确认中的 Gump ID) - 保留英文回退值,确保没有汉化项时仍可使用 --- .../UserControls/GumpControl.cs | 26 ++++++++++++------- .../Localization/Dictionaries/zh-CN.json | 12 +++++++++ 2 files changed, 28 insertions(+), 10 deletions(-) diff --git a/UoFiddler.Controls/UserControls/GumpControl.cs b/UoFiddler.Controls/UserControls/GumpControl.cs index 194d7263..cfb15615 100644 --- a/UoFiddler.Controls/UserControls/GumpControl.cs +++ b/UoFiddler.Controls/UserControls/GumpControl.cs @@ -782,7 +782,8 @@ private void OnClickCopyImage(object sender, EventArgs e) if (!ImageClipboard.TryCopy(Gumps.GetGump(id), out string error)) { - MessageBox.Show(error, "Copy Image", MessageBoxButtons.OK, MessageBoxIcon.Warning); + string title = _localizationGetter?.Invoke("Forms.GumpControl.Messages.CopyImage") ?? "Copy Image"; + MessageBox.Show(error, title, MessageBoxButtons.OK, MessageBoxIcon.Warning); } } @@ -797,7 +798,8 @@ private void OnClickPasteImage(object sender, EventArgs e) using Bitmap pasted = ImageClipboard.TryPaste(out string error); if (pasted == null) { - MessageBox.Show(error, "Paste Image", MessageBoxButtons.OK, MessageBoxIcon.Warning); + string title = _localizationGetter?.Invoke("Forms.GumpControl.Messages.PasteImage") ?? "Paste Image"; + MessageBox.Show(error, title, MessageBoxButtons.OK, MessageBoxIcon.Warning); return; } @@ -805,12 +807,11 @@ private void OnClickPasteImage(object sender, EventArgs e) // decoder refuses anything past 0xFFFF on either axis. if (pasted.Width == 0 || pasted.Height == 0 || pasted.Width > 0xFFFF || pasted.Height > 0xFFFF) { - MessageBox.Show( - $"Invalid gump dimensions!\n\n" + - $"Clipboard image: {pasted.Width}x{pasted.Height}\n" + - $"Gumps may be up to 65535x65535 pixels.\n\n" + - "No changes made.", - "Invalid Size", MessageBoxButtons.OK, MessageBoxIcon.Warning); + string template = _localizationGetter?.Invoke("Forms.GumpControl.Messages.InvalidGumpDimensions") + ?? "Invalid gump dimensions!\n\nClipboard image: {0}x{1}\nGumps may be up to 65535x65535 pixels.\n\nNo changes made."; + string message = string.Format(template, pasted.Width, pasted.Height); + string title = _localizationGetter?.Invoke("Forms.GumpControl.Messages.InvalidSize") ?? "Invalid Size"; + MessageBox.Show(message, title, MessageBoxButtons.OK, MessageBoxIcon.Warning); return; } @@ -884,7 +885,9 @@ private void OnClickReplace(object sender, EventArgs e) private void OnClickSave(object sender, EventArgs e) { - DialogResult result = MessageBox.Show("Are you sure? Will take a while", "Save", MessageBoxButtons.YesNo, + string message = _localizationGetter?.Invoke("Forms.GumpControl.Messages.SaveConfirm") ?? "Are you sure? Will take a while"; + string title = _localizationGetter?.Invoke("Forms.GumpControl.Messages.Save") ?? "Save"; + DialogResult result = MessageBox.Show(message, title, MessageBoxButtons.YesNo, MessageBoxIcon.Warning, MessageBoxDefaultButton.Button2); if (result != DialogResult.Yes) { @@ -903,7 +906,10 @@ private void OnClickRemove(object sender, EventArgs e) return; } - DialogResult result = MessageBox.Show($"Are you sure to remove {i}", "Remove", MessageBoxButtons.YesNo, + string template = _localizationGetter?.Invoke("Forms.GumpControl.Messages.RemoveConfirm") ?? "Are you sure to remove {0}"; + string message = string.Format(template, i); + string title = _localizationGetter?.Invoke("Forms.GumpControl.Messages.Remove") ?? "Remove"; + DialogResult result = MessageBox.Show(message, title, MessageBoxButtons.YesNo, MessageBoxIcon.Question, MessageBoxDefaultButton.Button2); if (result != DialogResult.Yes) { diff --git a/UoFiddler/Localization/Dictionaries/zh-CN.json b/UoFiddler/Localization/Dictionaries/zh-CN.json index 8b553d2b..5268f3c5 100644 --- a/UoFiddler/Localization/Dictionaries/zh-CN.json +++ b/UoFiddler/Localization/Dictionaries/zh-CN.json @@ -422,6 +422,18 @@ "ExportSelectedAsTiff": "保存为 TIFF", "ExportSelectedAsJpg": "保存为 JPG", "ExportSelectedAsPng": "保存为 PNG", + "Messages": { + "CopyImageError": "复制图像失败", + "CopyImage": "复制图像", + "PasteImageError": "粘贴图像失败", + "PasteImage": "粘贴图像", + "InvalidGumpDimensions": "无效的 Gump 尺寸!\n\n剪贴板图像:{0}x{1}\nGump 可支持的最大尺寸为 65535x65535 像素。\n\n未做任何更改。", + "InvalidSize": "无效的尺寸", + "SaveConfirm": "确定要保存吗?这可能需要一些时间", + "Save": "保存", + "RemoveConfirm": "确定要删除 {0} 吗?", + "Remove": "删除" + }, "Tags": { "one-hand": "单手武器", "two-hand": "双手武器", From 3f498953d4b39921ea70d4c10d2c2cd72076088a Mon Sep 17 00:00:00 2001 From: nbyaya Date: Sun, 4 Oct 2026 21:32:50 +0800 Subject: [PATCH 26/30] =?UTF-8?q?feat:=20=E6=B1=89=E5=8C=96=20HuesControl?= =?UTF-8?q?=20=E5=92=8C=20HueEditForm=EF=BC=8C=E4=BF=AE=E5=A4=8D=20Load=20?= =?UTF-8?q?=E4=BA=8B=E4=BB=B6=E9=87=8D=E5=A4=8D=E8=B0=83=E7=94=A8=E9=99=B7?= =?UTF-8?q?=E9=98=B1?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit - 修复 HuesControl/GumpControl Load 事件中的重复 ApplyLocalization() 调用 - 为 HueEditForm 添加汉化支持(SetLocalization/ApplyLocalization) - 处理动态窗口标题的汉化(保留索引信息) - 在 HuesControl 中调用 HueEditForm 时传入汉化 getter - 更新 MainForm 为 hueControl 调用 SetLocalization() - 添加 HueEditForm 的 14 个汉化词条到 zh-CN.json --- UoFiddler.Controls/Forms/HueEditForm.cs | 40 +++++++++++++++++++ .../UserControls/GumpControl.cs | 3 -- .../UserControls/HuesControl.cs | 30 +++++++++++++- UoFiddler/Forms/MainForm.cs | 1 + .../Localization/Dictionaries/zh-CN.json | 28 +++++++++++++ 5 files changed, 98 insertions(+), 4 deletions(-) diff --git a/UoFiddler.Controls/Forms/HueEditForm.cs b/UoFiddler.Controls/Forms/HueEditForm.cs index f3aebe5b..b8ff00ab 100644 --- a/UoFiddler.Controls/Forms/HueEditForm.cs +++ b/UoFiddler.Controls/Forms/HueEditForm.cs @@ -25,6 +25,7 @@ public partial class HueEditForm : Form private int _selected; private int _secondSel; private Bitmap _preview; + private Func? _localizationGetter; private int Selected { @@ -70,6 +71,45 @@ public HueEditForm(int index) pictureBoxPreview.Image = new Bitmap(pictureBoxPreview.Width, pictureBoxPreview.Height); } + /// + /// 设置本地化函数 + /// + public void SetLocalization(Func getLocalized) + { + _localizationGetter = getLocalized; + ApplyLocalization(); + } + + private void ApplyLocalization() + { + if (_localizationGetter == null) return; + + // 窗口标题 - 动态生成,保持索引信息 + var titleFormat = _localizationGetter("Forms.HueEditForm.Title") ?? "HueEdit"; + int hueIndex = int.Parse(Text.Split('/')[0].Replace("HueEdit ", "").Trim()); + Text = $"{titleFormat} {hueIndex} / 0x{hueIndex:X}"; + + // 按钮 + ColorPickerButton.Text = _localizationGetter("Forms.HueEditForm.ColorPickerButton") ?? "Color Picker"; + SaveButton.Text = _localizationGetter("Forms.HueEditForm.SaveButton") ?? "Save"; + Spread.Text = _localizationGetter("Forms.HueEditForm.Spread") ?? "Linear Gradient"; + ExpGradientButton.Text = _localizationGetter("Forms.HueEditForm.ExpGradientButton") ?? "Exp Gradient"; + InverseButton.Text = _localizationGetter("Forms.HueEditForm.InverseButton") ?? "Inverse"; + ModifyRangeButton.Text = _localizationGetter("Forms.HueEditForm.ModifyRangeButton") ?? "Modify Range"; + SetColorButton.Text = _localizationGetter("Forms.HueEditForm.SetColorButton") ?? "Set color"; + + // 标签 + RLabel.Text = _localizationGetter("Forms.HueEditForm.RLabel") ?? "R:"; + GLabel.Text = _localizationGetter("Forms.HueEditForm.GLabel") ?? "G:"; + BLabel.Text = _localizationGetter("Forms.HueEditForm.BLabel") ?? "B:"; + + // 菜单项 + itemToolStripMenuItem.Text = _localizationGetter("Forms.HueEditForm.itemToolStripMenuItem") ?? "Item"; + animationToolStripMenuItem.Text = _localizationGetter("Forms.HueEditForm.animationToolStripMenuItem") ?? "Animation"; + gumpToolStripMenuItem.Text = _localizationGetter("Forms.HueEditForm.gumpToolStripMenuItem") ?? "Gump"; + hueOnlyGreyToolStripMenuItem.Text = _localizationGetter("Forms.HueEditForm.hueOnlyGreyToolStripMenuItem") ?? "Hue only Grey"; + } + private int GetIndex(int x) { return (int)(x * 1.0 / (pictureBox.Width * 1.0 / _colors.Length * 1.0)); diff --git a/UoFiddler.Controls/UserControls/GumpControl.cs b/UoFiddler.Controls/UserControls/GumpControl.cs index cfb15615..08140e04 100644 --- a/UoFiddler.Controls/UserControls/GumpControl.cs +++ b/UoFiddler.Controls/UserControls/GumpControl.cs @@ -48,9 +48,6 @@ public GumpControl() _refMarker = this; pictureBox.BackColor = Options.PreviewBackgroundColor; - - // 在加载时应用本地化 - this.Load += (s, e) => ApplyLocalization(); } public void SetLocalization(Func getLocalized) diff --git a/UoFiddler.Controls/UserControls/HuesControl.cs b/UoFiddler.Controls/UserControls/HuesControl.cs index d29fc46b..1f1e30e1 100644 --- a/UoFiddler.Controls/UserControls/HuesControl.cs +++ b/UoFiddler.Controls/UserControls/HuesControl.cs @@ -33,6 +33,32 @@ public HuesControl() pictureBox.MouseWheel += OnMouseWheel; } + private Func? _localizationGetter; + + /// + /// 设置本地化函数 + /// + public void SetLocalization(Func getLocalized) + { + _localizationGetter = getLocalized; + ApplyLocalization(); + } + + private void ApplyLocalization() + { + if (_localizationGetter == null) return; + + saveToolStripMenuItem.Text = _localizationGetter("Forms.HuesControl.saveToolStripMenuItem") ?? "Save"; + replaceToolStripMenuItem.Text = _localizationGetter("Forms.HuesControl.replaceToolStripMenuItem") ?? "Replace With.."; + exportToolStripMenuItem.Text = _localizationGetter("Forms.HuesControl.exportToolStripMenuItem") ?? "Export.."; + importToolStripMenuItem.Text = _localizationGetter("Forms.HuesControl.importToolStripMenuItem") ?? "Import.."; + exportAllHueNamesListToolStripMenuItem.Text = _localizationGetter("Forms.HuesControl.exportAllHueNamesListToolStripMenuItem") ?? "Export all hue names list"; + HueIndexToolStripLabel.Text = _localizationGetter("Forms.HuesControl.HueIndexToolStripLabel") ?? "Index:"; + HueNameToolStripLabel.Text = _localizationGetter("Forms.HuesControl.HueNameToolStripLabel") ?? "Name:"; + SearchNameToolStripButton.Text = _localizationGetter("Forms.HuesControl.SearchNameToolStripButton") ?? "Find next"; + IndexOffsetButton.Text = _localizationGetter("Forms.HuesControl.IndexOffsetButton") ?? "Show ingame numbers"; + } + private const int _itemHeight = 20; private int _selected; private bool _loaded; @@ -232,7 +258,9 @@ private void OnMouseDoubleClick(object sender, MouseEventArgs e) if (Selected >= 0) { - new HueEditForm(Selected).Show(); + var form = new HueEditForm(Selected); + form.SetLocalization(key => _localizationGetter?.Invoke(key)); + form.Show(); } } diff --git a/UoFiddler/Forms/MainForm.cs b/UoFiddler/Forms/MainForm.cs index 53cb62f9..28e41032 100644 --- a/UoFiddler/Forms/MainForm.cs +++ b/UoFiddler/Forms/MainForm.cs @@ -58,6 +58,7 @@ public MainForm(ILogger logger) // 为主标签页控件调用本地化(GumpControl等需要手动调用SetLocalization) gumpsControl.SetLocalization(key => LocalizationService.GetString(key)); + hueControl.SetLocalization(key => LocalizationService.GetString(key)); darkModeMenuItem.Checked = AppSettings.DarkMode; diff --git a/UoFiddler/Localization/Dictionaries/zh-CN.json b/UoFiddler/Localization/Dictionaries/zh-CN.json index 5268f3c5..ae3e5707 100644 --- a/UoFiddler/Localization/Dictionaries/zh-CN.json +++ b/UoFiddler/Localization/Dictionaries/zh-CN.json @@ -387,6 +387,34 @@ "chkMultiSelect": "多选", "applyHue1ToHue2": "应用色调到左侧" }, + "HuesControl": { + "saveToolStripMenuItem": "保存", + "replaceToolStripMenuItem": "替换为..", + "exportToolStripMenuItem": "导出..", + "importToolStripMenuItem": "导入..", + "exportAllHueNamesListToolStripMenuItem": "导出所有色调名称列表", + "HueIndexToolStripLabel": "索引:", + "HueNameToolStripLabel": "名称:", + "SearchNameToolStripButton": "查找下一个", + "IndexOffsetButton": "显示游戏内数字" + }, + "HueEditForm": { + "Title": "色调编辑", + "ColorPickerButton": "颜色拾取器", + "SaveButton": "保存", + "Spread": "线性渐变", + "ExpGradientButton": "指数渐变", + "InverseButton": "反转", + "ModifyRangeButton": "修改范围", + "SetColorButton": "设置颜色", + "RLabel": "R:", + "GLabel": "G:", + "BLabel": "B:", + "itemToolStripMenuItem": "物品", + "animationToolStripMenuItem": "动画", + "gumpToolStripMenuItem": "Gump", + "hueOnlyGreyToolStripMenuItem": "仅色调灰度" + }, "GumpControl": { "showFreeSlotsToolStripMenuItem": "显示空闲槽位", "findNextFreeSlotToolStripMenuItem": "查找下一个空闲槽位", From 0d653d7ae2cdc080091254f5e24dbb75e1a75fe8 Mon Sep 17 00:00:00 2001 From: nbyaya Date: Sun, 4 Oct 2026 21:40:37 +0800 Subject: [PATCH 27/30] =?UTF-8?q?=E6=B1=89=E5=8C=96=20MultisControl=20?= =?UTF-8?q?=E6=A0=87=E7=AD=BE=E9=A1=B9=E5=A4=9A=E9=87=8D=E7=BB=84=E4=BB=B6?= =?UTF-8?q?=E7=AA=97=E5=8F=A3=E5=86=85=E5=AE=B9?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit - 为 MultisControl.cs 添加 SetLocalization/ApplyLocalization 方法 - 实现 55 个菜单项、标签页、按钮的汉化 - 支持 MUL 和 UOP 两个标签页 - MainForm.cs 中调用 multisControl.SetLocalization() - zh-CN.json 已包含所有 55 个词条 修复类型: 类型 1 - 简单 UI 控件文本汉化(非侵入式) --- .../UserControls/MultisControl.cs | 96 +++++++++++++++++++ UoFiddler/Forms/MainForm.cs | 1 + .../Localization/Dictionaries/zh-CN.json | 64 +++++++++++++ 3 files changed, 161 insertions(+) diff --git a/UoFiddler.Controls/UserControls/MultisControl.cs b/UoFiddler.Controls/UserControls/MultisControl.cs index 8ca277cc..eb51900b 100644 --- a/UoFiddler.Controls/UserControls/MultisControl.cs +++ b/UoFiddler.Controls/UserControls/MultisControl.cs @@ -49,6 +49,7 @@ public MultisControl() private bool _loaded; private bool _showFreeSlots; private readonly MultisControl _refMarker; + private Func? _localizationGetter; // Virtual ListView backing: row index → multi id. _mulIds includes both // present and (when _showFreeSlots is on) empty slots; emptiness is @@ -1626,6 +1627,101 @@ private void OnClick_SaveAllToXML(object sender, EventArgs e) FileSavedDialog.Show(FindForm(), fileName, "All Multis saved successfully."); } + /// + /// 设置本地化函数 + /// + public void SetLocalization(Func getLocalized) + { + _localizationGetter = getLocalized; + ApplyLocalization(); + } + + private void ApplyLocalization() + { + if (_localizationGetter == null) return; + + // MUL 标签页菜单项 + toolStripMenuItem4.Text = _localizationGetter("Forms.MultisControl.toolStripMenuItem4") ?? "Show Free Slots"; + importToolStripMenuItem.Text = _localizationGetter("Forms.MultisControl.importToolStripMenuItem") ?? "Import.."; + exportToolStripMenuItem.Text = _localizationGetter("Forms.MultisControl.exportToolStripMenuItem") ?? "Export.."; + removeToolStripMenuItem.Text = _localizationGetter("Forms.MultisControl.removeToolStripMenuItem") ?? "Remove"; + saveToolStripMenuItem1.Text = _localizationGetter("Forms.MultisControl.saveToolStripMenuItem1") ?? "Save"; + + toTextfileToolStripMenuItem.Text = _localizationGetter("Forms.MultisControl.toTextfileToolStripMenuItem") ?? "Export to Text File"; + toUOAToolStripMenuItem.Text = _localizationGetter("Forms.MultisControl.toUOAToolStripMenuItem") ?? "Export to UOA"; + toWscToolStripMenuItem.Text = _localizationGetter("Forms.MultisControl.toWscToolStripMenuItem") ?? "Export to WSC"; + toCsvToolStripMenuItem.Text = _localizationGetter("Forms.MultisControl.toCsvToolStripMenuItem") ?? "Export to CSV"; + toUOX3ToolStripMenuItem.Text = _localizationGetter("Forms.MultisControl.toUOX3ToolStripMenuItem") ?? "Export to UOX3"; + + // 工具栏菜单项 + toolStripDropDownButton1.Text = _localizationGetter("Forms.MultisControl.toolStripDropDownButton1") ?? "Misc"; + exportAllImagesToolStripMenuItem.Text = _localizationGetter("Forms.MultisControl.exportAllImagesToolStripMenuItem") ?? "Export all Images"; + aToolStripMenuItem.Text = _localizationGetter("Forms.MultisControl.aToolStripMenuItem") ?? "Export as BMP"; + asTiffToolStripMenuItem1.Text = _localizationGetter("Forms.MultisControl.asTiffToolStripMenuItem1") ?? "Export as TIFF"; + asJpgToolStripMenuItem.Text = _localizationGetter("Forms.MultisControl.asJpgToolStripMenuItem") ?? "Export as JPG"; + asPngToolStripMenuItem1.Text = _localizationGetter("Forms.MultisControl.asPngToolStripMenuItem1") ?? "Export as PNG"; + + ChangeBackgroundColorToolStripMenuItem.Text = _localizationGetter("Forms.MultisControl.ChangeBackgroundColorToolStripMenuItem") ?? "Change Background Color"; + UseTransparencyForPNGToolStripMenuItem.Text = _localizationGetter("Forms.MultisControl.UseTransparencyForPNGToolStripMenuItem") ?? "Use Transparency for PNG"; + + exportAllPartsToolStripMenuItem.Text = _localizationGetter("Forms.MultisControl.exportAllPartsToolStripMenuItem") ?? "Export all Parts"; + toTextFileToolStripMenuItem1.Text = _localizationGetter("Forms.MultisControl.toTextFileToolStripMenuItem1") ?? "Export to Text File"; + toUOAFileToolStripMenuItem.Text = _localizationGetter("Forms.MultisControl.toUOAFileToolStripMenuItem") ?? "Export to UOA File"; + toWSCFileToolStripMenuItem.Text = _localizationGetter("Forms.MultisControl.toWSCFileToolStripMenuItem") ?? "Export to WSC File"; + toCSVFileToolStripMenuItem.Text = _localizationGetter("Forms.MultisControl.toCSVFileToolStripMenuItem") ?? "Export to CSV File"; + toUOX3FileToolStripMenuItem.Text = _localizationGetter("Forms.MultisControl.toUOX3FileToolStripMenuItem") ?? "Export to UOX3 File"; + toXMLFileToolStripMenuItem.Text = _localizationGetter("Forms.MultisControl.toXMLFileToolStripMenuItem") ?? "Export to XML File (CentrED+)"; + + fitModeToolStripMenuItem.Text = _localizationGetter("Forms.MultisControl.fitModeToolStripMenuItem") ?? "Fit Mode"; + helpToolStripButton.Text = _localizationGetter("Forms.MultisControl.helpToolStripButton") ?? "Help"; + + // 标签页 + listViewMultiColumn.Text = _localizationGetter("Forms.MultisControl.listViewMultiColumn") ?? "Multi"; + tabPage5.Text = _localizationGetter("Forms.MultisControl.tabPage5") ?? "Graphics"; + tabPage6.Text = _localizationGetter("Forms.MultisControl.tabPage6") ?? "Components"; + + // MUL 预览菜单 + extractImageToolStripMenuItem.Text = _localizationGetter("Forms.MultisControl.extractImageToolStripMenuItem") ?? "Extract Image.."; + asBmpToolStripMenuItem.Text = _localizationGetter("Forms.MultisControl.asBmpToolStripMenuItem") ?? "Export as BMP"; + asTiffToolStripMenuItem.Text = _localizationGetter("Forms.MultisControl.asTiffToolStripMenuItem") ?? "Export as TIFF"; + asJpgToolStripMenuItem1.Text = _localizationGetter("Forms.MultisControl.asJpgToolStripMenuItem1") ?? "Export as JPG"; + asPngToolStripMenuItem.Text = _localizationGetter("Forms.MultisControl.asPngToolStripMenuItem") ?? "Export as PNG"; + + // UOP 标签页菜单项 + listViewUopColumn.Text = _localizationGetter("Forms.MultisControl.listViewUopColumn") ?? "UOP"; + tabPageMul.Text = _localizationGetter("Forms.MultisControl.tabPageMul") ?? "MUL"; + tabPageUop.Text = _localizationGetter("Forms.MultisControl.tabPageUop") ?? "UOP"; + tabPageUopPreview.Text = _localizationGetter("Forms.MultisControl.tabPageUopPreview") ?? "Preview"; + tabPageUopComponents.Text = _localizationGetter("Forms.MultisControl.tabPageUopComponents") ?? "Components"; + + uopExportToolStripMenuItem.Text = _localizationGetter("Forms.MultisControl.uopExportToolStripMenuItem") ?? "Export"; + uopToUOAToolStripMenuItem.Text = _localizationGetter("Forms.MultisControl.uopToUOAToolStripMenuItem") ?? "Export to UOA"; + uopToWscToolStripMenuItem.Text = _localizationGetter("Forms.MultisControl.uopToWscToolStripMenuItem") ?? "Export to WSC"; + uopToCsvToolStripMenuItem.Text = _localizationGetter("Forms.MultisControl.uopToCsvToolStripMenuItem") ?? "Export to CSV"; + + toolStripDropDownUop.Text = _localizationGetter("Forms.MultisControl.toolStripDropDownUop") ?? "Misc"; + uopExportAllImagesToolStripMenuItem.Text = _localizationGetter("Forms.MultisControl.uopExportAllImagesToolStripMenuItem") ?? "Export all Images"; + uopAsBmpToolStripMenuItem.Text = _localizationGetter("Forms.MultisControl.uopAsBmpToolStripMenuItem") ?? "Export as BMP"; + uopAsTiffToolStripMenuItem.Text = _localizationGetter("Forms.MultisControl.uopAsTiffToolStripMenuItem") ?? "Export as TIFF"; + uopAsJpgToolStripMenuItem.Text = _localizationGetter("Forms.MultisControl.uopAsJpgToolStripMenuItem") ?? "Export as JPG"; + uopAsPngToolStripMenuItem.Text = _localizationGetter("Forms.MultisControl.uopAsPngToolStripMenuItem") ?? "Export as PNG"; + + uopExportAllPartsToolStripMenuItem.Text = _localizationGetter("Forms.MultisControl.uopExportAllPartsToolStripMenuItem") ?? "Export all Parts"; + uopToTextfileToolStripMenuItem.Text = _localizationGetter("Forms.MultisControl.uopToTextfileToolStripMenuItem") ?? "Export to Text File"; + uopToUOAFileToolStripMenuItem.Text = _localizationGetter("Forms.MultisControl.uopToUOAFileToolStripMenuItem") ?? "Export to UOA File"; + uopToWSCFileToolStripMenuItem.Text = _localizationGetter("Forms.MultisControl.uopToWSCFileToolStripMenuItem") ?? "Export to WSC File"; + uopToCSVFileToolStripMenuItem.Text = _localizationGetter("Forms.MultisControl.uopToCSVFileToolStripMenuItem") ?? "Export to CSV File"; + + uopFitModeToolStripMenuItem.Text = _localizationGetter("Forms.MultisControl.uopFitModeToolStripMenuItem") ?? "Fit Mode"; + uopHelpToolStripButton.Text = _localizationGetter("Forms.MultisControl.uopHelpToolStripButton") ?? "Help"; + + uopExtractImageToolStripMenuItem.Text = _localizationGetter("Forms.MultisControl.uopExtractImageToolStripMenuItem") ?? "Extract Image.."; + uopAsBmpPicToolStripMenuItem.Text = _localizationGetter("Forms.MultisControl.uopAsBmpPicToolStripMenuItem") ?? "Export as BMP"; + uopAsTiffPicToolStripMenuItem.Text = _localizationGetter("Forms.MultisControl.uopAsTiffPicToolStripMenuItem") ?? "Export as TIFF"; + uopAsJpgPicToolStripMenuItem.Text = _localizationGetter("Forms.MultisControl.uopAsJpgPicToolStripMenuItem") ?? "Export as JPG"; + uopAsPngPicToolStripMenuItem.Text = _localizationGetter("Forms.MultisControl.uopAsPngPicToolStripMenuItem") ?? "Export as PNG"; + } + private sealed class MouseWheelFilter : IMessageFilter { private const int _wmMouseWheel = 0x020A; diff --git a/UoFiddler/Forms/MainForm.cs b/UoFiddler/Forms/MainForm.cs index 28e41032..0c06e0d4 100644 --- a/UoFiddler/Forms/MainForm.cs +++ b/UoFiddler/Forms/MainForm.cs @@ -59,6 +59,7 @@ public MainForm(ILogger logger) // 为主标签页控件调用本地化(GumpControl等需要手动调用SetLocalization) gumpsControl.SetLocalization(key => LocalizationService.GetString(key)); hueControl.SetLocalization(key => LocalizationService.GetString(key)); + multisControl.SetLocalization(key => LocalizationService.GetString(key)); darkModeMenuItem.Checked = AppSettings.DarkMode; diff --git a/UoFiddler/Localization/Dictionaries/zh-CN.json b/UoFiddler/Localization/Dictionaries/zh-CN.json index ae3e5707..8dee8d45 100644 --- a/UoFiddler/Localization/Dictionaries/zh-CN.json +++ b/UoFiddler/Localization/Dictionaries/zh-CN.json @@ -415,6 +415,70 @@ "gumpToolStripMenuItem": "Gump", "hueOnlyGreyToolStripMenuItem": "仅色调灰度" }, + "MultisControl": { + "listViewMultiColumn": "多重", + "toolStripMenuItem4": "显示空闲槽位", + "importToolStripMenuItem": "导入..", + "exportToolStripMenuItem": "导出..", + "removeToolStripMenuItem": "删除", + "saveToolStripMenuItem1": "保存", + "toTextfileToolStripMenuItem": "导出为文本文件", + "toUOAToolStripMenuItem": "导出为 UOA", + "toWscToolStripMenuItem": "导出为 WSC", + "toCsvToolStripMenuItem": "导出为 CSV", + "toUOX3ToolStripMenuItem": "导出为 UOX3", + "toolStripDropDownButton1": "杂项", + "exportAllImagesToolStripMenuItem": "导出所有图像", + "aToolStripMenuItem": "导出为 BMP", + "asTiffToolStripMenuItem1": "导出为 TIFF", + "asJpgToolStripMenuItem": "导出为 JPG", + "asPngToolStripMenuItem1": "导出为 PNG", + "ChangeBackgroundColorToolStripMenuItem": "改变背景颜色", + "UseTransparencyForPNGToolStripMenuItem": "PNG 使用透明背景", + "exportAllPartsToolStripMenuItem": "导出所有部分", + "toTextFileToolStripMenuItem1": "导出为文本文件", + "toUOAFileToolStripMenuItem": "导出为 UOA 文件", + "toWSCFileToolStripMenuItem": "导出为 WSC 文件", + "toCSVFileToolStripMenuItem": "导出为 CSV 文件", + "toUOX3FileToolStripMenuItem": "导出为 UOX3 文件", + "toXMLFileToolStripMenuItem": "导出为 XML 文件 (CentrED+)", + "fitModeToolStripMenuItem": "适应窗口", + "helpToolStripButton": "帮助", + "tabPage5": "图形", + "tabPage6": "组件", + "extractImageToolStripMenuItem": "导出图像..", + "asBmpToolStripMenuItem": "导出为 BMP", + "asTiffToolStripMenuItem": "导出为 TIFF", + "asJpgToolStripMenuItem1": "导出为 JPG", + "asPngToolStripMenuItem": "导出为 PNG", + "listViewUopColumn": "UOP", + "tabPageMul": "MUL", + "tabPageUop": "UOP", + "tabPageUopPreview": "预览", + "tabPageUopComponents": "组件", + "uopExportToolStripMenuItem": "导出", + "uopToUOAToolStripMenuItem": "导出为 UOA", + "uopToWscToolStripMenuItem": "导出为 WSC", + "uopToCsvToolStripMenuItem": "导出为 CSV", + "toolStripDropDownUop": "杂项", + "uopExportAllImagesToolStripMenuItem": "导出所有图像", + "uopAsBmpToolStripMenuItem": "导出为 BMP", + "uopAsTiffToolStripMenuItem": "导出为 TIFF", + "uopAsJpgToolStripMenuItem": "导出为 JPG", + "uopAsPngToolStripMenuItem": "导出为 PNG", + "uopExportAllPartsToolStripMenuItem": "导出所有部分", + "uopToTextfileToolStripMenuItem": "导出为文本文件", + "uopToUOAFileToolStripMenuItem": "导出为 UOA 文件", + "uopToWSCFileToolStripMenuItem": "导出为 WSC 文件", + "uopToCSVFileToolStripMenuItem": "导出为 CSV 文件", + "uopFitModeToolStripMenuItem": "适应窗口", + "uopHelpToolStripButton": "帮助", + "uopExtractImageToolStripMenuItem": "导出图像..", + "uopAsBmpPicToolStripMenuItem": "导出为 BMP", + "uopAsTiffPicToolStripMenuItem": "导出为 TIFF", + "uopAsJpgPicToolStripMenuItem": "导出为 JPG", + "uopAsPngPicToolStripMenuItem": "导出为 PNG" + }, "GumpControl": { "showFreeSlotsToolStripMenuItem": "显示空闲槽位", "findNextFreeSlotToolStripMenuItem": "查找下一个空闲槽位", From 422ee507108b6e88acde3c85aa6c0bcd4b48bc04 Mon Sep 17 00:00:00 2001 From: nbyaya Date: Sun, 4 Oct 2026 22:31:36 +0800 Subject: [PATCH 28/30] =?UTF-8?q?=E6=B1=89=E5=8C=96=20MultisControl=20?= =?UTF-8?q?=E7=8A=B6=E6=80=81=E6=A0=8F=E5=92=8C=E5=B8=AE=E5=8A=A9=E7=AA=97?= =?UTF-8?q?=E5=8F=A3=20-=20JSON=20=E8=AF=8D=E6=9D=A1?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit - 添加 35 个汉化词条到 zh-CN.json - Status 子字典:尺寸、最大高度、多重区域、表面、缩放 - HelpForm 子字典:帮助窗口完整的键盘快捷方式文本 修复类型: 汉化词条 --- .../Localization/Dictionaries/zh-CN.json | 35 ++++++++++++++++++- 1 file changed, 34 insertions(+), 1 deletion(-) diff --git a/UoFiddler/Localization/Dictionaries/zh-CN.json b/UoFiddler/Localization/Dictionaries/zh-CN.json index 8dee8d45..811a75ca 100644 --- a/UoFiddler/Localization/Dictionaries/zh-CN.json +++ b/UoFiddler/Localization/Dictionaries/zh-CN.json @@ -477,7 +477,40 @@ "uopAsBmpPicToolStripMenuItem": "导出为 BMP", "uopAsTiffPicToolStripMenuItem": "导出为 TIFF", "uopAsJpgPicToolStripMenuItem": "导出为 JPG", - "uopAsPngPicToolStripMenuItem": "导出为 PNG" + "uopAsPngPicToolStripMenuItem": "导出为 PNG", + "Status": { + "Size": "尺寸", + "MaxHeight": "最大高度", + "MultiRegion": "多重区域", + "Surface": "表面", + "Zoom": "缩放", + "Empty": "尺寸: 0,0 最大高度: 0 多重区域: 0,0,0,0" + }, + "HelpForm": { + "Title": "多重组件 — 键盘快捷方式和控制", + "ColumnShortcut": "快捷方式 / 控制", + "ColumnAction": "操作", + "ButtonClose": "关闭", + "HeaderPreview": "预览", + "PreviewFit": "适应窗口", + "PreviewFitDesc": "切换工具栏上的按钮 — 缩放以适应或以 100% 显示并显示滚动条", + "HeaderZoom": "缩放(仅 100% 模式)", + "ZoomCtrlWheel": "Ctrl + 鼠标滚轮", + "ZoomCtrlWheelDesc": "放大 / 缩小", + "ZoomShiftPlus": "Shift + = (加号键)", + "ZoomShiftPlusDesc": "放大", + "ZoomMinus": "- (减号键)", + "ZoomMinusDesc": "缩小", + "ZoomNumpadPlus": "数字键盘 +", + "ZoomNumpadPlusDesc": "放大", + "ZoomNumpadMinus": "数字键盘 -", + "ZoomNumpadMinusDesc": "缩小", + "ZoomCtrl0": "Ctrl + 0", + "ZoomCtrl0Desc": "重置缩放为 100%", + "HeaderPanning": "平移(仅 100% 模式)", + "PanningLeftDrag": "左键单击拖动", + "PanningLeftDragDesc": "平移视图" + } }, "GumpControl": { "showFreeSlotsToolStripMenuItem": "显示空闲槽位", From 7c751e0a0c3cbd3c7f016e296ca6c4ee0cc9ff07 Mon Sep 17 00:00:00 2001 From: nbyaya Date: Sun, 4 Oct 2026 22:32:10 +0800 Subject: [PATCH 29/30] =?UTF-8?q?=E6=B1=89=E5=8C=96=20MultisControl=20-=20?= =?UTF-8?q?=E7=8A=B6=E6=80=81=E6=96=87=E6=9C=AC=E5=92=8C=E5=B8=AE=E5=8A=A9?= =?UTF-8?q?=E7=AA=97=E5=8F=A3?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit - 实现 FormatMultiStatus()、GetMaxHeightLabel()、GetZoomLabel() - 添加 SetLocalization() 和 ApplyLocalization() - 动态状态文本应用汉化(类型8) - 帮助窗口汉化支持(类型11) --- .../UserControls/MultisControl.cs | 71 ++++++++++++++++--- 1 file changed, 61 insertions(+), 10 deletions(-) diff --git a/UoFiddler.Controls/UserControls/MultisControl.cs b/UoFiddler.Controls/UserControls/MultisControl.cs index eb51900b..af403d09 100644 --- a/UoFiddler.Controls/UserControls/MultisControl.cs +++ b/UoFiddler.Controls/UserControls/MultisControl.cs @@ -360,15 +360,17 @@ private void AfterSelect_Multi(object sender, EventArgs e) if (multi == MultiComponentList.Empty) { HeightChangeMulti.Maximum = 0; - toolTip.SetToolTip(HeightChangeMulti, "MaxHeight: 0"); - SetMulStatus("Size: 0,0 MaxHeight: 0 MultiRegion: 0,0,0,0"); + string maxHeightLabel = GetMaxHeightLabel(); + toolTip.SetToolTip(HeightChangeMulti, $"{maxHeightLabel}: 0"); + SetMulStatus(FormatMultiStatus(multi)); } else { HeightChangeMulti.Maximum = multi.MaxHeight; + string maxHeightLabel = GetMaxHeightLabel(); toolTip.SetToolTip(HeightChangeMulti, - $"MaxHeight: {HeightChangeMulti.Maximum - HeightChangeMulti.Value}"); - SetMulStatus($"Size: {multi.Width},{multi.Height} MaxHeight: {multi.MaxHeight} MultiRegion: {multi.Min.X},{multi.Min.Y},{multi.Max.X},{multi.Max.Y} Surface: {multi.Surface}"); + $"{maxHeightLabel}: {HeightChangeMulti.Maximum - HeightChangeMulti.Value}"); + SetMulStatus(FormatMultiStatus(multi)); } ChangeComponentList(multi); RefreshMulBitmap(); @@ -999,14 +1001,16 @@ private void AfterSelect_UopMulti(object sender, EventArgs e) if (multi == MultiComponentList.Empty) { HeightChangeUop.Maximum = 0; - toolTip.SetToolTip(HeightChangeUop, "MaxHeight: 0"); - SetUopStatus("Size: 0,0 MaxHeight: 0 MultiRegion: 0,0,0,0"); + string maxHeightLabel = GetMaxHeightLabel(); + toolTip.SetToolTip(HeightChangeUop, $"{maxHeightLabel}: 0"); + SetUopStatus(FormatMultiStatus(multi)); } else { HeightChangeUop.Maximum = multi.MaxHeight; - toolTip.SetToolTip(HeightChangeUop, $"MaxHeight: {HeightChangeUop.Maximum - HeightChangeUop.Value}"); - SetUopStatus($"Size: {multi.Width},{multi.Height} MaxHeight: {multi.MaxHeight} MultiRegion: {multi.Min.X},{multi.Min.Y},{multi.Max.X},{multi.Max.Y} Surface: {multi.Surface}"); + string maxHeightLabel = GetMaxHeightLabel(); + toolTip.SetToolTip(HeightChangeUop, $"{maxHeightLabel}: {HeightChangeUop.Maximum - HeightChangeUop.Value}"); + SetUopStatus(FormatMultiStatus(multi)); } ChangeUopComponentList(multi); @@ -1237,12 +1241,47 @@ private void UpdateZoomStatus() SetUopStatus(_uopStatusBase); } + /// + /// 格式化多重组件状态文本(应用汉化) + /// + private string FormatMultiStatus(MultiComponentList multi) + { + if (multi == MultiComponentList.Empty) + { + return _localizationGetter?.Invoke("Forms.MultisControl.Status.Empty") + ?? "Size: 0,0 MaxHeight: 0 MultiRegion: 0,0,0,0"; + } + + string sizeLabel = _localizationGetter?.Invoke("Forms.MultisControl.Status.Size") ?? "Size"; + string maxHeightLabel = _localizationGetter?.Invoke("Forms.MultisControl.Status.MaxHeight") ?? "MaxHeight"; + string regionLabel = _localizationGetter?.Invoke("Forms.MultisControl.Status.MultiRegion") ?? "MultiRegion"; + string surfaceLabel = _localizationGetter?.Invoke("Forms.MultisControl.Status.Surface") ?? "Surface"; + + return $"{sizeLabel}: {multi.Width},{multi.Height} {maxHeightLabel}: {multi.MaxHeight} {regionLabel}: {multi.Min.X},{multi.Min.Y},{multi.Max.X},{multi.Max.Y} {surfaceLabel}: {multi.Surface}"; + } + + /// + /// 获取本地化的 MaxHeight 标签文本 + /// + private string GetMaxHeightLabel() + { + return _localizationGetter?.Invoke("Forms.MultisControl.Status.MaxHeight") ?? "MaxHeight"; + } + private void SetMulStatus(string baseText) { _mulStatusBase = baseText; StatusMultiText.Text = _previewFitMode ? baseText - : $"{baseText} Zoom: {_zoomLevel * 100:F0}%"; + : $"{baseText} {GetZoomLabel()}: {_zoomLevel * 100:F0}%"; + } + + /// + /// 获取本地化的 Zoom 标签文本 + /// + private string GetZoomLabel() + { + return _localizationGetter?.Invoke("Forms.MultisControl.Status.Zoom") ?? "Zoom"; } private void SetUopStatus(string baseText) @@ -1250,7 +1289,7 @@ private void SetUopStatus(string baseText) _uopStatusBase = baseText; StatusUopText.Text = _previewFitMode ? baseText - : $"{baseText} Zoom: {_zoomLevel * 100:F0}%"; + : $"{baseText} {GetZoomLabel()}: {_zoomLevel * 100:F0}%"; } protected override void OnHandleCreated(EventArgs e) @@ -1299,6 +1338,11 @@ protected override bool ProcessCmdKey(ref Message msg, Keys keyData) private void OnClickHelp(object sender, EventArgs e) { using var form = new MultisHelpForm(); + // 为帮助窗口提供汉化 + if (_localizationGetter != null) + { + form.SetLocalization(_localizationGetter); + } form.ShowDialog(this); } @@ -1722,6 +1766,13 @@ private void ApplyLocalization() uopAsPngPicToolStripMenuItem.Text = _localizationGetter("Forms.MultisControl.uopAsPngPicToolStripMenuItem") ?? "Export as PNG"; } + private void UpdateStatusDisplay() + { + // 重新显示状态文本以应用新的汉化 + SetMulStatus(_mulStatusBase); + SetUopStatus(_uopStatusBase); + } + private sealed class MouseWheelFilter : IMessageFilter { private const int _wmMouseWheel = 0x020A; From 1f6f9c5fe74889a577c27b959a1861203f664a12 Mon Sep 17 00:00:00 2001 From: nbyaya Date: Sun, 4 Oct 2026 22:32:19 +0800 Subject: [PATCH 30/30] =?UTF-8?q?=E6=B1=89=E5=8C=96=20MultisHelpForm=20-?= =?UTF-8?q?=20=E5=B8=AE=E5=8A=A9=E7=AA=97=E5=8F=A3?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit - 实现 SetLocalization() 和 ApplyLocalization() - 汉化窗口标题、列标题、按钮、快捷方式说明 - Designer.cs 硬编码文本修改 --- .../Forms/MultisHelpForm.Designer.cs | 8 +- UoFiddler.Controls/Forms/MultisHelpForm.cs | 74 +++++++++++++++---- 2 files changed, 65 insertions(+), 17 deletions(-) diff --git a/UoFiddler.Controls/Forms/MultisHelpForm.Designer.cs b/UoFiddler.Controls/Forms/MultisHelpForm.Designer.cs index 7401afd0..85e61ee5 100644 --- a/UoFiddler.Controls/Forms/MultisHelpForm.Designer.cs +++ b/UoFiddler.Controls/Forms/MultisHelpForm.Designer.cs @@ -51,12 +51,12 @@ private void InitializeComponent() // // _columnKey // - _columnKey.Text = "Shortcut / Control"; + _columnKey.Text = "快捷方式 / 控制"; _columnKey.Width = 180; // // _columnAction // - _columnAction.Text = "Action"; + _columnAction.Text = "操作"; _columnAction.Width = 420; // // _btnClose @@ -67,7 +67,7 @@ private void InitializeComponent() _btnClose.Name = "_btnClose"; _btnClose.Size = new System.Drawing.Size(75, 27); _btnClose.TabIndex = 1; - _btnClose.Text = "Close"; + _btnClose.Text = "关闭"; _btnClose.UseVisualStyleBackColor = true; // // MultisHelpForm @@ -85,7 +85,7 @@ private void InitializeComponent() Padding = new System.Windows.Forms.Padding(8); ShowInTaskbar = false; StartPosition = System.Windows.Forms.FormStartPosition.CenterParent; - Text = "Multis — Keyboard Shortcuts & Controls"; + Text = "多重组件 — 键盘快捷方式和控制"; ResumeLayout(false); } diff --git a/UoFiddler.Controls/Forms/MultisHelpForm.cs b/UoFiddler.Controls/Forms/MultisHelpForm.cs index e41f2a2c..2d5a3c49 100644 --- a/UoFiddler.Controls/Forms/MultisHelpForm.cs +++ b/UoFiddler.Controls/Forms/MultisHelpForm.cs @@ -9,6 +9,7 @@ * ***************************************************************************/ +using System; using System.Drawing; using System.Windows.Forms; using UoFiddler.Controls.Classes; @@ -17,27 +18,74 @@ namespace UoFiddler.Controls.Forms { public partial class MultisHelpForm : Form { + private Func? _localizationGetter; + public MultisHelpForm() { InitializeComponent(); + } + + public void SetLocalization(Func getLocalized) + { + _localizationGetter = getLocalized; + ApplyLocalization(); + } + + private void ApplyLocalization() + { + if (_localizationGetter == null) + { + // 如果没有汉化,使用默认英文 + PopulateShortcuts(); + return; + } + + // 应用窗口标题 + Text = _localizationGetter("Forms.MultisControl.HelpForm.Title") ?? "Multis — Keyboard Shortcuts & Controls"; + + // 应用列标题 + _columnKey.Text = _localizationGetter("Forms.MultisControl.HelpForm.ColumnShortcut") ?? "Shortcut / Control"; + _columnAction.Text = _localizationGetter("Forms.MultisControl.HelpForm.ColumnAction") ?? "Action"; + + // 应用按钮文本 + _btnClose.Text = _localizationGetter("Forms.MultisControl.HelpForm.ButtonClose") ?? "Close"; + + // 清除并重新填充列表 + _listView.Items.Clear(); PopulateShortcuts(); } private void PopulateShortcuts() { - AddHeader("Preview"); - Add("Fit preview to window", "Toggle button on toolbar — scales to fit or shows at 100% with scrollbars"); - - AddHeader("Zoom (100% mode only)"); - Add("Ctrl + Mouse Wheel", "Zoom In / Out"); - Add("Shift + = (Plus key)", "Zoom In"); - Add("- (Minus key)", "Zoom Out"); - Add("Numpad +", "Zoom In"); - Add("Numpad -", "Zoom Out"); - Add("Ctrl + 0", "Reset zoom to 100%"); - - AddHeader("Panning (100% mode only)"); - Add("Left-click drag", "Pan the view"); + // Preview 部分 + AddHeader(GetLocalizedString("Forms.MultisControl.HelpForm.HeaderPreview", "Preview")); + Add(GetLocalizedString("Forms.MultisControl.HelpForm.PreviewFit", "Fit preview to window"), + GetLocalizedString("Forms.MultisControl.HelpForm.PreviewFitDesc", "Toggle button on toolbar — scales to fit or shows at 100% with scrollbars")); + + // Zoom 部分 + AddHeader(GetLocalizedString("Forms.MultisControl.HelpForm.HeaderZoom", "Zoom (100% mode only)")); + Add(GetLocalizedString("Forms.MultisControl.HelpForm.ZoomCtrlWheel", "Ctrl + Mouse Wheel"), + GetLocalizedString("Forms.MultisControl.HelpForm.ZoomCtrlWheelDesc", "Zoom In / Out")); + Add(GetLocalizedString("Forms.MultisControl.HelpForm.ZoomShiftPlus", "Shift + = (Plus key)"), + GetLocalizedString("Forms.MultisControl.HelpForm.ZoomShiftPlusDesc", "Zoom In")); + Add(GetLocalizedString("Forms.MultisControl.HelpForm.ZoomMinus", "- (Minus key)"), + GetLocalizedString("Forms.MultisControl.HelpForm.ZoomMinusDesc", "Zoom Out")); + Add(GetLocalizedString("Forms.MultisControl.HelpForm.ZoomNumpadPlus", "Numpad +"), + GetLocalizedString("Forms.MultisControl.HelpForm.ZoomNumpadPlusDesc", "Zoom In")); + Add(GetLocalizedString("Forms.MultisControl.HelpForm.ZoomNumpadMinus", "Numpad -"), + GetLocalizedString("Forms.MultisControl.HelpForm.ZoomNumpadMinusDesc", "Zoom Out")); + Add(GetLocalizedString("Forms.MultisControl.HelpForm.ZoomCtrl0", "Ctrl + 0"), + GetLocalizedString("Forms.MultisControl.HelpForm.ZoomCtrl0Desc", "Reset zoom to 100%")); + + // Panning 部分 + AddHeader(GetLocalizedString("Forms.MultisControl.HelpForm.HeaderPanning", "Panning (100% mode only)")); + Add(GetLocalizedString("Forms.MultisControl.HelpForm.PanningLeftDrag", "Left-click drag"), + GetLocalizedString("Forms.MultisControl.HelpForm.PanningLeftDragDesc", "Pan the view")); + } + + private string GetLocalizedString(string key, string fallback) + { + return _localizationGetter?.Invoke(key) ?? fallback; } private void AddHeader(string text)