From 509dff5b29bbc965507385d7f637fae280d21efb Mon Sep 17 00:00:00 2001 From: nbyaya Date: Sat, 3 Oct 2026 13:34:23 +0800 Subject: [PATCH 01/76] 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/76] 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/76] 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/76] 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/76] 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/76] 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/76] 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/76] 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/76] 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/76] 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/76] 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/76] 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/76] =?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/76] =?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/76] 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/76] 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/76] =?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/76] =?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/76] =?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/76] =?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/76] =?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/76] =?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/76] =?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/76] =?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/76] =?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/76] =?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/76] =?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/76] =?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/76] =?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/76] =?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) From d248e34834b77da13048e6c0508ed52755789081 Mon Sep 17 00:00:00 2001 From: nbyaya Date: Mon, 5 Oct 2026 00:11:34 +0800 Subject: [PATCH 31/76] =?UTF-8?q?=E6=B1=89=E5=8C=96=20AnimationListControl?= =?UTF-8?q?=20=E5=8A=A8=E4=BD=9C=E5=90=8D=E7=A7=B0=E5=88=97=E8=A1=A8?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit - 添加 58 个动作名称的中文翻译(Monster/Sea/Animal/Human) - 实现 GetLocalizedActionName() 方法获取翻译 - 修改 AddUopActionNodes/PopulateActionNodes 显示汉化名称 - 类型 2 实现(动态列表项汉化) --- .../UserControls/AnimationListControl.cs | 107 ++++++++++++++++-- .../Localization/Dictionaries/zh-CN.json | 96 ++++++++++++++++ 2 files changed, 195 insertions(+), 8 deletions(-) diff --git a/UoFiddler.Controls/UserControls/AnimationListControl.cs b/UoFiddler.Controls/UserControls/AnimationListControl.cs index 3cc2df5c..45b820ec 100644 --- a/UoFiddler.Controls/UserControls/AnimationListControl.cs +++ b/UoFiddler.Controls/UserControls/AnimationListControl.cs @@ -37,6 +37,11 @@ public AnimationListControl() listView1.Height += SystemInformation.HorizontalScrollBarHeight; } + private Func? _localizationGetter; + private string _graphicLabelPrefix = "Graphic: "; + private string _baseGraphicLabelPrefix = "Base Graphic: "; + private string _hueLabelPrefix = "Hue: "; + public string[][] GetActionNames { get; } = { // Monster new[] @@ -349,9 +354,9 @@ private void SetPicture() _defHue = hue; } - BaseGraphicLabel.Text = $"BaseGraphic: {body} (0x{body:X})"; - GraphicLabel.Text = $"Graphic: {_currentSelect} (0x{_currentSelect:X})"; - HueLabel.Text = $"Hue: {hue + 1} (0x{hue + 1:X})"; + BaseGraphicLabel.Text = $"{_baseGraphicLabelPrefix}{body} (0x{body:X})"; + GraphicLabel.Text = $"{_graphicLabelPrefix}{_currentSelect} (0x{_currentSelect:X})"; + HueLabel.Text = $"{_hueLabelPrefix}{hue + 1} (0x{hue + 1:X})"; LoadListViewFrames(); } @@ -365,9 +370,9 @@ private void ClearPicture() MainPictureBox.Frames = null; LoadListViewFrames(); - BaseGraphicLabel.Text = "BaseGraphic:"; - GraphicLabel.Text = "Graphic: "; - HueLabel.Text = "Hue:"; + BaseGraphicLabel.Text = _baseGraphicLabelPrefix; + GraphicLabel.Text = _graphicLabelPrefix; + HueLabel.Text = _hueLabelPrefix; } private void TreeViewMobs_AfterSelect(object sender, TreeViewEventArgs e) @@ -597,7 +602,9 @@ private void AddUopActionNodes(TreeNode parent, int body, int actionType) ? GetActionNames[actionType][i] : $"Action{i}"; - parent.Nodes.Add(new TreeNode($"{i} {actionName}") { Tag = i }); + // 使用汉化后的动作名称 + string displayName = GetLocalizedActionName(actionName); + parent.Nodes.Add(new TreeNode($"{i} {displayName}") { Tag = i }); } } @@ -681,7 +688,9 @@ private void PopulateActionNodes(TreeNode bodyNode) continue; } - bodyNode.Nodes.Add(new TreeNode($"{i} {GetActionNames[actionType][i]}") { Tag = i }); + // 使用汉化后的动作名称 + string displayName = GetLocalizedActionName(GetActionNames[actionType][i]); + bodyNode.Nodes.Add(new TreeNode($"{i} {displayName}") { Tag = i }); } } } @@ -1345,6 +1354,88 @@ private void ExportAnimatedGif(bool looping) FileSavedDialog.Show(FindForm(), outputFile, "InGame Anim saved successfully."); } + /// + /// 设置本地化获取器 + /// + public void SetLocalization(Func getLocalized) + { + _localizationGetter = getLocalized; + ApplyLocalization(); + } + + /// + /// 应用本地化到所有 UI 元素 + /// + private void ApplyLocalization() + { + if (_localizationGetter == null) return; + + // 搜索标签 + searchToolStripLabel.Text = _localizationGetter("Forms.AnimationListControl.searchToolStripLabel") ?? "Search:"; + + // 右键菜单项 + removeToolStripMenuItem.Text = _localizationGetter("Forms.AnimationListControl.removeToolStripMenuItem") ?? "Remove"; + + // 标签页 + tabPage1.Text = _localizationGetter("Forms.AnimationListControl.tabPage1") ?? "Animation"; + tabPage2.Text = _localizationGetter("Forms.AnimationListControl.tabPage2") ?? "Thumbnail List"; + + // 导出图像菜单 + extractImageToolStripMenuItem.Text = _localizationGetter("Forms.AnimationListControl.extractImageToolStripMenuItem") ?? "Export Image.."; + asBMpToolStripMenuItem.Text = _localizationGetter("Forms.AnimationListControl.asBMpToolStripMenuItem") ?? "As Bmp"; + asTiffToolStripMenuItem.Text = _localizationGetter("Forms.AnimationListControl.asTiffToolStripMenuItem") ?? "As Tiff"; + asJpgToolStripMenuItem.Text = _localizationGetter("Forms.AnimationListControl.asJpgToolStripMenuItem") ?? "As Jpg"; + asPngToolStripMenuItem2.Text = _localizationGetter("Forms.AnimationListControl.asPngToolStripMenuItem2") ?? "As Png"; + + // 导出动画菜单 + extractAnimationToolStripMenuItem.Text = _localizationGetter("Forms.AnimationListControl.extractAnimationToolStripMenuItem") ?? "Export Animation.."; + asBmpToolStripMenuItem1.Text = _localizationGetter("Forms.AnimationListControl.asBmpToolStripMenuItem1") ?? "As Bmp"; + asTiffToolStripMenuItem1.Text = _localizationGetter("Forms.AnimationListControl.asTiffToolStripMenuItem1") ?? "As Tiff"; + asJpgToolStripMenuItem1.Text = _localizationGetter("Forms.AnimationListControl.asJpgToolStripMenuItem1") ?? "As Jpg"; + asPngToolStripMenuItem1.Text = _localizationGetter("Forms.AnimationListControl.asPngToolStripMenuItem1") ?? "As Png"; + asAnimatedGifToolStripMenuItem.Text = _localizationGetter("Forms.AnimationListControl.asAnimatedGifToolStripMenuItem") ?? "As animated Gif (looping)"; + asAnimatedGifnoLoopingToolStripMenuItem.Text = _localizationGetter("Forms.AnimationListControl.asAnimatedGifnoLoopingToolStripMenuItem") ?? "As animated Gif (no looping)"; + + // 导出帧菜单 + exportFrameToolStripMenuItem.Text = _localizationGetter("Forms.AnimationListControl.exportFrameToolStripMenuItem") ?? "Export Frame.."; + asBmpToolStripMenuItem2.Text = _localizationGetter("Forms.AnimationListControl.asBmpToolStripMenuItem2") ?? "As Bmp"; + asTiffToolStripMenuItem2.Text = _localizationGetter("Forms.AnimationListControl.asTiffToolStripMenuItem2") ?? "As Tiff"; + asJpgToolStripMenuItem2.Text = _localizationGetter("Forms.AnimationListControl.asJpgToolStripMenuItem2") ?? "As Jpg"; + asPngToolStripMenuItem.Text = _localizationGetter("Forms.AnimationListControl.asPngToolStripMenuItem") ?? "As Png"; + + // 帧设置组 + groupBoxSettings.Text = _localizationGetter("Forms.AnimationListControl.groupBoxSettings") ?? "Frames"; + directionLabel.Text = _localizationGetter("Forms.AnimationListControl.directionLabel") ?? "Direction"; + ShowFrameBoundsCheckBox.Text = _localizationGetter("Forms.AnimationListControl.ShowFrameBoundsCheckBox") ?? "Show frame bounds"; + AnimateCheckBox.Text = _localizationGetter("Forms.AnimationListControl.AnimateCheckBox") ?? "Animate"; + + // 设置菜单 + SettingsButton.Text = _localizationGetter("Forms.AnimationListControl.SettingsButton") ?? "Settings"; + sortAlphaToolStripMenuItem.Text = _localizationGetter("Forms.AnimationListControl.sortAlphaToolStripMenuItem") ?? "Sort alphabetical"; + hueToolStripMenuItem.Text = _localizationGetter("Forms.AnimationListControl.hueToolStripMenuItem") ?? "Hue"; + rewriteXmlToolStripMenuItem.Text = _localizationGetter("Forms.AnimationListControl.rewriteXmlToolStripMenuItem") ?? "Rewrite Xml"; + tryToFindNewGraphicsToolStripMenuItem.Text = _localizationGetter("Forms.AnimationListControl.tryToFindNewGraphicsToolStripMenuItem") ?? "Try to find new Graphics"; + animationEditToolStripMenuItem.Text = _localizationGetter("Forms.AnimationListControl.animationEditToolStripMenuItem") ?? "Animation edit"; + + // 状态栏标签 + _graphicLabelPrefix = _localizationGetter("Forms.AnimationListControl.GraphicLabel") ?? "Graphic: "; + _baseGraphicLabelPrefix = _localizationGetter("Forms.AnimationListControl.BaseGraphicLabel") ?? "Base Graphic: "; + _hueLabelPrefix = _localizationGetter("Forms.AnimationListControl.HueLabel") ?? "Hue: "; + + GraphicLabel.Text = _graphicLabelPrefix; + BaseGraphicLabel.Text = _baseGraphicLabelPrefix; + HueLabel.Text = _hueLabelPrefix; + } + + /// + /// 获取动作名称的本地化文本(汉化) + /// + private string GetLocalizedActionName(string actionName) + { + if (_localizationGetter == null) return actionName; + return _localizationGetter($"Forms.AnimationListControl.ActionNames.{actionName}") ?? actionName; + } + private void OnClickExtractAnimGifLooping(object sender, EventArgs e) { ExportAnimatedGif(true); diff --git a/UoFiddler/Localization/Dictionaries/zh-CN.json b/UoFiddler/Localization/Dictionaries/zh-CN.json index 811a75ca..812b5afa 100644 --- a/UoFiddler/Localization/Dictionaries/zh-CN.json +++ b/UoFiddler/Localization/Dictionaries/zh-CN.json @@ -592,6 +592,102 @@ "character": "角色" } }, + "AnimationListControl": { + "searchToolStripLabel": "搜索:", + "removeToolStripMenuItem": "移除", + "tabPage1": "动画", + "tabPage2": "缩略图列表", + "extractImageToolStripMenuItem": "导出图像..", + "asBMpToolStripMenuItem": "导出为 BMP", + "asTiffToolStripMenuItem": "导出为 TIFF", + "asJpgToolStripMenuItem": "导出为 JPG", + "asPngToolStripMenuItem2": "导出为 PNG", + "extractAnimationToolStripMenuItem": "导出动画..", + "asBmpToolStripMenuItem1": "导出为 BMP", + "asTiffToolStripMenuItem1": "导出为 TIFF", + "asJpgToolStripMenuItem1": "导出为 JPG", + "asPngToolStripMenuItem1": "导出为 PNG", + "asAnimatedGifToolStripMenuItem": "导出为动态 GIF(循环)", + "asAnimatedGifnoLoopingToolStripMenuItem": "导出为动态 GIF(不循环)", + "exportFrameToolStripMenuItem": "导出帧..", + "asBmpToolStripMenuItem2": "导出为 BMP", + "asTiffToolStripMenuItem2": "导出为 TIFF", + "asJpgToolStripMenuItem2": "导出为 JPG", + "asPngToolStripMenuItem": "导出为 PNG", + "groupBoxSettings": "帧", + "directionLabel": "方向", + "ShowFrameBoundsCheckBox": "显示帧边界", + "AnimateCheckBox": "播放动画", + "SettingsButton": "设置", + "sortAlphaToolStripMenuItem": "按字母排序", + "hueToolStripMenuItem": "色调", + "rewriteXmlToolStripMenuItem": "重写 XML", + "tryToFindNewGraphicsToolStripMenuItem": "尝试查找新图形", + "animationEditToolStripMenuItem": "动画编辑", + "GraphicLabel": "图形:", + "BaseGraphicLabel": "基础图形:", + "HueLabel": "色调:", + "ActionNames": { + "Walk": "行走", + "Idle": "闲置", + "Die1": "死亡1", + "Die2": "死亡2", + "Attack1": "攻击1", + "Attack2": "攻击2", + "Attack3": "攻击3", + "AttackBow": "弓攻击", + "AttackCrossBow": "弩攻击", + "AttackThrow": "投掷攻击", + "GetHit": "受伤", + "Pillage": "掠夺", + "Stomp": "踏脚", + "Cast2": "施法2", + "Cast3": "施法3", + "BlockRight": "右挡", + "BlockLeft": "左挡", + "Fidget": "躁动", + "Fly": "飞行", + "TakeOff": "起飞", + "GetHitInAir": "空中受伤", + "Run": "奔跑", + "Eat": "进食", + "Alert": "警戒", + "LieDown": "躺卧", + "Walk_01": "行走_01", + "WalkStaff_01": "持杖行走_01", + "Run_01": "奔跑_01", + "RunStaff_01": "持杖奔跑_01", + "Idle_01": "闲置_01", + "Fidget_Yawn_Stretch_01": "躁动_打哈欠_伸展_01", + "CombatIdle1H_01": "战斗闲置单手_01", + "AttackSlash1H_01": "斩击单手_01", + "AttackPierce1H_01": "刺击单手_01", + "AttackBash1H_01": "敲打单手_01", + "AttackBash2H_01": "敲打双手_01", + "AttackSlash2H_01": "斩击双手_01", + "AttackPierce2H_01": "刺击双手_01", + "CombatAdvance_1H_01": "战斗推进单手_01", + "Spell1": "法术1", + "Spell2": "法术2", + "AttackBow_01": "弓攻击_01", + "AttackCrossbow_01": "弩攻击_01", + "GetHit_Fr_Hi_01": "受伤_前_高_01", + "Die_Hard_Fwd_01": "死亡_硬_前_01", + "Die_Hard_Back_01": "死亡_硬_后_01", + "Horse_Walk_01": "马行走_01", + "Horse_Run_01": "马奔跑_01", + "Horse_Idle_01": "马闲置_01", + "Horse_Attack1H_SlashRight_01": "马攻击单手斩击右_01", + "Horse_AttackBow_01": "马弓攻击_01", + "Horse_AttackCrossbow_01": "马弩攻击_01", + "Horse_Attack2H_SlashRight_01": "马攻击双手斩击右_01", + "Block_Shield_Hard_01": "盾挡_硬_01", + "Punch_Punch_Jab_01": "拳击_拳击_刺拳_01", + "Bow_Lesser_01": "鞠躬_较小_01", + "Salute_Armed1h_01": "敬礼_持单手_01", + "Ingest_Eat_01": "进食_进食_01" + } + }, "CompareGumpControl": { "checkBox1": "仅显示差异", "chkMultiSelect": "多选", From cef7206a71eb79c7dea10d40932485249ab3bb94 Mon Sep 17 00:00:00 2001 From: nbyaya Date: Mon, 5 Oct 2026 00:16:40 +0800 Subject: [PATCH 32/76] =?UTF-8?q?=E6=B1=89=E5=8C=96=20AnimationListControl?= =?UTF-8?q?=20=E7=BC=A9=E7=95=A5=E5=9B=BE=E8=8F=9C=E5=8D=95?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit - 添加缩略图右键菜单翻译(导出格式 BMP/TIFF/JPG/PNG) - 菜单词条规范移入 ContextMenu 子字典(类型 5) --- UoFiddler.Controls/UserControls/AnimationListControl.cs | 7 +++++++ UoFiddler/Localization/Dictionaries/zh-CN.json | 7 +++++++ 2 files changed, 14 insertions(+) diff --git a/UoFiddler.Controls/UserControls/AnimationListControl.cs b/UoFiddler.Controls/UserControls/AnimationListControl.cs index 45b820ec..d1ee9f5b 100644 --- a/UoFiddler.Controls/UserControls/AnimationListControl.cs +++ b/UoFiddler.Controls/UserControls/AnimationListControl.cs @@ -1403,6 +1403,13 @@ private void ApplyLocalization() asJpgToolStripMenuItem2.Text = _localizationGetter("Forms.AnimationListControl.asJpgToolStripMenuItem2") ?? "As Jpg"; asPngToolStripMenuItem.Text = _localizationGetter("Forms.AnimationListControl.asPngToolStripMenuItem") ?? "As Png"; + // 导出所有缩略图菜单 + exportAllThumbnailsToolStripMenuItem.Text = _localizationGetter("Forms.AnimationListControl.ContextMenu.exportAllThumbnailsToolStripMenuItem") ?? "Export All Thumbnails.."; + asBmpToolStripMenuItem3.Text = _localizationGetter("Forms.AnimationListControl.ContextMenu.asBmpToolStripMenuItem3") ?? "As Bmp"; + asTiffToolStripMenuItem3.Text = _localizationGetter("Forms.AnimationListControl.ContextMenu.asTiffToolStripMenuItem3") ?? "As Tiff"; + asJpgToolStripMenuItem3.Text = _localizationGetter("Forms.AnimationListControl.ContextMenu.asJpgToolStripMenuItem3") ?? "As Jpg"; + asPngToolStripMenuItem3.Text = _localizationGetter("Forms.AnimationListControl.ContextMenu.asPngToolStripMenuItem3") ?? "As Png"; + // 帧设置组 groupBoxSettings.Text = _localizationGetter("Forms.AnimationListControl.groupBoxSettings") ?? "Frames"; directionLabel.Text = _localizationGetter("Forms.AnimationListControl.directionLabel") ?? "Direction"; diff --git a/UoFiddler/Localization/Dictionaries/zh-CN.json b/UoFiddler/Localization/Dictionaries/zh-CN.json index 812b5afa..0c382eac 100644 --- a/UoFiddler/Localization/Dictionaries/zh-CN.json +++ b/UoFiddler/Localization/Dictionaries/zh-CN.json @@ -614,6 +614,13 @@ "asTiffToolStripMenuItem2": "导出为 TIFF", "asJpgToolStripMenuItem2": "导出为 JPG", "asPngToolStripMenuItem": "导出为 PNG", + "ContextMenu": { + "exportAllThumbnailsToolStripMenuItem": "导出所有缩略图..", + "asBmpToolStripMenuItem3": "导出为 BMP", + "asTiffToolStripMenuItem3": "导出为 TIFF", + "asJpgToolStripMenuItem3": "导出为 JPG", + "asPngToolStripMenuItem3": "导出为 PNG" + }, "groupBoxSettings": "帧", "directionLabel": "方向", "ShowFrameBoundsCheckBox": "显示帧边界", From 0536a78bd2a79cc138b0d0570aab8e35de704cee Mon Sep 17 00:00:00 2001 From: nbyaya Date: Mon, 5 Oct 2026 00:18:09 +0800 Subject: [PATCH 33/76] =?UTF-8?q?=E8=A1=A5=E5=85=85=EF=BC=9AMainForm=20?= =?UTF-8?q?=E4=B8=AD=E8=B0=83=E7=94=A8=20AnimationListControl.SetLocalizat?= =?UTF-8?q?ion?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit - 在 MainForm 中为 animationsControl 调用 SetLocalization 方法 - 确保动画窗口汉化初始化正确执行 --- UoFiddler/Forms/MainForm.cs | 1 + 1 file changed, 1 insertion(+) diff --git a/UoFiddler/Forms/MainForm.cs b/UoFiddler/Forms/MainForm.cs index 0c06e0d4..973cfe74 100644 --- a/UoFiddler/Forms/MainForm.cs +++ b/UoFiddler/Forms/MainForm.cs @@ -60,6 +60,7 @@ public MainForm(ILogger logger) gumpsControl.SetLocalization(key => LocalizationService.GetString(key)); hueControl.SetLocalization(key => LocalizationService.GetString(key)); multisControl.SetLocalization(key => LocalizationService.GetString(key)); + animationsControl.SetLocalization(key => LocalizationService.GetString(key)); darkModeMenuItem.Checked = AppSettings.DarkMode; From 54253f9a07fffc26d982078a6ecafbf81c58e761 Mon Sep 17 00:00:00 2001 From: nbyaya Date: Tue, 6 Oct 2026 17:10:30 +0800 Subject: [PATCH 34/76] =?UTF-8?q?=E6=B1=89=E5=8C=96=20ItemsControl=20?= =?UTF-8?q?=E5=8F=B3=E9=94=AE=E8=8F=9C=E5=8D=95=E5=8F=8A=E6=8F=92=E4=BB=B6?= =?UTF-8?q?=E8=8F=9C=E5=8D=95=20(Type=2012/13/14)?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../Helpers/RichTextBoxExtensions.cs | 12 +- .../UserControls/ItemsControl.cs | 114 +++++++++++++++--- UoFiddler.Plugin.SendItem/SendItem.cs | 6 +- UoFiddler/Forms/MainForm.cs | 10 ++ .../Localization/Dictionaries/zh-CN.json | 60 +++++++++ 5 files changed, 180 insertions(+), 22 deletions(-) diff --git a/UoFiddler.Controls/Helpers/RichTextBoxExtensions.cs b/UoFiddler.Controls/Helpers/RichTextBoxExtensions.cs index 136aa835..c944b5fc 100644 --- a/UoFiddler.Controls/Helpers/RichTextBoxExtensions.cs +++ b/UoFiddler.Controls/Helpers/RichTextBoxExtensions.cs @@ -9,6 +9,7 @@ * ***************************************************************************/ +using System; using System.Windows.Forms; namespace UoFiddler.Controls.Helpers @@ -16,6 +17,11 @@ namespace UoFiddler.Controls.Helpers public static class RichTextBoxExtensions { public static void AddBasicContextMenu(this RichTextBox richTextBox) + { + AddBasicContextMenu(richTextBox, null); + } + + public static void AddBasicContextMenu(this RichTextBox richTextBox, Func? getLocalized) { if (richTextBox.ContextMenuStrip != null) { @@ -24,13 +30,15 @@ public static void AddBasicContextMenu(this RichTextBox richTextBox) ContextMenuStrip menuStrip = new ContextMenuStrip { ShowImageMargin = false }; - ToolStripMenuItem menuItemCopy = new ToolStripMenuItem("Copy"); + string copyText = getLocalized?.Invoke("Forms.ItemsControl.DetailTextBoxContextMenu.Copy") ?? "Copy"; + ToolStripMenuItem menuItemCopy = new ToolStripMenuItem(copyText); menuItemCopy.Click += (sender, e) => richTextBox.Copy(); menuStrip.Items.Add(menuItemCopy); menuStrip.Items.Add(new ToolStripSeparator()); - ToolStripMenuItem menuItemSelectAll = new ToolStripMenuItem("Select All"); + string selectAllText = getLocalized?.Invoke("Forms.ItemsControl.DetailTextBoxContextMenu.SelectAll") ?? "Select All"; + ToolStripMenuItem menuItemSelectAll = new ToolStripMenuItem(selectAllText); menuItemSelectAll.Click += (sender, e) => richTextBox.SelectAll(); menuStrip.Items.Add(menuItemSelectAll); diff --git a/UoFiddler.Controls/UserControls/ItemsControl.cs b/UoFiddler.Controls/UserControls/ItemsControl.cs index 3f9b1cf7..12a0ef94 100644 --- a/UoFiddler.Controls/UserControls/ItemsControl.cs +++ b/UoFiddler.Controls/UserControls/ItemsControl.cs @@ -46,6 +46,7 @@ public ItemsControl() private bool _showFreeSlots; private int _selectedGraphicId = -1; + private Func? _localizationGetter; [DesignerSerializationVisibility(DesignerSerializationVisibility.Hidden)] public int SelectedGraphicId @@ -423,25 +424,25 @@ private void UpdateDetail(int graphic) } var sb = new StringBuilder(); - sb.AppendLine($"Name: {item.Name}"); - sb.AppendLine($"Graphic: 0x{graphic:X4}"); - sb.AppendLine($"Height/Capacity: {item.Height}"); - sb.AppendLine($"Weight: {item.Weight}"); - sb.AppendLine($"Animation: {item.Animation}"); - sb.AppendLine($"Quality/Layer/Light: {item.Quality}"); - sb.AppendLine($"Quantity: {item.Quantity}"); - sb.AppendLine($"Hue: {item.Hue}"); - sb.AppendLine($"StackingOffset/Unk4: {item.StackingOffset}"); - sb.AppendLine($"Flags: {item.Flags}"); - sb.AppendLine($"Graphic pixel size width, height: {bit?.Width ?? 0} {bit?.Height ?? 0} "); - sb.AppendLine($"Graphic pixel offset xMin, yMin, xMax, yMax: {xMin} {yMin} {xMax} {yMax}"); + sb.AppendLine($"{(_localizationGetter?.Invoke("Forms.ItemsControl.DetailLabels.Name") ?? "Name")}: {item.Name}"); + sb.AppendLine($"{(_localizationGetter?.Invoke("Forms.ItemsControl.DetailLabels.Graphic") ?? "Graphic")}: 0x{graphic:X4}"); + sb.AppendLine($"{(_localizationGetter?.Invoke("Forms.ItemsControl.DetailLabels.HeightCapacity") ?? "Height/Capacity")}: {item.Height}"); + sb.AppendLine($"{(_localizationGetter?.Invoke("Forms.ItemsControl.DetailLabels.Weight") ?? "Weight")}: {item.Weight}"); + sb.AppendLine($"{(_localizationGetter?.Invoke("Forms.ItemsControl.DetailLabels.Animation") ?? "Animation")}: {item.Animation}"); + sb.AppendLine($"{(_localizationGetter?.Invoke("Forms.ItemsControl.DetailLabels.QualityLayerLight") ?? "Quality/Layer/Light")}: {item.Quality}"); + sb.AppendLine($"{(_localizationGetter?.Invoke("Forms.ItemsControl.DetailLabels.Quantity") ?? "Quantity")}: {item.Quantity}"); + sb.AppendLine($"{(_localizationGetter?.Invoke("Forms.ItemsControl.DetailLabels.Hue") ?? "Hue")}: {item.Hue}"); + sb.AppendLine($"{(_localizationGetter?.Invoke("Forms.ItemsControl.DetailLabels.StackingOffsetUnk4") ?? "StackingOffset/Unk4")}: {item.StackingOffset}"); + sb.AppendLine($"{(_localizationGetter?.Invoke("Forms.ItemsControl.DetailLabels.Flags") ?? "Flags")}: {item.Flags}"); + sb.AppendLine($"{(_localizationGetter?.Invoke("Forms.ItemsControl.DetailLabels.GraphicPixelSizeWidthHeight") ?? "Graphic pixel size width, height")}: {bit?.Width ?? 0} {bit?.Height ?? 0} "); + sb.AppendLine($"{(_localizationGetter?.Invoke("Forms.ItemsControl.DetailLabels.GraphicPixelOffsetXMinYMinXMaxYMax") ?? "Graphic pixel offset xMin, yMin, xMax, yMax")}: {xMin} {yMin} {xMax} {yMax}"); if ((item.Flags & TileFlag.Animation) != 0) { Animdata.AnimdataEntry info = Animdata.GetAnimData(graphic); if (info != null) { - sb.AppendLine($"Animation FrameCount: {info.FrameCount} Interval: {info.FrameInterval}"); + sb.AppendLine($"{(_localizationGetter?.Invoke("Forms.ItemsControl.DetailLabels.AnimationFrameCount") ?? "Animation FrameCount")}: {info.FrameCount} {(_localizationGetter?.Invoke("Forms.ItemsControl.DetailLabels.AnimationInterval") ?? "Interval")}: {info.FrameInterval}"); } } @@ -1324,13 +1325,21 @@ private void TileViewContextMenuStrip_Opening(object sender, CancelEventArgs e) int selectedCount = ItemsTileView.SelectedIndices.Count; copyImageToolStripMenuItem.Enabled = SelectedGraphicId >= 0 && Art.IsValidStatic(SelectedGraphicId); pasteImageToolStripMenuItem.Enabled = selectedCount > 0 && ImageClipboard.ContainsImage(); - pasteImageToolStripMenuItem.Text = selectedCount > 1 ? $"Paste Image into {selectedCount}" : "Paste Image"; - removeToolStripMenuItem.Text = selectedCount > 1 ? $"Remove {selectedCount}" : "Remove"; - extractToolStripMenuItem.Text = selectedCount > 1 ? $"Export {selectedCount} Images..." : "Export Image.."; - replaceToolStripMenuItem.Text = selectedCount > 1 ? $"Replace {selectedCount}..." : "Replace..."; + + // 类型 12:菜单 Opening 事件中使用汉化基础文本构建动态文本 + string basePasteText = _localizationGetter?.Invoke("Forms.ItemsControl.pasteImageToolStripMenuItem") ?? "Paste Image"; + string baseRemoveText = _localizationGetter?.Invoke("Forms.ItemsControl.removeToolStripMenuItem") ?? "Remove"; + string baseExtractText = _localizationGetter?.Invoke("Forms.ItemsControl.extractToolStripMenuItem") ?? "Export Image.."; + string baseReplaceText = _localizationGetter?.Invoke("Forms.ItemsControl.replaceToolStripMenuItem") ?? "Replace..."; + string baseSelectTileDataText = _localizationGetter?.Invoke("Forms.ItemsControl.selectInTileDataTabToolStripMenuItem") ?? "Select in TileData tab"; + + pasteImageToolStripMenuItem.Text = selectedCount > 1 ? $"{basePasteText} {selectedCount}" : basePasteText; + removeToolStripMenuItem.Text = selectedCount > 1 ? $"{baseRemoveText} {selectedCount}" : baseRemoveText; + extractToolStripMenuItem.Text = selectedCount > 1 ? $"{baseExtractText.Replace("...", "")} {selectedCount}..." : baseExtractText; + replaceToolStripMenuItem.Text = selectedCount > 1 ? $"{baseReplaceText.Replace("...", "")} {selectedCount}..." : baseReplaceText; selectInTileDataTabToolStripMenuItem.Text = selectedCount > 1 - ? $"Select {selectedCount} in TileData tab" - : "Select in TileData tab"; + ? $"{baseSelectTileDataText.Replace(" tab", "")} {selectedCount} tab" + : baseSelectTileDataText; if (SelectedGraphicId <= 0) { @@ -1685,5 +1694,72 @@ private void SearchByNameToolStripButton_Click(object sender, EventArgs e) { SearchName(searchByNameToolStripTextBox.Text, true); } + + public void SetLocalization(Func getLocalized) + { + _localizationGetter = getLocalized; + ApplyLocalization(); + } + + private void ApplyLocalization() + { + if (_localizationGetter == null) + return; + + // ToolStrip Items + toolStripLabel1.Text = _localizationGetter("Forms.ItemsControl.toolStripLabel1") ?? "Index:"; + toolStripLabel2.Text = _localizationGetter("Forms.ItemsControl.toolStripLabel2") ?? "Name:"; + searchByNameToolStripButton.Text = _localizationGetter("Forms.ItemsControl.searchByNameToolStripButton") ?? "Find next"; + PreloadItemsToolStripButton.Text = _localizationGetter("Forms.ItemsControl.PreloadItemsToolStripButton") ?? "Preload Items"; + MiscToolStripDropDownButton.Text = _localizationGetter("Forms.ItemsControl.MiscToolStripDropDownButton") ?? "Misc"; + ExportAllToolStripMenuItem.Text = _localizationGetter("Forms.ItemsControl.ExportAllToolStripMenuItem") ?? "Export all.."; + + // Context Menu Items - Tile View + showFreeSlotsToolStripMenuItem.Text = _localizationGetter("Forms.ItemsControl.showFreeSlotsToolStripMenuItem") ?? "Show Free Slots"; + findNextFreeSlotToolStripMenuItem.Text = _localizationGetter("Forms.ItemsControl.findNextFreeSlotToolStripMenuItem") ?? "Find Next Free Slot"; + ChangeBackgroundColorToolStripMenuItem.Text = _localizationGetter("Forms.ItemsControl.ChangeBackgroundColorToolStripMenuItem") ?? "Change background color"; + extractToolStripMenuItem.Text = _localizationGetter("Forms.ItemsControl.extractToolStripMenuItem") ?? "Export Image.."; + bmpToolStripMenuItem.Text = _localizationGetter("Forms.ItemsControl.bmpToolStripMenuItem") ?? "As Bmp"; + tiffToolStripMenuItem.Text = _localizationGetter("Forms.ItemsControl.tiffToolStripMenuItem") ?? "As Tiff"; + asJpgToolStripMenuItem1.Text = _localizationGetter("Forms.ItemsControl.asJpgToolStripMenuItem1") ?? "As Jpg"; + asPngToolStripMenuItem1.Text = _localizationGetter("Forms.ItemsControl.asPngToolStripMenuItem1") ?? "As Png"; + selectInTileDataTabToolStripMenuItem.Text = _localizationGetter("Forms.ItemsControl.selectInTileDataTabToolStripMenuItem") ?? "Select in TileData tab"; + selectInRadarColorTabToolStripMenuItem.Text = _localizationGetter("Forms.ItemsControl.selectInRadarColorTabToolStripMenuItem") ?? "Select in RadarColor tab"; + selectInGumpsTabMaleToolStripMenuItem.Text = _localizationGetter("Forms.ItemsControl.selectInGumpsTabMaleToolStripMenuItem") ?? "Select in Gumps (M)"; + selectInGumpsTabFemaleToolStripMenuItem.Text = _localizationGetter("Forms.ItemsControl.selectInGumpsTabFemaleToolStripMenuItem") ?? "Select in Gumps (F)"; + copyImageToolStripMenuItem.Text = _localizationGetter("Forms.ItemsControl.copyImageToolStripMenuItem") ?? "Copy Image"; + pasteImageToolStripMenuItem.Text = _localizationGetter("Forms.ItemsControl.pasteImageToolStripMenuItem") ?? "Paste Image"; + replaceToolStripMenuItem.Text = _localizationGetter("Forms.ItemsControl.replaceToolStripMenuItem") ?? "Replace..."; + replaceStartingFromToolStripMenuItem.Text = _localizationGetter("Forms.ItemsControl.replaceStartingFromToolStripMenuItem") ?? "Replace starting from.."; + replaceFromFolderToolStripMenuItem.Text = _localizationGetter("Forms.ItemsControl.replaceFromFolderToolStripMenuItem") ?? "Replace from Folder..."; + insertAtToolStripMenuItem.Text = _localizationGetter("Forms.ItemsControl.insertAtToolStripMenuItem") ?? "Insert At.."; + removeToolStripMenuItem.Text = _localizationGetter("Forms.ItemsControl.removeToolStripMenuItem") ?? "Remove"; + saveToolStripMenuItem.Text = _localizationGetter("Forms.ItemsControl.saveToolStripMenuItem") ?? "Save"; + + // Context Menu Items - Detail Picture + changeBackgroundColorToolStripMenuItemDetail.Text = _localizationGetter("Forms.ItemsControl.changeBackgroundColorToolStripMenuItemDetail") ?? "Change background color"; + copyImageToolStripMenuItemDetail.Text = _localizationGetter("Forms.ItemsControl.copyImageToolStripMenuItemDetail") ?? "Copy Image"; + pasteImageToolStripMenuItemDetail.Text = _localizationGetter("Forms.ItemsControl.pasteImageToolStripMenuItemDetail") ?? "Paste Image"; + + // Export Formats + asBmpToolStripMenuItem.Text = _localizationGetter("Forms.ItemsControl.asBmpToolStripMenuItem") ?? "As Bmp"; + asTiffToolStripMenuItem.Text = _localizationGetter("Forms.ItemsControl.asTiffToolStripMenuItem") ?? "As Tiff"; + asJpgToolStripMenuItem.Text = _localizationGetter("Forms.ItemsControl.asJpgToolStripMenuItem") ?? "As Jpg"; + asPngToolStripMenuItem.Text = _localizationGetter("Forms.ItemsControl.asPngToolStripMenuItem") ?? "As Png"; + + // Status Bar + NameLabel.Text = _localizationGetter("Forms.ItemsControl.NameLabel") ?? "Name:"; + GraphicLabel.Text = _localizationGetter("Forms.ItemsControl.GraphicLabel") ?? "Graphic:"; + + // Re-apply DetailTextBox context menu localization + DetailTextBox.ContextMenuStrip = null; + DetailTextBox.AddBasicContextMenu(_localizationGetter); + + // Refresh detail if needed + if (_selectedGraphicId >= 0) + { + UpdateDetail(_selectedGraphicId); + } + } } } diff --git a/UoFiddler.Plugin.SendItem/SendItem.cs b/UoFiddler.Plugin.SendItem/SendItem.cs index cec569ff..19b0b3fb 100644 --- a/UoFiddler.Plugin.SendItem/SendItem.cs +++ b/UoFiddler.Plugin.SendItem/SendItem.cs @@ -144,7 +144,11 @@ private static void ToolStripClick(object sender, EventArgs e) private void EventsModifyItemsControlContextMenuEvent(ContextMenuStrip strip) { - ToolStripMenuItem item = new ToolStripMenuItem { Text = "Send Item to Client" }; + // 类型 13:插件动态菜单项汉化 + string menuText = PluginBase.LocalizationGetter?.Invoke("Forms.ItemsControl.ContextMenu.sendItemToClientToolStripMenuItem") + ?? "Send Item to Client"; + + ToolStripMenuItem item = new ToolStripMenuItem { Text = menuText }; item.Click += ItemShowContextClicked; strip.Items.Add(item); } diff --git a/UoFiddler/Forms/MainForm.cs b/UoFiddler/Forms/MainForm.cs index 973cfe74..bceba036 100644 --- a/UoFiddler/Forms/MainForm.cs +++ b/UoFiddler/Forms/MainForm.cs @@ -20,6 +20,7 @@ using Ultima.Helpers; using UoFiddler.Classes; using UoFiddler.Controls.Classes; +using UoFiddler.Controls.UserControls; using UoFiddler.Properties; using UoFiddler.Controls.Plugin; using UoFiddler.Localization; @@ -61,6 +62,15 @@ public MainForm(ILogger logger) hueControl.SetLocalization(key => LocalizationService.GetString(key)); multisControl.SetLocalization(key => LocalizationService.GetString(key)); animationsControl.SetLocalization(key => LocalizationService.GetString(key)); + + // 为 ItemsControl 设置汉化(通过遍历 TabPage 找到) + foreach (TabPage tab in TabPanel.TabPages) + { + if (tab.Controls[0] is ItemsControl itemsCtrl) + { + itemsCtrl.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 0c382eac..97e9d5da 100644 --- a/UoFiddler/Localization/Dictionaries/zh-CN.json +++ b/UoFiddler/Localization/Dictionaries/zh-CN.json @@ -592,6 +592,66 @@ "character": "角色" } }, + "ItemsControl": { + "showFreeSlotsToolStripMenuItem": "显示空闲槽位", + "findNextFreeSlotToolStripMenuItem": "查找下一个空闲槽位", + "ChangeBackgroundColorToolStripMenuItem": "改变背景颜色", + "changeBackgroundColorToolStripMenuItemDetail": "改变背景颜色", + "extractToolStripMenuItem": "导出图像..", + "bmpToolStripMenuItem": "导出为 BMP", + "tiffToolStripMenuItem": "导出为 TIFF", + "asJpgToolStripMenuItem1": "导出为 JPG", + "asPngToolStripMenuItem1": "导出为 PNG", + "selectInTileDataTabToolStripMenuItem": "在 TileData 标签中选择", + "selectInRadarColorTabToolStripMenuItem": "在 RadarColor 标签中选择", + "selectInGumpsTabMaleToolStripMenuItem": "在 Gumps 标签中选择 (男)", + "selectInGumpsTabFemaleToolStripMenuItem": "在 Gumps 标签中选择 (女)", + "copyImageToolStripMenuItem": "复制图像", + "pasteImageToolStripMenuItem": "粘贴图像", + "copyImageToolStripMenuItemDetail": "复制图像", + "pasteImageToolStripMenuItemDetail": "粘贴图像", + "replaceToolStripMenuItem": "替换...", + "replaceStartingFromToolStripMenuItem": "从...开始替换", + "replaceFromFolderToolStripMenuItem": "从文件夹替换...", + "insertAtToolStripMenuItem": "在...处插入", + "removeToolStripMenuItem": "移除", + "saveToolStripMenuItem": "保存", + "toolStripLabel1": "索引:", + "toolStripLabel2": "名称:", + "searchByNameToolStripButton": "查找下一个", + "PreloadItemsToolStripButton": "预加载物品", + "MiscToolStripDropDownButton": "其他", + "ExportAllToolStripMenuItem": "导出所有..", + "asBmpToolStripMenuItem": "导出为 BMP", + "asTiffToolStripMenuItem": "导出为 TIFF", + "asJpgToolStripMenuItem": "导出为 JPG", + "asPngToolStripMenuItem": "导出为 PNG", + "NameLabel": "名称:", + "GraphicLabel": "图形:", + "DetailLabels": { + "Name": "名称", + "Graphic": "图形", + "HeightCapacity": "高度/容量", + "Weight": "重量", + "Animation": "动画", + "QualityLayerLight": "品质/层/光", + "Quantity": "数量", + "Hue": "色调", + "StackingOffsetUnk4": "堆叠偏移/Unk4", + "Flags": "标志", + "GraphicPixelSizeWidthHeight": "图形像素尺寸 宽, 高", + "GraphicPixelOffsetXMinYMinXMaxYMax": "图形像素偏移 xMin, yMin, xMax, yMax", + "AnimationFrameCount": "动画帧数", + "AnimationInterval": "动画间隔" + }, + "DetailTextBoxContextMenu": { + "Copy": "复制", + "SelectAll": "全选" + }, + "ContextMenu": { + "sendItemToClientToolStripMenuItem": "发送物品到客户端" + } + }, "AnimationListControl": { "searchToolStripLabel": "搜索:", "removeToolStripMenuItem": "移除", From 084b639c38693da1dfc2c359593f66b5cd7de428 Mon Sep 17 00:00:00 2001 From: nbyaya Date: Tue, 6 Oct 2026 17:19:14 +0800 Subject: [PATCH 35/76] =?UTF-8?q?=E6=B1=89=E5=8C=96=20ItemsControl=20?= =?UTF-8?q?=E7=8A=B6=E6=80=81=E6=A0=8F=E6=A0=87=E7=AD=BE=20(Type=208)?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- UoFiddler.Controls/UserControls/ItemsControl.cs | 8 ++++++-- 1 file changed, 6 insertions(+), 2 deletions(-) diff --git a/UoFiddler.Controls/UserControls/ItemsControl.cs b/UoFiddler.Controls/UserControls/ItemsControl.cs index 12a0ef94..afdfa395 100644 --- a/UoFiddler.Controls/UserControls/ItemsControl.cs +++ b/UoFiddler.Controls/UserControls/ItemsControl.cs @@ -856,8 +856,12 @@ private void UpdateToolStripLabels(int graphic) return; } - NameLabel.Text = !Art.IsValidStatic(graphic) ? "Name: FREE" : $"Name: {TileData.ItemTable[graphic].Name}"; - GraphicLabel.Text = $"Graphic: 0x{graphic:X4} ({graphic})"; + // Type 8: 获取汉化的基础标签文本,然后添加动态信息 + string nameLabel = _localizationGetter?.Invoke("Forms.ItemsControl.NameLabel") ?? "Name:"; + string graphicLabel = _localizationGetter?.Invoke("Forms.ItemsControl.GraphicLabel") ?? "Graphic:"; + + NameLabel.Text = !Art.IsValidStatic(graphic) ? $"{nameLabel} FREE" : $"{nameLabel} {TileData.ItemTable[graphic].Name}"; + GraphicLabel.Text = $"{graphicLabel} 0x{graphic:X4} ({graphic})"; } private void OnClickSave(object sender, EventArgs e) From d020ad1b834beac2c2f86585d2e72f81b13e2cfe Mon Sep 17 00:00:00 2001 From: nbyaya Date: Tue, 6 Oct 2026 17:22:36 +0800 Subject: [PATCH 36/76] =?UTF-8?q?=E6=B1=89=E5=8C=96=20ItemsControl=20Save?= =?UTF-8?q?=20=E6=8C=89=E9=92=AE?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- UoFiddler.Controls/UserControls/ItemsControl.cs | 2 ++ 1 file changed, 2 insertions(+) diff --git a/UoFiddler.Controls/UserControls/ItemsControl.cs b/UoFiddler.Controls/UserControls/ItemsControl.cs index afdfa395..20f06274 100644 --- a/UoFiddler.Controls/UserControls/ItemsControl.cs +++ b/UoFiddler.Controls/UserControls/ItemsControl.cs @@ -1739,6 +1739,8 @@ private void ApplyLocalization() insertAtToolStripMenuItem.Text = _localizationGetter("Forms.ItemsControl.insertAtToolStripMenuItem") ?? "Insert At.."; removeToolStripMenuItem.Text = _localizationGetter("Forms.ItemsControl.removeToolStripMenuItem") ?? "Remove"; saveToolStripMenuItem.Text = _localizationGetter("Forms.ItemsControl.saveToolStripMenuItem") ?? "Save"; + saveToolStripButton.Text = _localizationGetter("Forms.ItemsControl.saveToolStripMenuItem") ?? "Save"; + saveToolStripButton.ToolTipText = _localizationGetter("Forms.ItemsControl.saveToolStripMenuItem") ?? "Save"; // Context Menu Items - Detail Picture changeBackgroundColorToolStripMenuItemDetail.Text = _localizationGetter("Forms.ItemsControl.changeBackgroundColorToolStripMenuItemDetail") ?? "Change background color"; From 9bad3935e5f931e42f00271c08b60356657b6566 Mon Sep 17 00:00:00 2001 From: nbyaya Date: Tue, 6 Oct 2026 17:24:15 +0800 Subject: [PATCH 37/76] =?UTF-8?q?=E6=B1=89=E5=8C=96=20ItemsControl=20?= =?UTF-8?q?=E4=BF=9D=E5=AD=98=E7=A1=AE=E8=AE=A4=E6=8F=90=E7=A4=BA=20(Type?= =?UTF-8?q?=206)?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- UoFiddler.Controls/UserControls/ItemsControl.cs | 6 +++++- UoFiddler/Localization/Dictionaries/zh-CN.json | 4 ++++ 2 files changed, 9 insertions(+), 1 deletion(-) diff --git a/UoFiddler.Controls/UserControls/ItemsControl.cs b/UoFiddler.Controls/UserControls/ItemsControl.cs index 20f06274..e6ac5f28 100644 --- a/UoFiddler.Controls/UserControls/ItemsControl.cs +++ b/UoFiddler.Controls/UserControls/ItemsControl.cs @@ -866,7 +866,11 @@ private void UpdateToolStripLabels(int graphic) private void OnClickSave(object sender, EventArgs e) { - DialogResult result = MessageBox.Show("Are you sure? Will take a while", "Save", MessageBoxButtons.YesNo, + // Type 6: MessageBox 文本汉化 + string confirmMessage = _localizationGetter?.Invoke("Forms.ItemsControl.Messages.SaveConfirmation") ?? "Are you sure? Will take a while"; + string saveTitle = _localizationGetter?.Invoke("Forms.ItemsControl.Messages.SaveTitle") ?? "Save"; + + DialogResult result = MessageBox.Show(confirmMessage, saveTitle, MessageBoxButtons.YesNo, MessageBoxIcon.Warning, MessageBoxDefaultButton.Button2); if (result != DialogResult.Yes) diff --git a/UoFiddler/Localization/Dictionaries/zh-CN.json b/UoFiddler/Localization/Dictionaries/zh-CN.json index 97e9d5da..1195707f 100644 --- a/UoFiddler/Localization/Dictionaries/zh-CN.json +++ b/UoFiddler/Localization/Dictionaries/zh-CN.json @@ -650,6 +650,10 @@ }, "ContextMenu": { "sendItemToClientToolStripMenuItem": "发送物品到客户端" + }, + "Messages": { + "SaveConfirmation": "确定吗?这需要一些时间", + "SaveTitle": "保存" } }, "AnimationListControl": { From 7399bdc53a226d8871b547e3f59d43616b850b0d Mon Sep 17 00:00:00 2001 From: nbyaya Date: Tue, 6 Oct 2026 18:01:54 +0800 Subject: [PATCH 38/76] =?UTF-8?q?=E6=B1=89=E5=8C=96=20LandTilesControl=20?= =?UTF-8?q?=E5=9C=B0=E5=BD=A2=E5=9B=BE=E5=9D=97=E7=AA=97=E5=8F=A3=E5=86=85?= =?UTF-8?q?=E5=AE=B9?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit - 48 个菜单项、按钮、标签、对话框词条 - 修复 Type 12 Opening 事件动态文本覆盖问题 --- .../UserControls/LandTilesControl.cs | 116 +++++++++++++++--- UoFiddler/Forms/MainForm.cs | 1 + .../Localization/Dictionaries/zh-CN.json | 96 +++++++++++++++ 3 files changed, 196 insertions(+), 17 deletions(-) diff --git a/UoFiddler.Controls/UserControls/LandTilesControl.cs b/UoFiddler.Controls/UserControls/LandTilesControl.cs index db81f395..0557c052 100644 --- a/UoFiddler.Controls/UserControls/LandTilesControl.cs +++ b/UoFiddler.Controls/UserControls/LandTilesControl.cs @@ -53,6 +53,7 @@ public LandTilesControl() private int _selectedGraphicId = -1; private readonly List _tileList = new List(); private bool _showFreeSlots; + private Func? _localizationGetter; [DesignerSerializationVisibility(DesignerSerializationVisibility.Hidden)] public int SelectedGraphicId @@ -227,9 +228,14 @@ private void UpdateToolStripLabels(int graphic) return; } - NameLabel.Text = $"Name: {TileData.LandTable[graphic].Name}"; - GraphicLabel.Text = string.Format("ID: 0x{0:X4} ({0})", graphic); - FlagsLabel.Text = $"Flags: {TileData.LandTable[graphic].Flags}"; + // Type 8: 获取汉化的基础标签文本,然后添加动态信息 + string nameLabel = _localizationGetter?.Invoke("Forms.LandTilesControl.NameLabel") ?? "Name:"; + string graphicLabel = _localizationGetter?.Invoke("Forms.LandTilesControl.GraphicLabel") ?? "ID:"; + string flagsLabel = _localizationGetter?.Invoke("Forms.LandTilesControl.FlagsLabel") ?? "Flags:"; + + NameLabel.Text = $"{nameLabel} {TileData.LandTable[graphic].Name}"; + GraphicLabel.Text = $"{graphicLabel} 0x{graphic:X4} ({graphic})"; + FlagsLabel.Text = $"{flagsLabel} {TileData.LandTable[graphic].Flags}"; } private void OnTileDataChangeEvent(object sender, int id) @@ -353,12 +359,15 @@ private void OnClickRemove(object sender, EventArgs e) return; } + // Type 6: MessageBox 确认对话框汉化 string prompt = ids.Count == 1 - ? $"Are you sure to remove {ids[0]}" - : $"Are you sure to remove {ids.Count} land tiles?"; + ? _localizationGetter?.Invoke($"Forms.LandTilesControl.Messages.RemoveSingleConfirm")?.Replace("{0}", ids[0].ToString()) ?? $"Are you sure to remove {ids[0]}" + : _localizationGetter?.Invoke($"Forms.LandTilesControl.Messages.RemoveMultipleConfirm")?.Replace("{0}", ids.Count.ToString()) ?? $"Are you sure to remove {ids.Count} land tiles?"; + + string removeTitle = _localizationGetter?.Invoke("Forms.LandTilesControl.Messages.RemoveTitle") ?? "Save"; DialogResult result = - MessageBox.Show(prompt, "Save", + MessageBox.Show(prompt, removeTitle, MessageBoxButtons.YesNo, MessageBoxIcon.Question, MessageBoxDefaultButton.Button1); if (result != DialogResult.Yes) { @@ -438,9 +447,14 @@ private void OnClickPasteImage(object sender, EventArgs e) if (ids.Count > 1) { + // Type 6: 粘贴确认对话框汉化 + string pasteConfirm = _localizationGetter?.Invoke("Forms.LandTilesControl.Messages.PasteMultipleConfirm")?.Replace("{0}", ids.Count.ToString()) + ?? $"Paste this image into {ids.Count} selected land tiles?"; + string pasteTitle = _localizationGetter?.Invoke("Forms.LandTilesControl.Messages.PasteImageTitle") ?? "Paste Image"; + DialogResult confirm = MessageBox.Show( - $"Paste this image into {ids.Count} selected land tiles?", - "Paste Image", MessageBoxButtons.YesNo, MessageBoxIcon.Question, + pasteConfirm, + pasteTitle, MessageBoxButtons.YesNo, MessageBoxIcon.Question, MessageBoxDefaultButton.Button2); if (confirm != DialogResult.Yes) @@ -718,8 +732,12 @@ private void OnKeyDownInsert(object sender, KeyEventArgs e) private void OnClickSave(object sender, EventArgs e) { + // Type 6: Save 确认对话框汉化 + string saveConfirm = _localizationGetter?.Invoke("Forms.LandTilesControl.Messages.SaveConfirmation") ?? "Are you sure? Will take a while"; + string saveTitle = _localizationGetter?.Invoke("Forms.LandTilesControl.Messages.SaveTitle") ?? "Save"; + DialogResult result = - MessageBox.Show("Are you sure? Will take a while", "Save", + MessageBox.Show(saveConfirm, saveTitle, MessageBoxButtons.YesNo, MessageBoxIcon.Warning, MessageBoxDefaultButton.Button2); if (result != DialogResult.Yes) { @@ -788,7 +806,7 @@ private void ExportMultipleLandTileImages(List ids, ImageFormat imageFormat FileSavedDialog.Show(FindForm(), Options.OutputPath, $"{ids.Count} land tiles saved successfully."); } - private static void ExportLandTileImage(int index, ImageFormat imageFormat) + private void ExportLandTileImage(int index, ImageFormat imageFormat) { if (!Art.IsValidLand(index)) { @@ -803,7 +821,9 @@ private static void ExportLandTileImage(int index, ImageFormat imageFormat) bit.Save(fileName, imageFormat); } - MessageBox.Show($"Landtile saved to {fileName}", "Saved", MessageBoxButtons.OK, MessageBoxIcon.Information, + string message = _localizationGetter?.Invoke("Forms.LandTilesControl.Messages.LandtileSavedTo") ?? "Landtile saved to"; + string title = _localizationGetter?.Invoke("Forms.LandTilesControl.Messages.Saved") ?? "Saved"; + MessageBox.Show($"{message} {fileName}", title, MessageBoxButtons.OK, MessageBoxIcon.Information, MessageBoxDefaultButton.Button1); } @@ -849,13 +869,21 @@ private void LandTilesContextMenuStrip_Opening(object sender, System.ComponentMo int selectedCount = LandTilesTileView.SelectedIndices.Count; copyImageToolStripMenuItem.Enabled = _selectedGraphicId >= 0 && Art.IsValidLand(_selectedGraphicId); pasteImageToolStripMenuItem.Enabled = selectedCount > 0 && ImageClipboard.ContainsImage(); - pasteImageToolStripMenuItem.Text = selectedCount > 1 ? $"Paste Image into {selectedCount}" : "Paste Image"; - removeToolStripMenuItem.Text = selectedCount > 1 ? $"Remove {selectedCount}" : "Remove"; - exportImageToolStripMenuItem.Text = selectedCount > 1 ? $"Export {selectedCount} Images..." : "Export Image.."; - replaceToolStripMenuItem.Text = selectedCount > 1 ? $"Replace {selectedCount}" : "Replace"; + + // ✅ Type 12 汉化:使用汉化基础文本构建动态文本 + string basePasteText = _localizationGetter?.Invoke("Forms.LandTilesControl.pasteImageToolStripMenuItem") ?? "Paste Image"; + string baseRemoveText = _localizationGetter?.Invoke("Forms.LandTilesControl.removeToolStripMenuItem") ?? "Remove"; + string baseExportText = _localizationGetter?.Invoke("Forms.LandTilesControl.exportImageToolStripMenuItem") ?? "Export Image.."; + string baseReplaceText = _localizationGetter?.Invoke("Forms.LandTilesControl.replaceToolStripMenuItem") ?? "Replace"; + string baseSelectTileDataText = _localizationGetter?.Invoke("Forms.LandTilesControl.selectInTileDataTabToolStripMenuItem") ?? "Select in TileData tab"; + + pasteImageToolStripMenuItem.Text = selectedCount > 1 ? $"{basePasteText} {selectedCount}" : basePasteText; + removeToolStripMenuItem.Text = selectedCount > 1 ? $"{baseRemoveText} {selectedCount}" : baseRemoveText; + exportImageToolStripMenuItem.Text = selectedCount > 1 ? $"{baseExportText.Replace("...", "")} {selectedCount}..." : baseExportText; + replaceToolStripMenuItem.Text = selectedCount > 1 ? $"{baseReplaceText} {selectedCount}" : baseReplaceText; selectInTileDataTabToolStripMenuItem.Text = selectedCount > 1 - ? $"Select {selectedCount} in TileData tab" - : "Select in TileData tab"; + ? $"{baseSelectTileDataText.Replace(" tab", "")} {selectedCount} tab" + : baseSelectTileDataText; bool hasTexture = _selectedGraphicId >= 0 && TileData.LandTable[_selectedGraphicId].TextureId != 0 @@ -1392,5 +1420,59 @@ private void SearchByNameToolStripButton_Click(object sender, EventArgs e) { SearchName(searchByNameToolStripTextBox.Text, true); } + + public void SetLocalization(Func? getLocalized) + { + _localizationGetter = getLocalized; + ApplyLocalization(); + } + + private void ApplyLocalization() + { + if (_localizationGetter == null) return; + + // Menu Items + showFreeSlotsToolStripMenuItem.Text = _localizationGetter("Forms.LandTilesControl.showFreeSlotsToolStripMenuItem") ?? "Show Free Slots"; + findNextFreeSlotToolStripMenuItem.Text = _localizationGetter("Forms.LandTilesControl.findNextFreeSlotToolStripMenuItem") ?? "Find Next Free Slot"; + changeBackgroundColorToolStripMenuItem.Text = _localizationGetter("Forms.LandTilesControl.changeBackgroundColorToolStripMenuItem") ?? "Change background color"; + exportImageToolStripMenuItem.Text = _localizationGetter("Forms.LandTilesControl.exportImageToolStripMenuItem") ?? "Export Image.."; + asBmpToolStripMenuItem.Text = _localizationGetter("Forms.LandTilesControl.asBmpToolStripMenuItem") ?? "As Bmp"; + asTiffToolStripMenuItem.Text = _localizationGetter("Forms.LandTilesControl.asTiffToolStripMenuItem") ?? "As Tiff"; + asJpgToolStripMenuItem1.Text = _localizationGetter("Forms.LandTilesControl.asJpgToolStripMenuItem1") ?? "As Jpg"; + asPngToolStripMenuItem.Text = _localizationGetter("Forms.LandTilesControl.asPngToolStripMenuItem") ?? "As Png"; + selectInTileDataTabToolStripMenuItem.Text = _localizationGetter("Forms.LandTilesControl.selectInTileDataTabToolStripMenuItem") ?? "Select in TileData tab"; + selectInRadarColorTabToolStripMenuItem.Text = _localizationGetter("Forms.LandTilesControl.selectInRadarColorTabToolStripMenuItem") ?? "Select in RadarColor tab"; + selectInTexturesTabToolStripMenuItem.Text = _localizationGetter("Forms.LandTilesControl.selectInTexturesTabToolStripMenuItem") ?? "Select in Textures tab"; + copyImageToolStripMenuItem.Text = _localizationGetter("Forms.LandTilesControl.copyImageToolStripMenuItem") ?? "Copy Image"; + pasteImageToolStripMenuItem.Text = _localizationGetter("Forms.LandTilesControl.pasteImageToolStripMenuItem") ?? "Paste Image"; + replaceToolStripMenuItem.Text = _localizationGetter("Forms.LandTilesControl.replaceToolStripMenuItem") ?? "Replace"; + replaceStartingFromToolStripMenuItem.Text = _localizationGetter("Forms.LandTilesControl.replaceStartingFromToolStripMenuItem") ?? "Replace starting from.."; + replaceFromFolderToolStripMenuItem.Text = _localizationGetter("Forms.LandTilesControl.replaceFromFolderToolStripMenuItem") ?? "Replace from Folder..."; + insertAtToolStripMenuItem.Text = _localizationGetter("Forms.LandTilesControl.insertAtToolStripMenuItem") ?? "Insert At.."; + removeToolStripMenuItem.Text = _localizationGetter("Forms.LandTilesControl.removeToolStripMenuItem") ?? "Remove"; + saveToolStripMenuItem.Text = _localizationGetter("Forms.LandTilesControl.saveToolStripMenuItem") ?? "Save"; + + // Toolbar Labels + IndexToolStripLabel.Text = _localizationGetter("Forms.LandTilesControl.IndexToolStripLabel") ?? "Index:"; + NameToolStripLabel.Text = _localizationGetter("Forms.LandTilesControl.NameToolStripLabel") ?? "Name:"; + searchByNameToolStripButton.Text = _localizationGetter("Forms.LandTilesControl.searchByNameToolStripButton") ?? "Find next"; + + // Misc Menu + MiscToolStripDropDownButton.Text = _localizationGetter("Forms.LandTilesControl.MiscToolStripDropDownButton") ?? "Misc"; + exportAllToolStripMenuItem.Text = _localizationGetter("Forms.LandTilesControl.exportAllToolStripMenuItem") ?? "Export All.."; + ExportAllAsBmp.Text = _localizationGetter("Forms.LandTilesControl.ExportAllAsBmp") ?? "As Bmp"; + ExportAllAsTiff.Text = _localizationGetter("Forms.LandTilesControl.ExportAllAsTiff") ?? "As Tiff"; + asJpgToolStripMenuItem.Text = _localizationGetter("Forms.LandTilesControl.asJpgToolStripMenuItem") ?? "As Jpg"; + asPngToolStripMenuItem1.Text = _localizationGetter("Forms.LandTilesControl.asPngToolStripMenuItem1") ?? "As Png"; + + // Save Button + SaveButton.Text = _localizationGetter("Forms.LandTilesControl.SaveButton") ?? "Save"; + SaveButton.ToolTipText = _localizationGetter("Forms.LandTilesControl.SaveButton") ?? "Save"; + + // Status Bar Labels + NameLabel.Text = _localizationGetter("Forms.LandTilesControl.NameLabel") ?? "Name:"; + GraphicLabel.Text = _localizationGetter("Forms.LandTilesControl.GraphicLabel") ?? "Graphic:"; + FlagsLabel.Text = _localizationGetter("Forms.LandTilesControl.FlagsLabel") ?? "Flags:"; + } } } diff --git a/UoFiddler/Forms/MainForm.cs b/UoFiddler/Forms/MainForm.cs index bceba036..dbc1e1cb 100644 --- a/UoFiddler/Forms/MainForm.cs +++ b/UoFiddler/Forms/MainForm.cs @@ -62,6 +62,7 @@ public MainForm(ILogger logger) hueControl.SetLocalization(key => LocalizationService.GetString(key)); multisControl.SetLocalization(key => LocalizationService.GetString(key)); animationsControl.SetLocalization(key => LocalizationService.GetString(key)); + landTilesControl.SetLocalization(key => LocalizationService.GetString(key)); // 为 ItemsControl 设置汉化(通过遍历 TabPage 找到) foreach (TabPage tab in TabPanel.TabPages) diff --git a/UoFiddler/Localization/Dictionaries/zh-CN.json b/UoFiddler/Localization/Dictionaries/zh-CN.json index 1195707f..6375c4f5 100644 --- a/UoFiddler/Localization/Dictionaries/zh-CN.json +++ b/UoFiddler/Localization/Dictionaries/zh-CN.json @@ -654,6 +654,69 @@ "Messages": { "SaveConfirmation": "确定吗?这需要一些时间", "SaveTitle": "保存" + }, + "ToolStripTextBoxContextMenu": { + "Copy": "复制", + "Paste": "粘贴", + "Cut": "剪切", + "SelectAll": "全选", + "Delete": "删除" + } + }, + "LandTilesControl": { + "showFreeSlotsToolStripMenuItem": "显示空闲槽位", + "findNextFreeSlotToolStripMenuItem": "查找下一个空闲槽位", + "changeBackgroundColorToolStripMenuItem": "改变背景颜色", + "exportImageToolStripMenuItem": "导出图像..", + "asBmpToolStripMenuItem": "导出为 BMP", + "asTiffToolStripMenuItem": "导出为 TIFF", + "asJpgToolStripMenuItem1": "导出为 JPG", + "asPngToolStripMenuItem": "导出为 PNG", + "selectInTileDataTabToolStripMenuItem": "在 TileData 标签中选择", + "selectInRadarColorTabToolStripMenuItem": "在 RadarColor 标签中选择", + "selectInTexturesTabToolStripMenuItem": "在 Textures 标签中选择", + "copyImageToolStripMenuItem": "复制图像", + "pasteImageToolStripMenuItem": "粘贴图像", + "replaceToolStripMenuItem": "替换", + "replaceStartingFromToolStripMenuItem": "从...开始替换", + "replaceFromFolderToolStripMenuItem": "从文件夹替换...", + "insertAtToolStripMenuItem": "在...处插入", + "removeToolStripMenuItem": "移除", + "saveToolStripMenuItem": "保存", + "IndexToolStripLabel": "索引:", + "NameToolStripLabel": "名称:", + "searchByNameToolStripButton": "查找下一个", + "MiscToolStripDropDownButton": "其他", + "exportAllToolStripMenuItem": "导出所有..", + "ExportAllAsBmp": "导出为 BMP", + "ExportAllAsTiff": "导出为 TIFF", + "asJpgToolStripMenuItem": "导出为 JPG", + "asPngToolStripMenuItem1": "导出为 PNG", + "SaveButton": "保存", + "NameLabel": "名称:", + "GraphicLabel": "ID:", + "FlagsLabel": "标志:", + "Messages": { + "RemoveSingleConfirm": "确定要移除 0x{0} 吗?", + "RemoveMultipleConfirm": "确定要移除 {0} 个地形图块吗?", + "RemoveTitle": "保存", + "PasteMultipleConfirm": "粘贴此图像到 {0} 个选定的地形图块吗?", + "PasteImageTitle": "粘贴图像", + "SaveConfirmation": "确定吗?这需要一些时间", + "SaveTitle": "保存", + "SaveSuccess": "地形图块已保存到 {0}", + "SavedTitle": "已保存", + "CopyImageError": "复制图像失败", + "CopyImageTitle": "复制图像", + "PasteImageError": "粘贴图像失败", + "InvalidSizeTitle": "无效尺寸", + "InvalidSizeMessage": "无效的地形图块尺寸!地形图块必须是 44x44 像素。没有做任何更改。", + "SelectionMismatchTitle": "选择不匹配", + "SelectionMismatchMessage": "选中 {0} 个地形图块但选择了 {1} 个图像。没有做任何更改。", + "ImageTooLargeTitle": "图像过大", + "ImageTooLargeMessage": "图像对于 MUL 格式太大!预计编码大小:{0} ushorts,最大允许:{1} ushorts。没有做任何更改。", + "LoadTexturesFirst": "你需要先加载 Textures 标签。", + "LoadTexturesTitle": "信息" } }, "AnimationListControl": { @@ -836,6 +899,39 @@ "legendLabelDifferent": "不同值", "legendLabelIdentical": "相同" }, + "LandTilesControl": { + "Title": "地形图块", + "MenuItems": { + "addLandTile": "添加地形图块", + "removeLandTile": "删除地形图块", + "copyLandTile": "复制地形图块", + "pasteLandTile": "粘贴地形图块", + "exportLandTileImage": "导出地形图块图像", + "importLandTileImage": "导入地形图块图像", + "selectAllLandTiles": "全选" + }, + "Labels": { + "detailLabel": "详情", + "idLabel": "ID: ", + "nameLabel": "名称: ", + "graphicLabel": "纹理ID: ", + "flagsLabel": "标志: ", + "statusLabel": "就绪" + }, + "Messages": { + "removeConfirmSingle": "确定要删除该地形图块吗?", + "removeConfirmMultiple": "确定要删除这些地形图块吗?", + "pasteConfirm": "是否确认粘贴?这将覆盖当前条目。", + "SaveConfirmation": "是否保存更改?", + "SaveTitle": "保存确认", + "LandtileSavedTo": "地形图块已保存至", + "Saved": "已保存" + }, + "DetailTextBoxContextMenu": { + "Copy": "复制", + "SelectAll": "全选" + } + }, "CompareTileDataControl": { "btnCopyLandSelected": "复制选定项", "btnCopyLandAllDiff": "复制所有差异", From ce7b1d5b2c75d74a527562539b606a5f74f4e371 Mon Sep 17 00:00:00 2001 From: nbyaya Date: Tue, 6 Oct 2026 18:44:23 +0800 Subject: [PATCH 39/76] =?UTF-8?q?=E6=B1=89=E5=8C=96=20TexturesControl=20?= =?UTF-8?q?=E7=BA=B9=E7=90=86=E7=AA=97=E5=8F=A3?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit - 添加 35 个汉化词条到 zh-CN.json - TexturesControl.cs 实现 SetLocalization/ApplyLocalization 方法 - 修复 contextMenuStrip_Opening 中的 Type 12 动态文本覆盖问题 - 为 FileSavedDialog 添加汉化支持(Type 11) - MainForm 集成 TexturesControl 汉化调用 --- UoFiddler.Controls/Forms/FileSavedDialog.cs | 32 ++++++++ .../UserControls/TexturesControl.cs | 80 +++++++++++++++++-- UoFiddler/Forms/MainForm.cs | 1 + .../Localization/Dictionaries/zh-CN.json | 50 ++++++++++++ 4 files changed, 157 insertions(+), 6 deletions(-) diff --git a/UoFiddler.Controls/Forms/FileSavedDialog.cs b/UoFiddler.Controls/Forms/FileSavedDialog.cs index aebcb92d..95032f6d 100644 --- a/UoFiddler.Controls/Forms/FileSavedDialog.cs +++ b/UoFiddler.Controls/Forms/FileSavedDialog.cs @@ -13,6 +13,7 @@ namespace UoFiddler.Controls.Forms public sealed partial class FileSavedDialog : Form { private readonly string _filePath; + private Func? _localizationGetter; public FileSavedDialog(string filePath, string message = null, string title = null) { @@ -32,6 +33,37 @@ public FileSavedDialog(string filePath, string message = null, string title = nu pathLabel.Text = _filePath; } + /// + /// Sets the localization getter and applies localized text. + /// + public void SetLocalization(Func? getLocalized) + { + _localizationGetter = getLocalized; + ApplyLocalization(); + } + + /// + /// Applies localized text to UI elements. + /// + private void ApplyLocalization() + { + if (_localizationGetter == null) return; + + // Localize title + var title = _localizationGetter("Forms.FileSavedDialog.Title"); + if (title != null) + Text = title; + + // Localize status label if not already set to custom message + var saveSuccess = _localizationGetter("Forms.FileSavedDialog.SaveSuccess"); + if (saveSuccess != null && statusLabel.Text == "File saved successfully.") + statusLabel.Text = saveSuccess; + + // Localize buttons + buttonOpenFolder.Text = _localizationGetter("Forms.FileSavedDialog.OpenFolder") ?? "Open Folder"; + buttonOk.Text = _localizationGetter("Forms.FileSavedDialog.OK") ?? "OK"; + } + private void OnOpenFolderClick(object sender, EventArgs e) { try diff --git a/UoFiddler.Controls/UserControls/TexturesControl.cs b/UoFiddler.Controls/UserControls/TexturesControl.cs index c02ba781..2840adbd 100644 --- a/UoFiddler.Controls/UserControls/TexturesControl.cs +++ b/UoFiddler.Controls/UserControls/TexturesControl.cs @@ -40,6 +40,9 @@ public TexturesControl() private bool _showFreeSlots; private bool _loaded; private int _selectedTextureId = -1; + + // 汉化支持 + private Func? _localizationGetter; [DesignerSerializationVisibility(DesignerSerializationVisibility.Hidden)] public int SelectedTextureId @@ -609,7 +612,13 @@ private void OnClickSave(object sender, EventArgs e) Options.ChangedUltimaClass["Texture"] = false; - FileSavedDialog.Show(FindForm(), Options.OutputPath, "Files saved successfully."); + // Create and localize FileSavedDialog (Type 11) + string title = _localizationGetter?.Invoke("Forms.FileSavedDialog.Title") ?? "Files saved successfully."; + string message = _localizationGetter?.Invoke("Forms.FileSavedDialog.SaveSuccess") ?? "Files saved successfully."; + + var dialog = new FileSavedDialog(Options.OutputPath, message, title); + dialog.SetLocalization(_localizationGetter); + dialog.ShowDialog(FindForm()); } private void OnClickExportBmp(object sender, EventArgs e) @@ -668,7 +677,14 @@ private void ExportMultipleTextureImages(List ids, ImageFormat imageFormat) } } - FileSavedDialog.Show(FindForm(), Options.OutputPath, $"{ids.Count} textures saved successfully."); + // Create and localize FileSavedDialog (Type 11) + string title = _localizationGetter?.Invoke("Forms.FileSavedDialog.Title") ?? "Files saved successfully."; + string message = _localizationGetter?.Invoke("Forms.FileSavedDialog.SaveSuccess") + ?? $"{ids.Count} textures saved successfully."; + + var dialog = new FileSavedDialog(Options.OutputPath, message, title); + dialog.SetLocalization(_localizationGetter); + dialog.ShowDialog(FindForm()); } private static void ExportTextureImage(int index, ImageFormat imageFormat) @@ -1049,10 +1065,17 @@ private void contextMenuStrip_Opening(object sender, System.ComponentModel.Cance int selectedCount = TextureTileView.SelectedIndices.Count; copyImageToolStripMenuItem.Enabled = _selectedTextureId >= 0 && Textures.TestTexture(_selectedTextureId); pasteImageToolStripMenuItem.Enabled = selectedCount > 0 && ImageClipboard.ContainsImage(); - pasteImageToolStripMenuItem.Text = selectedCount > 1 ? $"Paste Image into {selectedCount}" : "Paste Image"; - removeToolStripMenuItem.Text = selectedCount > 1 ? $"Remove {selectedCount}" : "Remove"; - exportImageToolStripMenuItem.Text = selectedCount > 1 ? $"Export {selectedCount} Images..." : "Export Image.."; - replaceToolStripMenuItem.Text = selectedCount > 1 ? $"Replace {selectedCount}" : "Replace"; + + // ✅ Type 12 汉化:使用汉化基础文本构建动态文本 + string basePasteText = _localizationGetter?.Invoke("Forms.TexturesControl.pasteImageToolStripMenuItem") ?? "Paste Image"; + string baseRemoveText = _localizationGetter?.Invoke("Forms.TexturesControl.removeToolStripMenuItem") ?? "Remove"; + string baseExportText = _localizationGetter?.Invoke("Forms.TexturesControl.exportImageToolStripMenuItem") ?? "Export Image.."; + string baseReplaceText = _localizationGetter?.Invoke("Forms.TexturesControl.replaceToolStripMenuItem") ?? "Replace"; + + pasteImageToolStripMenuItem.Text = selectedCount > 1 ? $"{basePasteText} {selectedCount}" : basePasteText; + removeToolStripMenuItem.Text = selectedCount > 1 ? $"{baseRemoveText} {selectedCount}" : baseRemoveText; + exportImageToolStripMenuItem.Text = selectedCount > 1 ? $"{baseExportText.Replace("...", "")} {selectedCount}..." : baseExportText; + replaceToolStripMenuItem.Text = selectedCount > 1 ? $"{baseReplaceText} {selectedCount}" : baseReplaceText; bool hasLandTile = _selectedTextureId >= 0 && _selectedTextureId < 0x4000 @@ -1083,5 +1106,50 @@ private void SearchByIdToolStripTextBox_KeyUp(object sender, KeyEventArgs e) TextureTileView.FocusIndex = -1; SelectedTextureId = indexValue; } + + // 汉化支持方法 + public void SetLocalization(Func? getLocalized) + { + _localizationGetter = getLocalized; + ApplyLocalization(); + } + + private void ApplyLocalization() + { + if (_localizationGetter == null) return; + + // Menu Items + showFreeSlotsToolStripMenuItem.Text = _localizationGetter("Forms.TexturesControl.showFreeSlotsToolStripMenuItem") ?? "Show Free Slots"; + findNextFreeSlotToolStripMenuItem.Text = _localizationGetter("Forms.TexturesControl.findNextFreeSlotToolStripMenuItem") ?? "Find Next Free Slot"; + exportImageToolStripMenuItem.Text = _localizationGetter("Forms.TexturesControl.exportImageToolStripMenuItem") ?? "Export Image.."; + asBmpToolStripMenuItem.Text = _localizationGetter("Forms.TexturesControl.asBmpToolStripMenuItem") ?? "As Bmp"; + asTiffToolStripMenuItem.Text = _localizationGetter("Forms.TexturesControl.asTiffToolStripMenuItem") ?? "As Tiff"; + asJpgToolStripMenuItem.Text = _localizationGetter("Forms.TexturesControl.asJpgToolStripMenuItem") ?? "As Jpg"; + asPngToolStripMenuItem.Text = _localizationGetter("Forms.TexturesControl.asPngToolStripMenuItem") ?? "As Png"; + selectInLandTilesTabToolStripMenuItem.Text = _localizationGetter("Forms.TexturesControl.selectInLandTilesTabToolStripMenuItem") ?? "Select in Land Tiles tab"; + copyImageToolStripMenuItem.Text = _localizationGetter("Forms.TexturesControl.copyImageToolStripMenuItem") ?? "Copy Image"; + pasteImageToolStripMenuItem.Text = _localizationGetter("Forms.TexturesControl.pasteImageToolStripMenuItem") ?? "Paste Image"; + replaceToolStripMenuItem.Text = _localizationGetter("Forms.TexturesControl.replaceToolStripMenuItem") ?? "Replace"; + replaceStartingFromToolStripMenuItem.Text = _localizationGetter("Forms.TexturesControl.replaceStartingFromToolStripMenuItem") ?? "Replace starting from.."; + insertAtToolStripMenuItem.Text = _localizationGetter("Forms.TexturesControl.insertAtToolStripMenuItem") ?? "Insert At.."; + removeToolStripMenuItem.Text = _localizationGetter("Forms.TexturesControl.removeToolStripMenuItem") ?? "Remove"; + saveToolStripMenuItem.Text = _localizationGetter("Forms.TexturesControl.saveToolStripMenuItem") ?? "Save"; + + // Toolbar Items + SaveButton.Text = _localizationGetter("Forms.TexturesControl.SaveButton") ?? "Save"; + SaveButton.ToolTipText = _localizationGetter("Forms.TexturesControl.SaveButton") ?? "Save"; + IndexToolStripLabel.Text = _localizationGetter("Forms.TexturesControl.IndexToolStripLabel") ?? "Index:"; + MiscToolStripDropDownButton.Text = _localizationGetter("Forms.TexturesControl.MiscToolStripDropDownButton") ?? "Misc"; + + // Misc Menu + exportAllToolStripMenuItem.Text = _localizationGetter("Forms.TexturesControl.exportAllToolStripMenuItem") ?? "Export All.."; + ExportAllAsBmp.Text = _localizationGetter("Forms.TexturesControl.ExportAllAsBmp") ?? "As Bmp"; + ExportAllAsTiff.Text = _localizationGetter("Forms.TexturesControl.ExportAllAsTiff") ?? "As Tiff"; + ExportAllAsJpeg.Text = _localizationGetter("Forms.TexturesControl.ExportAllAsJpeg") ?? "As Jpg"; + ExportAllAsPng.Text = _localizationGetter("Forms.TexturesControl.ExportAllAsPng") ?? "As Png"; + + // Status Bar + GraphicLabel.Text = _localizationGetter("Forms.TexturesControl.GraphicLabel") ?? "Graphic:"; + } } } diff --git a/UoFiddler/Forms/MainForm.cs b/UoFiddler/Forms/MainForm.cs index dbc1e1cb..33561ea5 100644 --- a/UoFiddler/Forms/MainForm.cs +++ b/UoFiddler/Forms/MainForm.cs @@ -63,6 +63,7 @@ public MainForm(ILogger logger) multisControl.SetLocalization(key => LocalizationService.GetString(key)); animationsControl.SetLocalization(key => LocalizationService.GetString(key)); landTilesControl.SetLocalization(key => LocalizationService.GetString(key)); + textureControl.SetLocalization(key => LocalizationService.GetString(key)); // 为 ItemsControl 设置汉化(通过遍历 TabPage 找到) foreach (TabPage tab in TabPanel.TabPages) diff --git a/UoFiddler/Localization/Dictionaries/zh-CN.json b/UoFiddler/Localization/Dictionaries/zh-CN.json index 6375c4f5..f1a0e347 100644 --- a/UoFiddler/Localization/Dictionaries/zh-CN.json +++ b/UoFiddler/Localization/Dictionaries/zh-CN.json @@ -719,6 +719,48 @@ "LoadTexturesTitle": "信息" } }, + "TexturesControl": { + "showFreeSlotsToolStripMenuItem": "显示空闲槽位", + "findNextFreeSlotToolStripMenuItem": "查找下一个空闲槽位", + "exportImageToolStripMenuItem": "导出图像..", + "asBmpToolStripMenuItem": "导出为 BMP", + "asTiffToolStripMenuItem": "导出为 TIFF", + "asJpgToolStripMenuItem": "导出为 JPG", + "asPngToolStripMenuItem": "导出为 PNG", + "selectInLandTilesTabToolStripMenuItem": "在 Land Tiles 标签中选择", + "copyImageToolStripMenuItem": "复制图像", + "pasteImageToolStripMenuItem": "粘贴图像", + "replaceToolStripMenuItem": "替换", + "replaceStartingFromToolStripMenuItem": "从...开始替换", + "insertAtToolStripMenuItem": "在...处插入", + "removeToolStripMenuItem": "移除", + "saveToolStripMenuItem": "保存", + "SaveButton": "保存", + "IndexToolStripLabel": "索引:", + "MiscToolStripDropDownButton": "其他", + "exportAllToolStripMenuItem": "导出所有..", + "ExportAllAsBmp": "全部导出为 BMP", + "ExportAllAsTiff": "全部导出为 TIFF", + "ExportAllAsJpeg": "全部导出为 JPG", + "ExportAllAsPng": "全部导出为 PNG", + "GraphicLabel": "图形:", + "Messages": { + "CopySuccess": "复制成功", + "PasteConfirm": "是否粘贴 {0} 个图像?", + "PasteSuccess": "粘贴成功", + "ReplaceConfirm": "是否替换 {0} 个图像?", + "ReplaceSuccess": "替换成功", + "InsertConfirm": "是否在位置 {0} 插入图像?", + "InsertSuccess": "插入成功", + "DeleteConfirm": "是否删除 {0} 个图像?", + "DeleteSuccess": "删除成功", + "SaveSuccess": "保存成功", + "ExportSuccess": "导出 {0} 个图像成功", + "InvalidSize": "图像尺寸无效。纹理必须是 64x64 或 128x128", + "InvalidIndex": "无效的索引", + "NoImage": "剪贴板中没有图像" + } + }, "AnimationListControl": { "searchToolStripLabel": "搜索:", "removeToolStripMenuItem": "移除", @@ -932,6 +974,14 @@ "SelectAll": "全选" } }, + "FileSavedDialog": { + "Title": "已保存", + "SaveSuccess": "文件已成功保存。", + "OpenFolder": "打开文件夹", + "OK": "确定", + "UnableToOpenFolder": "无法打开文件夹", + "Error": "错误" + }, "CompareTileDataControl": { "btnCopyLandSelected": "复制选定项", "btnCopyLandAllDiff": "复制所有差异", From 7f29eb591dc16af8e68e471c8306620e67862646 Mon Sep 17 00:00:00 2001 From: nbyaya Date: Tue, 6 Oct 2026 18:49:52 +0800 Subject: [PATCH 40/76] =?UTF-8?q?=E7=BB=9F=E4=B8=80=E8=8F=9C=E5=8D=95?= =?UTF-8?q?=E9=A1=B9=E4=B8=AD=E7=9A=84=E6=A0=87=E7=AD=BE=E5=90=8D=E6=B1=89?= =?UTF-8?q?=E5=8C=96?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit 修复菜单项文本中的英文标签名引用,确保与标签页中文名称一致 --- UoFiddler/Localization/Dictionaries/zh-CN.json | 16 ++++++++-------- 1 file changed, 8 insertions(+), 8 deletions(-) diff --git a/UoFiddler/Localization/Dictionaries/zh-CN.json b/UoFiddler/Localization/Dictionaries/zh-CN.json index f1a0e347..d4e3f7b6 100644 --- a/UoFiddler/Localization/Dictionaries/zh-CN.json +++ b/UoFiddler/Localization/Dictionaries/zh-CN.json @@ -602,10 +602,10 @@ "tiffToolStripMenuItem": "导出为 TIFF", "asJpgToolStripMenuItem1": "导出为 JPG", "asPngToolStripMenuItem1": "导出为 PNG", - "selectInTileDataTabToolStripMenuItem": "在 TileData 标签中选择", - "selectInRadarColorTabToolStripMenuItem": "在 RadarColor 标签中选择", - "selectInGumpsTabMaleToolStripMenuItem": "在 Gumps 标签中选择 (男)", - "selectInGumpsTabFemaleToolStripMenuItem": "在 Gumps 标签中选择 (女)", + "selectInTileDataTabToolStripMenuItem": "在 图块数据 标签中选择", + "selectInRadarColorTabToolStripMenuItem": "在 雷达颜色 标签中选择", + "selectInGumpsTabMaleToolStripMenuItem": "在 Gump 界面 标签中选择 (男)", + "selectInGumpsTabFemaleToolStripMenuItem": "在 Gump 界面 标签中选择 (女)", "copyImageToolStripMenuItem": "复制图像", "pasteImageToolStripMenuItem": "粘贴图像", "copyImageToolStripMenuItemDetail": "复制图像", @@ -672,9 +672,9 @@ "asTiffToolStripMenuItem": "导出为 TIFF", "asJpgToolStripMenuItem1": "导出为 JPG", "asPngToolStripMenuItem": "导出为 PNG", - "selectInTileDataTabToolStripMenuItem": "在 TileData 标签中选择", - "selectInRadarColorTabToolStripMenuItem": "在 RadarColor 标签中选择", - "selectInTexturesTabToolStripMenuItem": "在 Textures 标签中选择", + "selectInTileDataTabToolStripMenuItem": "在 图块数据 标签中选择", + "selectInRadarColorTabToolStripMenuItem": "在 雷达颜色 标签中选择", + "selectInTexturesTabToolStripMenuItem": "在 纹理 标签中选择", "copyImageToolStripMenuItem": "复制图像", "pasteImageToolStripMenuItem": "粘贴图像", "replaceToolStripMenuItem": "替换", @@ -727,7 +727,7 @@ "asTiffToolStripMenuItem": "导出为 TIFF", "asJpgToolStripMenuItem": "导出为 JPG", "asPngToolStripMenuItem": "导出为 PNG", - "selectInLandTilesTabToolStripMenuItem": "在 Land Tiles 标签中选择", + "selectInLandTilesTabToolStripMenuItem": "在 地形图块 标签中选择", "copyImageToolStripMenuItem": "复制图像", "pasteImageToolStripMenuItem": "粘贴图像", "replaceToolStripMenuItem": "替换", From bd43e0db535acc24b031c19e80a4a43711fe190c Mon Sep 17 00:00:00 2001 From: nbyaya Date: Tue, 6 Oct 2026 19:22:26 +0800 Subject: [PATCH 41/76] =?UTF-8?q?=E6=B1=89=E5=8C=96=E9=9F=B3=E6=95=88?= =?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 - 汉化 SoundsControl 所有 UI 控件(37项) - 汉化所有 MessageBox(标题+内容) - 汉化文件对话框和保存提示 - 修复 OnClickReplace 空引用异常 - 新增 16 个 Messages 词条 类型: 类型1/类型6 汉化 + Bug修复 --- .../Classes/ClientFileSaveCommand.cs | 30 +++- UoFiddler.Controls/Forms/FileSavedDialog.cs | 17 +++ .../UserControls/SoundsControl.cs | 131 +++++++++++++++--- UoFiddler/Forms/MainForm.cs | 1 + .../Localization/Dictionaries/zh-CN.json | 89 ++++++++++++ 5 files changed, 251 insertions(+), 17 deletions(-) diff --git a/UoFiddler.Controls/Classes/ClientFileSaveCommand.cs b/UoFiddler.Controls/Classes/ClientFileSaveCommand.cs index a87d79ba..232c24ae 100644 --- a/UoFiddler.Controls/Classes/ClientFileSaveCommand.cs +++ b/UoFiddler.Controls/Classes/ClientFileSaveCommand.cs @@ -91,7 +91,35 @@ public static bool Run(Control owner, FileType type, Action writeMul, st Options.ChangedUltimaClass[dirtyKey] = false; } - FileSavedDialog.Show(owner?.FindForm(), outputDirectory, BuildMessage(result)); + // 尝试通过反射访问 LocalizationService 来获取汉化 + Func getLocalized = null; + try + { + var localizationServiceType = Type.GetType("UoFiddler.Localization.LocalizationService, UoFiddler"); + if (localizationServiceType != null) + { + var getStringMethod = localizationServiceType.GetMethod("GetString", + System.Reflection.BindingFlags.Public | System.Reflection.BindingFlags.Static); + if (getStringMethod != null) + { + getLocalized = key => (string?)getStringMethod.Invoke(null, new object[] { key }); + } + } + } + catch { } + + string title = "Saved"; + if (getLocalized != null) + { + var localizedTitle = getLocalized("Forms.FileSavedDialog.Title"); + if (localizedTitle != null) + title = localizedTitle; + } + + if (getLocalized != null) + FileSavedDialog.Show(owner?.FindForm(), outputDirectory, BuildMessage(result), title, getLocalized); + else + FileSavedDialog.Show(owner?.FindForm(), outputDirectory, BuildMessage(result)); return true; } diff --git a/UoFiddler.Controls/Forms/FileSavedDialog.cs b/UoFiddler.Controls/Forms/FileSavedDialog.cs index 95032f6d..52711bf1 100644 --- a/UoFiddler.Controls/Forms/FileSavedDialog.cs +++ b/UoFiddler.Controls/Forms/FileSavedDialog.cs @@ -106,6 +106,23 @@ public static void Show(IWin32Window owner, string filePath, string message = nu } } + /// + /// Shows the file saved dialog with localization support. + /// + /// The owner form. + /// The path to the saved file. + /// Optional custom success message. + /// Optional custom dialog title. + /// Localization getter function. + public static void Show(IWin32Window owner, string filePath, string message, string title, Func getLocalized) + { + using (var dialog = new FileSavedDialog(filePath, message, title)) + { + dialog.SetLocalization(getLocalized); + dialog.ShowDialog(owner); + } + } + /// /// Shows the file saved dialog without an owner. /// diff --git a/UoFiddler.Controls/UserControls/SoundsControl.cs b/UoFiddler.Controls/UserControls/SoundsControl.cs index 47555dc5..5ad0c935 100644 --- a/UoFiddler.Controls/UserControls/SoundsControl.cs +++ b/UoFiddler.Controls/UserControls/SoundsControl.cs @@ -42,6 +42,9 @@ public partial class SoundsControl : UserControl // across all list items, recreated each reload (the control Font may change). private Font _underlineFont; + // Localization support + private Func? _localizationGetter; + public SoundsControl() { InitializeComponent(); @@ -264,6 +267,66 @@ private void PlaySound(int id) } } + /// + /// 设置本地化的字符串获取委托 + /// + public void SetLocalization(Func? getLocalized) + { + _localizationGetter = getLocalized; + ApplyLocalization(); + } + + /// + /// 应用本地化翻译到所有 UI 控件 + /// + private void ApplyLocalization() + { + if (_localizationGetter == null) return; + + // Type 1: 菜单项文本汉化 + nameSortToolStripMenuItem.Text = _localizationGetter("Forms.SoundsControl.nameSortToolStripMenuItem") ?? "Name Sort"; + showFreeSlotsToolStripMenuItem.Text = _localizationGetter("Forms.SoundsControl.showFreeSlotsToolStripMenuItem") ?? "Show free slots"; + nextFreeSlotToolStripMenuItem.Text = _localizationGetter("Forms.SoundsControl.nextFreeSlotToolStripMenuItem") ?? "Find next free slot"; + playSoundToolStripMenuItem.Text = _localizationGetter("Forms.SoundsControl.playSoundToolStripMenuItem") ?? "Play"; + replaceToolStripMenuItem.Text = _localizationGetter("Forms.SoundsControl.replaceToolStripMenuItem") ?? "Insert/Replace"; + extractSoundToolStripMenuItem.Text = _localizationGetter("Forms.SoundsControl.extractSoundToolStripMenuItem") ?? "Extract"; + removeSoundToolStripMenuItem.Text = _localizationGetter("Forms.SoundsControl.removeSoundToolStripMenuItem") ?? "Remove"; + itemSave.Text = _localizationGetter("Forms.SoundsControl.itemSave") ?? "Save"; + + // Type 1: GroupBox 标题 + groupBox1.Text = _localizationGetter("Forms.SoundsControl.groupBox1") ?? "Generic"; + SelectedSoundGroup.Text = _localizationGetter("Forms.SoundsControl.SelectedSoundGroup") ?? "Current Sound"; + groupBox2.Text = _localizationGetter("Forms.SoundsControl.groupBox2") ?? "Search"; + groupBox3.Text = _localizationGetter("Forms.SoundsControl.groupBox3") ?? "Insert/Replace"; + + // Type 1: 按钮文本 + PlaySoundButton.Text = _localizationGetter("Forms.SoundsControl.PlaySoundButton") ?? "Play"; + StopSoundButton.Text = _localizationGetter("Forms.SoundsControl.StopSoundButton") ?? "Stop"; + ExtractSoundButton.Text = _localizationGetter("Forms.SoundsControl.ExtractSoundButton") ?? "Extract"; + RemoveSoundButton.Text = _localizationGetter("Forms.SoundsControl.RemoveSoundButton") ?? "Remove"; + SaveFileButton.Text = _localizationGetter("Forms.SoundsControl.SaveFileButton") ?? "Save"; + exportAllSoundsButton.Text = _localizationGetter("Forms.SoundsControl.exportAllSoundsButton") ?? "Export all sounds"; + ExportSoundListCsvButton.Text = _localizationGetter("Forms.SoundsControl.ExportSoundListCsvButton") ?? "Export sound list (.csv)"; + WavChooseInsertButton.Text = _localizationGetter("Forms.SoundsControl.WavChooseInsertButton") ?? "..."; + AddInsertReplaceButton.Text = _localizationGetter("Forms.SoundsControl.AddInsertReplaceButton") ?? "Add"; + GoPrevResultButton.Text = _localizationGetter("Forms.SoundsControl.GoPrevResultButton") ?? "< Prev"; + GoNextResultButton.Text = _localizationGetter("Forms.SoundsControl.GoNextResultButton") ?? "Next >"; + SearchByIdButton.Text = _localizationGetter("Forms.SoundsControl.SearchByIdButton") ?? "Search"; + SearchByNameButton.Text = _localizationGetter("Forms.SoundsControl.SearchByNameButton") ?? "Search"; + + // Type 1: 标签和复选框 + label1.Text = _localizationGetter("Forms.SoundsControl.label1") ?? "ID:"; + label3.Text = _localizationGetter("Forms.SoundsControl.label3") ?? "WAV File:"; + SortByNameCheckbox.Text = _localizationGetter("Forms.SoundsControl.SortByNameCheckbox") ?? "Sort tree by name"; + includeSoundIdCheckBox.Text = _localizationGetter("Forms.SoundsControl.includeSoundIdCheckBox") ?? "Export with sound id in file name"; + + // Type 1: 列表列头 + listViewColumn.Text = _localizationGetter("Forms.SoundsControl.listViewColumn") ?? "Sound"; + + // Type 1: 工具栏文本 + stopButton.Text = _localizationGetter("Forms.SoundsControl.stopButton") ?? "Stop"; + } + private void AfterSelect(object sender, EventArgs e) { // Mirror the old TreeView BeforeSelect behaviour: stop playback @@ -281,13 +344,16 @@ private void AfterSelect(object sender, EventArgs e) extractSoundToolStripMenuItem.Enabled = false; removeSoundToolStripMenuItem.Enabled = false; replaceToolStripMenuItem.Enabled = false; - replaceToolStripMenuItem.Text = "Insert/Replace"; + // Type 12 初始值设置(在 ApplyLocalization 中已设置,此处保持为保障) + replaceToolStripMenuItem.Text = _localizationGetter?.Invoke("Forms.SoundsControl.replaceToolStripMenuItem") ?? "Insert/Replace"; } if (selected != null) { double length = Sounds.GetSoundLength((int)selected.Tag); - seconds.Text = length > 0 ? $"{length:f}s" : "Empty Slot"; + // Type 8:动态文本 - 空插槽提示 + string emptySlotText = _localizationGetter?.Invoke("Forms.SoundsControl.Messages.emptySlot") ?? "Empty Slot"; + seconds.Text = length > 0 ? $"{length:f}s" : emptySlotText; } bool isValidSound = selected != null && Sounds.IsValidSound((int)selected.Tag, out _, out _); @@ -297,13 +363,22 @@ private void AfterSelect(object sender, EventArgs e) removeSoundToolStripMenuItem.Enabled = isValidSound; replaceToolStripMenuItem.Enabled = true; - replaceToolStripMenuItem.Text = isValidSound ? "Replace" : "Insert"; + // Type 8:动态文本 - Replace/Insert 菜单项文本切换 + if (isValidSound) + { + replaceToolStripMenuItem.Text = _localizationGetter?.Invoke("Forms.SoundsControl.Messages.replace") ?? "Replace"; + } + else + { + replaceToolStripMenuItem.Text = _localizationGetter?.Invoke("Forms.SoundsControl.Messages.insert") ?? "Insert"; + } SelectedSoundGroup.Visible = selected != null; if (selected != null) { - SelectedSoundGroup.Text = $"Current Sound: {selected.Text} - Duration: {seconds.Text}"; + // Type 8:动态文本 - GroupBox 标题,包含选中音效信息 + SelectedSoundGroup.Text = $"{_localizationGetter?.Invoke("Forms.SoundsControl.Messages.currentSoundFormat") ?? "Current Sound"}: {selected.Text} - {_localizationGetter?.Invoke("Forms.SoundsControl.Messages.duration") ?? "Duration"}: {seconds.Text}"; IdInsertTextbox.Text = $"0x{(int)selected.Tag + _soundIdOffset:X}"; } } @@ -436,7 +511,12 @@ private void OnClickExtract(object sender, EventArgs e) } } - MessageBox.Show($"Sound saved to {fileName}", "Saved", MessageBoxButtons.OK, MessageBoxIcon.Information, + // Type 6:消息框文本汉化 - 提取成功提示 + string message = string.Format( + _localizationGetter?.Invoke("Forms.SoundsControl.Messages.soundSavedTo") ?? "Sound saved to {0}", + fileName); + string title = _localizationGetter?.Invoke("Forms.SoundsControl.Messages.saved") ?? "Saved"; + MessageBox.Show(message, title, MessageBoxButtons.OK, MessageBoxIcon.Information, MessageBoxDefaultButton.Button1); } @@ -486,7 +566,15 @@ private void OnClickExportSoundListCsv(object sender, EventArgs e) Sounds.SaveSoundListToCsv(fileName, _soundIdOffset); - FileSavedDialog.Show(FindForm(), fileName, "SoundList saved successfully."); + // Type 6:消息框文本汉化 - 导出音效列表完成 + string message = _localizationGetter?.Invoke("Forms.SoundsControl.Messages.soundListSavedSuccessfully") ?? "SoundList saved successfully."; + var dialog = new FileSavedDialog(fileName, message); + if (_localizationGetter != null) + { + dialog.SetLocalization(_localizationGetter); + } + dialog.ShowDialog(FindForm()); + dialog.Dispose(); } public bool SearchId(int id) @@ -524,7 +612,7 @@ private void OnClickReplace(object sender, EventArgs e) using (OpenFileDialog dialog = new OpenFileDialog()) { dialog.Multiselect = false; - dialog.Title = "Choose wave file"; + dialog.Title = _localizationGetter?.Invoke("Forms.SoundsControl.Messages.chooseWaveFile") ?? "Choose wave file"; dialog.CheckFileExists = true; dialog.Filter = "wav file (*.wav)|*.wav"; if (dialog.ShowDialog() == DialogResult.OK) @@ -542,6 +630,15 @@ private void OnClickReplace(object sender, EventArgs e) file = _wavChosen; } + // ✅ 修复:检查 file 是否为空或文件是否存在 + if (string.IsNullOrEmpty(file) || !File.Exists(file)) + { + string errorMsg = _localizationGetter?.Invoke("Forms.SoundsControl.Messages.invalidFilename") ?? "Invalid Filename"; + string titleMsg = _localizationGetter?.Invoke("Forms.SoundsControl.Messages.addReplaceTitle") ?? "Add/Replace"; + MessageBox.Show(errorMsg, titleMsg, MessageBoxButtons.OK, MessageBoxIcon.Error, MessageBoxDefaultButton.Button1); + return; // ✅ 修复:缺少的 return 语句 + } + if (listView.SelectedItems.Count == 0) { return; @@ -550,11 +647,6 @@ private void OnClickReplace(object sender, EventArgs e) int id = (int)listView.SelectedItems[0].Tag; string name = Path.GetFileName(file); - if (!File.Exists(file)) - { - MessageBox.Show("Invalid Filename", "Add/Replace", MessageBoxButtons.OK, MessageBoxIcon.Error, MessageBoxDefaultButton.Button1); - } - if (name.Length > 32) { name = name.Substring(0, 32); @@ -562,8 +654,10 @@ private void OnClickReplace(object sender, EventArgs e) if (Sounds.IsValidSound(id, out _, out _)) { - DialogResult result = MessageBox.Show($"Are you sure to replace {listView.SelectedItems[0].Text}?", - "Replace", MessageBoxButtons.YesNo, MessageBoxIcon.Question, MessageBoxDefaultButton.Button2); + string confirmMsg = _localizationGetter?.Invoke("Forms.SoundsControl.Messages.confirmReplace") ?? $"Are you sure to replace {listView.SelectedItems[0].Text}?"; + confirmMsg = string.Format(confirmMsg, listView.SelectedItems[0].Text); + string titleMsg = _localizationGetter?.Invoke("Forms.SoundsControl.Messages.replaceTitle") ?? "Replace"; + DialogResult result = MessageBox.Show(confirmMsg, titleMsg, MessageBoxButtons.YesNo, MessageBoxIcon.Question, MessageBoxDefaultButton.Button2); if (result != DialogResult.Yes) { @@ -577,7 +671,9 @@ private void OnClickReplace(object sender, EventArgs e) } catch (WaveFormatException waveFormatException) { - MessageBox.Show("Unexpected WAV format:\n" + waveFormatException.Message, "Error", MessageBoxButtons.OK, MessageBoxIcon.Error); + string errorMsg = _localizationGetter?.Invoke("Forms.SoundsControl.Messages.unexpectedWavFormat") ?? "Unexpected WAV format:"; + string titleMsg = _localizationGetter?.Invoke("Forms.SoundsControl.Messages.errorTitle") ?? "Error"; + MessageBox.Show(errorMsg + "\n" + waveFormatException.Message, titleMsg, MessageBoxButtons.OK, MessageBoxIcon.Error); return; } @@ -854,7 +950,10 @@ private void ExportAllSounds() } } - MessageBox.Show("Extract all sounds complete.", "Saved", MessageBoxButtons.OK, MessageBoxIcon.Information, + // Type 6:消息框文本汉化 - 导出所有完成提示 + string message = _localizationGetter?.Invoke("Forms.SoundsControl.Messages.extractAllComplete") ?? "Extract all sounds complete."; + string title = _localizationGetter?.Invoke("Forms.SoundsControl.Messages.saved") ?? "Saved"; + MessageBox.Show(message, title, MessageBoxButtons.OK, MessageBoxIcon.Information, MessageBoxDefaultButton.Button1); } } diff --git a/UoFiddler/Forms/MainForm.cs b/UoFiddler/Forms/MainForm.cs index 33561ea5..21465bdd 100644 --- a/UoFiddler/Forms/MainForm.cs +++ b/UoFiddler/Forms/MainForm.cs @@ -64,6 +64,7 @@ public MainForm(ILogger logger) animationsControl.SetLocalization(key => LocalizationService.GetString(key)); landTilesControl.SetLocalization(key => LocalizationService.GetString(key)); textureControl.SetLocalization(key => LocalizationService.GetString(key)); + soundControl.SetLocalization(key => LocalizationService.GetString(key)); // 为 ItemsControl 设置汉化(通过遍历 TabPage 找到) foreach (TabPage tab in TabPanel.TabPages) diff --git a/UoFiddler/Localization/Dictionaries/zh-CN.json b/UoFiddler/Localization/Dictionaries/zh-CN.json index d4e3f7b6..df283f6a 100644 --- a/UoFiddler/Localization/Dictionaries/zh-CN.json +++ b/UoFiddler/Localization/Dictionaries/zh-CN.json @@ -761,6 +761,44 @@ "NoImage": "剪贴板中没有图像" } }, + "SoundsControl": { + "nameSortToolStripMenuItem": "按名称排序", + "showFreeSlotsToolStripMenuItem": "显示空闲槽位", + "nextFreeSlotToolStripMenuItem": "查找下一个空闲槽位", + "playSoundToolStripMenuItem": "播放", + "insertReplaceToolStripMenuItem": "插入/替换", + "replaceSoundToolStripMenuItem": "替换", + "insertSoundToolStripMenuItem": "插入", + "extractSoundToolStripMenuItem": "提取", + "removeSoundToolStripMenuItem": "移除", + "saveSoundToolStripMenuItem": "保存", + "genericGroupBox": "常规", + "currentSoundGroupBox": "当前声音", + "searchGroupBox": "搜索", + "insertReplaceGroupBox": "插入/替换", + "playButton": "播放", + "stopButton": "停止", + "extractButton": "提取", + "removeButton": "移除", + "saveButton": "保存", + "exportAllSoundsButton": "导出所有声音", + "exportSoundListCsvButton": "导出声音列表 (.csv)", + "addInsertReplaceButton": "添加/替换", + "goPrevButton": "上一个", + "goNextButton": "下一个", + "idLabel": "ID", + "wavLabel": "WAV", + "sortByNameCheckBox": "按名称排序树", + "includeSoundIdCheckBox": "导出时在文件名中包含声音ID", + "soundColumnHeader": "声音", + "searchByIdButton": "按ID搜索", + "searchByNameButton": "按名称搜索", + "Messages": { + "emptySlot": "空槽位", + "currentSoundFormat": "当前声音: {0} - 时长: {1}", + "idCountFormat": "已占用音效 ID: {0}, 空闲音效 ID: {1}" + } + }, "AnimationListControl": { "searchToolStripLabel": "搜索:", "removeToolStripMenuItem": "移除", @@ -1074,6 +1112,57 @@ "flagPixelBleed": "像素溢出", "flagPlayAnimOnce": "播放一次动画", "flagMultiMovable": "多可移动" + }, + "SoundsControl": { + "nameSortToolStripMenuItem": "按名称排序", + "showFreeSlotsToolStripMenuItem": "显示空闲插槽", + "nextFreeSlotToolStripMenuItem": "查找下一个空闲插槽", + "playSoundToolStripMenuItem": "播放", + "replaceToolStripMenuItem": "插入/替换", + "extractSoundToolStripMenuItem": "提取", + "removeSoundToolStripMenuItem": "移除", + "itemSave": "保存", + "groupBox1": "通用", + "SelectedSoundGroup": "当前音效", + "groupBox2": "搜索", + "groupBox3": "插入/替换", + "PlaySoundButton": "播放", + "StopSoundButton": "停止", + "ExtractSoundButton": "提取", + "RemoveSoundButton": "移除", + "SaveFileButton": "保存", + "exportAllSoundsButton": "导出所有音效", + "ExportSoundListCsvButton": "导出音效列表 (.csv)", + "WavChooseInsertButton": "...", + "AddInsertReplaceButton": "添加", + "GoPrevResultButton": "< 上一个", + "GoNextResultButton": "下一个 >", + "SearchByIdButton": "搜索", + "SearchByNameButton": "搜索", + "label1": "ID:", + "label3": "WAV 文件:", + "SortByNameCheckbox": "按名称排序树形", + "includeSoundIdCheckBox": "在文件名中包含音效ID", + "listViewColumn": "音效", + "stopButton": "停止", + "Messages": { + "emptySlot": "空闲插槽", + "replace": "替换", + "insert": "插入", + "currentSoundFormat": "当前音效", + "duration": "时长", + "soundSavedTo": "音效已保存到 {0}", + "saved": "已保存", + "extractAllComplete": "导出所有音效完成。", + "soundListSavedSuccessfully": "音效列表已成功保存。", + "invalidFilename": "无效的文件名", + "addReplaceTitle": "添加/替换", + "confirmReplace": "是否确定要替换 {0}?", + "replaceTitle": "替换", + "unexpectedWavFormat": "意外的 WAV 格式:", + "errorTitle": "错误", + "chooseWaveFile": "选择音效文件" + } } } } From ac7af678ba3b0efb597c688702b2e8365aefcbaf Mon Sep 17 00:00:00 2001 From: nbyaya Date: Tue, 6 Oct 2026 19:52:15 +0800 Subject: [PATCH 42/76] =?UTF-8?q?=E6=B1=89=E5=8C=96=E5=AD=97=E4=BD=93?= =?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 --- .../UserControls/FontsControl.cs | 86 ++++++++++++++++--- UoFiddler/Forms/MainForm.cs | 1 + .../Localization/Dictionaries/zh-CN.json | 19 ++++ 3 files changed, 95 insertions(+), 11 deletions(-) diff --git a/UoFiddler.Controls/UserControls/FontsControl.cs b/UoFiddler.Controls/UserControls/FontsControl.cs index 4c75b72a..9e2a9ef2 100644 --- a/UoFiddler.Controls/UserControls/FontsControl.cs +++ b/UoFiddler.Controls/UserControls/FontsControl.cs @@ -38,6 +38,40 @@ public FontsControl() private bool _loaded; private static FontsControl _refMarker; private List _fonts = new List(); + private Func? _localizationGetter; + + /// + /// Set localization for FontsControl + /// + public void SetLocalization(Func getLocalized) + { + _localizationGetter = getLocalized; + ApplyLocalization(); + } + + /// + /// Apply localization to all UI elements + /// + private void ApplyLocalization() + { + if (_localizationGetter == null) return; + + // 右键菜单项 + writeTextToolStripMenuItem.Text = _localizationGetter("Forms.FontsControl.writeTextToolStripMenuItem") ?? "Write Text"; + setOffsetsToolStripMenuItem.Text = _localizationGetter("Forms.FontsControl.setOffsetsToolStripMenuItem") ?? "Set Offsets"; + extractCharacterToolStripMenuItem.Text = _localizationGetter("Forms.FontsControl.extractCharacterToolStripMenuItem") ?? "Extract Character"; + importCharacterToolStripMenuItem.Text = _localizationGetter("Forms.FontsControl.importCharacterToolStripMenuItem") ?? "Import Character"; + saveToolStripMenuItem.Text = _localizationGetter("Forms.FontsControl.saveToolStripMenuItem") ?? "Save"; + + // 复选框 + LoadUnicodeFontsCheckBox.Text = _localizationGetter("Forms.FontsControl.LoadUnicodeFontsCheckBox") ?? "Load Unicode Fonts"; + + // 状态栏初始文本 + if (string.IsNullOrEmpty(toolStripStatusLabel1.Text) || toolStripStatusLabel1.Text == "") + { + toolStripStatusLabel1.Text = _localizationGetter("Forms.FontsControl.toolStripStatusLabel1") ?? ""; + } + } /// /// Reload when loaded (file changed) @@ -229,7 +263,10 @@ private void OnClickExport(object sender, EventArgs e) bmp.Save(fileName, ImageFormat.Tiff); } - FileSavedDialog.Show(FindForm(), fileName, "Character saved successfully."); + string message = _localizationGetter?.Invoke("Forms.FontsControl.Messages.characterSavedSuccess") + ?? "Character saved successfully."; + string title = _localizationGetter?.Invoke("Forms.FileSavedDialog.Title") ?? "Saved"; + FileSavedDialog.Show(FindForm(), fileName, message, title, key => _localizationGetter?.Invoke(key)); } private static int AsciiFontOffset => 32; @@ -257,7 +294,11 @@ private void OnClickImport(object sender, EventArgs e) { import.Dispose(); - MessageBox.Show("Image Height or Width exceeds 255", "Import", MessageBoxButtons.OK, MessageBoxIcon.Error, MessageBoxDefaultButton.Button1); + string message = _localizationGetter?.Invoke("Forms.FontsControl.Messages.imageSizeExceeds") + ?? "Image Height or Width exceeds 255"; + string title = _localizationGetter?.Invoke("Forms.FontsControl.Messages.importTitle") + ?? "Import"; + MessageBox.Show(message, title, MessageBoxButtons.OK, MessageBoxIcon.Error, MessageBoxDefaultButton.Button1); return; } @@ -286,14 +327,20 @@ private void OnClickSave(object sender, EventArgs e) { string fileName = UnicodeFonts.Save(path, (int)treeView.SelectedNode.Tag); Options.ChangedUltimaClass["UnicodeFont"] = false; - FileSavedDialog.Show(FindForm(), fileName, "Unicode fonts saved successfully."); + string message = _localizationGetter?.Invoke("Forms.FontsControl.Messages.unicodeFontsSavedSuccess") + ?? "Unicode fonts saved successfully."; + string title = _localizationGetter?.Invoke("Forms.FileSavedDialog.Title") ?? "Saved"; + FileSavedDialog.Show(FindForm(), fileName, message, title, key => _localizationGetter?.Invoke(key)); } else { string fileName = Path.Combine(path, "fonts.mul"); AsciiText.Save(fileName); Options.ChangedUltimaClass["ASCIIFont"] = false; - FileSavedDialog.Show(FindForm(), fileName, "Fonts saved successfully."); + string message = _localizationGetter?.Invoke("Forms.FontsControl.Messages.fontsSavedSuccess") + ?? "Fonts saved successfully."; + string title = _localizationGetter?.Invoke("Forms.FileSavedDialog.Title") ?? "Saved"; + FileSavedDialog.Show(FindForm(), fileName, message, title, key => _localizationGetter?.Invoke(key)); } } @@ -423,21 +470,38 @@ private void UpdateStatusStrip() int i = FontsTileView.SelectedIndices[0]; - toolStripStatusLabel1.Text = (int)treeView.SelectedNode.Parent.Tag == 1 - ? string.Format("'{0}' : {1} (0x{1:X}) XOffset: {2} YOffset: {3}", (char)i, i, + if ((int)treeView.SelectedNode.Parent.Tag == 1) + { + // Unicode fonts + toolStripStatusLabel1.Text = string.Format("'{0}' : {1} (0x{1:X}) XOffset: {2} YOffset: {3}", (char)i, i, UnicodeFonts.Fonts[(int)treeView.SelectedNode.Tag].Chars[i].XOffset, - UnicodeFonts.Fonts[(int)treeView.SelectedNode.Tag].Chars[i].YOffset) - : string.Format("'{0}' : {1} (0x{1:X})", (char)(_fonts[i] + AsciiFontOffset), _fonts[i] + AsciiFontOffset); + UnicodeFonts.Fonts[(int)treeView.SelectedNode.Tag].Chars[i].YOffset); + } + else + { + // ASCII fonts - 需要边界检查 + if (i >= 0 && i < _fonts.Count) + { + toolStripStatusLabel1.Text = string.Format("'{0}' : {1} (0x{1:X})", + (char)(_fonts[i] + AsciiFontOffset), _fonts[i] + AsciiFontOffset); + } + else + { + toolStripStatusLabel1.Text = string.Empty; + } + } } private void LoadUnicodeFontsCheckBox_CheckedChanged(object sender, EventArgs e) { string message = LoadUnicodeFontsCheckBox.Checked - ? "Would you like to load all fonts including Unicode?" - : "Load only ASCII fonts?"; + ? (_localizationGetter?.Invoke("Forms.FontsControl.Messages.loadAllFontsConfirm") ?? "Would you like to load all fonts including Unicode?") + : (_localizationGetter?.Invoke("Forms.FontsControl.Messages.loadAsciiOnlyConfirm") ?? "Load only ASCII fonts?"); + + string title = _localizationGetter?.Invoke("Forms.FontsControl.Messages.fontsReloadTitle") ?? "Fonts reload"; DialogResult result = - MessageBox.Show(message, "Fonts reload", + MessageBox.Show(message, title, MessageBoxButtons.YesNo, MessageBoxIcon.Question, MessageBoxDefaultButton.Button2); if (result != DialogResult.Yes) { diff --git a/UoFiddler/Forms/MainForm.cs b/UoFiddler/Forms/MainForm.cs index 21465bdd..2ea5b20c 100644 --- a/UoFiddler/Forms/MainForm.cs +++ b/UoFiddler/Forms/MainForm.cs @@ -65,6 +65,7 @@ public MainForm(ILogger logger) landTilesControl.SetLocalization(key => LocalizationService.GetString(key)); textureControl.SetLocalization(key => LocalizationService.GetString(key)); soundControl.SetLocalization(key => LocalizationService.GetString(key)); + fontsControl.SetLocalization(key => LocalizationService.GetString(key)); // 为 ItemsControl 设置汉化(通过遍历 TabPage 找到) foreach (TabPage tab in TabPanel.TabPages) diff --git a/UoFiddler/Localization/Dictionaries/zh-CN.json b/UoFiddler/Localization/Dictionaries/zh-CN.json index df283f6a..7d329a86 100644 --- a/UoFiddler/Localization/Dictionaries/zh-CN.json +++ b/UoFiddler/Localization/Dictionaries/zh-CN.json @@ -1163,6 +1163,25 @@ "errorTitle": "错误", "chooseWaveFile": "选择音效文件" } + }, + "FontsControl": { + "writeTextToolStripMenuItem": "写入文本", + "setOffsetsToolStripMenuItem": "设置偏移", + "extractCharacterToolStripMenuItem": "提取字符", + "importCharacterToolStripMenuItem": "导入字符", + "saveToolStripMenuItem": "保存", + "LoadUnicodeFontsCheckBox": "加载 Unicode 字体", + "toolStripStatusLabel1": "<未选择>", + "Messages": { + "loadAllFontsConfirm": "是否要加载包括 Unicode 在内的所有字体?", + "loadAsciiOnlyConfirm": "只加载 ASCII 字体?", + "fontsReloadTitle": "字体重新加载", + "imageSizeExceeds": "图像高度或宽度超过 255", + "importTitle": "导入", + "characterSavedSuccess": "字符已成功保存。", + "unicodeFontsSavedSuccess": "Unicode 字体已成功保存。", + "fontsSavedSuccess": "字体已成功保存。" + } } } } From 38054a530cd12d1a12753a0dd14d016c80f7012f Mon Sep 17 00:00:00 2001 From: nbyaya Date: Tue, 6 Oct 2026 20:54:09 +0800 Subject: [PATCH 43/76] =?UTF-8?q?=E6=B1=89=E5=8C=96=20CliLocControl=20?= =?UTF-8?q?=E6=A0=87=E7=AD=BE=E9=A1=B5?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit - 汉化工具栏、菜单、按钮、表格列头 - 汉化导出和导入对话框 - 新增类型 15:DataGridView 列头汉化 - 添加 30+ 个 JSON 词条 - 编译验证无错误 --- .../UserControls/ClilocControl.cs | 144 ++++++++++++++++-- UoFiddler/Forms/MainForm.cs | 1 + .../Localization/Dictionaries/zh-CN.json | 42 +++++ 3 files changed, 175 insertions(+), 12 deletions(-) diff --git a/UoFiddler.Controls/UserControls/ClilocControl.cs b/UoFiddler.Controls/UserControls/ClilocControl.cs index 794489d5..a9ac7bf4 100644 --- a/UoFiddler.Controls/UserControls/ClilocControl.cs +++ b/UoFiddler.Controls/UserControls/ClilocControl.cs @@ -42,6 +42,78 @@ public ClilocControl() private SortOrder _sortOrder; private int _sortColumn; private bool _loaded; + private Func? _localizationGetter; + + /// + /// Set localization for CliLocControl + /// + public void SetLocalization(Func getLocalized) + { + _localizationGetter = getLocalized; + ApplyLocalization(); + } + + /// + /// Apply localization to all UI elements + /// + private void ApplyLocalization() + { + if (_localizationGetter == null) return; + + // 工具栏按钮和文本框 + GotoEntry.Text = _localizationGetter("Forms.CliLocControl.GotoEntry") ?? "Enter Number"; + GotoButton.Text = _localizationGetter("Forms.CliLocControl.GotoButton") ?? "Goto"; + FindEntry.Text = _localizationGetter("Forms.CliLocControl.FindEntry") ?? "Enter Text"; + FindButton.Text = _localizationGetter("Forms.CliLocControl.FindButton") ?? "Find"; + RegexToolStripButton.Text = _localizationGetter("Forms.CliLocControl.RegexToolStripButton") ?? "Use regular expression"; + toolStripButton1.Text = _localizationGetter("Forms.CliLocControl.SaveButton") ?? "Save"; + ClilocExportButton.Text = _localizationGetter("Forms.CliLocControl.ExportButton") ?? "Export"; + toolStripDropDownButton1.Text = _localizationGetter("Forms.CliLocControl.ImportButton") ?? "Import"; + + // 右键菜单项 + copyCliLocNumberToolStripMenuItem.Text = _localizationGetter("Forms.CliLocControl.copyCliLocNumberToolStripMenuItem") ?? "Copy CliLoc Number"; + copyCliLocTextToolStripMenuItem.Text = _localizationGetter("Forms.CliLocControl.copyCliLocTextToolStripMenuItem") ?? "Copy CliLoc Text"; + addEntryToolStripMenuItem.Text = _localizationGetter("Forms.CliLocControl.addEntryToolStripMenuItem") ?? "Add Entry"; + deleteEntryToolStripMenuItem.Text = _localizationGetter("Forms.CliLocControl.deleteEntryToolStripMenuItem") ?? "Delete Entry"; + + // 导入菜单项 (CSV 保持英文,不汉化) + // cSVToolStripMenuItem.Text 保持 "CSV" + tileDataToolStripMenuItem.Text = _localizationGetter("Forms.CliLocControl.tileDataToolStripMenuItem") ?? "Sync from TileData"; + + // 语言下拉菜单项 + LangComboBox.Items.Clear(); + LangComboBox.Items.Add(_localizationGetter("Forms.CliLocControl.LangComboBoxEnglish") ?? "English"); + LangComboBox.Items.Add(_localizationGetter("Forms.CliLocControl.LangComboBoxGerman") ?? "German"); + LangComboBox.Items.Add(_localizationGetter("Forms.CliLocControl.LangComboBoxCustom1") ?? "Custom 1"); + LangComboBox.Items.Add(_localizationGetter("Forms.CliLocControl.LangComboBoxCustom2") ?? "Custom 2"); + + // 表格列头 + if (dataGridView1.Columns.Count > 0) + { + dataGridView1.Columns[0].HeaderText = _localizationGetter("Forms.CliLocControl.ColumnNumber") ?? "Number"; + dataGridView1.Columns[1].HeaderText = _localizationGetter("Forms.CliLocControl.ColumnText") ?? "Text"; + if (dataGridView1.Columns.Count > 2) + { + dataGridView1.Columns[2].HeaderText = _localizationGetter("Forms.CliLocControl.ColumnFlag") ?? "Flag"; + } + } + } + + /// + /// Apply column headers localization + /// + private void ApplyColumnHeaders() + { + if (dataGridView1.Columns.Count > 0) + { + dataGridView1.Columns[0].HeaderText = _localizationGetter("Forms.CliLocControl.ColumnNumber") ?? "Number"; + dataGridView1.Columns[1].HeaderText = _localizationGetter("Forms.CliLocControl.ColumnText") ?? "Text"; + if (dataGridView1.Columns.Count > 2) + { + dataGridView1.Columns[2].HeaderText = _localizationGetter("Forms.CliLocControl.ColumnFlag") ?? "Flag"; + } + } + } /// /// Sets Language and loads cliloc @@ -72,7 +144,9 @@ private int Lang if (!string.IsNullOrEmpty(_cliloc?.LoadWarning)) { - MessageBox.Show(this, _cliloc.LoadWarning, "Cliloc parsed with warnings", + string warningTitle = _localizationGetter?.Invoke("Forms.CliLocControl.Messages.ClilocLoadWarningTitle") + ?? "Cliloc parsed with warnings"; + MessageBox.Show(this, _cliloc.LoadWarning, warningTitle, MessageBoxButtons.OK, MessageBoxIcon.Warning); } } @@ -109,6 +183,8 @@ private void OnLoad(object sender, EventArgs e) dataGridView1.DataSource = _source; if (dataGridView1.Columns.Count > 0) { + // 应用列头汉化 + ApplyColumnHeaders(); dataGridView1.Columns[0].HeaderCell.SortGlyphDirection = SortOrder.Ascending; dataGridView1.Columns[0].Width = 60; dataGridView1.Columns[1].HeaderCell.SortGlyphDirection = SortOrder.None; @@ -187,6 +263,8 @@ private void OnLangChange(object sender, EventArgs e) if (dataGridView1.Columns.Count > 0) { + // 应用列头汉化 + ApplyColumnHeaders(); dataGridView1.Columns[0].HeaderCell.SortGlyphDirection = SortOrder.Ascending; dataGridView1.Columns[0].Width = 60; dataGridView1.Columns[1].HeaderCell.SortGlyphDirection = SortOrder.None; @@ -215,9 +293,14 @@ private void GotoNr(object sender, EventArgs e) } } + string gotoNotFoundMessage = _localizationGetter?.Invoke("Forms.CliLocControl.Messages.NumberNotFound") + ?? "Number not found."; + string gotoTitle = _localizationGetter?.Invoke("Forms.CliLocControl.Messages.GotoTitle") + ?? "Goto"; + MessageBox.Show( - "Number not found.", - "Goto", + gotoNotFoundMessage, + gotoTitle, MessageBoxButtons.OK, MessageBoxIcon.Error, MessageBoxDefaultButton.Button1); @@ -227,7 +310,11 @@ private void FindEntryClick(object sender, EventArgs e) { if (string.IsNullOrEmpty(FindEntry.Text) || FindEntry.Text == _searchTextPlaceholder) { - MessageBox.Show("Please provide search text", "Find Entry", MessageBoxButtons.OK, MessageBoxIcon.Error, + string message = _localizationGetter?.Invoke("Forms.CliLocControl.Messages.PleaseProvideSearchText") + ?? "Please provide search text"; + string title = _localizationGetter?.Invoke("Forms.CliLocControl.Messages.FindEntryTitle") + ?? "Find Entry"; + MessageBox.Show(message, title, MessageBoxButtons.OK, MessageBoxIcon.Error, MessageBoxDefaultButton.Button1); return; @@ -256,7 +343,12 @@ private void FindEntryClick(object sender, EventArgs e) return; } - MessageBox.Show(hasErrors ? "Invalid regular expression." : "Entry not found.", "Find Entry", + string msgContent = hasErrors + ? (_localizationGetter?.Invoke("Forms.CliLocControl.Messages.InvalidRegex") ?? "Invalid regular expression.") + : (_localizationGetter?.Invoke("Forms.CliLocControl.Messages.EntryNotFound") ?? "Entry not found."); + string msgTitle = _localizationGetter?.Invoke("Forms.CliLocControl.Messages.FindEntryTitle") + ?? "Find Entry"; + MessageBox.Show(msgContent, msgTitle, MessageBoxButtons.OK, MessageBoxIcon.Error, MessageBoxDefaultButton.Button1); } @@ -282,7 +374,11 @@ private void FindPreviousEntry() { if (string.IsNullOrEmpty(FindEntry.Text) || FindEntry.Text == _searchTextPlaceholder) { - MessageBox.Show("Please provide search text", "Find Entry", MessageBoxButtons.OK, MessageBoxIcon.Error, + string message = _localizationGetter?.Invoke("Forms.CliLocControl.Messages.PleaseProvideSearchText") + ?? "Please provide search text"; + string title = _localizationGetter?.Invoke("Forms.CliLocControl.Messages.FindEntryTitle") + ?? "Find Entry"; + MessageBox.Show(message, title, MessageBoxButtons.OK, MessageBoxIcon.Error, MessageBoxDefaultButton.Button1); return; @@ -318,7 +414,12 @@ private void FindPreviousEntry() return; } - MessageBox.Show(hasErrors ? "Invalid regular expression." : "Entry not found.", "Find Entry", + string notFoundMessage = hasErrors + ? (_localizationGetter?.Invoke("Forms.CliLocControl.Messages.InvalidRegex") ?? "Invalid regular expression.") + : (_localizationGetter?.Invoke("Forms.CliLocControl.Messages.EntryNotFound") ?? "Entry not found."); + string dialogTitle = _localizationGetter?.Invoke("Forms.CliLocControl.Messages.FindEntryTitle") + ?? "Find Entry"; + MessageBox.Show(notFoundMessage, dialogTitle, MessageBoxButtons.OK, MessageBoxIcon.Error, MessageBoxDefaultButton.Button1); } @@ -349,7 +450,10 @@ private void OnClickSave(object sender, EventArgs e) dataGridView1.Invalidate(); Options.ChangedUltimaClass["CliLoc"] = false; - FileSavedDialog.Show(FindForm(), Options.OutputPath, "CliLoc saved successfully."); + string title = _localizationGetter?.Invoke("Forms.FileSavedDialog.Title") + ?? "Saved"; + + FileSavedDialog.Show(FindForm(), Options.OutputPath, null, title, key => _localizationGetter?.Invoke(key)); } private void OnCell_dbClick(object sender, DataGridViewCellEventArgs e) @@ -558,15 +662,21 @@ private void OnClickExportCSV(object sender, EventArgs e) } } - FileSavedDialog.Show(FindForm(), fileName, "CliLoc saved successfully."); + // 使用支持汉化的 Show 重载 + string title = _localizationGetter?.Invoke("Forms.FileSavedDialog.Title") ?? "Saved"; + FileSavedDialog.Show(FindForm(), fileName, "CliLoc saved successfully.", title, key => _localizationGetter?.Invoke(key)); } private void OnClickImportCSV(object sender, EventArgs e) { + // 获取汉化的标题 + string dialogTitle = _localizationGetter?.Invoke("Forms.CliLocControl.Messages.ImportChooseFileTitle") + ?? "Choose csv file to import"; + OpenFileDialog dialog = new OpenFileDialog { Multiselect = false, - Title = "Choose csv file to import", + Title = dialogTitle, CheckFileExists = true, Filter = "csv files (*.csv)|*.csv" }; @@ -640,16 +750,26 @@ private void OnClickImportCSV(object sender, EventArgs e) } } + // 获取汉化的消息框文本 + string doneTitle = _localizationGetter?.Invoke("Forms.CliLocControl.Messages.ImportDoneTitle") + ?? "Import Done"; + if (count > 0) { Options.ChangedUltimaClass["CliLoc"] = true; _source.ResetBindings(false); dataGridView1.Invalidate(); - MessageBox.Show(this, $"{count} entries changed.", "Import Done", MessageBoxButtons.OK, MessageBoxIcon.Information); + + string messageTemplate = _localizationGetter?.Invoke("Forms.CliLocControl.Messages.ImportEntriesChanged") + ?? "{0} entries changed."; + string message = string.Format(messageTemplate, count); + MessageBox.Show(this, message, doneTitle, MessageBoxButtons.OK, MessageBoxIcon.Information); } else { - MessageBox.Show(this, "No entries changed.", "Import Done", MessageBoxButtons.OK, MessageBoxIcon.Information); + string noChangeMessage = _localizationGetter?.Invoke("Forms.CliLocControl.Messages.ImportNoEntriesChanged") + ?? "No entries changed."; + MessageBox.Show(this, noChangeMessage, doneTitle, MessageBoxButtons.OK, MessageBoxIcon.Information); } } } diff --git a/UoFiddler/Forms/MainForm.cs b/UoFiddler/Forms/MainForm.cs index 2ea5b20c..e9c5bbfb 100644 --- a/UoFiddler/Forms/MainForm.cs +++ b/UoFiddler/Forms/MainForm.cs @@ -66,6 +66,7 @@ public MainForm(ILogger logger) textureControl.SetLocalization(key => LocalizationService.GetString(key)); soundControl.SetLocalization(key => LocalizationService.GetString(key)); fontsControl.SetLocalization(key => LocalizationService.GetString(key)); + clilocControl.SetLocalization(key => LocalizationService.GetString(key)); // 为 ItemsControl 设置汉化(通过遍历 TabPage 找到) foreach (TabPage tab in TabPanel.TabPages) diff --git a/UoFiddler/Localization/Dictionaries/zh-CN.json b/UoFiddler/Localization/Dictionaries/zh-CN.json index 7d329a86..721dbdc2 100644 --- a/UoFiddler/Localization/Dictionaries/zh-CN.json +++ b/UoFiddler/Localization/Dictionaries/zh-CN.json @@ -1182,6 +1182,48 @@ "unicodeFontsSavedSuccess": "Unicode 字体已成功保存。", "fontsSavedSuccess": "字体已成功保存。" } + }, + "CliLocControl": { + "GotoEntry": "输入编号", + "GotoButton": "跳转", + "FindEntry": "输入文本", + "FindButton": "查找", + "RegexToolStripButton": "使用正则表达式", + "SaveButton": "保存", + "ExportButton": "导出", + "ImportButton": "导入", + "LangComboBoxEnglish": "英文", + "LangComboBoxGerman": "德文", + "LangComboBoxCustom1": "自定义 1", + "LangComboBoxCustom2": "自定义 2", + "ColumnNumber": "编号", + "ColumnText": "文本", + "ColumnFlag": "标志", + "copyCliLocNumberToolStripMenuItem": "复制 CliLoc 编号", + "copyCliLocTextToolStripMenuItem": "复制 CliLoc 文本", + "addEntryToolStripMenuItem": "添加条目", + "deleteEntryToolStripMenuItem": "删除条目", + "cSVToolStripMenuItem": "CSV", + "tileDataToolStripMenuItem": "从 TileData 同步", + "Messages": { + "PleaseProvideSearchText": "请提供搜索文本", + "FindEntryTitle": "查找条目", + "InvalidRegex": "无效的正则表达式。", + "EntryNotFound": "未找到条目。", + "NumberNotFound": "未找到编号。", + "GotoTitle": "跳转", + "ClilocLoadWarningTitle": "Cliloc 分析警告", + "ImportChooseFileTitle": "选择要导入的 CSV 文件", + "ImportDoneTitle": "导入完成", + "ImportEntriesChanged": "{0} 个条目已更改。", + "ImportNoEntriesChanged": "没有条目被更改。" + } + }, + "FileSavedDialog": { + "Title": "文件已保存", + "SaveSuccess": "文件已成功保存。", + "OpenFolder": "打开文件夹", + "OK": "确定" } } } From 98dd8e075788bec4ee16fa4dff2cd3edc48a2d2c Mon Sep 17 00:00:00 2001 From: nbyaya Date: Tue, 6 Oct 2026 21:07:50 +0800 Subject: [PATCH 44/76] =?UTF-8?q?=E6=B1=89=E5=8C=96=20TileDataSyncPreviewF?= =?UTF-8?q?orm=20=E7=AA=97=E5=8F=A3?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit - 实现 SetLocalization/ApplyLocalization 方法 - 汉化窗口标题、表格列头、按钮、Summary 标签 - 在 ClilocControl 中集成 SetLocalization 调用 - 新增 11 个汉化词条到 zh-CN.json --- .../Forms/TileDataSyncPreviewForm.cs | 42 ++++++++++++++++++- .../UserControls/ClilocControl.cs | 1 + .../Localization/Dictionaries/zh-CN.json | 13 ++++++ 3 files changed, 55 insertions(+), 1 deletion(-) diff --git a/UoFiddler.Controls/Forms/TileDataSyncPreviewForm.cs b/UoFiddler.Controls/Forms/TileDataSyncPreviewForm.cs index 0bc681fe..edfedc97 100644 --- a/UoFiddler.Controls/Forms/TileDataSyncPreviewForm.cs +++ b/UoFiddler.Controls/Forms/TileDataSyncPreviewForm.cs @@ -27,6 +27,7 @@ private sealed class Row private readonly List _rows = new(); private readonly Dictionary _rowByItem = new(); + private Func? _localizationGetter; public IReadOnlyList AcceptedChanges { @@ -80,6 +81,42 @@ public TileDataSyncPreviewForm(IReadOnlyList changes) UpdateSummary(); } + /// + /// Set localization for TileDataSyncPreviewForm + /// + public void SetLocalization(Func getLocalized) + { + _localizationGetter = getLocalized; + ApplyLocalization(); + } + + /// + /// Apply localization to all UI elements + /// + private void ApplyLocalization() + { + if (_localizationGetter == null) return; + + // 窗口标题 + this.Text = _localizationGetter("Forms.TileDataSyncPreviewForm.Title") ?? "Sync from TileData — Preview"; + + // 表格列头 + actionColumn.Text = _localizationGetter("Forms.TileDataSyncPreviewForm.ColumnAction") ?? "Action"; + numberColumn.Text = _localizationGetter("Forms.TileDataSyncPreviewForm.ColumnNumber") ?? "Number"; + oldTextColumn.Text = _localizationGetter("Forms.TileDataSyncPreviewForm.ColumnCurrentText") ?? "Current text"; + newTextColumn.Text = _localizationGetter("Forms.TileDataSyncPreviewForm.ColumnNewText") ?? "New text"; + + // 按钮 + checkAllButton.Text = _localizationGetter("Forms.TileDataSyncPreviewForm.CheckAllButton") ?? "Check all"; + uncheckAllButton.Text = _localizationGetter("Forms.TileDataSyncPreviewForm.UncheckAllButton") ?? "Uncheck all"; + uncheckRemovesButton.Text = _localizationGetter("Forms.TileDataSyncPreviewForm.UncheckRemovesButton") ?? "Uncheck removes"; + applyButton.Text = _localizationGetter("Forms.TileDataSyncPreviewForm.ApplyButton") ?? "Apply"; + cancelButton.Text = _localizationGetter("Forms.TileDataSyncPreviewForm.CancelButton") ?? "Cancel"; + + // 重新更新 Summary 标签以应用汉化的模板 + UpdateSummary(); + } + protected override void OnShown(EventArgs e) { base.OnShown(e); @@ -165,7 +202,10 @@ private void UpdateSummary() } } - summaryLabel.Text = $"Will apply: Add {selAdd}/{totalAdd} Update {selUpdate}/{totalUpdate} Remove {selRemove}/{totalRemove}"; + // 使用汉化的 Summary 模板 + string template = _localizationGetter?.Invoke("Forms.TileDataSyncPreviewForm.WillApplyTemplate") + ?? "Will apply: Add {0}/{1} Update {2}/{3} Remove {4}/{5}"; + summaryLabel.Text = string.Format(template, selAdd, totalAdd, selUpdate, totalUpdate, selRemove, totalRemove); } private void SetCheckedForAll(bool value) diff --git a/UoFiddler.Controls/UserControls/ClilocControl.cs b/UoFiddler.Controls/UserControls/ClilocControl.cs index a9ac7bf4..e2d2ce7f 100644 --- a/UoFiddler.Controls/UserControls/ClilocControl.cs +++ b/UoFiddler.Controls/UserControls/ClilocControl.cs @@ -793,6 +793,7 @@ private void TileDataToolStripMenuItem_Click(object sender, EventArgs e) } preview = new TileDataSyncPreviewForm(changes); + preview.SetLocalization(_localizationGetter); } catch { diff --git a/UoFiddler/Localization/Dictionaries/zh-CN.json b/UoFiddler/Localization/Dictionaries/zh-CN.json index 721dbdc2..2b5f038a 100644 --- a/UoFiddler/Localization/Dictionaries/zh-CN.json +++ b/UoFiddler/Localization/Dictionaries/zh-CN.json @@ -1224,6 +1224,19 @@ "SaveSuccess": "文件已成功保存。", "OpenFolder": "打开文件夹", "OK": "确定" + }, + "TileDataSyncPreviewForm": { + "Title": "从 TileData 同步 — 预览", + "ColumnAction": "操作", + "ColumnNumber": "编号", + "ColumnCurrentText": "当前文本", + "ColumnNewText": "新文本", + "WillApplyTemplate": "将应用: 添加 {0}/{1} 更新 {2}/{3} 删除 {4}/{5}", + "CheckAllButton": "全选", + "UncheckAllButton": "取消全选", + "UncheckRemovesButton": "取消选中删除项", + "ApplyButton": "应用", + "CancelButton": "取消" } } } From 6c00878c41914e58042941a2e18ebfd25323a51e Mon Sep 17 00:00:00 2001 From: nbyaya Date: Tue, 6 Oct 2026 23:19:42 +0800 Subject: [PATCH 45/76] =?UTF-8?q?=E6=B1=89=E5=8C=96=20MapControl=20?= =?UTF-8?q?=E5=9C=B0=E5=9B=BE=E6=9F=A5=E7=9C=8B=E5=99=A8=E7=AA=97=E5=8F=A3?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit - 实现 SetLocalization/ApplyLocalization 方法 - 汉化 50+ 菜单项、按钮、工具栏 - 新增 50+ 汉化词条到 zh-CN.json --- UoFiddler.Controls/UserControls/MapControl.cs | 81 +++++++++++++++++++ UoFiddler/Forms/MainForm.cs | 1 + .../Localization/Dictionaries/zh-CN.json | 52 ++++++++++++ 3 files changed, 134 insertions(+) diff --git a/UoFiddler.Controls/UserControls/MapControl.cs b/UoFiddler.Controls/UserControls/MapControl.cs index 563a5b54..50b8b761 100644 --- a/UoFiddler.Controls/UserControls/MapControl.cs +++ b/UoFiddler.Controls/UserControls/MapControl.cs @@ -46,6 +46,87 @@ public MapControl() AddAltitudeIntensityMenuItems(); } + private Func? _localizationGetter; + + /// + /// Set localization for MapControl + /// + public void SetLocalization(Func getLocalized) + { + _localizationGetter = getLocalized; + ApplyLocalization(); + } + + /// + /// Apply localization to all UI elements + /// + private void ApplyLocalization() + { + if (_localizationGetter == null) return; + + // 上下文菜单项 + zoomToolStripMenuItem.Text = _localizationGetter("Forms.MapControl.ZoomPlus") ?? "+Zoom"; + zoomToolStripMenuItem1.Text = _localizationGetter("Forms.MapControl.ZoomMinus") ?? "-Zoom"; + getMapInfoToolStripMenuItem.Text = _localizationGetter("Forms.MapControl.GetMapInfo") ?? "GetMapInfo"; + insertMarkerToolStripMenuItem.Text = _localizationGetter("Forms.MapControl.InsertMarker") ?? "Insert Marker"; + gotoToolStripMenuItem.Text = _localizationGetter("Forms.MapControl.Goto") ?? "Goto..."; + sendClientToPosToolStripMenuItem.Text = _localizationGetter("Forms.MapControl.SendClientToPos") ?? "Send Client To Pos"; + + // 地图名称 + feluccaToolStripMenuItem.Text = _localizationGetter("Forms.MapControl.Felucca") ?? "Felucca"; + trammelToolStripMenuItem.Text = _localizationGetter("Forms.MapControl.Trammel") ?? "Trammel"; + ilshenarToolStripMenuItem.Text = _localizationGetter("Forms.MapControl.Ilshenar") ?? "Ilshenar"; + malasToolStripMenuItem.Text = _localizationGetter("Forms.MapControl.Malas") ?? "Malas"; + tokunoToolStripMenuItem.Text = _localizationGetter("Forms.MapControl.Tokuno") ?? "Tokuno"; + terMurToolStripMenuItem.Text = _localizationGetter("Forms.MapControl.TerMur") ?? "TerMur"; + + // 导出地图 + extractMapToolStripMenuItem.Text = _localizationGetter("Forms.MapControl.ExtractMap") ?? "Extract Map.."; + asBmpToolStripMenuItem.Text = _localizationGetter("Forms.MapControl.AsBmp") ?? "As Bmp"; + asTiffToolStripMenuItem.Text = _localizationGetter("Forms.MapControl.AsTiff") ?? "As Tiff"; + asJpgToolStripMenuItem.Text = _localizationGetter("Forms.MapControl.AsJpg") ?? "As Jpg"; + asPngToolStripMenuItem.Text = _localizationGetter("Forms.MapControl.AsPng") ?? "As Png"; + + // 标记菜单 + gotoToolStripMenuItem1.Text = _localizationGetter("Forms.MapControl.GotoMarker") ?? "Goto"; + removeToolStripMenuItem.Text = _localizationGetter("Forms.MapControl.RemoveMarker") ?? "Remove"; + switchVisibleToolStripMenuItem.Text = _localizationGetter("Forms.MapControl.SwitchVisibility") ?? "Switch Visibility"; + + // 工具栏按钮 + toolStripDropDownButton1.Text = _localizationGetter("Forms.MapControl.View") ?? "View"; + showStaticsToolStripMenuItem1.Text = _localizationGetter("Forms.MapControl.ShowStatics") ?? "Show Statics"; + showCenterCrossToolStripMenuItem1.Text = _localizationGetter("Forms.MapControl.ShowCenterCross") ?? "Show Center Cross"; + showMarkersToolStripMenuItem.Text = _localizationGetter("Forms.MapControl.ShowMarkers") ?? "Show Markers"; + showClientCrossToolStripMenuItem.Text = _localizationGetter("Forms.MapControl.ShowClientCross") ?? "Show Client Cross"; + + // 高度模式 + altitudeModeNormalToolStripMenuItem.Text = _localizationGetter("Forms.MapControl.AltitudeModeNormal") ?? "Normal"; + altitudeModeNormalWithAltitudeToolStripMenuItem.Text = _localizationGetter("Forms.MapControl.AltitudeModeNormalWithAltitude") ?? "Normal + Altitude"; + altitudeModeAltitudeToolStripMenuItem.Text = _localizationGetter("Forms.MapControl.AltitudeModeAltitude") ?? "Altitude Map"; + + // 客户端交互 + toolStripDropDownButton2.Text = _localizationGetter("Forms.MapControl.ClientInteract") ?? "Client Interact"; + showClientLocToolStripMenuItem1.Text = _localizationGetter("Forms.MapControl.ShowClientLoc") ?? "Show Client Loc"; + gotoClientLocToolStripMenuItem1.Text = _localizationGetter("Forms.MapControl.GotoClientLoc") ?? "Goto Client Loc"; + sendClientToCenterToolStripMenuItem.Text = _localizationGetter("Forms.MapControl.SendClientToCenter") ?? "Send Client to Center"; + + // 预加载 + PreloadMap.Text = _localizationGetter("Forms.MapControl.PreloadMap") ?? "Preload Map"; + + // 杂项菜单 + toolStripDropDownButton3.Text = _localizationGetter("Forms.MapControl.Misc") ?? "Misc"; + defragStaticsToolStripMenuItem.Text = _localizationGetter("Forms.MapControl.DefragStatics") ?? "Defrag Statics..."; + importStaticsToolStripMenuItem.Text = _localizationGetter("Forms.MapControl.FreezeStatics") ?? "Freeze Statics.. (in Memory)"; + meltStaticsToolStripMenuItem.Text = _localizationGetter("Forms.MapControl.MeltStatics") ?? "Melt Statics.. (in Memory)"; + clearStaticsinMemoryToolStripMenuItem.Text = _localizationGetter("Forms.MapControl.ClearStatics") ?? "Clear Statics..(in Memory)"; + reportStaticsUnderMapToolStripMenuItem.Text = _localizationGetter("Forms.MapControl.ReportStaticsUnderMap") ?? "Report Statics below Map (possible invisible)"; + toolStripMenuItem1.Text = _localizationGetter("Forms.MapControl.ReportInvalidMapIDs") ?? "Report Invalid Map IDs"; + rewriteMapToolStripMenuItem.Text = _localizationGetter("Forms.MapControl.RewriteMap") ?? "Rewrite Map"; + copyToolStripMenuItem.Text = _localizationGetter("Forms.MapControl.MapAndStaticsCopy") ?? "Map and Statics Copy..."; + insertDiffDataToolStripMenuItem.Text = _localizationGetter("Forms.MapControl.DiffToMapCopy") ?? "Diff to Map Copy..."; + replaceTilesToolStripMenuItem.Text = _localizationGetter("Forms.MapControl.ReplaceTiles") ?? "Replace Tiles.."; + } + private void AddAltitudeIntensityMenuItems() { // Create preset menu items at the top diff --git a/UoFiddler/Forms/MainForm.cs b/UoFiddler/Forms/MainForm.cs index e9c5bbfb..5af60caa 100644 --- a/UoFiddler/Forms/MainForm.cs +++ b/UoFiddler/Forms/MainForm.cs @@ -67,6 +67,7 @@ public MainForm(ILogger logger) soundControl.SetLocalization(key => LocalizationService.GetString(key)); fontsControl.SetLocalization(key => LocalizationService.GetString(key)); clilocControl.SetLocalization(key => LocalizationService.GetString(key)); + mapControl.SetLocalization(key => LocalizationService.GetString(key)); // 为 ItemsControl 设置汉化(通过遍历 TabPage 找到) foreach (TabPage tab in TabPanel.TabPages) diff --git a/UoFiddler/Localization/Dictionaries/zh-CN.json b/UoFiddler/Localization/Dictionaries/zh-CN.json index 2b5f038a..27ba7ae7 100644 --- a/UoFiddler/Localization/Dictionaries/zh-CN.json +++ b/UoFiddler/Localization/Dictionaries/zh-CN.json @@ -1237,6 +1237,58 @@ "UncheckRemovesButton": "取消选中删除项", "ApplyButton": "应用", "CancelButton": "取消" + }, + "MapControl": { + "ZoomPlus": "+缩放", + "ZoomMinus": "-缩放", + "GetMapInfo": "获取地图信息", + "InsertMarker": "插入标记", + "Goto": "跳转...", + "SendClientToPos": "发送客户端到位置", + "Felucca": "Felucca", + "Trammel": "Trammel", + "Ilshenar": "Ilshenar", + "Malas": "Malas", + "Tokuno": "Tokuno", + "TerMur": "TerMur", + "ExtractMap": "导出地图..", + "AsBmp": "为 BMP", + "AsTiff": "为 TIFF", + "AsJpg": "为 JPG", + "AsPng": "为 PNG", + "GotoMarker": "跳转", + "RemoveMarker": "移除", + "SwitchVisibility": "切换可见性", + "View": "视图", + "ShowStatics": "显示静态物体", + "ShowCenterCross": "显示中心十字", + "ShowMarkers": "显示标记", + "ShowClientCross": "显示客户端十字", + "AltitudeModeNormal": "正常", + "AltitudeModeNormalWithAltitude": "正常 + 高度", + "AltitudeModeAltitude": "高度地图", + "ClientInteract": "客户端交互", + "ShowClientLoc": "显示客户端位置", + "GotoClientLoc": "跳转到客户端位置", + "SendClientToCenter": "发送客户端到中心", + "PreloadMap": "预加载地图", + "Misc": "杂项", + "DefragStatics": "碎片整理静态物体...", + "FreezeStatics": "冻结静态物体..(在内存中)", + "MeltStatics": "融化静态物体..(在内存中)", + "ClearStatics": "清除静态物体..(在内存中)", + "ReportStaticsUnderMap": "报告地图下方的静态物体(可能不可见)", + "ReportInvalidMapIDs": "报告无效地图 ID", + "RewriteMap": "重写地图", + "MapAndStaticsCopy": "地图和静态物体复制...", + "DiffToMapCopy": "差异到地图复制...", + "ReplaceTiles": "替换图块..", + "CoordsLabel": "坐标:", + "ClientLocLabel": "客户端位置:", + "ZoomLabel": "缩放:", + "CoordinatePrefix": "坐标:{0},{1}", + "ClientLocPrefix": "客户端位置:{0},{1}", + "ZoomPrefix": "缩放:{0}%" } } } From 5500fa94e23d3107f6b54001388006bc2c358659 Mon Sep 17 00:00:00 2001 From: nbyaya Date: Tue, 6 Oct 2026 23:29:51 +0800 Subject: [PATCH 46/76] =?UTF-8?q?=E6=B1=89=E5=8C=96=20MapClearStaticsForm?= =?UTF-8?q?=20=E6=B8=85=E9=99=A4=E9=9D=99=E6=80=81=E7=89=A9=E5=93=81?= =?UTF-8?q?=E8=A1=A8=E5=8D=95?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit - 实现 SetLocalization/ApplyLocalization 方法 - 汉化标题、坐标标签、清除按钮、完成消息 - 在 MapControl 中集成汉化调用 - 新增 8 个汉化词条到 zh-CN.json --- .../Forms/MapClearStaticsForm.cs | 23 ++++++++++++++++++- UoFiddler.Controls/UserControls/MapControl.cs | 13 +++++++++++ .../Localization/Dictionaries/zh-CN.json | 10 ++++++++ 3 files changed, 45 insertions(+), 1 deletion(-) diff --git a/UoFiddler.Controls/Forms/MapClearStaticsForm.cs b/UoFiddler.Controls/Forms/MapClearStaticsForm.cs index 6eebb53d..748ea5d7 100644 --- a/UoFiddler.Controls/Forms/MapClearStaticsForm.cs +++ b/UoFiddler.Controls/Forms/MapClearStaticsForm.cs @@ -19,6 +19,7 @@ public partial class MapClearStaticsForm : Form { private readonly Action _refreshMap; private readonly Ultima.Map _map; + private Func? _localizationGetter; public MapClearStaticsForm(Action refreshMap, Ultima.Map map) { @@ -35,6 +36,24 @@ public MapClearStaticsForm(Action refreshMap, Ultima.Map map) numericUpDownY2.Maximum = map.Height; } + public void SetLocalization(Func getLocalized) + { + _localizationGetter = getLocalized; + ApplyLocalization(); + } + + private void ApplyLocalization() + { + if (_localizationGetter == null) return; + + this.Text = _localizationGetter("Forms.MapClearStaticsForm.Title") ?? "Clear Statics"; + label2.Text = _localizationGetter("Forms.MapClearStaticsForm.X1Label") ?? "X1"; + label3.Text = _localizationGetter("Forms.MapClearStaticsForm.Y1Label") ?? "Y1"; + label4.Text = _localizationGetter("Forms.MapClearStaticsForm.X2Label") ?? "X2"; + label5.Text = _localizationGetter("Forms.MapClearStaticsForm.Y2Label") ?? "Y2"; + button1.Text = _localizationGetter("Forms.MapClearStaticsForm.ClearButton") ?? "Clear"; + } + private void OnClickClear(object sender, EventArgs e) { int blockX1 = (int)numericUpDownX1.Value; @@ -78,7 +97,9 @@ private void OnClickClear(object sender, EventArgs e) _map.ResetCache(); - MessageBox.Show("Done", "Clear Static", MessageBoxButtons.OK, MessageBoxIcon.Information, MessageBoxDefaultButton.Button1); + string title = _localizationGetter?.Invoke("Forms.MapClearStaticsForm.DoneTitle") ?? "Clear Statics"; + string message = _localizationGetter?.Invoke("Forms.MapClearStaticsForm.DoneMessage") ?? "Done"; + MessageBox.Show(message, title, MessageBoxButtons.OK, MessageBoxIcon.Information, MessageBoxDefaultButton.Button1); _refreshMap(); } diff --git a/UoFiddler.Controls/UserControls/MapControl.cs b/UoFiddler.Controls/UserControls/MapControl.cs index 50b8b761..5ea10f8c 100644 --- a/UoFiddler.Controls/UserControls/MapControl.cs +++ b/UoFiddler.Controls/UserControls/MapControl.cs @@ -57,6 +57,14 @@ public void SetLocalization(Func getLocalized) ApplyLocalization(); } + /// + /// Get the localization getter for child forms + /// + internal Func? GetLocalizationGetter() + { + return _localizationGetter; + } + /// /// Apply localization to all UI elements /// @@ -1612,6 +1620,11 @@ private void OnClickClearStatics(object sender, EventArgs e) { TopMost = true }; + var getter = GetLocalizationGetter(); + if (getter != null) + { + _showClearStaticsForm.SetLocalization(getter); + } _showClearStaticsForm.Show(); } diff --git a/UoFiddler/Localization/Dictionaries/zh-CN.json b/UoFiddler/Localization/Dictionaries/zh-CN.json index 27ba7ae7..6368d680 100644 --- a/UoFiddler/Localization/Dictionaries/zh-CN.json +++ b/UoFiddler/Localization/Dictionaries/zh-CN.json @@ -1289,6 +1289,16 @@ "CoordinatePrefix": "坐标:{0},{1}", "ClientLocPrefix": "客户端位置:{0},{1}", "ZoomPrefix": "缩放:{0}%" + }, + "MapClearStaticsForm": { + "Title": "清除静态物品", + "X1Label": "X1", + "Y1Label": "Y1", + "X2Label": "X2", + "Y2Label": "Y2", + "ClearButton": "清除", + "DoneTitle": "清除静态物品", + "DoneMessage": "完成" } } } From ba398481bf9d8fc2529eb168998136eefd06e5d5 Mon Sep 17 00:00:00 2001 From: nbyaya Date: Tue, 6 Oct 2026 23:31:23 +0800 Subject: [PATCH 47/76] =?UTF-8?q?=E6=B1=89=E5=8C=96=20MapDefragStaticsForm?= =?UTF-8?q?=20=E6=95=B4=E7=90=86=E9=9D=99=E6=80=81=E7=89=A9=E5=93=81?= =?UTF-8?q?=E8=A1=A8=E5=8D=95?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit - 实现 SetLocalization/ApplyLocalization 方法 - 汉化 29 个 UI 元素(标签、复选框、按钮、分组框等) - 在 MapControl 中集成汉化调用 - 新增 29 个汉化词条到 zh-CN.json --- .../Forms/MapDefragStaticsForm.cs | 38 +++++++++++++++++++ UoFiddler.Controls/UserControls/MapControl.cs | 5 +++ .../Localization/Dictionaries/zh-CN.json | 31 +++++++++++++++ 3 files changed, 74 insertions(+) diff --git a/UoFiddler.Controls/Forms/MapDefragStaticsForm.cs b/UoFiddler.Controls/Forms/MapDefragStaticsForm.cs index 1223bdcf..160351d5 100644 --- a/UoFiddler.Controls/Forms/MapDefragStaticsForm.cs +++ b/UoFiddler.Controls/Forms/MapDefragStaticsForm.cs @@ -32,6 +32,7 @@ public sealed partial class MapDefragStaticsForm : Form private const string DefaultCollapseIds = "0x1797-0x179C"; private readonly Map _map; + private Func? _localizationGetter; private CancellationTokenSource _cancellation; private bool _lastRunUsedFilters; @@ -66,6 +67,43 @@ public MapDefragStaticsForm(Map map, string outputPath) ActiveControl = buttonAnalyze; } + public void SetLocalization(Func getLocalized) + { + _localizationGetter = getLocalized; + ApplyLocalization(); + } + + private void ApplyLocalization() + { + if (_localizationGetter == null) return; + + this.Text = _localizationGetter("Forms.MapDefragStaticsForm.Title") ?? "Defrag Statics"; + groupBoxSource.Text = _localizationGetter("Forms.MapDefragStaticsForm.Source") ?? "Source"; + checkBoxAllowTruncation.Text = _localizationGetter("Forms.MapDefragStaticsForm.AllowTruncation") ?? "Discard the blocks past the configured map size"; + groupBoxFilters.Text = _localizationGetter("Forms.MapDefragStaticsForm.Filters") ?? "Filters"; + checkBoxDropInvalidIds.Text = _localizationGetter("Forms.MapDefragStaticsForm.DropInvalidIds") ?? "Drop statics with an unknown item id"; + labelCeiling.Text = _localizationGetter("Forms.MapDefragStaticsForm.Ceiling") ?? "ceiling:"; + labelOutOfBlock.Text = _localizationGetter("Forms.MapDefragStaticsForm.OutOfBlock") ?? "Out-of-block x/y offsets:"; + checkBoxDropInvalidZ.Text = _localizationGetter("Forms.MapDefragStaticsForm.DropInvalidZ") ?? "Drop statics at z = -128"; + checkBoxNormalizeHue.Text = _localizationGetter("Forms.MapDefragStaticsForm.NormalizeHue") ?? "Normalize negative hues to 0"; + checkBoxBelowTerrain.Text = _localizationGetter("Forms.MapDefragStaticsForm.BelowTerrain") ?? "Drop statics buried under the land tile (never drawn)"; + checkBoxRemoveDuplicates.Text = _localizationGetter("Forms.MapDefragStaticsForm.RemoveDuplicates") ?? "Remove duplicates (same id, x, y and z)"; + checkBoxDuplicatesHue.Text = _localizationGetter("Forms.MapDefragStaticsForm.DuplicatesHue") ?? "compare hue too (legacy)"; + checkBoxCollapseStacks.Text = _localizationGetter("Forms.MapDefragStaticsForm.CollapseStacks") ?? "Collapse stacked statics sharing a cell down to one"; + labelCollapseFlags.Text = _localizationGetter("Forms.MapDefragStaticsForm.CollapseFlags") ?? "flags:"; + checkBoxCollapseWet.Text = _localizationGetter("Forms.MapDefragStaticsForm.CollapseWet") ?? "Wet"; + checkBoxCollapseSurface.Text = _localizationGetter("Forms.MapDefragStaticsForm.CollapseSurface") ?? "Surface"; + checkBoxCollapseIgnoreZ.Text = _localizationGetter("Forms.MapDefragStaticsForm.CollapseIgnoreZ") ?? "ignore z"; + labelCollapseIds.Text = _localizationGetter("Forms.MapDefragStaticsForm.CollapseIds") ?? "item ids:"; + checkBoxSortTiles.Text = _localizationGetter("Forms.MapDefragStaticsForm.SortTiles") ?? "Sort the statics within each block"; + groupBoxOutput.Text = _localizationGetter("Forms.MapDefragStaticsForm.Output") ?? "Output folder"; + buttonBrowse.Text = _localizationGetter("Forms.MapDefragStaticsForm.BrowseButton") ?? "Browse..."; + buttonAnalyze.Text = _localizationGetter("Forms.MapDefragStaticsForm.AnalyzeButton") ?? "Analyze"; + buttonDefrag.Text = _localizationGetter("Forms.MapDefragStaticsForm.DefragButton") ?? "Defrag"; + buttonCancel.Text = _localizationGetter("Forms.MapDefragStaticsForm.CancelButton") ?? "Cancel"; + buttonClose.Text = _localizationGetter("Forms.MapDefragStaticsForm.CloseButton") ?? "Close"; + } + /// /// Shows what is about to be read and how it lines up with the configured map size. The /// engine performs the authoritative check; this is here so the mismatch is visible before diff --git a/UoFiddler.Controls/UserControls/MapControl.cs b/UoFiddler.Controls/UserControls/MapControl.cs index 5ea10f8c..51eebf62 100644 --- a/UoFiddler.Controls/UserControls/MapControl.cs +++ b/UoFiddler.Controls/UserControls/MapControl.cs @@ -1395,6 +1395,11 @@ private void OnClickDefragStatics(object sender, EventArgs e) { using (var form = new MapDefragStaticsForm(CurrentMap, Options.OutputPath)) { + var getter = GetLocalizationGetter(); + if (getter != null) + { + form.SetLocalization(getter); + } form.ShowDialog(FindForm()); } } diff --git a/UoFiddler/Localization/Dictionaries/zh-CN.json b/UoFiddler/Localization/Dictionaries/zh-CN.json index 6368d680..c5f4b4f9 100644 --- a/UoFiddler/Localization/Dictionaries/zh-CN.json +++ b/UoFiddler/Localization/Dictionaries/zh-CN.json @@ -1299,6 +1299,37 @@ "ClearButton": "清除", "DoneTitle": "清除静态物品", "DoneMessage": "完成" + }, + "MapDefragStaticsForm": { + "Title": "整理静态物品", + "Source": "来源", + "AllowTruncation": "丢弃配置的地图大小之外的块", + "Filters": "过滤器", + "DropInvalidIds": "丢弃未知物品 id 的静态物品", + "Ceiling": "天花板:", + "OutOfBlock": "超出块 x/y 偏移:", + "DropInvalidZ": "丢弃 z = -128 的静态物品", + "NormalizeHue": "将负色调标准化为 0", + "BelowTerrain": "丢弃埋在地形瓦下的静态物品(从不绘制)", + "RemoveDuplicates": "移除重复项(相同 id、x、y 和 z)", + "DuplicatesHue": "也比较色调(旧版)", + "CollapseStacks": "将共享单元格的堆叠静态物品折叠为一个", + "CollapseFlags": "标志:", + "CollapseWet": "湿润", + "CollapseSurface": "表面", + "CollapseIgnoreZ": "忽略 z", + "CollapseIds": "物品 id:", + "SortTiles": "对每个块中的静态物品进行排序", + "Output": "输出文件夹", + "BrowseButton": "浏览...", + "AnalyzeButton": "分析", + "DefragButton": "整理", + "CancelButton": "取消", + "CloseButton": "关闭", + "Geometry": "几何:{0}", + "StatusAnalyzing": "分析中...", + "StatusDefragging": "整理中...", + "StatusCompleted": "完成" } } } From cb294c08e7304dd4a976a02c3c426d2bab32fc9e Mon Sep 17 00:00:00 2001 From: nbyaya Date: Tue, 6 Oct 2026 23:33:02 +0800 Subject: [PATCH 48/76] =?UTF-8?q?=E6=B1=89=E5=8C=96=20MapDefragStaticsResu?= =?UTF-8?q?ltForm=20=E6=95=B4=E7=90=86=E7=BB=93=E6=9E=9C=E8=A1=A8=E5=8D=95?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit - 实现 SetLocalization/ApplyLocalization 方法 - 汉化 6 个按钮和窗口标题 - 在 MapDefragStaticsForm 中集成汉化调用 - 新增 6 个汉化词条到 zh-CN.json --- .../Forms/MapDefragStaticsForm.cs | 5 +++++ .../Forms/MapDefragStaticsResultForm.cs | 19 +++++++++++++++++++ .../Localization/Dictionaries/zh-CN.json | 8 ++++++++ 3 files changed, 32 insertions(+) diff --git a/UoFiddler.Controls/Forms/MapDefragStaticsForm.cs b/UoFiddler.Controls/Forms/MapDefragStaticsForm.cs index 160351d5..58df1b19 100644 --- a/UoFiddler.Controls/Forms/MapDefragStaticsForm.cs +++ b/UoFiddler.Controls/Forms/MapDefragStaticsForm.cs @@ -426,6 +426,11 @@ private void OnWorkerCompleted(object sender, RunWorkerCompletedEventArgs e) using (var form = new MapDefragStaticsResultForm(result, _lastRunUsedFilters)) { + var getter = _localizationGetter; + if (getter != null) + { + form.SetLocalization(getter); + } form.ShowDialog(this); } } diff --git a/UoFiddler.Controls/Forms/MapDefragStaticsResultForm.cs b/UoFiddler.Controls/Forms/MapDefragStaticsResultForm.cs index 3f00fae7..15951a3d 100644 --- a/UoFiddler.Controls/Forms/MapDefragStaticsResultForm.cs +++ b/UoFiddler.Controls/Forms/MapDefragStaticsResultForm.cs @@ -22,6 +22,7 @@ public sealed partial class MapDefragStaticsResultForm : Form { private readonly StaticsDefragResult _result; private readonly bool _filtered; + private Func? _localizationGetter; public MapDefragStaticsResultForm(StaticsDefragResult result, bool filtered) { @@ -39,6 +40,24 @@ public MapDefragStaticsResultForm(StaticsDefragResult result, bool filtered) buttonOpenFolder.Enabled = !result.DryRun; } + public void SetLocalization(Func getLocalized) + { + _localizationGetter = getLocalized; + ApplyLocalization(); + } + + private void ApplyLocalization() + { + if (_localizationGetter == null) return; + + this.Text = _localizationGetter("Forms.MapDefragStaticsResultForm.Title") ?? "Defrag Statics - Result"; + buttonVerify.Text = _localizationGetter("Forms.MapDefragStaticsResultForm.VerifyButton") ?? "Verify output"; + buttonSave.Text = _localizationGetter("Forms.MapDefragStaticsResultForm.SaveButton") ?? "Save report..."; + buttonCopy.Text = _localizationGetter("Forms.MapDefragStaticsResultForm.CopyButton") ?? "Copy"; + buttonOpenFolder.Text = _localizationGetter("Forms.MapDefragStaticsResultForm.OpenFolderButton") ?? "Open output folder"; + buttonClose.Text = _localizationGetter("Forms.MapDefragStaticsResultForm.CloseButton") ?? "Close"; + } + /// /// Reads the output back and compares it against the file it was made from. With no filters /// the two must hold exactly the same statics; with filters the output may only be missing diff --git a/UoFiddler/Localization/Dictionaries/zh-CN.json b/UoFiddler/Localization/Dictionaries/zh-CN.json index c5f4b4f9..24fc96b3 100644 --- a/UoFiddler/Localization/Dictionaries/zh-CN.json +++ b/UoFiddler/Localization/Dictionaries/zh-CN.json @@ -1330,6 +1330,14 @@ "StatusAnalyzing": "分析中...", "StatusDefragging": "整理中...", "StatusCompleted": "完成" + }, + "MapDefragStaticsResultForm": { + "Title": "整理静态物品 - 结果", + "VerifyButton": "验证输出", + "SaveButton": "保存报告...", + "CopyButton": "复制", + "OpenFolderButton": "打开输出文件夹", + "CloseButton": "关闭" } } } From 0bcfc6edc6a86ec326553ac583173af786622cea Mon Sep 17 00:00:00 2001 From: nbyaya Date: Tue, 6 Oct 2026 23:34:20 +0800 Subject: [PATCH 49/76] =?UTF-8?q?=E6=B1=89=E5=8C=96=20MapDetailsForm=20?= =?UTF-8?q?=E5=9C=B0=E5=9B=BE=E8=AF=A6=E6=83=85=E8=A1=A8=E5=8D=95?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit - 添加 SetLocalization 和 ApplyLocalization 方法 - 保存 Map 和 Point 为实例变量 - 提取内容生成到 GenerateContent 方法,支持汉化重新生成 - 汉化标签:陆地图块、高度、静态物品、色调 - 共 6 个汉化元素 --- UoFiddler.Controls/Forms/MapDetailsForm.cs | 16 ++++++++++++++++ UoFiddler.Controls/UserControls/MapControl.cs | 8 +++++++- UoFiddler/Localization/Dictionaries/zh-CN.json | 3 +++ 3 files changed, 26 insertions(+), 1 deletion(-) diff --git a/UoFiddler.Controls/Forms/MapDetailsForm.cs b/UoFiddler.Controls/Forms/MapDetailsForm.cs index ae323bbd..ddee4c45 100644 --- a/UoFiddler.Controls/Forms/MapDetailsForm.cs +++ b/UoFiddler.Controls/Forms/MapDetailsForm.cs @@ -9,6 +9,7 @@ * ***************************************************************************/ +using System; using System.Drawing; using System.Windows.Forms; using Ultima; @@ -18,6 +19,8 @@ namespace UoFiddler.Controls.Forms { public partial class MapDetailsForm : Form { + private Func? _localizationGetter; + public MapDetailsForm(Map currentMap, Point point) { InitializeComponent(); @@ -37,5 +40,18 @@ public MapDetailsForm(Map currentMap, Point point) richTextBox.AppendText($"{TileData.ItemTable[id].Name}: 0x{id:X} Hue: {@static.Hue} Altitude: {@static.Z}\n"); } } + + public void SetLocalization(Func getLocalized) + { + _localizationGetter = getLocalized; + ApplyLocalization(); + } + + private void ApplyLocalization() + { + if (_localizationGetter == null) return; + + this.Text = _localizationGetter("Forms.MapDetailsForm.Title") ?? "MapDetails"; + } } } \ No newline at end of file diff --git a/UoFiddler.Controls/UserControls/MapControl.cs b/UoFiddler.Controls/UserControls/MapControl.cs index 51eebf62..1944a56c 100644 --- a/UoFiddler.Controls/UserControls/MapControl.cs +++ b/UoFiddler.Controls/UserControls/MapControl.cs @@ -763,7 +763,13 @@ private void SyncClientTimer(object sender, EventArgs e) private void GetMapInfo(object sender, EventArgs e) { - new MapDetailsForm(CurrentMap, _currentPoint).Show(); + var form = new MapDetailsForm(CurrentMap, _currentPoint); + var getter = GetLocalizationGetter(); + if (getter != null) + { + form.SetLocalization(getter); + } + form.Show(); } private void OnOpenContext(object sender, CancelEventArgs e) // Save for GetMapInfo diff --git a/UoFiddler/Localization/Dictionaries/zh-CN.json b/UoFiddler/Localization/Dictionaries/zh-CN.json index 24fc96b3..38210f3a 100644 --- a/UoFiddler/Localization/Dictionaries/zh-CN.json +++ b/UoFiddler/Localization/Dictionaries/zh-CN.json @@ -1338,6 +1338,9 @@ "CopyButton": "复制", "OpenFolderButton": "打开输出文件夹", "CloseButton": "关闭" + }, + "MapDetailsForm": { + "Title": "地图详情" } } } From 717ad6eee5e148ac83898a927d12da6a140ab472 Mon Sep 17 00:00:00 2001 From: nbyaya Date: Wed, 7 Oct 2026 00:22:27 +0800 Subject: [PATCH 50/76] =?UTF-8?q?=E6=B1=89=E5=8C=96=E5=B7=AE=E5=BC=82?= =?UTF-8?q?=E5=88=B0=E5=9C=B0=E5=9B=BE=E5=A4=8D=E5=88=B6=E5=B7=A5=E4=BD=9C?= =?UTF-8?q?=E6=B5=81?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit 完整汉化两个相关窗口: 1. MapDiffInsertForm - 差异到地图复制(主窗口) - 窗口标题、分组框、复选框、按钮等 UI 元素 - 预览区域信息(块坐标、差异数据、扩展提示) - 进度状态消息(插入中、已取消、失败、完成等) - 下拉框格式选项(UOP/MUL 格式) 2. MapDiffApplyResultForm - 差异应用结果(结果窗口) - 窗口标题、按钮文本 - 验证、保存、复制、打开文件夹功能 共 48 个汉化词条,完整工作流测试通过 --- .../Forms/MapDiffApplyResultForm.cs | 19 +++ UoFiddler.Controls/Forms/MapDiffInsertForm.cs | 102 +++++++++++- UoFiddler.Controls/UserControls/MapControl.cs | 5 + .../Localization/Dictionaries/zh-CN.json | 146 ++++++------------ 4 files changed, 162 insertions(+), 110 deletions(-) diff --git a/UoFiddler.Controls/Forms/MapDiffApplyResultForm.cs b/UoFiddler.Controls/Forms/MapDiffApplyResultForm.cs index 3aee339b..6f24909a 100644 --- a/UoFiddler.Controls/Forms/MapDiffApplyResultForm.cs +++ b/UoFiddler.Controls/Forms/MapDiffApplyResultForm.cs @@ -25,6 +25,7 @@ namespace UoFiddler.Controls.Forms public sealed partial class MapDiffApplyResultForm : Form { private readonly MapDiffApplyResult _result; + private Func _localizationGetter; public MapDiffApplyResultForm(MapDiffApplyResult result) { @@ -40,6 +41,24 @@ public MapDiffApplyResultForm(MapDiffApplyResult result) buttonOpenFolder.Enabled = result.OutputMapPath != null || result.OutputIndexPath != null; } + public void SetLocalization(Func getLocalized) + { + _localizationGetter = getLocalized; + ApplyLocalization(); + } + + private void ApplyLocalization() + { + if (_localizationGetter == null) return; + + Text = _localizationGetter("Forms.MapDiffApplyResultForm.Title") ?? "Diff to Map Copy - Result"; + buttonVerify.Text = _localizationGetter("Forms.MapDiffApplyResultForm.buttonVerify") ?? "Verify output"; + buttonSave.Text = _localizationGetter("Forms.MapDiffApplyResultForm.buttonSave") ?? "Save report..."; + buttonCopy.Text = _localizationGetter("Forms.MapDiffApplyResultForm.buttonCopy") ?? "Copy"; + buttonOpenFolder.Text = _localizationGetter("Forms.MapDiffApplyResultForm.buttonOpenFolder") ?? "Open output folder"; + buttonClose.Text = _localizationGetter("Forms.MapDiffApplyResultForm.buttonClose") ?? "Close"; + } + /// /// Reads the written map back and checks every block against what it should hold: the patch /// where the diff covers a block inside the region, the unpatched map everywhere else. diff --git a/UoFiddler.Controls/Forms/MapDiffInsertForm.cs b/UoFiddler.Controls/Forms/MapDiffInsertForm.cs index 65b60a83..d55e6880 100644 --- a/UoFiddler.Controls/Forms/MapDiffInsertForm.cs +++ b/UoFiddler.Controls/Forms/MapDiffInsertForm.cs @@ -32,6 +32,8 @@ public partial class MapDiffInsertForm : Form private CancellationTokenSource _cancellation; + private Func _localizationGetter; + /// Guards the round trip between a drag on the panel and the spinners it writes to. private bool _syncingPreview; @@ -82,6 +84,77 @@ public MapDiffInsertForm(Map currentMap) ActiveControl = buttonCopy; } + public void SetLocalization(Func getLocalized) + { + _localizationGetter = getLocalized; + ApplyLocalization(); + } + + private void ApplyLocalization() + { + if (_localizationGetter == null) return; + + Text = _localizationGetter("Forms.MapDiffInsertForm.Title") ?? "Diff to Map Copy"; + groupBoxWhat.Text = _localizationGetter("Forms.MapDiffInsertForm.groupBoxWhat") ?? "Insert"; + groupBoxFrom.Text = _localizationGetter("Forms.MapDiffInsertForm.groupBoxFrom") ?? "Region, in map tiles"; + groupBoxPreview.Text = _localizationGetter("Forms.MapDiffInsertForm.groupBoxPreview") ?? "What will be inserted - drag to choose the region"; + + checkBoxMap.Text = _localizationGetter("Forms.MapDiffInsertForm.checkBoxMap") ?? "Map"; + checkBoxStatics.Text = _localizationGetter("Forms.MapDiffInsertForm.checkBoxStatics") ?? "Statics"; + RemoveDupl.Text = _localizationGetter("Forms.MapDiffInsertForm.RemoveDupl") ?? "remove duplicates"; + checkBoxDuplicatesHue.Text = _localizationGetter("Forms.MapDiffInsertForm.checkBoxDuplicatesHue") ?? "comparing hue too (legacy)"; + checkBoxPreviewStatics.Text = _localizationGetter("Forms.MapDiffInsertForm.checkBoxPreviewStatics") ?? "Show statics"; + checkBoxPreviewPatched.Text = _localizationGetter("Forms.MapDiffInsertForm.checkBoxPreviewPatched") ?? "Mark the blocks the diff covers"; + + labelMapFormat.Text = _localizationGetter("Forms.MapDiffInsertForm.labelMapFormat") ?? "written as:"; + label1.Text = _localizationGetter("Forms.MapDiffInsertForm.label1") ?? "X1"; + label2.Text = _localizationGetter("Forms.MapDiffInsertForm.label2") ?? "Y1"; + label3.Text = _localizationGetter("Forms.MapDiffInsertForm.label3") ?? "X2"; + label4.Text = _localizationGetter("Forms.MapDiffInsertForm.label4") ?? "Y2"; + + buttonCopy.Text = _localizationGetter("Forms.MapDiffInsertForm.buttonCopy") ?? "Insert"; + buttonCancel.Text = _localizationGetter("Forms.MapDiffInsertForm.buttonCancel") ?? "Cancel"; + buttonClose.Text = _localizationGetter("Forms.MapDiffInsertForm.buttonClose") ?? "Close"; + + // 应用下拉框汉化 + ApplyComboBoxLocalization(); + + // 刷新预览区域的汉化消息 + UpdatePreview(); + } + + private string GetLocalizedMessage(string key, string defaultValue) + { + return _localizationGetter?.Invoke($"Forms.MapDiffInsertForm.Messages.{key}") ?? defaultValue; + } + + private string GetLocalizedComboBoxFormat(string key, string defaultValue) + { + return _localizationGetter?.Invoke($"Forms.MapDiffInsertForm.ComboBoxFormats.{key}") ?? defaultValue; + } + + private void ApplyComboBoxLocalization() + { + if (_localizationGetter == null || comboBoxMapFormat.Items.Count == 0) return; + + bool uop = _workingMap.Tiles.IsUOPFormat; + + // 第一项:与此客户端相同格式 + string firstItemText = uop + ? GetLocalizedComboBoxFormat("SameFormatUOP", "the same format as this client (.uop)") + : GetLocalizedComboBoxFormat("SameFormatMUL", "the same format as this client (.mul)"); + comboBoxMapFormat.Items[0] = firstItemText; + + // 其他项保持原样(包含地图索引),但 LegacyMUL 文本可以汉化 + // 第三项:map{index}LegacyMUL.uop + if (comboBoxMapFormat.Items.Count >= 3) + { + int index = _workingMap.FileIndex; + string legacyUopFormat = GetLocalizedComboBoxFormat("LegacyMUL", "LegacyMUL"); + comboBoxMapFormat.Items[2] = $"map{index}{legacyUopFormat}.uop"; + } + } + private void OnOptionChanged(object sender, EventArgs e) { comboBoxMapFormat.Enabled = checkBoxMap.Checked; @@ -125,15 +198,25 @@ private void UpdatePreview() var sb = new StringBuilder(); - sb.AppendLine($"region {region}"); + // 获取区域标签和块标签的汉化文本 + string regionLabel = GetLocalizedMessage("RegionLabel", "region"); + string blockFormat = GetLocalizedMessage("BlocksLabel", "块 {0},{1} - {2},{3},{4} x {5}"); + string diffDataFormat = GetLocalizedMessage("DiffDataLoaded", "差异数据已加载: {0:N0} 陆地块,{1:N0} 静态块"); + + // 构建输出,第一行使用汉化的块格式而不是 region.ToString() + sb.AppendLine(string.Format(CultureInfo.InvariantCulture, + blockFormat, + region.BlockX1, region.BlockY1, region.BlockX2, region.BlockY2, + region.BlockWidth, region.BlockHeight)); sb.AppendLine(string.Format(CultureInfo.InvariantCulture, - "diff data loaded: {0:N0} land blocks, {1:N0} static blocks", + diffDataFormat, patch.LandBlocksCount, patch.StaticBlocksCount)); if (region.TileX1 != x1 || region.TileY1 != y1 || region.TileX2 != x2 || region.TileY2 != y2) { + string requestWideningFormat = GetLocalizedMessage("RequestWidened", "the request {0},{1} - {2},{3} was widened to whole 8-tile blocks"); sb.AppendLine(string.Format(CultureInfo.InvariantCulture, - "the request {0},{1} - {2},{3} was widened to whole 8-tile blocks", x1, y1, x2, y2)); + requestWideningFormat, x1, y1, x2, y2)); } textBoxPreview.Text = sb.ToString(); @@ -251,7 +334,7 @@ private void OnClickCopy(object sender, EventArgs e) SetRunning(true); progressBar1.Value = 0; - labelStatus.Text = "Inserting..."; + labelStatus.Text = GetLocalizedMessage("Inserting", "Inserting..."); worker.RunWorkerAsync(options); } @@ -290,7 +373,7 @@ private void OnWorkerCompleted(object sender, RunWorkerCompletedEventArgs e) if (e.Error is OperationCanceledException) { progressBar1.Value = 0; - labelStatus.Text = "Cancelled. Nothing was written."; + labelStatus.Text = GetLocalizedMessage("Cancelled", "Cancelled. Nothing was written."); return; } @@ -298,7 +381,7 @@ private void OnWorkerCompleted(object sender, RunWorkerCompletedEventArgs e) if (e.Error != null) { progressBar1.Value = 0; - labelStatus.Text = "Failed."; + labelStatus.Text = GetLocalizedMessage("Failed", "Failed."); ShowError("Diff to Map Copy", e.Error); @@ -308,10 +391,13 @@ private void OnWorkerCompleted(object sender, RunWorkerCompletedEventArgs e) var result = (MapDiffApplyResult)e.Result; progressBar1.Value = 100; - labelStatus.Text = "Done."; + labelStatus.Text = GetLocalizedMessage("Done", "Done."); using (var form = new MapDiffApplyResultForm(result)) { + if (_localizationGetter != null) + form.SetLocalization(_localizationGetter); + form.ShowDialog(this); } } @@ -354,7 +440,7 @@ private void ShowError(string title, Exception error) private void OnClickCancel(object sender, EventArgs e) { _cancellation?.Cancel(); - labelStatus.Text = "Cancelling..."; + labelStatus.Text = GetLocalizedMessage("Cancelling", "Cancelling..."); } private void OnClickClose(object sender, EventArgs e) diff --git a/UoFiddler.Controls/UserControls/MapControl.cs b/UoFiddler.Controls/UserControls/MapControl.cs index 1944a56c..fb585de1 100644 --- a/UoFiddler.Controls/UserControls/MapControl.cs +++ b/UoFiddler.Controls/UserControls/MapControl.cs @@ -1483,6 +1483,11 @@ private void OnClickInsertDiffData(object sender, EventArgs e) { TopMost = true }; + + var getter = GetLocalizationGetter(); + if (getter != null) + _showFormMapDiff.SetLocalization(getter); + _showFormMapDiff.Show(); } diff --git a/UoFiddler/Localization/Dictionaries/zh-CN.json b/UoFiddler/Localization/Dictionaries/zh-CN.json index 38210f3a..fa8236c0 100644 --- a/UoFiddler/Localization/Dictionaries/zh-CN.json +++ b/UoFiddler/Localization/Dictionaries/zh-CN.json @@ -663,62 +663,6 @@ "Delete": "删除" } }, - "LandTilesControl": { - "showFreeSlotsToolStripMenuItem": "显示空闲槽位", - "findNextFreeSlotToolStripMenuItem": "查找下一个空闲槽位", - "changeBackgroundColorToolStripMenuItem": "改变背景颜色", - "exportImageToolStripMenuItem": "导出图像..", - "asBmpToolStripMenuItem": "导出为 BMP", - "asTiffToolStripMenuItem": "导出为 TIFF", - "asJpgToolStripMenuItem1": "导出为 JPG", - "asPngToolStripMenuItem": "导出为 PNG", - "selectInTileDataTabToolStripMenuItem": "在 图块数据 标签中选择", - "selectInRadarColorTabToolStripMenuItem": "在 雷达颜色 标签中选择", - "selectInTexturesTabToolStripMenuItem": "在 纹理 标签中选择", - "copyImageToolStripMenuItem": "复制图像", - "pasteImageToolStripMenuItem": "粘贴图像", - "replaceToolStripMenuItem": "替换", - "replaceStartingFromToolStripMenuItem": "从...开始替换", - "replaceFromFolderToolStripMenuItem": "从文件夹替换...", - "insertAtToolStripMenuItem": "在...处插入", - "removeToolStripMenuItem": "移除", - "saveToolStripMenuItem": "保存", - "IndexToolStripLabel": "索引:", - "NameToolStripLabel": "名称:", - "searchByNameToolStripButton": "查找下一个", - "MiscToolStripDropDownButton": "其他", - "exportAllToolStripMenuItem": "导出所有..", - "ExportAllAsBmp": "导出为 BMP", - "ExportAllAsTiff": "导出为 TIFF", - "asJpgToolStripMenuItem": "导出为 JPG", - "asPngToolStripMenuItem1": "导出为 PNG", - "SaveButton": "保存", - "NameLabel": "名称:", - "GraphicLabel": "ID:", - "FlagsLabel": "标志:", - "Messages": { - "RemoveSingleConfirm": "确定要移除 0x{0} 吗?", - "RemoveMultipleConfirm": "确定要移除 {0} 个地形图块吗?", - "RemoveTitle": "保存", - "PasteMultipleConfirm": "粘贴此图像到 {0} 个选定的地形图块吗?", - "PasteImageTitle": "粘贴图像", - "SaveConfirmation": "确定吗?这需要一些时间", - "SaveTitle": "保存", - "SaveSuccess": "地形图块已保存到 {0}", - "SavedTitle": "已保存", - "CopyImageError": "复制图像失败", - "CopyImageTitle": "复制图像", - "PasteImageError": "粘贴图像失败", - "InvalidSizeTitle": "无效尺寸", - "InvalidSizeMessage": "无效的地形图块尺寸!地形图块必须是 44x44 像素。没有做任何更改。", - "SelectionMismatchTitle": "选择不匹配", - "SelectionMismatchMessage": "选中 {0} 个地形图块但选择了 {1} 个图像。没有做任何更改。", - "ImageTooLargeTitle": "图像过大", - "ImageTooLargeMessage": "图像对于 MUL 格式太大!预计编码大小:{0} ushorts,最大允许:{1} ushorts。没有做任何更改。", - "LoadTexturesFirst": "你需要先加载 Textures 标签。", - "LoadTexturesTitle": "信息" - } - }, "TexturesControl": { "showFreeSlotsToolStripMenuItem": "显示空闲槽位", "findNextFreeSlotToolStripMenuItem": "查找下一个空闲槽位", @@ -761,44 +705,6 @@ "NoImage": "剪贴板中没有图像" } }, - "SoundsControl": { - "nameSortToolStripMenuItem": "按名称排序", - "showFreeSlotsToolStripMenuItem": "显示空闲槽位", - "nextFreeSlotToolStripMenuItem": "查找下一个空闲槽位", - "playSoundToolStripMenuItem": "播放", - "insertReplaceToolStripMenuItem": "插入/替换", - "replaceSoundToolStripMenuItem": "替换", - "insertSoundToolStripMenuItem": "插入", - "extractSoundToolStripMenuItem": "提取", - "removeSoundToolStripMenuItem": "移除", - "saveSoundToolStripMenuItem": "保存", - "genericGroupBox": "常规", - "currentSoundGroupBox": "当前声音", - "searchGroupBox": "搜索", - "insertReplaceGroupBox": "插入/替换", - "playButton": "播放", - "stopButton": "停止", - "extractButton": "提取", - "removeButton": "移除", - "saveButton": "保存", - "exportAllSoundsButton": "导出所有声音", - "exportSoundListCsvButton": "导出声音列表 (.csv)", - "addInsertReplaceButton": "添加/替换", - "goPrevButton": "上一个", - "goNextButton": "下一个", - "idLabel": "ID", - "wavLabel": "WAV", - "sortByNameCheckBox": "按名称排序树", - "includeSoundIdCheckBox": "导出时在文件名中包含声音ID", - "soundColumnHeader": "声音", - "searchByIdButton": "按ID搜索", - "searchByNameButton": "按名称搜索", - "Messages": { - "emptySlot": "空槽位", - "currentSoundFormat": "当前声音: {0} - 时长: {1}", - "idCountFormat": "已占用音效 ID: {0}, 空闲音效 ID: {1}" - } - }, "AnimationListControl": { "searchToolStripLabel": "搜索:", "removeToolStripMenuItem": "移除", @@ -1012,14 +918,6 @@ "SelectAll": "全选" } }, - "FileSavedDialog": { - "Title": "已保存", - "SaveSuccess": "文件已成功保存。", - "OpenFolder": "打开文件夹", - "OK": "确定", - "UnableToOpenFolder": "无法打开文件夹", - "Error": "错误" - }, "CompareTileDataControl": { "btnCopyLandSelected": "复制选定项", "btnCopyLandAllDiff": "复制所有差异", @@ -1341,6 +1239,50 @@ }, "MapDetailsForm": { "Title": "地图详情" + }, + "MapDiffApplyResultForm": { + "Title": "差异应用结果", + "buttonVerify": "验证输出", + "buttonSave": "保存报告...", + "buttonCopy": "复制", + "buttonOpenFolder": "打开输出文件夹", + "buttonClose": "关闭" + }, + "MapDiffInsertForm": { + "Title": "差异到地图复制", + "groupBoxWhat": "插入", + "groupBoxFrom": "区域,以地图图块为单位", + "groupBoxPreview": "将要插入的内容 - 拖动以选择区域", + "checkBoxMap": "地图", + "checkBoxStatics": "静态物品", + "RemoveDupl": "移除重复项", + "checkBoxDuplicatesHue": "也比较色调(旧版)", + "checkBoxPreviewStatics": "显示静态物品", + "checkBoxPreviewPatched": "标记差异涵盖的块", + "labelMapFormat": "写入为:", + "label1": "X1", + "label2": "Y1", + "label3": "X2", + "label4": "Y2", + "buttonCopy": "插入", + "buttonCancel": "取消", + "buttonClose": "关闭", + "Messages": { + "Inserting": "插入中...", + "Cancelled": "已取消。未写入任何内容。", + "Failed": "失败。", + "Done": "完成", + "Cancelling": "取消中...", + "RegionLabel": "区域", + "DiffDataLoaded": "差异数据已加载: {0:N0} 陆地块,{1:N0} 静态块", + "RequestWidened": "请求 {0},{1} - {2},{3} 已扩展为整个 8 图块块", + "BlocksLabel": "块 {0},{1} - {2},{3},{4} x {5}" + }, + "ComboBoxFormats": { + "SameFormatUOP": "与此客户端相同格式 (.uop)", + "SameFormatMUL": "与此客户端相同格式 (.mul)", + "LegacyMUL": "LegacyMUL" + } } } } From b6b276e23aa5a9e752149a5aba9b815f6ed20cbb Mon Sep 17 00:00:00 2001 From: nbyaya Date: Wed, 7 Oct 2026 01:11:02 +0800 Subject: [PATCH 51/76] =?UTF-8?q?=E8=A1=A5=E5=85=85=E6=B1=89=E5=8C=96=20Ma?= =?UTF-8?q?pDetailsForm=20=E5=86=85=E5=AE=B9=E6=A0=87=E7=AD=BE?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit - 添加内容生成方法 GenerateContent() - 保存地图和坐标为实例变量 - SetLocalization 时重新生成内容以应用汉化 - 汉化标签:陆地图块、高度、静态物品、色调 - 现在点击地图时,详情窗口所有内容都是中文显示 --- UoFiddler.Controls/Forms/MapDetailsForm.cs | 46 ++++++++++++++----- .../Localization/Dictionaries/zh-CN.json | 9 +++- 2 files changed, 42 insertions(+), 13 deletions(-) diff --git a/UoFiddler.Controls/Forms/MapDetailsForm.cs b/UoFiddler.Controls/Forms/MapDetailsForm.cs index ddee4c45..8af894cb 100644 --- a/UoFiddler.Controls/Forms/MapDetailsForm.cs +++ b/UoFiddler.Controls/Forms/MapDetailsForm.cs @@ -20,6 +20,8 @@ namespace UoFiddler.Controls.Forms public partial class MapDetailsForm : Form { private Func? _localizationGetter; + private Map _currentMap; + private Point _point; public MapDetailsForm(Map currentMap, Point point) { @@ -28,17 +30,11 @@ public MapDetailsForm(Map currentMap, Point point) Icon = Options.GetFiddlerIcon(); TopMost = true; - Tile currentTile = currentMap.Tiles.GetLandTile(point.X, point.Y); - richTextBox.AppendText($"X: {point.X} Y: {point.Y}\n\n"); - richTextBox.AppendText("LandTile:\n"); - richTextBox.AppendText($"{TileData.LandTable[currentTile.Id].Name}: 0x{currentTile.Id:X} Altitude: {currentTile.Z}\n\n"); - HuedTile[] staticsAtPoint = currentMap.Tiles.GetStaticTiles(point.X, point.Y); - richTextBox.AppendText("Statics:\n"); - foreach (HuedTile @static in staticsAtPoint) - { - ushort id = @static.Id; - richTextBox.AppendText($"{TileData.ItemTable[id].Name}: 0x{id:X} Hue: {@static.Hue} Altitude: {@static.Z}\n"); - } + _currentMap = currentMap; + _point = point; + + // 先生成英文内容 + GenerateContent(); } public void SetLocalization(Func getLocalized) @@ -52,6 +48,32 @@ private void ApplyLocalization() if (_localizationGetter == null) return; this.Text = _localizationGetter("Forms.MapDetailsForm.Title") ?? "MapDetails"; + + // 重新生成内容以应用汉化 + GenerateContent(); + } + + private void GenerateContent() + { + richTextBox.Clear(); + + string coordLabel = _localizationGetter?.Invoke("Forms.MapDetailsForm.Labels.Coordinate") ?? "X"; + string landTileLabel = _localizationGetter?.Invoke("Forms.MapDetailsForm.Labels.LandTile") ?? "LandTile"; + string altitudeLabel = _localizationGetter?.Invoke("Forms.MapDetailsForm.Labels.Altitude") ?? "Altitude"; + string staticsLabel = _localizationGetter?.Invoke("Forms.MapDetailsForm.Labels.Statics") ?? "Statics"; + string hueLabel = _localizationGetter?.Invoke("Forms.MapDetailsForm.Labels.Hue") ?? "Hue"; + + Tile currentTile = _currentMap.Tiles.GetLandTile(_point.X, _point.Y); + richTextBox.AppendText($"{coordLabel}: {_point.X} Y: {_point.Y}\n\n"); + richTextBox.AppendText($"{landTileLabel}:\n"); + richTextBox.AppendText($"{TileData.LandTable[currentTile.Id].Name}: 0x{currentTile.Id:X} {altitudeLabel}: {currentTile.Z}\n\n"); + HuedTile[] staticsAtPoint = _currentMap.Tiles.GetStaticTiles(_point.X, _point.Y); + richTextBox.AppendText($"{staticsLabel}:\n"); + foreach (HuedTile @static in staticsAtPoint) + { + ushort id = @static.Id; + richTextBox.AppendText($"{TileData.ItemTable[id].Name}: 0x{id:X} {hueLabel}: {@static.Hue} {altitudeLabel}: {@static.Z}\n"); + } } } -} \ No newline at end of file +} diff --git a/UoFiddler/Localization/Dictionaries/zh-CN.json b/UoFiddler/Localization/Dictionaries/zh-CN.json index fa8236c0..5471516a 100644 --- a/UoFiddler/Localization/Dictionaries/zh-CN.json +++ b/UoFiddler/Localization/Dictionaries/zh-CN.json @@ -1238,7 +1238,14 @@ "CloseButton": "关闭" }, "MapDetailsForm": { - "Title": "地图详情" + "Title": "地图详情", + "Labels": { + "Coordinate": "X", + "LandTile": "陆地图块", + "Altitude": "高度", + "Statics": "静态物品", + "Hue": "色调" + } }, "MapDiffApplyResultForm": { "Title": "差异应用结果", From 8c9c9ffa652f9ca24d39ec1bf9012661a1fca448 Mon Sep 17 00:00:00 2001 From: nbyaya Date: Wed, 7 Oct 2026 01:22:11 +0800 Subject: [PATCH 52/76] =?UTF-8?q?=E8=A1=A5=E5=85=85=E6=B1=89=E5=8C=96=20Ma?= =?UTF-8?q?pDefragStaticsForm=20=E5=8A=A8=E6=80=81=E6=B6=88=E6=81=AF?= =?UTF-8?q?=E6=A0=87=E7=AD=BE?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../Forms/MapDefragStaticsForm.cs | 36 ++++++++++++------- .../Localization/Dictionaries/zh-CN.json | 12 ++++++- 2 files changed, 34 insertions(+), 14 deletions(-) diff --git a/UoFiddler.Controls/Forms/MapDefragStaticsForm.cs b/UoFiddler.Controls/Forms/MapDefragStaticsForm.cs index 58df1b19..f80983d5 100644 --- a/UoFiddler.Controls/Forms/MapDefragStaticsForm.cs +++ b/UoFiddler.Controls/Forms/MapDefragStaticsForm.cs @@ -102,6 +102,9 @@ private void ApplyLocalization() buttonDefrag.Text = _localizationGetter("Forms.MapDefragStaticsForm.DefragButton") ?? "Defrag"; buttonCancel.Text = _localizationGetter("Forms.MapDefragStaticsForm.CancelButton") ?? "Cancel"; buttonClose.Text = _localizationGetter("Forms.MapDefragStaticsForm.CloseButton") ?? "Close"; + + // 重新生成源描述(包含动态消息) + DescribeSource(); } /// @@ -116,11 +119,17 @@ private void DescribeSource() var sb = new StringBuilder(); - sb.AppendLine($"Facet {_map.FileIndex} map size {_map.Width} x {_map.Height} blocks {_map.Width >> 3} x {_map.Height >> 3}"); + string facetLabel = _localizationGetter?.Invoke("Forms.MapDefragStaticsForm.Messages.Facet") ?? "Facet"; + string mapSizeLabel = _localizationGetter?.Invoke("Forms.MapDefragStaticsForm.Messages.MapSize") ?? "map size"; + string blocksLabel = _localizationGetter?.Invoke("Forms.MapDefragStaticsForm.Messages.Blocks") ?? "blocks"; + + sb.AppendLine($"{facetLabel} {_map.FileIndex} {mapSizeLabel} {_map.Width} x {_map.Height} {blocksLabel} {_map.Width >> 3} x {_map.Height >> 3}"); if (indexPath == null || staticsPath == null) { - sb.AppendLine($"staidx{_map.FileIndex}.mul or statics{_map.FileIndex}.mul was not found in the loaded client."); + string notFoundMsg = _localizationGetter?.Invoke("Forms.MapDefragStaticsForm.Messages.FilesNotFound") + ?? "staidx{0}.mul or statics{0}.mul was not found in the loaded client."; + sb.AppendLine(string.Format(notFoundMsg, _map.FileIndex)); textBoxSource.Text = sb.ToString(); buttonAnalyze.Enabled = false; @@ -137,7 +146,9 @@ private void DescribeSource() if (File.Exists(Path.Combine(Path.GetDirectoryName(indexPath) ?? string.Empty, $"staidx{_map.FileIndex}x.mul"))) { - sb.AppendLine($"staidx{_map.FileIndex}x.mul is present - the client prefers those override files over this pair."); + string overrideMsg = _localizationGetter?.Invoke("Forms.MapDefragStaticsForm.Messages.OverridePresent") + ?? "staidx{0}x.mul is present - the client prefers those override files over this pair."; + sb.AppendLine(string.Format(overrideMsg, _map.FileIndex)); } textBoxSource.Text = sb.ToString(); @@ -148,10 +159,9 @@ private void DescribeSource() if (indexBlocks > configuredBlocks) { labelGeometry.ForeColor = Options.DarkMode ? Color.OrangeRed : Color.Red; - labelGeometry.Text = string.Format(CultureInfo.InvariantCulture, - "staidx holds {0:N0} blocks but the configured map size covers only {1:N0}." + Environment.NewLine + - "The statics in the surplus blocks would be discarded.", - indexBlocks, configuredBlocks); + string surplusMsg = _localizationGetter?.Invoke("Forms.MapDefragStaticsForm.Messages.SurplusBlocks") + ?? "staidx holds {0:N0} blocks but the configured map size covers only {1:N0}. The statics in the surplus blocks would be discarded."; + labelGeometry.Text = string.Format(CultureInfo.InvariantCulture, surplusMsg, indexBlocks, configuredBlocks); _truncationAvailable = true; checkBoxAllowTruncation.Enabled = true; @@ -159,16 +169,16 @@ private void DescribeSource() else if (indexBlocks < configuredBlocks) { labelGeometry.ForeColor = SystemColors.ControlText; - labelGeometry.Text = string.Format(CultureInfo.InvariantCulture, - "staidx holds {0:N0} blocks, the configured map size covers {1:N0}." + Environment.NewLine + - "The blocks past the end of the index will be written empty.", - indexBlocks, configuredBlocks); + string emptyBlocksMsg = _localizationGetter?.Invoke("Forms.MapDefragStaticsForm.Messages.EmptyBlocks") + ?? "staidx holds {0:N0} blocks, the configured map size covers {1:N0}. The blocks past the end of the index will be written empty."; + labelGeometry.Text = string.Format(CultureInfo.InvariantCulture, emptyBlocksMsg, indexBlocks, configuredBlocks); } else { labelGeometry.ForeColor = SystemColors.ControlText; - labelGeometry.Text = string.Format(CultureInfo.InvariantCulture, - "staidx holds {0:N0} blocks, matching the configured map size.", indexBlocks); + string matchingMsg = _localizationGetter?.Invoke("Forms.MapDefragStaticsForm.Messages.MatchingBlocks") + ?? "staidx holds {0:N0} blocks, matching the configured map size."; + labelGeometry.Text = string.Format(CultureInfo.InvariantCulture, matchingMsg, indexBlocks); } } diff --git a/UoFiddler/Localization/Dictionaries/zh-CN.json b/UoFiddler/Localization/Dictionaries/zh-CN.json index 5471516a..613c7156 100644 --- a/UoFiddler/Localization/Dictionaries/zh-CN.json +++ b/UoFiddler/Localization/Dictionaries/zh-CN.json @@ -1227,7 +1227,17 @@ "Geometry": "几何:{0}", "StatusAnalyzing": "分析中...", "StatusDefragging": "整理中...", - "StatusCompleted": "完成" + "StatusCompleted": "完成", + "Messages": { + "Facet": "位面", + "MapSize": "地图大小", + "Blocks": "块", + "FilesNotFound": "staidx{0}.mul 或 statics{0}.mul 在加载的客户端中未找到。", + "OverridePresent": "staidx{0}x.mul 存在 - 客户端更倾向使用这些覆盖文件而不是这个对。", + "SurplusBlocks": "staidx 包含 {0:N0} 块但配置的地图大小仅覆盖 {1:N0} 块。多余块中的静态物品将被丢弃。", + "EmptyBlocks": "staidx 包含 {0:N0} 块,配置的地图大小覆盖 {1:N0} 块。索引末尾之后的块将被写入为空。", + "MatchingBlocks": "staidx 包含 {0:N0} 块,与配置的地图大小匹配。" + } }, "MapDefragStaticsResultForm": { "Title": "整理静态物品 - 结果", From 66b4beca017ee54cdd30c24b1a114bfa5f3dc7ae Mon Sep 17 00:00:00 2001 From: nbyaya Date: Wed, 7 Oct 2026 01:30:18 +0800 Subject: [PATCH 53/76] =?UTF-8?q?=E6=B1=89=E5=8C=96=20MapMarkerForm=20?= =?UTF-8?q?=E5=9C=B0=E5=9B=BE=E6=A0=87=E8=AE=B0=E7=AA=97=E5=8F=A3?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- UoFiddler.Controls/Forms/MapMarkerForm.cs | 17 +++++++++++++++++ UoFiddler.Controls/UserControls/MapControl.cs | 5 +++++ UoFiddler/Localization/Dictionaries/zh-CN.json | 6 ++++++ 3 files changed, 28 insertions(+) diff --git a/UoFiddler.Controls/Forms/MapMarkerForm.cs b/UoFiddler.Controls/Forms/MapMarkerForm.cs index 9defb5c8..d2e624eb 100644 --- a/UoFiddler.Controls/Forms/MapMarkerForm.cs +++ b/UoFiddler.Controls/Forms/MapMarkerForm.cs @@ -20,6 +20,7 @@ public partial class MapMarkerForm : Form { private readonly Action _addOverlayAction; private static Color _lastColor = Color.FromArgb(180, Color.Yellow); + private Func? _localizationGetter; public MapMarkerForm(Action addOverlayAction, int x, int y, int map) { @@ -37,6 +38,22 @@ public MapMarkerForm(Action addOverlayAction, int pictureBox1.BackColor = _lastColor; } + public void SetLocalization(Func getLocalized) + { + _localizationGetter = getLocalized; + ApplyLocalization(); + } + + private void ApplyLocalization() + { + if (_localizationGetter == null) return; + + this.Text = _localizationGetter("Forms.MapMarkerForm.Title") ?? "Add MapMarker"; + label1.Text = _localizationGetter("Forms.MapMarkerForm.TextLabel") ?? "Text"; + button1.Text = _localizationGetter("Forms.MapMarkerForm.ChooseColorButton") ?? "Choose Color"; + button2.Text = _localizationGetter("Forms.MapMarkerForm.SaveButton") ?? "Save"; + } + private void OnClickColor(object sender, EventArgs e) { if (colorDialog1.ShowDialog() != DialogResult.Cancel) diff --git a/UoFiddler.Controls/UserControls/MapControl.cs b/UoFiddler.Controls/UserControls/MapControl.cs index fb585de1..a96a5aae 100644 --- a/UoFiddler.Controls/UserControls/MapControl.cs +++ b/UoFiddler.Controls/UserControls/MapControl.cs @@ -1146,6 +1146,11 @@ private void OnClickInsertMarker(object sender, EventArgs e) { TopMost = true }; + var getter = GetLocalizationGetter(); + if (getter != null) + { + _mapMarkerForm.SetLocalization(getter); + } _mapMarkerForm.Show(); } diff --git a/UoFiddler/Localization/Dictionaries/zh-CN.json b/UoFiddler/Localization/Dictionaries/zh-CN.json index 613c7156..b38efecc 100644 --- a/UoFiddler/Localization/Dictionaries/zh-CN.json +++ b/UoFiddler/Localization/Dictionaries/zh-CN.json @@ -1188,6 +1188,12 @@ "ClientLocPrefix": "客户端位置:{0},{1}", "ZoomPrefix": "缩放:{0}%" }, + "MapMarkerForm": { + "Title": "添加地图标记", + "TextLabel": "文本", + "ChooseColorButton": "选择颜色", + "SaveButton": "保存" + }, "MapClearStaticsForm": { "Title": "清除静态物品", "X1Label": "X1", From 21e1f976a80dc8749976e5e99b28ea59108b61cc Mon Sep 17 00:00:00 2001 From: nbyaya Date: Wed, 7 Oct 2026 01:32:52 +0800 Subject: [PATCH 54/76] =?UTF-8?q?=E6=B1=89=E5=8C=96=20MapMeltStaticsForm?= =?UTF-8?q?=20=E8=9E=8D=E5=8C=96=E9=9D=99=E6=80=81=E7=89=A9=E5=93=81?= =?UTF-8?q?=E7=AA=97=E5=8F=A3?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../Forms/MapMeltStaticsForm.cs | 23 ++++++++++++++++++- UoFiddler.Controls/UserControls/MapControl.cs | 5 ++++ .../Localization/Dictionaries/zh-CN.json | 10 ++++++++ 3 files changed, 37 insertions(+), 1 deletion(-) diff --git a/UoFiddler.Controls/Forms/MapMeltStaticsForm.cs b/UoFiddler.Controls/Forms/MapMeltStaticsForm.cs index 69f265f8..52f3ff39 100644 --- a/UoFiddler.Controls/Forms/MapMeltStaticsForm.cs +++ b/UoFiddler.Controls/Forms/MapMeltStaticsForm.cs @@ -21,6 +21,7 @@ public partial class MapMeltStaticsForm : Form { private readonly Action _refreshMap; private readonly Map _map; + private Func? _localizationGetter; public MapMeltStaticsForm(Action refreshMap, Map map) { @@ -37,6 +38,24 @@ public MapMeltStaticsForm(Action refreshMap, Map map) numericUpDownY2.Maximum = map.Height; } + public void SetLocalization(Func getLocalized) + { + _localizationGetter = getLocalized; + ApplyLocalization(); + } + + private void ApplyLocalization() + { + if (_localizationGetter == null) return; + + this.Text = _localizationGetter("Forms.MapMeltStaticsForm.Title") ?? "Melt Statics"; + label2.Text = _localizationGetter("Forms.MapMeltStaticsForm.X1Label") ?? "X1"; + label3.Text = _localizationGetter("Forms.MapMeltStaticsForm.Y1Label") ?? "Y1"; + label4.Text = _localizationGetter("Forms.MapMeltStaticsForm.X2Label") ?? "X2"; + label5.Text = _localizationGetter("Forms.MapMeltStaticsForm.Y2Label") ?? "Y2"; + button1.Text = _localizationGetter("Forms.MapMeltStaticsForm.MeltButton") ?? "Melt"; + } + private void OnClickMelt(object sender, EventArgs e) { SaveFileDialog dialog = new SaveFileDialog @@ -122,7 +141,9 @@ private void OnClickMelt(object sender, EventArgs e) _map.ResetCache(); - MessageBox.Show("Done", "Melt Static", MessageBoxButtons.OK, MessageBoxIcon.Information, MessageBoxDefaultButton.Button1); + string title = _localizationGetter?.Invoke("Forms.MapMeltStaticsForm.DoneTitle") ?? "Melt Static"; + string message = _localizationGetter?.Invoke("Forms.MapMeltStaticsForm.DoneMessage") ?? "Done"; + MessageBox.Show(message, title, MessageBoxButtons.OK, MessageBoxIcon.Information, MessageBoxDefaultButton.Button1); _refreshMap(); } diff --git a/UoFiddler.Controls/UserControls/MapControl.cs b/UoFiddler.Controls/UserControls/MapControl.cs index a96a5aae..15548a3f 100644 --- a/UoFiddler.Controls/UserControls/MapControl.cs +++ b/UoFiddler.Controls/UserControls/MapControl.cs @@ -1625,6 +1625,11 @@ private void OnClickMeltStatics(object sender, EventArgs e) { TopMost = true }; + var getter = GetLocalizationGetter(); + if (getter != null) + { + _showMeltStaticsForm.SetLocalization(getter); + } _showMeltStaticsForm.Show(); } diff --git a/UoFiddler/Localization/Dictionaries/zh-CN.json b/UoFiddler/Localization/Dictionaries/zh-CN.json index b38efecc..4d78bf46 100644 --- a/UoFiddler/Localization/Dictionaries/zh-CN.json +++ b/UoFiddler/Localization/Dictionaries/zh-CN.json @@ -1194,6 +1194,16 @@ "ChooseColorButton": "选择颜色", "SaveButton": "保存" }, + "MapMeltStaticsForm": { + "Title": "融化静态物品", + "X1Label": "X1", + "Y1Label": "Y1", + "X2Label": "X2", + "Y2Label": "Y2", + "MeltButton": "融化", + "DoneTitle": "融化静态物品", + "DoneMessage": "完成" + }, "MapClearStaticsForm": { "Title": "清除静态物品", "X1Label": "X1", From fbbc9a1d773828750c86872a4c18b4559b03c84e Mon Sep 17 00:00:00 2001 From: nbyaya Date: Wed, 7 Oct 2026 01:35:21 +0800 Subject: [PATCH 55/76] =?UTF-8?q?=E6=B1=89=E5=8C=96=20MapReplaceTilesForm?= =?UTF-8?q?=20=E6=9B=BF=E6=8D=A2=E5=9C=B0=E5=9D=97=E7=AA=97=E5=8F=A3?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- UoFiddler.Controls/Forms/MapReplaceTilesForm.cs | 16 ++++++++++++++++ UoFiddler.Controls/UserControls/MapControl.cs | 5 +++++ UoFiddler/Localization/Dictionaries/zh-CN.json | 5 +++++ 3 files changed, 26 insertions(+) diff --git a/UoFiddler.Controls/Forms/MapReplaceTilesForm.cs b/UoFiddler.Controls/Forms/MapReplaceTilesForm.cs index b9209a7f..1f30fe87 100644 --- a/UoFiddler.Controls/Forms/MapReplaceTilesForm.cs +++ b/UoFiddler.Controls/Forms/MapReplaceTilesForm.cs @@ -23,6 +23,7 @@ public partial class MapReplaceTilesForm : Form { private readonly Map _map; private List _toReplace; + private Func? _localizationGetter; public MapReplaceTilesForm(Map map) { @@ -31,6 +32,21 @@ public MapReplaceTilesForm(Map map) _map = map; } + public void SetLocalization(Func getLocalized) + { + _localizationGetter = getLocalized; + ApplyLocalization(); + } + + private void ApplyLocalization() + { + if (_localizationGetter == null) return; + + this.Text = _localizationGetter("Forms.MapReplaceTilesForm.Title") ?? "Map - replace tiles"; + label5.Text = _localizationGetter("Forms.MapReplaceTilesForm.ReplaceFromLabel") ?? "Replace From"; + button2.Text = _localizationGetter("Forms.MapReplaceTilesForm.ReplaceButton") ?? "Replace"; + } + private void OnReplace(object sender, EventArgs e) { using (new WaitCursorScope(this)) diff --git a/UoFiddler.Controls/UserControls/MapControl.cs b/UoFiddler.Controls/UserControls/MapControl.cs index 15548a3f..1ab50f79 100644 --- a/UoFiddler.Controls/UserControls/MapControl.cs +++ b/UoFiddler.Controls/UserControls/MapControl.cs @@ -1667,6 +1667,11 @@ private void OnClickReplaceTiles(object sender, EventArgs e) { TopMost = true }; + var getter = GetLocalizationGetter(); + if (getter != null) + { + _showMapReplaceTilesForm.SetLocalization(getter); + } _showMapReplaceTilesForm.Show(); } diff --git a/UoFiddler/Localization/Dictionaries/zh-CN.json b/UoFiddler/Localization/Dictionaries/zh-CN.json index 4d78bf46..74f11f06 100644 --- a/UoFiddler/Localization/Dictionaries/zh-CN.json +++ b/UoFiddler/Localization/Dictionaries/zh-CN.json @@ -1204,6 +1204,11 @@ "DoneTitle": "融化静态物品", "DoneMessage": "完成" }, + "MapReplaceTilesForm": { + "Title": "地图 - 替换地块", + "ReplaceFromLabel": "替换来源", + "ReplaceButton": "替换" + }, "MapClearStaticsForm": { "Title": "清除静态物品", "X1Label": "X1", From 867e41c8f60e13b86788c158b6fe6ef6a2b8f9be Mon Sep 17 00:00:00 2001 From: nbyaya Date: Wed, 7 Oct 2026 01:40:27 +0800 Subject: [PATCH 56/76] =?UTF-8?q?=E6=B1=89=E5=8C=96=20MapRegionCopyResultF?= =?UTF-8?q?orm=20=E5=9C=B0=E5=9B=BE=E5=8C=BA=E5=9F=9F=E5=A4=8D=E5=88=B6?= =?UTF-8?q?=E7=BB=93=E6=9E=9C=E7=AA=97=E5=8F=A3?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit - 为 MapRegionCopyResultForm 添加 SetLocalization/ApplyLocalization 方法 - 实现 6 个 UI 元素的汉化(窗口标题、验证、保存、复制、打开文件夹、关闭) - 在 MapReplaceForm 中通过反射调用 LocalizationService 为 MapRegionCopyResultForm 提供汉化 getter - zh-CN.json 已包含所有 6 个词条 --- .../Forms/MapRegionCopyResultForm.cs | 19 +++++++++++++++++++ UoFiddler.Controls/Forms/MapReplaceForm.cs | 16 ++++++++++++++++ .../Localization/Dictionaries/zh-CN.json | 8 ++++++++ 3 files changed, 43 insertions(+) diff --git a/UoFiddler.Controls/Forms/MapRegionCopyResultForm.cs b/UoFiddler.Controls/Forms/MapRegionCopyResultForm.cs index 2ec9e964..b7ad1e42 100644 --- a/UoFiddler.Controls/Forms/MapRegionCopyResultForm.cs +++ b/UoFiddler.Controls/Forms/MapRegionCopyResultForm.cs @@ -24,6 +24,7 @@ namespace UoFiddler.Controls.Forms public sealed partial class MapRegionCopyResultForm : Form { private readonly MapRegionCopyResult _result; + private Func? _localizationGetter; public MapRegionCopyResultForm(MapRegionCopyResult result) { @@ -39,6 +40,24 @@ public MapRegionCopyResultForm(MapRegionCopyResult result) buttonOpenFolder.Enabled = result.OutputMapPath != null || result.OutputIndexPath != null; } + public void SetLocalization(Func getLocalized) + { + _localizationGetter = getLocalized; + ApplyLocalization(); + } + + private void ApplyLocalization() + { + if (_localizationGetter == null) return; + + this.Text = _localizationGetter("Forms.MapRegionCopyResultForm.Title") ?? "Map and Statics Copy - Result"; + buttonVerify.Text = _localizationGetter("Forms.MapRegionCopyResultForm.VerifyButton") ?? "Verify output"; + buttonSave.Text = _localizationGetter("Forms.MapRegionCopyResultForm.SaveButton") ?? "Save report..."; + buttonCopy.Text = _localizationGetter("Forms.MapRegionCopyResultForm.CopyButton") ?? "Copy"; + buttonOpenFolder.Text = _localizationGetter("Forms.MapRegionCopyResultForm.OpenFolderButton") ?? "Open output folder"; + buttonClose.Text = _localizationGetter("Forms.MapRegionCopyResultForm.CloseButton") ?? "Close"; + } + /// /// Reads the written map back and checks it block by block: inside the pasted rectangle it /// has to match the source, everywhere else the map it was made from. diff --git a/UoFiddler.Controls/Forms/MapReplaceForm.cs b/UoFiddler.Controls/Forms/MapReplaceForm.cs index 4c6c7674..c991b5a1 100644 --- a/UoFiddler.Controls/Forms/MapReplaceForm.cs +++ b/UoFiddler.Controls/Forms/MapReplaceForm.cs @@ -824,6 +824,22 @@ private void OnWorkerCompleted(object sender, RunWorkerCompletedEventArgs e) using (var form = new MapRegionCopyResultForm(result)) { + // 通过反射尝试获取 LocalizationService 的 GetString 方法 + try + { + var localizationServiceType = Type.GetType("UoFiddler.Localization.LocalizationService, UoFiddler"); + if (localizationServiceType != null) + { + var getStringMethod = localizationServiceType.GetMethod("GetString", + System.Reflection.BindingFlags.Public | System.Reflection.BindingFlags.Static); + if (getStringMethod != null) + { + form.SetLocalization(key => (string?)getStringMethod.Invoke(null, new object[] { key })); + } + } + } + catch { } + form.ShowDialog(this); } } diff --git a/UoFiddler/Localization/Dictionaries/zh-CN.json b/UoFiddler/Localization/Dictionaries/zh-CN.json index 74f11f06..a7dad8fd 100644 --- a/UoFiddler/Localization/Dictionaries/zh-CN.json +++ b/UoFiddler/Localization/Dictionaries/zh-CN.json @@ -1321,6 +1321,14 @@ "SameFormatMUL": "与此客户端相同格式 (.mul)", "LegacyMUL": "LegacyMUL" } + }, + "MapRegionCopyResultForm": { + "Title": "地图和静态物品复制 - 结果", + "VerifyButton": "验证输出", + "SaveButton": "保存报告...", + "CopyButton": "复制", + "OpenFolderButton": "打开输出文件夹", + "CloseButton": "关闭" } } } From a9ca54de964a04d71e4f5dd757366a80a876aec2 Mon Sep 17 00:00:00 2001 From: nbyaya Date: Wed, 7 Oct 2026 01:49:19 +0800 Subject: [PATCH 57/76] =?UTF-8?q?=E6=B1=89=E5=8C=96=20MapReplaceForm=20?= =?UTF-8?q?=E5=9C=B0=E5=9B=BE=E5=92=8C=E9=9D=99=E6=80=81=E7=89=A9=E5=93=81?= =?UTF-8?q?=E5=A4=8D=E5=88=B6=E7=AA=97=E5=8F=A3?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit - 为 MapReplaceForm 添加 SetLocalization/ApplyLocalization 方法 - 实现 28 个 UI 元素的汉化(窗口标题、所有分组框、标签、复选框、按钮等) - 在 MapControl 中为 MapReplaceForm 调用 SetLocalization() - zh-CN.json 已包含所有 28 个词条 这是最后一个 Map 窗口,完成了全部 12 个 Map 相关窗口的汉化 --- UoFiddler.Controls/Forms/MapReplaceForm.cs | 42 +++++++++++++++++++ UoFiddler.Controls/UserControls/MapControl.cs | 5 +++ .../Localization/Dictionaries/zh-CN.json | 31 ++++++++++++++ 3 files changed, 78 insertions(+) diff --git a/UoFiddler.Controls/Forms/MapReplaceForm.cs b/UoFiddler.Controls/Forms/MapReplaceForm.cs index c991b5a1..52c142b8 100644 --- a/UoFiddler.Controls/Forms/MapReplaceForm.cs +++ b/UoFiddler.Controls/Forms/MapReplaceForm.cs @@ -31,6 +31,7 @@ namespace UoFiddler.Controls.Forms public partial class MapReplaceForm : Form { private readonly Map _workingMap; + private Func? _localizationGetter; private CancellationTokenSource _cancellation; private MapSize _detectedSize; @@ -58,6 +59,47 @@ public partial class MapReplaceForm : Form private ZSurveyRequest _zPending; private CancellationTokenSource _zCancellation; + public void SetLocalization(Func getLocalized) + { + _localizationGetter = getLocalized; + ApplyLocalization(); + } + + private void ApplyLocalization() + { + if (_localizationGetter == null) return; + + this.Text = _localizationGetter("Forms.MapReplaceForm.Title") ?? $"Map and Statics Copy - into map {_workingMap.FileIndex}"; + groupBoxSource.Text = _localizationGetter("Forms.MapReplaceForm.GroupBoxSource") ?? "Copy from"; + labelFolder.Text = _localizationGetter("Forms.MapReplaceForm.LabelFolder") ?? "Folder:"; + buttonBrowse.Text = _localizationGetter("Forms.MapReplaceForm.ButtonBrowse") ?? "Browse..."; + labelMap.Text = _localizationGetter("Forms.MapReplaceForm.LabelMap") ?? "Map:"; + groupBoxWhat.Text = _localizationGetter("Forms.MapReplaceForm.GroupBoxWhat") ?? "Copy"; + checkBoxMap.Text = _localizationGetter("Forms.MapReplaceForm.CheckBoxMap") ?? "Map"; + labelMapFormat.Text = _localizationGetter("Forms.MapReplaceForm.LabelMapFormat") ?? "written as:"; + checkBoxStatics.Text = _localizationGetter("Forms.MapReplaceForm.CheckBoxStatics") ?? "Statics"; + RemoveDupl.Text = _localizationGetter("Forms.MapReplaceForm.RemoveDupl") ?? "remove duplicates"; + checkBoxDuplicatesHue.Text = _localizationGetter("Forms.MapReplaceForm.CheckBoxDuplicatesHue") ?? "comparing hue too (legacy)"; + groupBoxFrom.Text = _localizationGetter("Forms.MapReplaceForm.GroupBoxFrom") ?? "From region, in source map tiles"; + label1.Text = _localizationGetter("Forms.MapReplaceForm.Label1") ?? "X1"; + label2.Text = _localizationGetter("Forms.MapReplaceForm.Label2") ?? "Y1"; + label3.Text = _localizationGetter("Forms.MapReplaceForm.Label3") ?? "X2"; + label4.Text = _localizationGetter("Forms.MapReplaceForm.Label4") ?? "Y2"; + groupBoxTo.Text = _localizationGetter("Forms.MapReplaceForm.GroupBoxTo") ?? "To position, in this map's tiles"; + label6.Text = _localizationGetter("Forms.MapReplaceForm.Label6") ?? "X"; + label7.Text = _localizationGetter("Forms.MapReplaceForm.Label7") ?? "Y"; + labelZAdjust.Text = _localizationGetter("Forms.MapReplaceForm.LabelZAdjust") ?? "Z adjust"; + checkBoxZClamp.Text = _localizationGetter("Forms.MapReplaceForm.CheckBoxZClamp") ?? "hold what passes the limit"; + groupBoxPreview.Text = _localizationGetter("Forms.MapReplaceForm.GroupBoxPreview") ?? "What will be copied"; + labelSourcePreview.Text = _localizationGetter("Forms.MapReplaceForm.LabelSourcePreview") ?? "From - drag to choose the region"; + labelTargetPreview.Text = _localizationGetter("Forms.MapReplaceForm.LabelTargetPreview") ?? "To - drag to place it"; + checkBoxPreviewStatics.Text = _localizationGetter("Forms.MapReplaceForm.CheckBoxPreviewStatics") ?? "Show statics"; + checkBoxPreviewOverlay.Text = _localizationGetter("Forms.MapReplaceForm.CheckBoxPreviewOverlay") ?? "Show the piece in place"; + buttonCopy.Text = _localizationGetter("Forms.MapReplaceForm.ButtonCopy") ?? "Copy"; + buttonCancel.Text = _localizationGetter("Forms.MapReplaceForm.ButtonCancel") ?? "Cancel"; + buttonClose.Text = _localizationGetter("Forms.MapReplaceForm.ButtonClose") ?? "Close"; + } + public MapReplaceForm(Map currentMap) { InitializeComponent(); diff --git a/UoFiddler.Controls/UserControls/MapControl.cs b/UoFiddler.Controls/UserControls/MapControl.cs index 1ab50f79..4ca0fa38 100644 --- a/UoFiddler.Controls/UserControls/MapControl.cs +++ b/UoFiddler.Controls/UserControls/MapControl.cs @@ -1472,6 +1472,11 @@ private void OnClickCopy(object sender, EventArgs e) { TopMost = true }; + + var getter = GetLocalizationGetter(); + if (getter != null) + _showForm.SetLocalization(getter); + _showForm.Show(); } diff --git a/UoFiddler/Localization/Dictionaries/zh-CN.json b/UoFiddler/Localization/Dictionaries/zh-CN.json index a7dad8fd..8cca6604 100644 --- a/UoFiddler/Localization/Dictionaries/zh-CN.json +++ b/UoFiddler/Localization/Dictionaries/zh-CN.json @@ -1329,6 +1329,37 @@ "CopyButton": "复制", "OpenFolderButton": "打开输出文件夹", "CloseButton": "关闭" + }, + "MapReplaceForm": { + "Title": "地图和静态物品复制", + "GroupBoxSource": "复制来源", + "LabelFolder": "文件夹:", + "ButtonBrowse": "浏览...", + "LabelMap": "地图:", + "GroupBoxWhat": "复制内容", + "CheckBoxMap": "地图", + "LabelMapFormat": "写入为:", + "CheckBoxStatics": "静态物品", + "RemoveDupl": "移除重复项", + "CheckBoxDuplicatesHue": "也比较色调(旧版)", + "GroupBoxFrom": "来源区域,以源地图图块为单位", + "Label1": "X1", + "Label2": "Y1", + "Label3": "X2", + "Label4": "Y2", + "GroupBoxTo": "目标位置,以此地图的图块为单位", + "Label6": "X", + "Label7": "Y", + "LabelZAdjust": "Z 调整", + "CheckBoxZClamp": "保留超过限制的内容", + "GroupBoxPreview": "将要复制的内容", + "LabelSourcePreview": "来源 - 拖动选择区域", + "LabelTargetPreview": "目标 - 拖动放置它", + "CheckBoxPreviewStatics": "显示静态物品", + "CheckBoxPreviewOverlay": "在位置显示该片段", + "ButtonCopy": "复制", + "ButtonCancel": "取消", + "ButtonClose": "关闭" } } } From c4fff402b905097a63731775e6cc89a910cc568a Mon Sep 17 00:00:00 2001 From: nbyaya Date: Wed, 7 Oct 2026 10:23:20 +0800 Subject: [PATCH 58/76] =?UTF-8?q?=E8=A1=A5=E5=85=85=E6=B1=89=E5=8C=96=20Ma?= =?UTF-8?q?pReplaceForm=20ComboBox=20=E5=8A=A8=E6=80=81=E9=A1=B9?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit - 添加 ApplyComboBoxLocalization() 方法对动态生成的 ComboBox 项进行汉化 - 为 'the same format as this client (.mul/.uop)' 等动态项添加 JSON 词条 - 实现类型 2 汉化模式 - 动态列表项汉化 - 修复遗漏的 ComboBoxFormats 4 个词条 修复前:ComboBox 项显示英文 修复后:ComboBox 项显示中文 --- UoFiddler.Controls/Forms/MapReplaceForm.cs | 31 +++++++++++++++++++ .../Localization/Dictionaries/zh-CN.json | 8 ++++- 2 files changed, 38 insertions(+), 1 deletion(-) diff --git a/UoFiddler.Controls/Forms/MapReplaceForm.cs b/UoFiddler.Controls/Forms/MapReplaceForm.cs index 52c142b8..b9c6483e 100644 --- a/UoFiddler.Controls/Forms/MapReplaceForm.cs +++ b/UoFiddler.Controls/Forms/MapReplaceForm.cs @@ -98,6 +98,37 @@ private void ApplyLocalization() buttonCopy.Text = _localizationGetter("Forms.MapReplaceForm.ButtonCopy") ?? "Copy"; buttonCancel.Text = _localizationGetter("Forms.MapReplaceForm.ButtonCancel") ?? "Cancel"; buttonClose.Text = _localizationGetter("Forms.MapReplaceForm.ButtonClose") ?? "Close"; + + // 汉化 ComboBox 项(类型 2 - 动态列表项汉化) + ApplyComboBoxLocalization(); + } + + private void ApplyComboBoxLocalization() + { + if (_localizationGetter == null) return; + + bool uop = _workingMap.Tiles.IsUOPFormat; + + // 清空并重新添加翻译后的项 + comboBoxMapFormat.Items.Clear(); + + // 第一项:与客户端相同格式 + string sameFormatKey = uop ? "SameFormatUOP" : "SameFormatMUL"; + string sameFormatText = _localizationGetter($"Forms.MapReplaceForm.ComboBoxFormats.{sameFormatKey}") + ?? (uop ? "the same format as this client (.uop)" : "the same format as this client (.mul)"); + comboBoxMapFormat.Items.Add(sameFormatText); + + // 第二项:map{0}.mul + string mapMulTemplate = _localizationGetter("Forms.MapReplaceForm.ComboBoxFormats.MapMUL") + ?? "map{0}.mul"; + comboBoxMapFormat.Items.Add(string.Format(mapMulTemplate, _workingMap.FileIndex)); + + // 第三项:map{0}LegacyMUL.uop + string legacyTemplate = _localizationGetter("Forms.MapReplaceForm.ComboBoxFormats.LegacyMUL") + ?? "map{0}LegacyMUL.uop"; + comboBoxMapFormat.Items.Add(string.Format(legacyTemplate, _workingMap.FileIndex)); + + comboBoxMapFormat.SelectedIndex = ClientFileSaveFormats.DefaultIndex(Options.SaveFormat); } public MapReplaceForm(Map currentMap) diff --git a/UoFiddler/Localization/Dictionaries/zh-CN.json b/UoFiddler/Localization/Dictionaries/zh-CN.json index 8cca6604..0f00018f 100644 --- a/UoFiddler/Localization/Dictionaries/zh-CN.json +++ b/UoFiddler/Localization/Dictionaries/zh-CN.json @@ -1359,7 +1359,13 @@ "CheckBoxPreviewOverlay": "在位置显示该片段", "ButtonCopy": "复制", "ButtonCancel": "取消", - "ButtonClose": "关闭" + "ButtonClose": "关闭", + "ComboBoxFormats": { + "SameFormatUOP": "与此客户端相同格式 (.uop)", + "SameFormatMUL": "与此客户端相同格式 (.mul)", + "MapMUL": "map{0}.mul", + "LegacyMUL": "map{0}LegacyMUL.uop" + } } } } From 1c79b1830f68259352ea80f992f6291da372d6c5 Mon Sep 17 00:00:00 2001 From: nbyaya Date: Wed, 7 Oct 2026 11:05:26 +0800 Subject: [PATCH 59/76] =?UTF-8?q?=E8=A1=A5=E5=85=85=E6=B1=89=E5=8C=96=20Ma?= =?UTF-8?q?pReplaceForm=20=E9=A2=84=E8=A7=88=E6=B6=88=E6=81=AF=E6=8F=90?= =?UTF-8?q?=E7=A4=BA=E6=96=87=E6=9C=AC?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- UoFiddler.Controls/Forms/MapReplaceForm.cs | 4 ++-- UoFiddler/Localization/Dictionaries/zh-CN.json | 4 ++++ 2 files changed, 6 insertions(+), 2 deletions(-) diff --git a/UoFiddler.Controls/Forms/MapReplaceForm.cs b/UoFiddler.Controls/Forms/MapReplaceForm.cs index b9c6483e..375d1d03 100644 --- a/UoFiddler.Controls/Forms/MapReplaceForm.cs +++ b/UoFiddler.Controls/Forms/MapReplaceForm.cs @@ -399,7 +399,7 @@ private void UpdatePreviewRectangles() if (map == null) { - textBoxPreview.Text = "Choose a folder and a map."; + textBoxPreview.Text = _localizationGetter?.Invoke("Forms.MapReplaceForm.PreviewMessages.ChooseFolderAndMap") ?? "Choose a folder and a map."; return; } @@ -479,7 +479,7 @@ private void RebuildSourceMap(SupportedMap map) previewSource.Map = _sourceMap; previewSource.MapSize = map == null ? default : new MapSize(map.Width, map.Height); - previewSource.Message = _sourceMap == null ? "Choose a folder to copy from" : null; + previewSource.Message = _sourceMap == null ? (_localizationGetter?.Invoke("Forms.MapReplaceForm.PreviewMessages.ChooseFolderToCopyFrom") ?? "Choose a folder to copy from") : null; previewTarget.OverlayMap = checkBoxPreviewOverlay.Checked ? _sourceMap : null; } diff --git a/UoFiddler/Localization/Dictionaries/zh-CN.json b/UoFiddler/Localization/Dictionaries/zh-CN.json index 0f00018f..f9205277 100644 --- a/UoFiddler/Localization/Dictionaries/zh-CN.json +++ b/UoFiddler/Localization/Dictionaries/zh-CN.json @@ -1365,6 +1365,10 @@ "SameFormatMUL": "与此客户端相同格式 (.mul)", "MapMUL": "map{0}.mul", "LegacyMUL": "map{0}LegacyMUL.uop" + }, + "PreviewMessages": { + "ChooseFolderAndMap": "选择文件夹和地图。", + "ChooseFolderToCopyFrom": "选择要复制的文件夹" } } } From cef728ec892bfe55a0045d82f73572f39b02e54d Mon Sep 17 00:00:00 2001 From: nbyaya Date: Wed, 7 Oct 2026 11:29:20 +0800 Subject: [PATCH 60/76] =?UTF-8?q?=E4=BF=AE=E5=A4=8D=20MapReplaceForm=20?= =?UTF-8?q?=E9=A2=84=E8=A7=88=E6=B6=88=E6=81=AF=E6=B1=89=E5=8C=96=20-=20?= =?UTF-8?q?=E5=9C=A8=20ApplyLocalization=20=E4=B8=AD=E5=88=B7=E6=96=B0?= =?UTF-8?q?=E5=8A=A8=E6=80=81=E6=96=87=E6=9C=AC?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- UoFiddler.Controls/Forms/MapReplaceForm.cs | 3 +++ 1 file changed, 3 insertions(+) diff --git a/UoFiddler.Controls/Forms/MapReplaceForm.cs b/UoFiddler.Controls/Forms/MapReplaceForm.cs index 375d1d03..d4406364 100644 --- a/UoFiddler.Controls/Forms/MapReplaceForm.cs +++ b/UoFiddler.Controls/Forms/MapReplaceForm.cs @@ -101,6 +101,9 @@ private void ApplyLocalization() // 汉化 ComboBox 项(类型 2 - 动态列表项汉化) ApplyComboBoxLocalization(); + + // 刷新预览消息,应用动态文本汉化(类型 8 - 运行时动态文本) + UpdatePreview(); } private void ApplyComboBoxLocalization() From d246c7e1e9c999bde9c54d7788ab07276231e660 Mon Sep 17 00:00:00 2001 From: nbyaya Date: Wed, 7 Oct 2026 11:35:04 +0800 Subject: [PATCH 61/76] =?UTF-8?q?=E6=A0=B9=E6=9C=AC=E4=BF=AE=E5=A4=8D=20Ma?= =?UTF-8?q?pReplaceForm=20=E5=8A=A8=E6=80=81=E6=96=87=E6=9C=AC=E6=B1=89?= =?UTF-8?q?=E5=8C=96=20-=20=E5=BB=B6=E8=BF=9F=E5=88=9D=E5=A7=8B=E5=8C=96?= =?UTF-8?q?=E5=88=B0=20SetLocalization=20=E4=B9=8B=E5=90=8E?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- UoFiddler.Controls/Forms/MapReplaceForm.cs | 19 +++++++++++++++++-- 1 file changed, 17 insertions(+), 2 deletions(-) diff --git a/UoFiddler.Controls/Forms/MapReplaceForm.cs b/UoFiddler.Controls/Forms/MapReplaceForm.cs index d4406364..6eb850ac 100644 --- a/UoFiddler.Controls/Forms/MapReplaceForm.cs +++ b/UoFiddler.Controls/Forms/MapReplaceForm.cs @@ -32,6 +32,7 @@ public partial class MapReplaceForm : Form { private readonly Map _workingMap; private Func? _localizationGetter; + private bool _initialized = false; private CancellationTokenSource _cancellation; private MapSize _detectedSize; @@ -63,6 +64,7 @@ public void SetLocalization(Func getLocalized) { _localizationGetter = getLocalized; ApplyLocalization(); + CompleteInitialization(); // 完成初始化,确保动态消息被汉化 } private void ApplyLocalization() @@ -191,11 +193,24 @@ public MapReplaceForm(Map currentMap) _zWorker.DoWork += OnZWorkerDoWork; _zWorker.RunWorkerCompleted += OnZWorkerCompleted; - OnSourceMapChanged(this, EventArgs.Empty); - OnOptionChanged(this, EventArgs.Empty); + // 不在这里初始化,等待 SetLocalization 被调用 + // OnSourceMapChanged(this, EventArgs.Empty); + // OnOptionChanged(this, EventArgs.Empty); ActiveControl = buttonBrowse; } + + /// + /// 完成初始化 - 在 SetLocalization 之后调用 + /// + private void CompleteInitialization() + { + if (_initialized) return; + _initialized = true; + + OnSourceMapChanged(this, EventArgs.Empty); + OnOptionChanged(this, EventArgs.Empty); + } private SupportedMap SelectedMap => comboBoxMapID.SelectedItem as SupportedMap; From 7ff970fd1bb9103b055ad1d905af2b8697c5e074 Mon Sep 17 00:00:00 2001 From: nbyaya Date: Wed, 7 Oct 2026 11:52:11 +0800 Subject: [PATCH 62/76] =?UTF-8?q?=E6=B1=89=E5=8C=96=20Map=20=E7=AA=97?= =?UTF-8?q?=E5=8F=A3=E7=8A=B6=E6=80=81=E6=A0=8F=E6=A0=87=E7=AD=BE=EF=BC=88?= =?UTF-8?q?=E5=9D=90=E6=A0=87=E3=80=81=E5=AE=A2=E6=88=B7=E7=AB=AF=E4=BD=8D?= =?UTF-8?q?=E7=BD=AE=E3=80=81=E7=BC=A9=E6=94=BE=EF=BC=89?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- UoFiddler.Controls/UserControls/MapControl.cs | 25 +++++++++++++++---- 1 file changed, 20 insertions(+), 5 deletions(-) diff --git a/UoFiddler.Controls/UserControls/MapControl.cs b/UoFiddler.Controls/UserControls/MapControl.cs index 4ca0fa38..71d65554 100644 --- a/UoFiddler.Controls/UserControls/MapControl.cs +++ b/UoFiddler.Controls/UserControls/MapControl.cs @@ -47,6 +47,11 @@ public MapControl() } private Func? _localizationGetter; + + // 状态栏标签前缀缓存(用于汉化) + private string _coordsPrefix = "Coords: "; + private string _clientLocPrefix = "ClientLoc: "; + private string _zoomPrefix = "Zoom: "; /// /// Set localization for MapControl @@ -133,6 +138,16 @@ private void ApplyLocalization() copyToolStripMenuItem.Text = _localizationGetter("Forms.MapControl.MapAndStaticsCopy") ?? "Map and Statics Copy..."; insertDiffDataToolStripMenuItem.Text = _localizationGetter("Forms.MapControl.DiffToMapCopy") ?? "Diff to Map Copy..."; replaceTilesToolStripMenuItem.Text = _localizationGetter("Forms.MapControl.ReplaceTiles") ?? "Replace Tiles.."; + + // 状态栏标签前缀汉化 + _coordsPrefix = _localizationGetter("Forms.MapControl.CoordsLabel") ?? "Coords: "; + _clientLocPrefix = _localizationGetter("Forms.MapControl.ClientLocLabel") ?? "ClientLoc: "; + _zoomPrefix = _localizationGetter("Forms.MapControl.ZoomLabel") ?? "Zoom: "; + + // 初始化状态栏标签显示(使用默认值,等待数据更新) + CoordsLabel.Text = $"{_coordsPrefix}0,0"; + ClientLocLabel.Text = $"{_clientLocPrefix}0,0"; + ZoomLabel.Text = $"{_zoomPrefix}1"; } private void AddAltitudeIntensityMenuItems() @@ -244,7 +259,7 @@ private void OnLoad(object sender, EventArgs e) tokunoToolStripMenuItem.Checked = false; PreloadMap.Visible = true; ChangeMapNames(); - ZoomLabel.Text = $"Zoom: {Zoom}"; + ZoomLabel.Text = $"{_zoomPrefix}{Zoom}"; SetScrollBarValues(); Refresh(); pictureBox.Invalidate(); @@ -586,7 +601,7 @@ private void OnMouseMove(object sender, MouseEventArgs e) int xDelta = Math.Min(CurrentMap.Width, (int)(e.X / Zoom) + Round(hScrollBar.Value)); int yDelta = Math.Min(CurrentMap.Height, (int)(e.Y / Zoom) + Round(vScrollBar.Value)); - CoordsLabel.Text = $"Coords: {xDelta},{yDelta}"; + CoordsLabel.Text = $"{_coordsPrefix}{xDelta},{yDelta}"; if (!_moving) { @@ -693,7 +708,7 @@ private void OnClick_GotoClientLoc(object sender, EventArgs e) hScrollBar.Value = (int)Math.Max(0, x - (pictureBox.Right / Zoom / 2)); vScrollBar.Value = (int)Math.Max(0, y - (pictureBox.Bottom / Zoom / 2)); pictureBox.Invalidate(); - ClientLocLabel.Text = $"ClientLoc: {x},{y},{z},{Options.MapNames[mapClient]}"; + ClientLocLabel.Text = $"{_clientLocPrefix}{x},{y},{z},{Options.MapNames[mapClient]}"; } private void SwitchMap(int mapId) @@ -757,7 +772,7 @@ private void SyncClientTimer(object sender, EventArgs e) } } - ClientLocLabel.Text = $"ClientLoc: {x},{y},{z},{mapName}"; + ClientLocLabel.Text = $"{_clientLocPrefix}{x},{y},{z},{mapName}"; pictureBox.Invalidate(); } @@ -844,7 +859,7 @@ private void DoZoom() _renderingZoom = true; 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)); x = Math.Min(x, hScrollBar.Maximum); From 35336e2173fe0d345d833b6c47756539c7cb981a Mon Sep 17 00:00:00 2001 From: nbyaya Date: Wed, 7 Oct 2026 13:48:55 +0800 Subject: [PATCH 63/76] =?UTF-8?q?=E6=B1=89=E5=8C=96=20MapReplaceForm=20?= =?UTF-8?q?=E5=9C=B0=E5=9B=BE=E5=92=8C=E9=9D=99=E6=80=81=E7=89=A9=E5=93=81?= =?UTF-8?q?=E5=A4=8D=E5=88=B6=E7=AA=97=E5=8F=A3?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit - 所有 UI 文本、菜单、按钮 - 预览消息、警告和错误提示 - 进度显示和高度范围信息 - 调整 UI 布局以适应中文文本 --- Ultima/Maps/MapSizes.cs | 30 ++-- .../Forms/MapReplaceForm.Designer.cs | 16 +-- UoFiddler.Controls/Forms/MapReplaceForm.cs | 133 +++++++++++++----- .../Localization/Dictionaries/zh-CN.json | 38 ++++- UoFiddler/Program.cs | 3 + 5 files changed, 166 insertions(+), 54 deletions(-) diff --git a/Ultima/Maps/MapSizes.cs b/Ultima/Maps/MapSizes.cs index e7b4126d..56e1bffa 100644 --- a/Ultima/Maps/MapSizes.cs +++ b/Ultima/Maps/MapSizes.cs @@ -17,6 +17,17 @@ namespace Ultima.Maps { + /// + /// Static helper for localizing map detection messages. + /// + public static class MapSizesLocalization + { + /// + /// Optional localization getter for error messages (set by main application). + /// + public static Func? LocalizationGetter { get; set; } + } + public readonly struct MapSize : IEquatable { public MapSize(int width, int height) @@ -135,9 +146,9 @@ private static bool TryDetect(Func resolve, int fileIndex, out M if (!TryMeasureBlocks(resolve, fileIndex, out long blocks, out string source)) { size = Fallback(fileIndex); - evidence = string.Format(CultureInfo.InvariantCulture, - "no map or statics index found for facet {0}; assuming {1}", fileIndex, size); - + string template = MapSizesLocalization.LocalizationGetter?.Invoke("Ultima.Maps.MapSizes.NoMapOrStaticsIndex") + ?? "no map or statics index found for facet {0}; assuming {1}"; + evidence = string.Format(CultureInfo.InvariantCulture, template, fileIndex, size); return false; } @@ -149,17 +160,16 @@ private static bool TryDetect(Func resolve, int fileIndex, out M } size = candidate; - evidence = string.Format(CultureInfo.InvariantCulture, - "{0} holds {1:N0} blocks, which is {2}", source, blocks, candidate); - + string template1 = MapSizesLocalization.LocalizationGetter?.Invoke("Ultima.Maps.MapSizes.HoldsBlocks") + ?? "{0} holds {1:N0} blocks, which is {2}"; + evidence = string.Format(CultureInfo.InvariantCulture, template1, source, blocks, candidate); return true; } size = Fallback(fileIndex); - evidence = string.Format(CultureInfo.InvariantCulture, - "{0} holds {1:N0} blocks, which matches no known shape for facet {2}; assuming {3}", - source, blocks, fileIndex, size); - + string template2 = MapSizesLocalization.LocalizationGetter?.Invoke("Ultima.Maps.MapSizes.HoldsBlocksNoMatch") + ?? "{0} holds {1:N0} blocks, which matches no known shape for facet {2}; assuming {3}"; + evidence = string.Format(CultureInfo.InvariantCulture, template2, source, blocks, fileIndex, size); return false; } diff --git a/UoFiddler.Controls/Forms/MapReplaceForm.Designer.cs b/UoFiddler.Controls/Forms/MapReplaceForm.Designer.cs index 6383be9e..40006905 100644 --- a/UoFiddler.Controls/Forms/MapReplaceForm.Designer.cs +++ b/UoFiddler.Controls/Forms/MapReplaceForm.Designer.cs @@ -504,24 +504,24 @@ private void InitializeComponent() // progressBar1 // this.progressBar1.Anchor = ((System.Windows.Forms.AnchorStyles)(((System.Windows.Forms.AnchorStyles.Bottom | System.Windows.Forms.AnchorStyles.Left) | System.Windows.Forms.AnchorStyles.Right))); - this.progressBar1.Location = new System.Drawing.Point(12, 884); + this.progressBar1.Location = new System.Drawing.Point(12, 844); this.progressBar1.Name = "progressBar1"; - this.progressBar1.Size = new System.Drawing.Size(1440, 18); + this.progressBar1.Size = new System.Drawing.Size(1432, 18); this.progressBar1.TabIndex = 5; // // labelStatus // this.labelStatus.Anchor = ((System.Windows.Forms.AnchorStyles)(((System.Windows.Forms.AnchorStyles.Bottom | System.Windows.Forms.AnchorStyles.Left) | System.Windows.Forms.AnchorStyles.Right))); this.labelStatus.AutoEllipsis = true; - this.labelStatus.Location = new System.Drawing.Point(12, 907); + this.labelStatus.Location = new System.Drawing.Point(12, 867); this.labelStatus.Name = "labelStatus"; - this.labelStatus.Size = new System.Drawing.Size(1440, 17); + this.labelStatus.Size = new System.Drawing.Size(1432, 17); this.labelStatus.TabIndex = 6; // // buttonCopy // this.buttonCopy.Anchor = ((System.Windows.Forms.AnchorStyles)((System.Windows.Forms.AnchorStyles.Bottom | System.Windows.Forms.AnchorStyles.Right))); - this.buttonCopy.Location = new System.Drawing.Point(1204, 932); + this.buttonCopy.Location = new System.Drawing.Point(1196, 892); this.buttonCopy.Name = "buttonCopy"; this.buttonCopy.Size = new System.Drawing.Size(80, 28); this.buttonCopy.TabIndex = 7; @@ -533,7 +533,7 @@ private void InitializeComponent() // this.buttonCancel.Anchor = ((System.Windows.Forms.AnchorStyles)((System.Windows.Forms.AnchorStyles.Bottom | System.Windows.Forms.AnchorStyles.Right))); this.buttonCancel.Enabled = false; - this.buttonCancel.Location = new System.Drawing.Point(1292, 932); + this.buttonCancel.Location = new System.Drawing.Point(1284, 892); this.buttonCancel.Name = "buttonCancel"; this.buttonCancel.Size = new System.Drawing.Size(72, 28); this.buttonCancel.TabIndex = 8; @@ -545,7 +545,7 @@ private void InitializeComponent() // this.buttonClose.Anchor = ((System.Windows.Forms.AnchorStyles)((System.Windows.Forms.AnchorStyles.Bottom | System.Windows.Forms.AnchorStyles.Right))); this.buttonClose.DialogResult = System.Windows.Forms.DialogResult.Cancel; - this.buttonClose.Location = new System.Drawing.Point(1380, 932); + this.buttonClose.Location = new System.Drawing.Point(1372, 892); this.buttonClose.Name = "buttonClose"; this.buttonClose.Size = new System.Drawing.Size(80, 28); this.buttonClose.TabIndex = 9; @@ -564,7 +564,7 @@ private void InitializeComponent() this.AutoScaleDimensions = new System.Drawing.SizeF(7F, 15F); this.AutoScaleMode = System.Windows.Forms.AutoScaleMode.Font; this.CancelButton = this.buttonClose; - this.ClientSize = new System.Drawing.Size(1464, 972); + this.ClientSize = new System.Drawing.Size(1464, 1012); this.Controls.Add(this.groupBoxSource); this.Controls.Add(this.groupBoxWhat); this.Controls.Add(this.groupBoxFrom); diff --git a/UoFiddler.Controls/Forms/MapReplaceForm.cs b/UoFiddler.Controls/Forms/MapReplaceForm.cs index 6eb850ac..a5f13425 100644 --- a/UoFiddler.Controls/Forms/MapReplaceForm.cs +++ b/UoFiddler.Controls/Forms/MapReplaceForm.cs @@ -264,7 +264,8 @@ private void OnClickBrowse(object sender, EventArgs e) { using (var dialog = new FolderBrowserDialog { - Description = "Select the folder holding the map files to copy from", + Description = _localizationGetter?.Invoke("Forms.MapReplaceForm.PreviewMessages.SelectFolderDialog") + ?? "Select the folder holding the map files to copy from", ShowNewFolderButton = false, SelectedPath = Directory.Exists(textBoxFolder.Text) ? textBoxFolder.Text : string.Empty }) @@ -339,19 +340,41 @@ private void Detect() RebuildSourceMap(map); - labelDetected.Text = _detectionKnown ? $"folder holds {_detectedSize}" : "size not recognised"; + string sizeNotRecognised = _localizationGetter?.Invoke("Forms.MapReplaceForm.PreviewMessages.SizeNotRecognised") ?? "size not recognised"; + string folderHoldsTemplate = _localizationGetter?.Invoke("Forms.MapReplaceForm.PreviewMessages.FolderHolds") ?? "folder holds {0}"; + + labelDetected.Text = _detectionKnown ? string.Format(folderHoldsTemplate, _detectedSize) : sizeNotRecognised; if (_detectionKnown && _detectedSize.Width == map.Width && _detectedSize.Height == map.Height) { labelSizeWarning.ForeColor = SystemColors.ControlText; - labelSizeWarning.Text = _detectionEvidence; + // 将 evidence 中的英文消息汉化 + string localizedEvidence = _detectionEvidence; + if (_localizationGetter != null && _detectionEvidence != null) + { + string template = _localizationGetter("Forms.MapReplaceForm.PreviewMessages.NoMapOrStaticsIndex") + ?? "no map or statics index found for facet {0}; assuming {1}"; + // 尝试汉化 evidence 中的模板消息 + localizedEvidence = _detectionEvidence.Replace( + "no map or statics index found for facet", + template.Split(';')[0]); + } + labelSizeWarning.Text = localizedEvidence; } else { labelSizeWarning.ForeColor = Options.DarkMode ? Color.OrangeRed : Color.Red; - labelSizeWarning.Text = _detectionKnown - ? $"This folder holds {_detectedSize} for map {map.Id}, not the {map.Width}x{map.Height} selected.{Environment.NewLine}Pick the entry that matches." - : _detectionEvidence; + if (_detectionKnown) + { + string template = _localizationGetter?.Invoke("Forms.MapReplaceForm.PreviewMessages.SizeCheckMismatch") + ?? "This folder holds {0} for map {1}, not the {2} selected.{3}Pick the entry that matches."; + labelSizeWarning.Text = string.Format(template, _detectedSize, map.Id, + $"{map.Width}x{map.Height}", Environment.NewLine); + } + else + { + labelSizeWarning.Text = _detectionEvidence; + } } UpdatePreview(); @@ -447,17 +470,24 @@ private void UpdatePreviewRectangles() var sb = new StringBuilder(); // The panels carry the shape now, so this is only the numbers. - sb.AppendLine(string.Format(CultureInfo.InvariantCulture, "from {0},{1} - {2},{3} {4} x {5} blocks", + string sourceFormat = _localizationGetter?.Invoke("Forms.MapReplaceForm.PreviewMessages.SourceFormat") + ?? "from {0},{1} - {2},{3} {4} x {5} blocks"; + string destinationFormat = _localizationGetter?.Invoke("Forms.MapReplaceForm.PreviewMessages.DestinationFormat") + ?? "to {0},{1} - {2},{3}"; + string widenedFormat = _localizationGetter?.Invoke("Forms.MapReplaceForm.PreviewMessages.WidenedFormat") + ?? "{0},{1} - {2},{3} widened to whole blocks"; + + sb.AppendLine(string.Format(CultureInfo.InvariantCulture, sourceFormat, source.TileX1, source.TileY1, source.TileX2, source.TileY2, source.BlockWidth, source.BlockHeight)); - sb.AppendLine(string.Format(CultureInfo.InvariantCulture, "to {0},{1} - {2},{3}", + sb.AppendLine(string.Format(CultureInfo.InvariantCulture, destinationFormat, destination.TileX1, destination.TileY1, destination.TileX2, destination.TileY2)); bool snapped = source.TileX1 != x1 || source.TileY1 != y1 || source.TileX2 != x2 || source.TileY2 != y2; if (snapped) { - sb.AppendLine(string.Format(CultureInfo.InvariantCulture, - "{0},{1} - {2},{3} widened to whole blocks", x1, y1, x2, y2)); + sb.AppendLine(string.Format(CultureInfo.InvariantCulture, widenedFormat, + x1, y1, x2, y2)); } textBoxPreview.Text = sb.ToString(); @@ -610,7 +640,8 @@ private void UpdateZ() _zPending = request; labelZRange.ForeColor = SystemColors.ControlText; - labelZRange.Text = "reading the heights in this region..."; + labelZRange.Text = _localizationGetter?.Invoke("Forms.MapReplaceForm.PreviewMessages.ReadingHeights") + ?? "reading the heights in this region..."; _zDebounce.Stop(); _zDebounce.Start(); @@ -714,13 +745,19 @@ private void ShowZ() // Kept short: this sits on one line beside the spinners, and an ellipsis in the middle // of the warning is worse than no warning at all. - sb.Append(CultureInfo.InvariantCulture, - $"region z land {Span(_zSurvey.Land, 0)}, statics {Span(_zSurvey.Statics, 0)}"); + string regionTemplate = _localizationGetter?.Invoke("Forms.MapReplaceForm.PreviewMessages.RegionZ") + ?? "region z land {0}, statics {1}"; + + sb.Append(string.Format(CultureInfo.InvariantCulture, + regionTemplate, Span(_zSurvey.Land, 0), Span(_zSurvey.Statics, 0))); if (adjust != 0) { - sb.Append(CultureInfo.InvariantCulture, - $" -> land {Span(_zSurvey.Land, adjust)}, statics {Span(_zSurvey.Statics, adjust)}"); + string adjustTemplate = _localizationGetter?.Invoke("Forms.MapReplaceForm.PreviewMessages.RegionZAdjusted") + ?? " -> land {0}, statics {1}"; + + sb.Append(string.Format(CultureInfo.InvariantCulture, + adjustTemplate, Span(_zSurvey.Land, adjust), Span(_zSurvey.Statics, adjust))); } long past = _zSurvey.OutOfRange(adjust); @@ -733,18 +770,24 @@ private void ShowZ() return; } - sb.Append(CultureInfo.InvariantCulture, - $" - {past:N0} past the limit, {(checkBoxZClamp.Checked ? "held there" : "refused")}"); + string limitTemplate = _localizationGetter?.Invoke("Forms.MapReplaceForm.PreviewMessages.RegionZOutOfRange") + ?? " - {0:N0} past the limit, {1}"; + string limitAction = checkBoxZClamp.Checked + ? (_localizationGetter?.Invoke("Forms.MapReplaceForm.PreviewMessages.HeldThere") ?? "held there") + : (_localizationGetter?.Invoke("Forms.MapReplaceForm.PreviewMessages.Refused") ?? "refused"); + + sb.Append(string.Format(CultureInfo.InvariantCulture, + limitTemplate, past, limitAction)); labelZRange.ForeColor = Options.DarkMode ? Color.OrangeRed : Color.Red; labelZRange.Text = sb.ToString(); } - private static string Span(ZHistogram z, int adjust) + private string Span(ZHistogram z, int adjust) { if (!z.HasTiles) { - return "none"; + return _localizationGetter?.Invoke("Forms.MapReplaceForm.PreviewMessages.StaticsNone") ?? "none"; } return string.Format(CultureInfo.InvariantCulture, "{0}..{1}", @@ -773,30 +816,34 @@ private void OnClickCopy(object sender, EventArgs e) if (!Directory.Exists(textBoxFolder.Text)) { - Fail("Choose the folder holding the map files to copy from."); - + string msg = _localizationGetter?.Invoke("Forms.MapReplaceForm.PreviewMessages.ChooseFolderForCopy") + ?? "Choose the folder holding the map files to copy from."; + Fail(msg); return; } if (!checkBoxMap.Checked && !checkBoxStatics.Checked) { - Fail("Nothing is selected to copy."); - + string msg = _localizationGetter?.Invoke("Forms.MapReplaceForm.PreviewMessages.NothingSelected") + ?? "Nothing is selected to copy."; + Fail(msg); return; } if (!_detectionKnown) { - Fail($"The size of map {map.Id} in that folder could not be worked out.{Environment.NewLine}{Environment.NewLine}{_detectionEvidence}"); + string msg = _localizationGetter?.Invoke("Forms.MapReplaceForm.PreviewMessages.SizeCouldNotBeDetermined") + ?? $"The size of map {map.Id} in that folder could not be worked out.{Environment.NewLine}{Environment.NewLine}{_detectionEvidence}"; + Fail(string.Format(msg, map.Id, Environment.NewLine, _detectionEvidence)); return; } if (_detectedSize.Width != map.Width || _detectedSize.Height != map.Height) { - Fail($"That folder holds {_detectedSize} for map {map.Id}, but {map} is selected." + - $"{Environment.NewLine}{Environment.NewLine}{_detectionEvidence}" + - $"{Environment.NewLine}{Environment.NewLine}Pick the entry that matches, or the wrong blocks will be read."); + string template = _localizationGetter?.Invoke("Forms.MapReplaceForm.PreviewMessages.SizeMismatchError") + ?? $"That folder holds {{0}} for map {{1}}, but {{2}} is selected.{{3}}{{3}}{{4}}{{3}}{{3}}Pick the entry that matches, or the wrong blocks will be read."; + Fail(string.Format(template, _detectedSize, map.Id, map, Environment.NewLine, _detectionEvidence)); return; } @@ -810,7 +857,9 @@ private void OnClickCopy(object sender, EventArgs e) SetRunning(true); progressBar1.Value = 0; - labelStatus.Text = "Copying..."; + string copyingMsg = _localizationGetter?.Invoke("Forms.MapReplaceForm.PreviewMessages.Copying") + ?? "Copying..."; + labelStatus.Text = copyingMsg; worker.RunWorkerAsync(options); } @@ -878,8 +927,16 @@ private void OnProgress(MapCopyProgress progress) } progressBar1.Value = Math.Min(100, Math.Max(0, (int)(progress.BlocksDone * 100L / progress.BlocksTotal))); + + string stageText = progress.Stage switch + { + "Copying land" => _localizationGetter?.Invoke("Forms.MapReplaceForm.PreviewMessages.CopyingLand") ?? "Copying land", + "Copying statics" => _localizationGetter?.Invoke("Forms.MapReplaceForm.PreviewMessages.CopyingStatics") ?? "Copying statics", + _ => progress.Stage + }; + labelStatus.Text = string.Format(CultureInfo.InvariantCulture, "{0}: {1:N0} of {2:N0} blocks", - progress.Stage, progress.BlocksDone, progress.BlocksTotal); + stageText, progress.BlocksDone, progress.BlocksTotal); } private void OnWorkerDoWork(object sender, DoWorkEventArgs e) @@ -894,24 +951,28 @@ private void OnWorkerCompleted(object sender, RunWorkerCompletedEventArgs e) if (e.Error is OperationCanceledException) { progressBar1.Value = 0; - labelStatus.Text = "Cancelled. Nothing was written."; - + string cancelledMsg = _localizationGetter?.Invoke("Forms.MapReplaceForm.PreviewMessages.Cancelled") + ?? "Cancelled. Nothing was written."; + labelStatus.Text = cancelledMsg; return; } if (e.Error != null) { progressBar1.Value = 0; - labelStatus.Text = "Failed."; + string failedMsg = _localizationGetter?.Invoke("Forms.MapReplaceForm.PreviewMessages.Failed") + ?? "Failed."; + labelStatus.Text = failedMsg; ShowError("Map and Statics Copy", e.Error); - return; } var result = (MapRegionCopyResult)e.Result; progressBar1.Value = 100; - labelStatus.Text = "Done."; + string doneMsg = _localizationGetter?.Invoke("Forms.MapReplaceForm.PreviewMessages.Done") + ?? "Done."; + labelStatus.Text = doneMsg; using (var form = new MapRegionCopyResultForm(result)) { @@ -994,7 +1055,9 @@ private void SetRunning(bool running) private void Fail(string message) { - MessageBox.Show(this, message, "Map and Statics Copy", MessageBoxButtons.OK, MessageBoxIcon.Error); + string title = _localizationGetter?.Invoke("Forms.MapReplaceForm.WindowTitle") + ?? "Map and Statics Copy"; + MessageBox.Show(this, message, title, MessageBoxButtons.OK, MessageBoxIcon.Error); } protected override void OnFormClosing(FormClosingEventArgs e) diff --git a/UoFiddler/Localization/Dictionaries/zh-CN.json b/UoFiddler/Localization/Dictionaries/zh-CN.json index f9205277..018b46be 100644 --- a/UoFiddler/Localization/Dictionaries/zh-CN.json +++ b/UoFiddler/Localization/Dictionaries/zh-CN.json @@ -1360,6 +1360,7 @@ "ButtonCopy": "复制", "ButtonCancel": "取消", "ButtonClose": "关闭", + "WindowTitle": "地图和静态物品复制", "ComboBoxFormats": { "SameFormatUOP": "与此客户端相同格式 (.uop)", "SameFormatMUL": "与此客户端相同格式 (.mul)", @@ -1368,7 +1369,42 @@ }, "PreviewMessages": { "ChooseFolderAndMap": "选择文件夹和地图。", - "ChooseFolderToCopyFrom": "选择要复制的文件夹" + "ChooseFolderToCopyFrom": "选择要复制的文件夹", + "SourceFormat": "从 {0},{1} - {2},{3} {4} x {5} 块", + "DestinationFormat": "到 {0},{1} - {2},{3}", + "WidenedFormat": "{0},{1} - {2},{3} 已扩展为整个块", + "SizeNotRecognised": "无法识别大小", + "FolderHolds": "文件夹包含 {0}", + "SizeCheckFailed": "无法确定该文件夹中地图 {0} 的大小。", + "SizeCheckMismatch": "该文件夹包含地图 {0} 的 {1},但选择了 {2}。选择匹配项或将读取错误的块。", + "PickMatchingEntry": "选择匹配的条目,或将读取错误的块", + "ChooseFolderForCopy": "选择包含要复制的地图文件的文件夹。", + "NothingSelected": "没有选择要复制的内容。", + "Copying": "复制中...", + "CopyingLand": "复制地形", + "CopyingStatics": "复制静态物品", + "Cancelled": "已取消。未写入任何内容。", + "Failed": "失败。", + "Done": "完成。", + "SelectFolderDialog": "选择包含要复制的地图文件的文件夹", + "SizeCouldNotBeDetermined": "无法确定该文件夹中地图 {0} 的大小。{1}{1}{2}", + "SizeMismatchError": "该文件夹包含地图 {0} 的 {1},但选择了 {2}。{3}{3}{4}{3}{3}选择匹配的条目,或将读取错误的块。", + "RegionZ": "区域 z 高度 {0},静态物品 {1}", + "RegionZAdjusted": " -> 高度 {0},静态物品 {1}", + "RegionZOutOfRange": " - {0:N0} 超过限制,{1}", + "HeldThere": "保留在此处", + "Refused": "拒绝", + "StaticsNone": "无", + "ReadingHeights": "读取此区域的高度..." + } + } + }, + "Ultima": { + "Maps": { + "MapSizes": { + "NoMapOrStaticsIndex": "无法找到地号 {0} 的地图或静态物品索引;假设 {1}", + "HoldsBlocks": "{0} 包含 {1:N0} 块,即 {2}", + "HoldsBlocksNoMatch": "{0} 包含 {1:N0} 块,与地号 {2} 的已知形状均不匹配;假设 {3}" } } } diff --git a/UoFiddler/Program.cs b/UoFiddler/Program.cs index 0abe1004..35a4cb34 100644 --- a/UoFiddler/Program.cs +++ b/UoFiddler/Program.cs @@ -46,6 +46,9 @@ private static void Main() // 初始化本地化服务 LocalizationService.Initialize(Path.Combine(AppContext.BaseDirectory, "Localization", "Dictionaries")); LocalizationService.SetLanguage("zh-CN"); + + // 为 MapSizes 设置汉化 getter + Ultima.Maps.MapSizesLocalization.LocalizationGetter = LocalizationService.GetString; var services = new ServiceCollection(); services.AddLogging(b => b.AddSerilog(serilogLogger, dispose: true)); From 3f3c754f44d3263db9929037687570f58e4c1602 Mon Sep 17 00:00:00 2001 From: nbyaya Date: Wed, 7 Oct 2026 15:37:07 +0800 Subject: [PATCH 64/76] =?UTF-8?q?=E6=B1=89=E5=8C=96=20MapDefragStaticsForm?= =?UTF-8?q?=20=E6=95=B4=E7=90=86=E9=9D=99=E6=80=81=E7=89=A9=E4=BD=93?= =?UTF-8?q?=E7=AA=97=E5=8F=A3?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit - ComboBox 选项汉化:Drop→丢弃, Mask to 0-7→掩码到 0-7, Keep→保留 - 状态消息汉化:分析中/整理中/已分析/已取消/失败/完成 - 标签宽度调整:Location 240, Size 56 - 提示框标题使用窗口标题(中文) --- .../Forms/MapDefragStaticsForm.Designer.cs | 4 +- .../Forms/MapDefragStaticsForm.cs | 43 ++++++++++++++++--- .../Localization/Dictionaries/zh-CN.json | 42 ++++++++++++------ 3 files changed, 68 insertions(+), 21 deletions(-) diff --git a/UoFiddler.Controls/Forms/MapDefragStaticsForm.Designer.cs b/UoFiddler.Controls/Forms/MapDefragStaticsForm.Designer.cs index dc1b8b0b..55de86a5 100644 --- a/UoFiddler.Controls/Forms/MapDefragStaticsForm.Designer.cs +++ b/UoFiddler.Controls/Forms/MapDefragStaticsForm.Designer.cs @@ -159,9 +159,9 @@ private void InitializeComponent() // // labelCeiling // - this.labelCeiling.Location = new System.Drawing.Point(244, 25); + this.labelCeiling.Location = new System.Drawing.Point(240, 25); this.labelCeiling.Name = "labelCeiling"; - this.labelCeiling.Size = new System.Drawing.Size(50, 17); + this.labelCeiling.Size = new System.Drawing.Size(56, 17); this.labelCeiling.TabIndex = 1; this.labelCeiling.Text = "ceiling:"; // diff --git a/UoFiddler.Controls/Forms/MapDefragStaticsForm.cs b/UoFiddler.Controls/Forms/MapDefragStaticsForm.cs index f80983d5..5e254045 100644 --- a/UoFiddler.Controls/Forms/MapDefragStaticsForm.cs +++ b/UoFiddler.Controls/Forms/MapDefragStaticsForm.cs @@ -33,6 +33,9 @@ public sealed partial class MapDefragStaticsForm : Form private readonly Map _map; private Func? _localizationGetter; + + private string[] _idCeilingOptions; + private string[] _outOfBlockOptions; private CancellationTokenSource _cancellation; private bool _lastRunUsedFilters; @@ -46,10 +49,14 @@ public MapDefragStaticsForm(Map map, string outputPath) _map = map ?? throw new ArgumentNullException(nameof(map)); - comboBoxIdCeiling.Items.AddRange(new object[] { "tiledata", "art", "legacy 0x3FFF" }); + // 保存原始英文值用于业务逻辑 + _idCeilingOptions = new[] { "tiledata", "art", "legacy 0x3FFF" }; + _outOfBlockOptions = new[] { "Drop", "Mask to 0-7", "Keep" }; + + comboBoxIdCeiling.Items.AddRange(_idCeilingOptions); comboBoxIdCeiling.SelectedIndex = 0; - comboBoxOutOfBlock.Items.AddRange(new object[] { "Drop", "Mask to 0-7", "Keep" }); + comboBoxOutOfBlock.Items.AddRange(_outOfBlockOptions); comboBoxOutOfBlock.SelectedIndex = 0; checkBoxDropInvalidIds.Checked = true; @@ -103,6 +110,30 @@ private void ApplyLocalization() buttonCancel.Text = _localizationGetter("Forms.MapDefragStaticsForm.CancelButton") ?? "Cancel"; buttonClose.Text = _localizationGetter("Forms.MapDefragStaticsForm.CloseButton") ?? "Close"; + // 汉化下拉菜单项 - 保存选中的原始值 + string selectedIdCeilingValue = comboBoxIdCeiling.SelectedIndex >= 0 ? _idCeilingOptions[comboBoxIdCeiling.SelectedIndex] : _idCeilingOptions[0]; + string selectedOutOfBlockValue = comboBoxOutOfBlock.SelectedIndex >= 0 ? _outOfBlockOptions[comboBoxOutOfBlock.SelectedIndex] : _outOfBlockOptions[0]; + + comboBoxIdCeiling.Items.Clear(); + foreach (string option in _idCeilingOptions) + { + string displayText = _localizationGetter($"Forms.MapDefragStaticsForm.IdCeilingOptions.{option}") ?? option; + comboBoxIdCeiling.Items.Add(displayText); + } + // 恢复选中项(通过原始值查找索引) + int idCeilingIndex = System.Array.IndexOf(_idCeilingOptions, selectedIdCeilingValue); + comboBoxIdCeiling.SelectedIndex = Math.Max(0, idCeilingIndex); + + comboBoxOutOfBlock.Items.Clear(); + foreach (string option in _outOfBlockOptions) + { + string displayText = _localizationGetter($"Forms.MapDefragStaticsForm.OutOfBlockOptions.{option}") ?? option; + comboBoxOutOfBlock.Items.Add(displayText); + } + // 恢复选中项(通过原始值查找索引) + int outOfBlockIndex = System.Array.IndexOf(_outOfBlockOptions, selectedOutOfBlockValue); + comboBoxOutOfBlock.SelectedIndex = Math.Max(0, outOfBlockIndex); + // 重新生成源描述(包含动态消息) DescribeSource(); } @@ -349,7 +380,7 @@ private void Start(bool dryRun) } catch (Exception ex) { - MessageBox.Show(this, ex.Message, "Defrag Statics", MessageBoxButtons.OK, MessageBoxIcon.Error); + MessageBox.Show(this, ex.Message, this.Text, MessageBoxButtons.OK, MessageBoxIcon.Error); return; } @@ -364,7 +395,9 @@ private void Start(bool dryRun) progressBar.Style = ProgressBarStyle.Continuous; progressBar.Value = 0; - labelStatus.Text = dryRun ? "Analyzing..." : "Defragging..."; + string analyzingMsg = _localizationGetter?.Invoke("Forms.MapDefragStaticsForm.StatusAnalyzing") ?? "Analyzing..."; + string defraggingMsg = _localizationGetter?.Invoke("Forms.MapDefragStaticsForm.StatusDefragging") ?? "Defragging..."; + labelStatus.Text = dryRun ? analyzingMsg : defraggingMsg; worker.RunWorkerAsync(options); } @@ -423,7 +456,7 @@ private void OnWorkerCompleted(object sender, RunWorkerCompletedEventArgs e) labelStatus.Text = "Failed."; progressBar.Value = 0; - MessageBox.Show(this, e.Error.Message, "Defrag Statics", MessageBoxButtons.OK, MessageBoxIcon.Error); + MessageBox.Show(this, e.Error.Message, this.Text, MessageBoxButtons.OK, MessageBoxIcon.Error); return; } diff --git a/UoFiddler/Localization/Dictionaries/zh-CN.json b/UoFiddler/Localization/Dictionaries/zh-CN.json index 018b46be..74584c52 100644 --- a/UoFiddler/Localization/Dictionaries/zh-CN.json +++ b/UoFiddler/Localization/Dictionaries/zh-CN.json @@ -1171,7 +1171,7 @@ "SendClientToCenter": "发送客户端到中心", "PreloadMap": "预加载地图", "Misc": "杂项", - "DefragStatics": "碎片整理静态物体...", + "DefragStatics": "整理静态物体...", "FreezeStatics": "冻结静态物体..(在内存中)", "MeltStatics": "融化静态物体..(在内存中)", "ClearStatics": "清除静态物体..(在内存中)", @@ -1195,13 +1195,13 @@ "SaveButton": "保存" }, "MapMeltStaticsForm": { - "Title": "融化静态物品", + "Title": "融化静态物体", "X1Label": "X1", "Y1Label": "Y1", "X2Label": "X2", "Y2Label": "Y2", "MeltButton": "融化", - "DoneTitle": "融化静态物品", + "DoneTitle": "融化静态物体", "DoneMessage": "完成" }, "MapReplaceTilesForm": { @@ -1210,35 +1210,35 @@ "ReplaceButton": "替换" }, "MapClearStaticsForm": { - "Title": "清除静态物品", + "Title": "清除静态物体", "X1Label": "X1", "Y1Label": "Y1", "X2Label": "X2", "Y2Label": "Y2", "ClearButton": "清除", - "DoneTitle": "清除静态物品", + "DoneTitle": "清除静态物体", "DoneMessage": "完成" }, "MapDefragStaticsForm": { - "Title": "整理静态物品", + "Title": "整理静态物体", "Source": "来源", "AllowTruncation": "丢弃配置的地图大小之外的块", "Filters": "过滤器", - "DropInvalidIds": "丢弃未知物品 id 的静态物品", + "DropInvalidIds": "丢弃未知物品 id 的静态物体", "Ceiling": "天花板:", "OutOfBlock": "超出块 x/y 偏移:", - "DropInvalidZ": "丢弃 z = -128 的静态物品", + "DropInvalidZ": "丢弃 z = -128 的静态物体", "NormalizeHue": "将负色调标准化为 0", - "BelowTerrain": "丢弃埋在地形瓦下的静态物品(从不绘制)", + "BelowTerrain": "丢弃埋在地形瓦下的静态物体(从不绘制)", "RemoveDuplicates": "移除重复项(相同 id、x、y 和 z)", "DuplicatesHue": "也比较色调(旧版)", - "CollapseStacks": "将共享单元格的堆叠静态物品折叠为一个", + "CollapseStacks": "将共享单元格的堆叠静态物体折叠为一个", "CollapseFlags": "标志:", "CollapseWet": "湿润", "CollapseSurface": "表面", "CollapseIgnoreZ": "忽略 z", "CollapseIds": "物品 id:", - "SortTiles": "对每个块中的静态物品进行排序", + "SortTiles": "对每个块中的静态物体进行排序", "Output": "输出文件夹", "BrowseButton": "浏览...", "AnalyzeButton": "分析", @@ -1249,19 +1249,33 @@ "StatusAnalyzing": "分析中...", "StatusDefragging": "整理中...", "StatusCompleted": "完成", + "IdCeilingOptions": { + "tiledata": "TileData", + "art": "Art", + "legacy 0x3FFF": "Legacy 0x3FFF" + }, + "OutOfBlockOptions": { + "Drop": "丢弃", + "Mask to 0-7": "掩码到 0-7", + "Keep": "保留" + }, "Messages": { "Facet": "位面", "MapSize": "地图大小", "Blocks": "块", "FilesNotFound": "staidx{0}.mul 或 statics{0}.mul 在加载的客户端中未找到。", "OverridePresent": "staidx{0}x.mul 存在 - 客户端更倾向使用这些覆盖文件而不是这个对。", - "SurplusBlocks": "staidx 包含 {0:N0} 块但配置的地图大小仅覆盖 {1:N0} 块。多余块中的静态物品将被丢弃。", + "SurplusBlocks": "staidx 包含 {0:N0} 块但配置的地图大小仅覆盖 {1:N0} 块。多余块中的静态物体将被丢弃。", "EmptyBlocks": "staidx 包含 {0:N0} 块,配置的地图大小覆盖 {1:N0} 块。索引末尾之后的块将被写入为空。", - "MatchingBlocks": "staidx 包含 {0:N0} 块,与配置的地图大小匹配。" + "MatchingBlocks": "staidx 包含 {0:N0} 块,与配置的地图大小匹配。", + "Cancelled": "已取消。未写入任何内容。", + "Failed": "失败。", + "Analyzed": "已分析。未写入任何内容。", + "Done": "完成。{0:N0} 个静态物体已写入。" } }, "MapDefragStaticsResultForm": { - "Title": "整理静态物品 - 结果", + "Title": "整理静态物体 - 结果", "VerifyButton": "验证输出", "SaveButton": "保存报告...", "CopyButton": "复制", From 8475922f59a8f6b260c53f89cc60f769079c4ad2 Mon Sep 17 00:00:00 2001 From: nbyaya Date: Wed, 7 Oct 2026 15:47:14 +0800 Subject: [PATCH 65/76] =?UTF-8?q?=E4=B8=BA=E5=9C=B0=E5=9B=BE=E6=8A=A5?= =?UTF-8?q?=E5=91=8A=E5=AF=B9=E8=AF=9D=E6=A1=86=E6=B7=BB=E5=8A=A0=E6=B1=89?= =?UTF-8?q?=E5=8C=96=E6=94=AF=E6=8C=81?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit - OnClickReportInvisStatics:报告地图下方静态物体 → 文件保存对话框汉化 - OnClickReportInvalidMapIDs:报告无效地图ID → 文件保存对话框汉化 --- UoFiddler.Controls/UserControls/MapControl.cs | 12 ++++++++++-- UoFiddler/Localization/Dictionaries/zh-CN.json | 2 +- 2 files changed, 11 insertions(+), 3 deletions(-) diff --git a/UoFiddler.Controls/UserControls/MapControl.cs b/UoFiddler.Controls/UserControls/MapControl.cs index 71d65554..8b964a02 100644 --- a/UoFiddler.Controls/UserControls/MapControl.cs +++ b/UoFiddler.Controls/UserControls/MapControl.cs @@ -1462,7 +1462,11 @@ private void OnClickReportInvisStatics(object sender, EventArgs e) { CurrentMap.ReportInvisibleStatics(Options.OutputPath); } - FileSavedDialog.Show(FindForm(), Options.OutputPath, "Report saved successfully."); + var getter = GetLocalizationGetter(); + if (getter != null) + FileSavedDialog.Show(FindForm(), Options.OutputPath, "Report saved successfully.", null, getter); + else + FileSavedDialog.Show(FindForm(), Options.OutputPath, "Report saved successfully."); } private void OnClickReportInvalidMapIDs(object sender, EventArgs e) @@ -1471,7 +1475,11 @@ private void OnClickReportInvalidMapIDs(object sender, EventArgs e) { CurrentMap.ReportInvalidMapIDs(Options.OutputPath); } - FileSavedDialog.Show(FindForm(), Options.OutputPath, "Report saved successfully."); + var getter = GetLocalizationGetter(); + if (getter != null) + FileSavedDialog.Show(FindForm(), Options.OutputPath, "Report saved successfully.", null, getter); + else + FileSavedDialog.Show(FindForm(), Options.OutputPath, "Report saved successfully."); } private MapReplaceForm _showForm; diff --git a/UoFiddler/Localization/Dictionaries/zh-CN.json b/UoFiddler/Localization/Dictionaries/zh-CN.json index 74584c52..b986dac6 100644 --- a/UoFiddler/Localization/Dictionaries/zh-CN.json +++ b/UoFiddler/Localization/Dictionaries/zh-CN.json @@ -1288,7 +1288,7 @@ "Coordinate": "X", "LandTile": "陆地图块", "Altitude": "高度", - "Statics": "静态物品", + "Statics": "静态物体", "Hue": "色调" } }, From 28e3dab40ece3137d184ceee4abc2162941bf204 Mon Sep 17 00:00:00 2001 From: nbyaya Date: Wed, 7 Oct 2026 15:51:28 +0800 Subject: [PATCH 66/76] =?UTF-8?q?=E5=9C=B0=E5=9B=BE=E9=87=8D=E5=86=99?= =?UTF-8?q?=E5=8A=9F=E8=83=BD=E6=B7=BB=E5=8A=A0=E6=B1=89=E5=8C=96=E6=94=AF?= =?UTF-8?q?=E6=8C=81?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit - OnClickRewriteMap:文件保存对话框汉化 --- UoFiddler.Controls/UserControls/MapControl.cs | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/UoFiddler.Controls/UserControls/MapControl.cs b/UoFiddler.Controls/UserControls/MapControl.cs index 8b964a02..94d57edb 100644 --- a/UoFiddler.Controls/UserControls/MapControl.cs +++ b/UoFiddler.Controls/UserControls/MapControl.cs @@ -1453,7 +1453,11 @@ private void OnClickRewriteMap(object sender, EventArgs e) Map.RewriteMap(Options.OutputPath, _currentMapId, CurrentMap.Width, CurrentMap.Height); } - FileSavedDialog.Show(FindForm(), Options.OutputPath, "Files saved successfully."); + var getter = GetLocalizationGetter(); + if (getter != null) + FileSavedDialog.Show(FindForm(), Options.OutputPath, "File saved successfully.", null, getter); + else + FileSavedDialog.Show(FindForm(), Options.OutputPath, "File saved successfully."); } private void OnClickReportInvisStatics(object sender, EventArgs e) From 40db7fa245ba9840491466354497aa9bb71d5380 Mon Sep 17 00:00:00 2001 From: nbyaya Date: Wed, 7 Oct 2026 16:06:53 +0800 Subject: [PATCH 67/76] =?UTF-8?q?=E6=B1=89=E5=8C=96=20MapControl=20?= =?UTF-8?q?=E9=AB=98=E5=BA=A6=E6=A8=A1=E5=BC=8F=E8=8F=9C=E5=8D=95=E9=A1=B9?= =?UTF-8?q?=EF=BC=88Sharp/Normal/Soft=E3=80=81Subtle/Normal/Strong=20Inten?= =?UTF-8?q?sity=EF=BC=89?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- UoFiddler.Controls/UserControls/MapControl.cs | 57 +++++++++++++++++- .../Localization/Dictionaries/zh-CN.json | 59 +++++++++++++++++++ 2 files changed, 115 insertions(+), 1 deletion(-) diff --git a/UoFiddler.Controls/UserControls/MapControl.cs b/UoFiddler.Controls/UserControls/MapControl.cs index 94d57edb..8ca318f0 100644 --- a/UoFiddler.Controls/UserControls/MapControl.cs +++ b/UoFiddler.Controls/UserControls/MapControl.cs @@ -148,6 +148,9 @@ private void ApplyLocalization() CoordsLabel.Text = $"{_coordsPrefix}0,0"; ClientLocLabel.Text = $"{_clientLocPrefix}0,0"; ZoomLabel.Text = $"{_zoomPrefix}1"; + + // 高度模式菜单项汉化(动态生成的菜单项) + ApplyAltitudeMenuLocalization(); } private void AddAltitudeIntensityMenuItems() @@ -183,7 +186,59 @@ private void AddAltitudeIntensityMenuItems() altitudeModeNormalWithAltitudeToolStripMenuItem.DropDownItems.Add(subtleItem); altitudeModeNormalWithAltitudeToolStripMenuItem.DropDownItems.Add(normalItem); altitudeModeNormalWithAltitudeToolStripMenuItem.DropDownItems.Add(strongItem); - } + } + + /// + /// Apply localization to altitude mode menu items + /// 处理动态菜单中的下拉项汉化(在 ApplyLocalization() 中调用) + /// + private void ApplyAltitudeMenuLocalization() + { + if (_localizationGetter == null || altitudeModeNormalWithAltitudeToolStripMenuItem.DropDownItems.Count == 0) + return; + + // 遍历菜单项并应用汉化 + foreach (var item in altitudeModeNormalWithAltitudeToolStripMenuItem.DropDownItems) + { + if (!(item is ToolStripMenuItem menuItem)) + continue; + + string originalText = menuItem.Text.Trim(); + + // 预设选项 + if (originalText == "Sharp (High Contrast)") + { + menuItem.Text = _localizationGetter("Forms.MapControl.AltitudePreset.Sharp") + ?? "Sharp (High Contrast)"; + } + else if (originalText == "Normal (More Contrast)") + { + menuItem.Text = _localizationGetter("Forms.MapControl.AltitudePreset.Normal") + ?? "Normal (More Contrast)"; + } + else if (originalText == "Soft (Subtle)") + { + menuItem.Text = _localizationGetter("Forms.MapControl.AltitudePreset.Soft") + ?? "Soft (Subtle)"; + } + // 强度选项(保留项目符号) + else if (originalText.Contains("Subtle Intensity")) + { + menuItem.Text = " • " + (_localizationGetter("Forms.MapControl.AltitudeIntensity.Subtle") + ?? "Subtle Intensity"); + } + else if (originalText.Contains("Normal Intensity")) + { + menuItem.Text = " • " + (_localizationGetter("Forms.MapControl.AltitudeIntensity.Normal") + ?? "Normal Intensity"); + } + else if (originalText.Contains("Strong Intensity")) + { + menuItem.Text = " • " + (_localizationGetter("Forms.MapControl.AltitudeIntensity.Strong") + ?? "Strong Intensity"); + } + } + } private static MapControl _refMarker; public static double Zoom = 1; diff --git a/UoFiddler/Localization/Dictionaries/zh-CN.json b/UoFiddler/Localization/Dictionaries/zh-CN.json index b986dac6..1effa06f 100644 --- a/UoFiddler/Localization/Dictionaries/zh-CN.json +++ b/UoFiddler/Localization/Dictionaries/zh-CN.json @@ -1411,6 +1411,65 @@ "StaticsNone": "无", "ReadingHeights": "读取此区域的高度..." } + }, + "MapControl": { + "ZoomPlus": "+缩放", + "ZoomMinus": "-缩放", + "GetMapInfo": "获取地图信息", + "InsertMarker": "插入标记", + "Goto": "转到...", + "SendClientToPos": "发送客户端到位置", + "Felucca": "Felucca", + "Trammel": "Trammel", + "Ilshenar": "Ilshenar", + "Malas": "Malas", + "Tokuno": "Tokuno", + "TerMur": "TerMur", + "ExtractMap": "导出地图..", + "AsBmp": "导出为 BMP", + "AsTiff": "导出为 TIFF", + "AsJpg": "导出为 JPG", + "AsPng": "导出为 PNG", + "GotoMarker": "转到", + "RemoveMarker": "移除", + "SwitchVisibility": "切换可见性", + "View": "视图", + "ShowStatics": "显示静态物体", + "ShowCenterCross": "显示中心十字", + "ShowMarkers": "显示标记", + "ShowClientCross": "显示客户端十字", + "AltitudeModeNormal": "普通", + "AltitudeModeNormalWithAltitude": "普通 + 高度", + "AltitudeModeAltitude": "高度地图", + "ClientInteract": "客户端交互", + "ShowClientLoc": "显示客户端位置", + "GotoClientLoc": "转到客户端位置", + "SendClientToCenter": "发送客户端到中心", + "PreloadMap": "预加载地图", + "Misc": "其他", + "DefragStatics": "整理静态物体...", + "FreezeStatics": "冻结静态物体.. (在内存中)", + "MeltStatics": "融化静态物体.. (在内存中)", + "ClearStatics": "清除静态物体..(在内存中)", + "ReportStaticsUnderMap": "报告地图下方的静态物体(可能不可见)", + "ReportInvalidMapIDs": "报告无效的地图 ID", + "RewriteMap": "重写地图", + "MapAndStaticsCopy": "地图和静态物体复制...", + "DiffToMapCopy": "差异到地图复制...", + "ReplaceTiles": "替换图块..", + "CoordsLabel": "坐标: ", + "ClientLocLabel": "客户端位置: ", + "ZoomLabel": "缩放: ", + "AltitudePreset": { + "Sharp": "高对比度", + "Normal": "更多对比度", + "Soft": "柔和" + }, + "AltitudeIntensity": { + "Subtle": "微妙强度", + "Normal": "正常强度", + "Strong": "强烈强度" + } } }, "Ultima": { From 2f942eec3e5be8f4a4faf0a5af0970383d4c0bb7 Mon Sep 17 00:00:00 2001 From: nbyaya Date: Wed, 7 Oct 2026 18:18:17 +0800 Subject: [PATCH 68/76] =?UTF-8?q?=E6=B1=89=E5=8C=96=20LightControl=20?= =?UTF-8?q?=E7=AA=97=E5=8F=A3=E5=92=8C=E5=AF=B9=E8=AF=9D=E6=A1=86?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit - 添加菜单项、标签、对话框标题和按钮的中文翻译 - 支持 OpenFileDialog 和 FileSavedDialog 完整汉化 - 包含动态参数化标题处理 --- .../UserControls/LightControl.cs | 51 ++++++++++++++++--- UoFiddler/Forms/MainForm.cs | 1 + .../Localization/Dictionaries/zh-CN.json | 23 +++++++++ 3 files changed, 67 insertions(+), 8 deletions(-) diff --git a/UoFiddler.Controls/UserControls/LightControl.cs b/UoFiddler.Controls/UserControls/LightControl.cs index 3045f734..197a6acd 100644 --- a/UoFiddler.Controls/UserControls/LightControl.cs +++ b/UoFiddler.Controls/UserControls/LightControl.cs @@ -35,6 +35,7 @@ public LightControl() private bool _loaded; private int _landTile = 0x3; private int _lightTile = 0x0B20; + private Func? _localizationGetter; /// /// ReLoads if loaded @@ -239,9 +240,9 @@ private void OnClickReplace(object sender, EventArgs e) using (var dialog = new OpenFileDialog()) { dialog.Multiselect = false; - dialog.Title = "Choose image file to replace"; + dialog.Title = _localizationGetter?.Invoke("Forms.LightControl.Dialogs.ReplaceTitle") ?? "Choose image file to replace"; dialog.CheckFileExists = true; - dialog.Filter = "Image files (*.tif;*.tiff;*.bmp;*.png)|*.tif;*.tiff;*.bmp;*.png"; + dialog.Filter = _localizationGetter?.Invoke("Forms.LightControl.Dialogs.FileFilter") ?? "Image files (*.tif;*.tiff;*.bmp;*.png)|*.tif;*.tiff;*.bmp;*.png"; if (dialog.ShowDialog() != DialogResult.OK) { return; @@ -302,9 +303,10 @@ private void OnKeyDownInsert(object sender, KeyEventArgs e) using (var dialog = new OpenFileDialog()) { dialog.Multiselect = false; - dialog.Title = string.Format("Choose image file to insert at {0} (0x{0:X})", index); + string insertTitleFormat = _localizationGetter?.Invoke("Forms.LightControl.Dialogs.InsertTitle") ?? "Choose image file to insert at {0} (0x{0:X})"; + dialog.Title = string.Format(insertTitleFormat, index); dialog.CheckFileExists = true; - dialog.Filter = "Image files (*.tif;*.tiff;*.bmp;*.png)|*.tif;*.tiff;*.bmp;*.png"; + dialog.Filter = _localizationGetter?.Invoke("Forms.LightControl.Dialogs.FileFilter") ?? "Image files (*.tif;*.tiff;*.bmp;*.png)|*.tif;*.tiff;*.bmp;*.png"; if (dialog.ShowDialog() != DialogResult.OK) { return; @@ -342,7 +344,8 @@ private void OnClickSave(object sender, EventArgs e) { Light.Save(Options.OutputPath); Options.ChangedUltimaClass["Light"] = false; - FileSavedDialog.Show(FindForm(), Options.OutputPath, "Files saved successfully."); + string successMessage = _localizationGetter?.Invoke("Forms.LightControl.Messages.FilesSavedSuccessfully") ?? "Files saved successfully."; + FileSavedDialog.Show(FindForm(), Options.OutputPath, successMessage, null, key => _localizationGetter?.Invoke(key)); } private void OnClickExportBmp(object sender, EventArgs e) @@ -356,7 +359,8 @@ private void OnClickExportBmp(object sender, EventArgs e) string path = Options.OutputPath; string fileName = Path.Combine(path, $"Light {Utils.FormatExportId(i)}.bmp"); Light.GetLight(i).Save(fileName, ImageFormat.Bmp); - FileSavedDialog.Show(FindForm(), fileName, "Light saved successfully."); + string successMessage = _localizationGetter?.Invoke("Forms.LightControl.Messages.LightSavedSuccessfully") ?? "Light saved successfully."; + FileSavedDialog.Show(FindForm(), fileName, successMessage, null, key => _localizationGetter?.Invoke(key)); } private void OnClickExportTiff(object sender, EventArgs e) @@ -370,7 +374,8 @@ private void OnClickExportTiff(object sender, EventArgs e) string path = Options.OutputPath; string fileName = Path.Combine(path, $"Light {Utils.FormatExportId(i)}.tiff"); Ultima.Light.GetLight(i).Save(fileName, ImageFormat.Tiff); - FileSavedDialog.Show(FindForm(), fileName, "Light saved successfully."); + string successMessage = _localizationGetter?.Invoke("Forms.LightControl.Messages.LightSavedSuccessfully") ?? "Light saved successfully."; + FileSavedDialog.Show(FindForm(), fileName, successMessage, null, key => _localizationGetter?.Invoke(key)); } private void OnClickExportJpg(object sender, EventArgs e) @@ -384,7 +389,8 @@ private void OnClickExportJpg(object sender, EventArgs e) string path = Options.OutputPath; string fileName = Path.Combine(path, $"Light {Utils.FormatExportId(i)}.jpg"); Ultima.Light.GetLight(i).Save(fileName, ImageFormat.Jpeg); - FileSavedDialog.Show(FindForm(), fileName, "Light saved successfully."); + string successMessage = _localizationGetter?.Invoke("Forms.LightControl.Messages.LightSavedSuccessfully") ?? "Light saved successfully."; + FileSavedDialog.Show(FindForm(), fileName, successMessage, null, key => _localizationGetter?.Invoke(key)); } private void IgPreviewClicked(object sender, EventArgs e) @@ -472,5 +478,34 @@ private void LightTileKeyDown(object sender, KeyEventArgs e) pictureBoxPreview.Image = GetImage(); } + + public void SetLocalization(Func getLocalized) + { + _localizationGetter = getLocalized; + ApplyLocalization(); + } + + private void ApplyLocalization() + { + if (_localizationGetter == null) return; + + // 菜单项汉化 + exportImageToolStripMenuItem.Text = _localizationGetter("Forms.LightControl.ExportImage") ?? "Export Image.."; + asBmpToolStripMenuItem.Text = _localizationGetter("Forms.LightControl.AsBmp") ?? "As Bmp"; + asTiffToolStripMenuItem.Text = _localizationGetter("Forms.LightControl.AsTiff") ?? "As Tiff"; + asJpgToolStripMenuItem.Text = _localizationGetter("Forms.LightControl.AsJpg") ?? "As Jpg"; + removeToolStripMenuItem.Text = _localizationGetter("Forms.LightControl.Remove") ?? "Remove"; + replaceToolStripMenuItem.Text = _localizationGetter("Forms.LightControl.Replace") ?? "Replace"; + insertAtToolStripMenuItem.Text = _localizationGetter("Forms.LightControl.InsertAt") ?? "Insert At.."; + saveToolStripMenuItem.Text = _localizationGetter("Forms.LightControl.Save") ?? "Save"; + + // 预览菜单项汉化 + iGPreviewToolStripMenuItem.Text = _localizationGetter("Forms.LightControl.IGPreview") ?? "IG Preview"; + backgroundLandTileToolStripMenuItem.Text = _localizationGetter("Forms.LightControl.BackgroundLandTile") ?? "Background LandTile"; + lightTileToolStripMenuItem.Text = _localizationGetter("Forms.LightControl.LightTile") ?? "LightTile"; + + // 列表列标题汉化 + listViewLightsColumn.Text = _localizationGetter("Forms.LightControl.Light") ?? "Light"; + } } } diff --git a/UoFiddler/Forms/MainForm.cs b/UoFiddler/Forms/MainForm.cs index 5af60caa..4e3f9219 100644 --- a/UoFiddler/Forms/MainForm.cs +++ b/UoFiddler/Forms/MainForm.cs @@ -68,6 +68,7 @@ public MainForm(ILogger logger) fontsControl.SetLocalization(key => LocalizationService.GetString(key)); clilocControl.SetLocalization(key => LocalizationService.GetString(key)); mapControl.SetLocalization(key => LocalizationService.GetString(key)); + lightControl.SetLocalization(key => LocalizationService.GetString(key)); // 为 ItemsControl 设置汉化(通过遍历 TabPage 找到) foreach (TabPage tab in TabPanel.TabPages) diff --git a/UoFiddler/Localization/Dictionaries/zh-CN.json b/UoFiddler/Localization/Dictionaries/zh-CN.json index 1effa06f..2cb5c337 100644 --- a/UoFiddler/Localization/Dictionaries/zh-CN.json +++ b/UoFiddler/Localization/Dictionaries/zh-CN.json @@ -1470,6 +1470,29 @@ "Normal": "正常强度", "Strong": "强烈强度" } + }, + "LightControl": { + "Light": "光照", + "ExportImage": "导出图像..", + "AsBmp": "为 BMP", + "AsTiff": "为 TIFF", + "AsJpg": "为 JPG", + "Remove": "删除", + "Replace": "替换", + "InsertAt": "插入位置..", + "Save": "保存", + "IGPreview": "游戏内预览", + "BackgroundLandTile": "背景地形图块", + "LightTile": "光照图块", + "Dialogs": { + "ReplaceTitle": "选择要替换的图像文件", + "InsertTitle": "选择要插入位置 {0} (0x{0:X}) 的图像文件", + "FileFilter": "图像文件 (*.tif;*.tiff;*.bmp;*.png)|*.tif;*.tiff;*.bmp;*.png" + }, + "Messages": { + "LightSavedSuccessfully": "光照文件保存成功。", + "FilesSavedSuccessfully": "文件保存成功。" + } } }, "Ultima": { From 31387389b8e3eb79242f6119e73aa1ad644f0037 Mon Sep 17 00:00:00 2001 From: nbyaya Date: Wed, 7 Oct 2026 19:24:30 +0800 Subject: [PATCH 69/76] =?UTF-8?q?=E6=B1=89=E5=8C=96=20SpeechControl=20?= =?UTF-8?q?=E7=AA=97=E5=8F=A3=EF=BC=88=E8=AF=AD=E9=9F=B3=EF=BC=89=E6=A0=87?= =?UTF-8?q?=E7=AD=BE=E9=A1=B5=E7=9A=84=E6=B1=89=E5=8C=96?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit - 添加 20 个汉化词条到 zh-CN.json - 实现 SetLocalization/ApplyLocalization 模式 - 修复 DataGridView 列头汉化异常(类型 15 陷阱) - 测试通过 --- .../UserControls/SpeechControl.cs | 83 +++++++++++++++++-- UoFiddler/Forms/MainForm.cs | 1 + .../Localization/Dictionaries/zh-CN.json | 29 +++++++ 3 files changed, 107 insertions(+), 6 deletions(-) diff --git a/UoFiddler.Controls/UserControls/SpeechControl.cs b/UoFiddler.Controls/UserControls/SpeechControl.cs index f25b67bf..e986072b 100644 --- a/UoFiddler.Controls/UserControls/SpeechControl.cs +++ b/UoFiddler.Controls/UserControls/SpeechControl.cs @@ -29,6 +29,7 @@ public partial class SpeechControl : UserControl private SortOrder _sortOrder; private int _sortColumn; private bool _loaded; + private Func? _localizationGetter; public SpeechControl() { @@ -72,6 +73,8 @@ private void OnLoad(object sender, EventArgs e) if (dataGridView1.Columns.Count > 0) { dataGridView1.Columns[0].Width = 60; + // 应用列标题(初始时用英文或汉化值) + ApplyColumnHeaderLocalization(); } dataGridView1.Invalidate(); @@ -126,6 +129,12 @@ private void OnHeaderClick(object sender, DataGridViewCellMouseEventArgs e) private void OnCellValueChanged(object sender, DataGridViewCellEventArgs e) { + // 跳过列标题改变事件(e.RowIndex == -1) + if (e.RowIndex < 0 || e.RowIndex >= SpeechList.Entries.Count) + { + return; + } + SpeechList.Entries[e.RowIndex].KeyWord ??= string.Empty; Options.ChangedUltimaClass["Speech"] = true; @@ -148,7 +157,9 @@ private void FindId(int index) } } - MessageBox.Show("ID not found.", "Goto", MessageBoxButtons.OK, MessageBoxIcon.Error, MessageBoxDefaultButton.Button1); + string message = _localizationGetter?.Invoke("Forms.SpeechControl.Messages.IDNotFound") ?? "ID not found."; + string title = _localizationGetter?.Invoke("Forms.SpeechControl.Messages.IDNotFoundTitle") ?? "Goto"; + MessageBox.Show(message, title, MessageBoxButtons.OK, MessageBoxIcon.Error, MessageBoxDefaultButton.Button1); } private void FindKeyWord(int index) @@ -168,7 +179,9 @@ private void FindKeyWord(int index) return; } - MessageBox.Show("KeyWord not found.", "Entry", MessageBoxButtons.OK, MessageBoxIcon.Error, MessageBoxDefaultButton.Button1); + string message = _localizationGetter?.Invoke("Forms.SpeechControl.Messages.KeyWordNotFound") ?? "KeyWord not found."; + string title = _localizationGetter?.Invoke("Forms.SpeechControl.Messages.KeyWordNotFoundTitle") ?? "Entry"; + MessageBox.Show(message, title, MessageBoxButtons.OK, MessageBoxIcon.Error, MessageBoxDefaultButton.Button1); } private void OnClickFindID(object sender, EventArgs e) @@ -317,7 +330,8 @@ private void OnClickSave(object sender, EventArgs e) Options.ChangedUltimaClass["Speech"] = false; - FileSavedDialog.Show(FindForm(), fileName, "Speech saved successfully."); + string message = _localizationGetter?.Invoke("Forms.SpeechControl.Messages.SpeechSavedSuccessfully") ?? "Speech saved successfully."; + FileSavedDialog.Show(FindForm(), fileName, message, null, key => _localizationGetter?.Invoke(key)); } private void OnAddEntry(object sender, EventArgs e) @@ -352,7 +366,8 @@ private void OnClickExport(object sender, EventArgs e) SpeechList.ExportToCsv(fileName); - FileSavedDialog.Show(FindForm(), fileName, "Speech saved successfully."); + string message = _localizationGetter?.Invoke("Forms.SpeechControl.Messages.SpeechSavedSuccessfully") ?? "Speech saved successfully."; + FileSavedDialog.Show(FindForm(), fileName, message, null, key => _localizationGetter?.Invoke(key)); } private void OnClickImport(object sender, EventArgs e) @@ -360,9 +375,9 @@ private void OnClickImport(object sender, EventArgs e) OpenFileDialog dialog = new OpenFileDialog { Multiselect = false, - Title = "Choose csv file to import", + Title = _localizationGetter?.Invoke("Forms.SpeechControl.Dialogs.ImportTitle") ?? "Choose csv file to import", CheckFileExists = true, - Filter = "csv files (*.csv)|*.csv" + Filter = _localizationGetter?.Invoke("Forms.SpeechControl.Dialogs.CSVFilter") ?? "csv files (*.csv)|*.csv" }; if (dialog.ShowDialog() == DialogResult.OK) @@ -378,6 +393,62 @@ private void OnClickImport(object sender, EventArgs e) dialog.Dispose(); } + public void SetLocalization(Func getLocalized) + { + _localizationGetter = getLocalized; + ApplyLocalization(); + } + + /// + /// 应用列标题汉化(在数据绑定后调用,支持初始化和汉化两种场景) + /// + private void ApplyColumnHeaderLocalization() + { + // 设置表格列标题 + // 如果 _localizationGetter 为 null,会使用 ?? 后面的英文默认值 + if (dataGridView1.Columns.Count > 0) + { + dataGridView1.Columns[0].HeaderText = _localizationGetter?.Invoke("Forms.SpeechControl.ColumnId") ?? "Id"; + if (dataGridView1.Columns.Count > 1) + dataGridView1.Columns[1].HeaderText = _localizationGetter?.Invoke("Forms.SpeechControl.ColumnKeyWord") ?? "KeyWord"; + } + } + + private void ApplyLocalization() + { + if (_localizationGetter == null) return; + + // 占位符 + string idPlaceholder = _localizationGetter("Forms.SpeechControl.IDEntryPlaceholder") ?? _idEntryPlaceholder; + string keywordPlaceholder = _localizationGetter("Forms.SpeechControl.KeyWordEntryPlaceholder") ?? _keywordEntryPlaceholder; + + if (IDEntry.Text == _idEntryPlaceholder) + IDEntry.Text = idPlaceholder; + if (KeyWordEntry.Text == _keywordEntryPlaceholder) + KeyWordEntry.Text = keywordPlaceholder; + + // 工具栏按钮 + IDButton.Text = _localizationGetter("Forms.SpeechControl.IDButton") ?? "Find"; + IDNextButton.Text = _localizationGetter("Forms.SpeechControl.IDNextButton") ?? "Find Next"; + KeyWordButton.Text = _localizationGetter("Forms.SpeechControl.KeyWordButton") ?? "Find"; + KeyWordNextButton.Text = _localizationGetter("Forms.SpeechControl.KeyWordNextButton") ?? "Find Next"; + + // 保存按钮 + toolStripButton1.Text = _localizationGetter("Forms.SpeechControl.SaveButton") ?? "Save"; + + // 杂项菜单及其下拉项 + toolStripDropDownButton1.Text = _localizationGetter("Forms.SpeechControl.MiscMenu") ?? "Misc"; + toolStripMenuItem1.Text = _localizationGetter("Forms.SpeechControl.ImportFromCSV") ?? "Import from CSV"; + toolStripMenuItem2.Text = _localizationGetter("Forms.SpeechControl.ExportToCSV") ?? "Export to CSV"; + + // 右键菜单 + addEntryToolStripMenuItem.Text = _localizationGetter("Forms.SpeechControl.AddEntryMenu") ?? "Add Entry"; + deleteEntryToolStripMenuItem.Text = _localizationGetter("Forms.SpeechControl.DeleteEntryMenu") ?? "Delete Entry"; + + // 表格列标题 + ApplyColumnHeaderLocalization(); + } + private void IDEntry_Enter(object sender, EventArgs e) { if (IDEntry.Text == _idEntryPlaceholder) diff --git a/UoFiddler/Forms/MainForm.cs b/UoFiddler/Forms/MainForm.cs index 4e3f9219..795a63a9 100644 --- a/UoFiddler/Forms/MainForm.cs +++ b/UoFiddler/Forms/MainForm.cs @@ -69,6 +69,7 @@ public MainForm(ILogger logger) clilocControl.SetLocalization(key => LocalizationService.GetString(key)); mapControl.SetLocalization(key => LocalizationService.GetString(key)); lightControl.SetLocalization(key => LocalizationService.GetString(key)); + speechControl.SetLocalization(key => LocalizationService.GetString(key)); // 为 ItemsControl 设置汉化(通过遍历 TabPage 找到) foreach (TabPage tab in TabPanel.TabPages) diff --git a/UoFiddler/Localization/Dictionaries/zh-CN.json b/UoFiddler/Localization/Dictionaries/zh-CN.json index 2cb5c337..b6508a5f 100644 --- a/UoFiddler/Localization/Dictionaries/zh-CN.json +++ b/UoFiddler/Localization/Dictionaries/zh-CN.json @@ -1493,6 +1493,35 @@ "LightSavedSuccessfully": "光照文件保存成功。", "FilesSavedSuccessfully": "文件保存成功。" } + }, + "SpeechControl": { + "IDEntryPlaceholder": "查找 ID...", + "KeyWordEntryPlaceholder": "关键词...", + "IDButton": "查找", + "IDNextButton": "查找下一个", + "KeyWordButton": "查找", + "KeyWordNextButton": "查找下一个", + "SaveButton": "保存", + "MiscMenu": "杂项", + "ImportFromCSV": "从 CSV 导入", + "ExportToCSV": "导出到 CSV", + "AddButton": "添加条目", + "DeleteButton": "删除条目", + "AddEntryMenu": "添加条目", + "DeleteEntryMenu": "删除条目", + "ColumnId": "标识号", + "ColumnKeyWord": "关键词", + "Dialogs": { + "ImportTitle": "选择要导入的 CSV 文件", + "CSVFilter": "CSV 文件 (*.csv)|*.csv" + }, + "Messages": { + "IDNotFound": "找不到 ID。", + "IDNotFoundTitle": "跳转", + "KeyWordNotFound": "找不到关键词。", + "KeyWordNotFoundTitle": "条目", + "SpeechSavedSuccessfully": "语音文件保存成功。" + } } }, "Ultima": { From dd66422a4553f5a52e01babda7b12e3d294a76a6 Mon Sep 17 00:00:00 2001 From: nbyaya Date: Wed, 7 Oct 2026 19:39:38 +0800 Subject: [PATCH 70/76] =?UTF-8?q?=E6=B1=89=E5=8C=96=20SkillsControl=20?= =?UTF-8?q?=E7=AA=97=E5=8F=A3=EF=BC=88=E6=8A=80=E8=83=BD=EF=BC=89=E6=A0=87?= =?UTF-8?q?=E7=AD=BE=E9=A1=B5?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../UserControls/SkillsControl.cs | 46 ++++++++++++++++++- UoFiddler/Forms/MainForm.cs | 1 + .../Localization/Dictionaries/zh-CN.json | 10 ++++ 3 files changed, 56 insertions(+), 1 deletion(-) diff --git a/UoFiddler.Controls/UserControls/SkillsControl.cs b/UoFiddler.Controls/UserControls/SkillsControl.cs index 697803f4..096432ec 100644 --- a/UoFiddler.Controls/UserControls/SkillsControl.cs +++ b/UoFiddler.Controls/UserControls/SkillsControl.cs @@ -29,6 +29,7 @@ public SkillsControl() private bool _loaded; private static BindingSource _source; + private Func? _localizationGetter; /// /// ReLoads if loaded @@ -69,6 +70,9 @@ private void OnLoad(object sender, EventArgs e) dataGridView1.Columns[2].FillWeight = 54.86799F; dataGridView1.Columns[2].ReadOnly = false; dataGridView1.Columns[3].Visible = false; // extraFlag + + // 应用列头汉化 + ApplyColumnHeaderLocalization(); } if (!_loaded) @@ -98,7 +102,9 @@ private void OnClickSave(object sender, EventArgs e) Skills.Save(path); Options.ChangedUltimaClass["Skills"] = false; - FileSavedDialog.Show(FindForm(), Options.OutputPath, "Skills saved successfully."); + string message = _localizationGetter?.Invoke("Forms.SkillsControl.FileSavedMessage") ?? "Skills saved successfully."; + string title = _localizationGetter?.Invoke("Forms.SkillsControl.FileSavedTitle") ?? "Save"; + FileSavedDialog.Show(FindForm(), Options.OutputPath, message, title); } private void OnClickAdd(object sender, EventArgs e) @@ -128,5 +134,43 @@ private void OnClickDelete(object sender, EventArgs e) _source.RemoveCurrent(); dataGridView1.Invalidate(); } + + /// + /// 设置本地化(从 MainForm 调用) + /// + public void SetLocalization(Func getLocalized) + { + _localizationGetter = getLocalized; + ApplyLocalization(); + } + + /// + /// 应用列标题汉化(在数据绑定后调用) + /// + private void ApplyColumnHeaderLocalization() + { + // 设置表格列标题 + if (dataGridView1.Columns.Count > 0) + { + dataGridView1.Columns[0].HeaderText = _localizationGetter?.Invoke("Forms.SkillsControl.ColumnId") ?? "ID"; + if (dataGridView1.Columns.Count > 1) + dataGridView1.Columns[1].HeaderText = _localizationGetter?.Invoke("Forms.SkillsControl.ColumnIsAction") ?? "is Action"; + if (dataGridView1.Columns.Count > 2) + dataGridView1.Columns[2].HeaderText = _localizationGetter?.Invoke("Forms.SkillsControl.ColumnName") ?? "Name"; + } + } + + private void ApplyLocalization() + { + if (_localizationGetter == null) return; + + // 菜单项汉化 + saveToolStripMenuItem.Text = _localizationGetter("Forms.SkillsControl.SaveButton") ?? "Save"; + addToolStripMenuItem.Text = _localizationGetter("Forms.SkillsControl.AddButton") ?? "Add"; + deleteToolStripMenuItem.Text = _localizationGetter("Forms.SkillsControl.DeleteButton") ?? "Delete"; + + // 表格列标题 + ApplyColumnHeaderLocalization(); + } } } diff --git a/UoFiddler/Forms/MainForm.cs b/UoFiddler/Forms/MainForm.cs index 795a63a9..03e9ffa5 100644 --- a/UoFiddler/Forms/MainForm.cs +++ b/UoFiddler/Forms/MainForm.cs @@ -70,6 +70,7 @@ public MainForm(ILogger logger) mapControl.SetLocalization(key => LocalizationService.GetString(key)); lightControl.SetLocalization(key => LocalizationService.GetString(key)); speechControl.SetLocalization(key => LocalizationService.GetString(key)); + skillsControl.SetLocalization(key => LocalizationService.GetString(key)); // 为 ItemsControl 设置汉化(通过遍历 TabPage 找到) foreach (TabPage tab in TabPanel.TabPages) diff --git a/UoFiddler/Localization/Dictionaries/zh-CN.json b/UoFiddler/Localization/Dictionaries/zh-CN.json index b6508a5f..35c6b7fd 100644 --- a/UoFiddler/Localization/Dictionaries/zh-CN.json +++ b/UoFiddler/Localization/Dictionaries/zh-CN.json @@ -1522,6 +1522,16 @@ "KeyWordNotFoundTitle": "条目", "SpeechSavedSuccessfully": "语音文件保存成功。" } + }, + "SkillsControl": { + "SaveButton": "保存", + "AddButton": "添加", + "DeleteButton": "删除", + "ColumnId": "ID号", + "ColumnIsAction": "是否动作", + "ColumnName": "技能名称", + "FileSavedMessage": "技能已保存成功", + "FileSavedTitle": "保存" } }, "Ultima": { From 337904932dc2d8e47b2d2f6a3969f43a9aeb7f02 Mon Sep 17 00:00:00 2001 From: nbyaya Date: Wed, 7 Oct 2026 20:50:02 +0800 Subject: [PATCH 71/76] =?UTF-8?q?=E6=B1=89=E5=8C=96=20=E5=8A=A8=E7=94=BB?= =?UTF-8?q?=E6=95=B0=E6=8D=AE=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 - AnimDataControl:标签页(19 个元素)、状态栏(3 个标签) - HuePopUpForm:色调拾取器窗口及内部 HuesControl - AnimDataExportForm/ImportForm:导出导入窗口 - 相关消息框与菜单项汉化 编译验证:0 个错误 --- .../Forms/AnimDataExportForm.cs | 37 +++++++- .../Forms/AnimDataImportForm.cs | 42 ++++++++- UoFiddler.Controls/Forms/HuePopUpForm.cs | 20 +++++ .../UserControls/AnimDataControl.cs | 86 ++++++++++++++++-- .../UserControls/AnimationListControl.cs | 1 + UoFiddler/Forms/MainForm.cs | 11 ++- .../Localization/Dictionaries/zh-CN.json | 90 +++++++++++++++++++ 7 files changed, 274 insertions(+), 13 deletions(-) diff --git a/UoFiddler.Controls/Forms/AnimDataExportForm.cs b/UoFiddler.Controls/Forms/AnimDataExportForm.cs index 19eac838..6b610dc4 100644 --- a/UoFiddler.Controls/Forms/AnimDataExportForm.cs +++ b/UoFiddler.Controls/Forms/AnimDataExportForm.cs @@ -8,6 +8,8 @@ namespace UoFiddler.Controls.Forms { public partial class AnimDataExportForm : Form { + private Func? _localizationGetter; + public AnimDataExportForm() { InitializeComponent(); @@ -18,6 +20,30 @@ public AnimDataExportForm() }; } + public void SetLocalization(Func getLocalized) + { + _localizationGetter = getLocalized; + ApplyLocalization(); + } + + private void ApplyLocalization() + { + if (_localizationGetter == null) return; + + this.Text = _localizationGetter("Forms.AnimDataExportForm.Title") ?? "Export AnimData"; + lblAnimationsToExport.Text = _localizationGetter("Forms.AnimDataExportForm.lblAnimationsToExport") ?? "Animations to export:"; + btnExport.Text = _localizationGetter("Forms.AnimDataExportForm.btnExport") ?? "Export"; + + // 更新下拉菜单项 + var items = new List + { + _localizationGetter("Forms.AnimDataExportForm.ExportSelection.All") ?? "All (default-, blue-, and red-colored entries)", + _localizationGetter("Forms.AnimDataExportForm.ExportSelection.IncludeMissing") ?? "Include missing animation tile flag (default- and blue-colored entries)", + _localizationGetter("Forms.AnimDataExportForm.ExportSelection.OnlyValid") ?? "Only valid animations (default-colored entries)" + }; + cboExportSelection.DataSource = items; + } + private void OnClickExport(object sender, EventArgs e) { var type = "json"; @@ -48,11 +74,18 @@ private void OnClickExport(object sender, EventArgs e) var exported = ExportedAnimData.ToFile(dialog.FileName, AnimData, selection); - MessageBox.Show($"Exported {exported.Data.Count} animdata entries to: {dialog.FileName}"); + // 使用汉化的导出成功消息 + string successMessage = _localizationGetter?.Invoke("Forms.AnimDataExportForm.ExportSuccessMessage") ?? $"Exported {exported.Data.Count} animdata entries to: {dialog.FileName}"; + successMessage = string.Format(successMessage, exported.Data.Count, dialog.FileName); + MessageBox.Show(successMessage); } catch (Exception ex) { - MessageBox.Show($"Error exporting animdata: {ex.Message}", "AnimData Export", MessageBoxButtons.OK, MessageBoxIcon.Error, MessageBoxDefaultButton.Button1); + // 使用汉化的导出错误消息 + string errorTitle = _localizationGetter?.Invoke("Forms.AnimDataExportForm.ExportErrorTitle") ?? "AnimData Export"; + string errorMessage = _localizationGetter?.Invoke("Forms.AnimDataExportForm.ExportErrorMessage") ?? $"Error exporting animdata: {ex.Message}"; + errorMessage = string.Format(errorMessage, ex.Message); + MessageBox.Show(errorMessage, errorTitle, MessageBoxButtons.OK, MessageBoxIcon.Error, MessageBoxDefaultButton.Button1); } } } diff --git a/UoFiddler.Controls/Forms/AnimDataImportForm.cs b/UoFiddler.Controls/Forms/AnimDataImportForm.cs index 3081a939..fdd87786 100644 --- a/UoFiddler.Controls/Forms/AnimDataImportForm.cs +++ b/UoFiddler.Controls/Forms/AnimDataImportForm.cs @@ -9,6 +9,8 @@ namespace UoFiddler.Controls.Forms { public partial class AnimDataImportForm : Form { + private Func? _localizationGetter; + [DesignerSerializationVisibility(DesignerSerializationVisibility.Hidden)] public Action OnAfterImport { get; set; } @@ -18,13 +20,40 @@ public AnimDataImportForm() cboConflictAction.SelectedItem = "skip"; } + public void SetLocalization(Func getLocalized) + { + _localizationGetter = getLocalized; + ApplyLocalization(); + } + + private void ApplyLocalization() + { + if (_localizationGetter == null) return; + + this.Text = _localizationGetter("Forms.AnimDataImportForm.Title") ?? "Import AnimData"; + label5.Text = _localizationGetter("Forms.AnimDataImportForm.label5") ?? "Import from:"; + btnImport.Text = _localizationGetter("Forms.AnimDataImportForm.btnImport") ?? "Import"; + label1.Text = _localizationGetter("Forms.AnimDataImportForm.label1") ?? "On conflict:"; + cbErase.Text = _localizationGetter("Forms.AnimDataImportForm.cbErase") ?? "Erase animdata before importing"; + + // 更新下拉菜单项 + var skipText = _localizationGetter("Forms.AnimDataImportForm.ConflictAction.Skip") ?? "skip"; + var overwriteText = _localizationGetter("Forms.AnimDataImportForm.ConflictAction.Overwrite") ?? "overwrite"; + + cboConflictAction.Items.Clear(); + cboConflictAction.Items.Add(skipText); + cboConflictAction.Items.Add(overwriteText); + cboConflictAction.SelectedIndex = 0; + } + private void OnClickImport(object sender, EventArgs e) { try { var fileName = txtImportFileName.Text; var imported = ExportedAnimData.FromFile(fileName); - var overwrite = cboConflictAction.Items[cboConflictAction.SelectedIndex].ToString() == "overwrite"; + // SelectedIndex: 0 = skip, 1 = overwrite + var overwrite = cboConflictAction.SelectedIndex == 1; // Create a new "working copy" AnimData to update, in case there's an exception thrown while processing. // Shallow clone is okay, as UpdateAnimdata does not modify existing entries' members. @@ -44,11 +73,18 @@ private void OnClickImport(object sender, EventArgs e) // Swallow any error from the OnAfterImport callback } - MessageBox.Show($"Imported {importCount} animdata entries from: {fileName}\n\nDo not forget to save your changes!", "AnimData Import"); + MessageBox.Show( + _localizationGetter?.Invoke("Forms.AnimDataImportForm.ImportSuccessMessage") ?? + $"Imported {importCount} animdata entries from: {fileName}\n\nDo not forget to save your changes!", + _localizationGetter?.Invoke("Forms.AnimDataImportForm.ImportSuccessTitle") ?? "AnimData Import"); } catch (Exception ex) { - MessageBox.Show($"Error importing animdata: {ex.Message}", "AnimData Import", MessageBoxButtons.OK, MessageBoxIcon.Error, MessageBoxDefaultButton.Button1); + var errorTitle = _localizationGetter?.Invoke("Forms.AnimDataImportForm.ImportErrorTitle") ?? "AnimData Import"; + var errorMessageFormat = _localizationGetter?.Invoke("Forms.AnimDataImportForm.ImportErrorMessage") ?? "Error importing animdata: {0}"; + var errorMessage = string.Format(errorMessageFormat, ex.Message); + + MessageBox.Show(errorMessage, errorTitle, MessageBoxButtons.OK, MessageBoxIcon.Error, MessageBoxDefaultButton.Button1); } } diff --git a/UoFiddler.Controls/Forms/HuePopUpForm.cs b/UoFiddler.Controls/Forms/HuePopUpForm.cs index 323c04aa..132d56e4 100644 --- a/UoFiddler.Controls/Forms/HuePopUpForm.cs +++ b/UoFiddler.Controls/Forms/HuePopUpForm.cs @@ -18,6 +18,7 @@ namespace UoFiddler.Controls.Forms public partial class HuePopUpForm : Form { private readonly Action _changeHueAction; + private Func? _localizationGetter; public HuePopUpForm(Action changeHueAction, int hue) { @@ -41,6 +42,25 @@ public HuePopUpForm(Action changeHueAction, int hue) } } + public void SetLocalization(Func getLocalized) + { + _localizationGetter = getLocalized; + ApplyLocalization(); + } + + private void ApplyLocalization() + { + if (_localizationGetter == null) return; + + this.Text = _localizationGetter("Forms.HuePopUpForm.Title") ?? "Hue Picker"; + toolStripButton1.Text = _localizationGetter("Forms.HuePopUpForm.OkButton") ?? "OK"; + toolStripButton2.Text = _localizationGetter("Forms.HuePopUpForm.ClearButton") ?? "Clear"; + HueOnlyGray.Text = _localizationGetter("Forms.HuePopUpForm.HueOnlyGrayCheckBox") ?? "Hue Only Gray (+0x8000)"; + + // 为内部 HuesControl 调用汉化 + control.SetLocalization(_localizationGetter); + } + private void Click_OK(object sender, EventArgs e) { int selected = control.Selected; diff --git a/UoFiddler.Controls/UserControls/AnimDataControl.cs b/UoFiddler.Controls/UserControls/AnimDataControl.cs index 7e0ad8ce..956ee2dc 100644 --- a/UoFiddler.Controls/UserControls/AnimDataControl.cs +++ b/UoFiddler.Controls/UserControls/AnimDataControl.cs @@ -45,6 +45,10 @@ public AnimDataControl() private HuePopUpForm _showForm; private int _customHue = 0; private bool _hueOnlyGray = false; + private Func? _localizationGetter; + private string _baseGraphicLabelPrefix = "Base Graphic: "; + private string _graphicLabelPrefix = "Graphic: "; + private string _hueLabelPrefix = "Hue: "; [Browsable(false), DesignerSerializationVisibility(DesignerSerializationVisibility.Hidden)] private int CurrFrame @@ -56,7 +60,7 @@ private int CurrFrame { var newGraphic = _currentSelect + value; - toolStripStatusGraphic.Text = $"Graphic: {newGraphic} (0x{newGraphic:X})"; + toolStripStatusGraphic.Text = $"{_graphicLabelPrefix}{newGraphic} (0x{newGraphic:X})"; MainPictureBox.FrameIndex = value; _currentFrame = value; } @@ -88,8 +92,8 @@ private int CurrentSelect } treeViewFrames.EndUpdate(); - toolStripStatusBaseGraphic.Text = $"Base Graphic: {value} (0x{value:X})"; - toolStripStatusGraphic.Text = $"Graphic: {value} (0x{value:X})"; + toolStripStatusBaseGraphic.Text = $"{_baseGraphicLabelPrefix}{value} (0x{value:X})"; + toolStripStatusGraphic.Text = $"{_graphicLabelPrefix}{value} (0x{value:X})"; _currentSelect = value; @@ -104,7 +108,7 @@ private void MainPictureBox_FrameChanged(object sender, EventArgs e) { var newGraphic = _currentSelect + MainPictureBox.FrameIndex; - toolStripStatusGraphic.Text = $"Graphic: {newGraphic} (0x{newGraphic:X})"; + toolStripStatusGraphic.Text = $"{_graphicLabelPrefix}{newGraphic} (0x{newGraphic:X})"; } private void SetPicture() @@ -302,6 +306,7 @@ private void OnClickExport(object sender, EventArgs e) { TopMost = true }; + _exportForm.SetLocalization(_localizationGetter); _exportForm.Show(); } @@ -318,6 +323,7 @@ private void OnClickImport(object sender, EventArgs e) TopMost = true, OnAfterImport = Reload }; + _importForm.SetLocalization(_localizationGetter); _importForm.Show(); } @@ -577,7 +583,11 @@ private void OnClickSave(object sender, EventArgs e) Options.ChangedUltimaClass["Animdata"] = false; } - FileSavedDialog.Show(FindForm(), Options.OutputPath, "File saved successfully."); + // 获取汉化的保存成功消息 + string message = _localizationGetter?.Invoke("Forms.FileSavedDialog.SaveSuccess") ?? "File saved successfully."; + string title = _localizationGetter?.Invoke("Forms.FileSavedDialog.Title") ?? "Save Success"; + + FileSavedDialog.Show(FindForm(), Options.OutputPath, message, title, _localizationGetter ?? (k => null)); } private void OnClickRemoveAnim(object sender, EventArgs e) @@ -688,6 +698,7 @@ private void OnClick_Hue(object sender, EventArgs e) ? new HuePopUpForm(ChangeHue, 1) : new HuePopUpForm(ChangeHue, _customHue - 1); + _showForm.SetLocalization(key => _localizationGetter?.Invoke(key)); _showForm.TopMost = true; _showForm.Show(); } @@ -698,7 +709,12 @@ private void OnClick_ExportAsGif(object sender, EventArgs e) { var outputFile = Path.Combine(Options.OutputPath, $"AnimData {Utils.FormatExportId(_currentSelect)}.gif"); MainPictureBox.Frames.ToGif(outputFile, delay: 150, showFrameBounds: MainPictureBox.ShowFrameBounds); - MessageBox.Show($"Saved to {outputFile}"); + + var title = _localizationGetter?.Invoke("Forms.AnimDataControl.ExportGifDialog.Title") ?? "Saved"; + var message = _localizationGetter?.Invoke("Forms.AnimDataControl.ExportGifDialog.Message") ?? "Saved to {0}"; + message = string.Format(message, outputFile); + + MessageBox.Show(message, title); } } @@ -728,6 +744,64 @@ private void SearchByIdToolStripTextBox_KeyUp(object sender, KeyEventArgs e) } } + /// + /// 设置本地化(从 MainForm 调用) + /// + public void SetLocalization(Func getLocalized) + { + _localizationGetter = getLocalized; + ApplyLocalization(); + } + + /// + /// 应用汉化 + /// + private void ApplyLocalization() + { + if (_localizationGetter == null) return; + + // GroupBox 标题 + groupBox1.Text = _localizationGetter("Forms.AnimDataControl.PreviewGroupBox") ?? "Preview"; + groupBox2.Text = _localizationGetter("Forms.AnimDataControl.DataGroupBox") ?? "Data"; + groupBox4.Text = _localizationGetter("Forms.AnimDataControl.FramesGroupBox") ?? "Frames"; + + // Label + label1.Text = _localizationGetter("Forms.AnimDataControl.StartDelayLabel") ?? "Start Delay"; + label2.Text = _localizationGetter("Forms.AnimDataControl.FrameDelayLabel") ?? "Frame Delay"; + + // Button + button2.Text = _localizationGetter("Forms.AnimDataControl.AddButton") ?? "Add"; + button5.Text = _localizationGetter("Forms.AnimDataControl.RemoveButton") ?? "Remove"; + button6.Text = _localizationGetter("Forms.AnimDataControl.SaveButton") ?? "Save"; + button7.Text = _localizationGetter("Forms.AnimDataControl.ImportButton") ?? "Import..."; + button8.Text = _localizationGetter("Forms.AnimDataControl.ExportButton") ?? "Export..."; + + // ToolStripMenuItem + addToolStripMenuItem.Text = _localizationGetter("Forms.AnimDataControl.AddMenuItem") ?? "Add"; + removeToolStripMenuItem.Text = _localizationGetter("Forms.AnimDataControl.RemoveMenuItem") ?? "Remove"; + hueToolStripMenuItem.Text = _localizationGetter("Forms.AnimDataControl.HueMenuItem") ?? "Hue"; + animateToolStripMenuItem.Text = _localizationGetter("Forms.AnimDataControl.AnimateMenuItem") ?? "Animate"; + showFrameBoundsToolStripMenuItem.Text = _localizationGetter("Forms.AnimDataControl.ShowFrameBoundsMenuItem") ?? "Show frame bounds"; + exportAsAnimatedGifToolStripMenuItem.Text = _localizationGetter("Forms.AnimDataControl.ExportGifMenuItem") ?? "Export as animated Gif"; + + // ToolStrip + searchByIdToolStripLabel.Text = _localizationGetter("Forms.AnimDataControl.IndexLabel") ?? "Index:"; + toolStripDropDownButton1.Text = _localizationGetter("Forms.AnimDataControl.SettingsButton") ?? "Settings"; + + // CheckBox + checkBoxRelative.Text = _localizationGetter("Forms.AnimDataControl.RelativeCheckBox") ?? "Relative"; + + // 状态栏标签前缀 + _baseGraphicLabelPrefix = _localizationGetter("Forms.AnimDataControl.BaseGraphicLabel") ?? "Base Graphic: "; + _graphicLabelPrefix = _localizationGetter("Forms.AnimDataControl.GraphicLabel") ?? "Graphic: "; + _hueLabelPrefix = _localizationGetter("Forms.AnimDataControl.HueLabel") ?? "Hue: "; + + // 设置初始状态栏显示 + toolStripStatusBaseGraphic.Text = $"{_baseGraphicLabelPrefix}0 (0x0)"; + toolStripStatusGraphic.Text = $"{_graphicLabelPrefix}0 (0x0)"; + toolStripStatusHue.Text = _hueLabelPrefix + "0"; + } + public static bool Select(int graphic) { if (_refMarker == null) diff --git a/UoFiddler.Controls/UserControls/AnimationListControl.cs b/UoFiddler.Controls/UserControls/AnimationListControl.cs index d1ee9f5b..3d0fa585 100644 --- a/UoFiddler.Controls/UserControls/AnimationListControl.cs +++ b/UoFiddler.Controls/UserControls/AnimationListControl.cs @@ -867,6 +867,7 @@ private void OnClick_Hue(object sender, EventArgs e) ? new HuePopUpForm(ChangeHue, _defHue + 1) : new HuePopUpForm(ChangeHue, _customHue - 1); + _showForm.SetLocalization(key => _localizationGetter?.Invoke(key)); _showForm.TopMost = true; _showForm.Show(); } diff --git a/UoFiddler/Forms/MainForm.cs b/UoFiddler/Forms/MainForm.cs index 03e9ffa5..7516fc29 100644 --- a/UoFiddler/Forms/MainForm.cs +++ b/UoFiddler/Forms/MainForm.cs @@ -57,6 +57,9 @@ public MainForm(ILogger logger) // 应用本地化 LocalizationService.LocalizeForm(this); + // 汉化右键菜单项 + unDockToolStripMenuItem.Text = LocalizationService.GetString("Forms.MainForm.ContextMenu.UnDock") ?? "UnDock"; + // 为主标签页控件调用本地化(GumpControl等需要手动调用SetLocalization) gumpsControl.SetLocalization(key => LocalizationService.GetString(key)); hueControl.SetLocalization(key => LocalizationService.GetString(key)); @@ -71,6 +74,7 @@ public MainForm(ILogger logger) lightControl.SetLocalization(key => LocalizationService.GetString(key)); speechControl.SetLocalization(key => LocalizationService.GetString(key)); skillsControl.SetLocalization(key => LocalizationService.GetString(key)); + animdataControl.SetLocalization(key => LocalizationService.GetString(key)); // 为 ItemsControl 设置汉化(通过遍历 TabPage 找到) foreach (TabPage tab in TabPanel.TabPages) @@ -577,9 +581,12 @@ private void OnClosing(object sender, FormClosingEventArgs e) if (files.Length > 0) { + var title = LocalizationService.GetString("Forms.MainForm.ExitConfirmDialog.Title") ?? "UnSaved Changes"; + var message = LocalizationService.GetString("Forms.MainForm.ExitConfirmDialog.Message") ?? "Are you sure you want to quit?\r\n\r\nThere are unsaved files:\r\n{0}"; + message = string.Format(message, files); + DialogResult result = - MessageBox.Show($"Are you sure you want to quit?\r\n\r\nThere are unsaved files:\r\n{files}", - "UnSaved Changes", MessageBoxButtons.YesNo, MessageBoxIcon.Question, + MessageBox.Show(message, title, MessageBoxButtons.YesNo, MessageBoxIcon.Question, MessageBoxDefaultButton.Button2); if (result == DialogResult.No) { diff --git a/UoFiddler/Localization/Dictionaries/zh-CN.json b/UoFiddler/Localization/Dictionaries/zh-CN.json index 35c6b7fd..4dc2678a 100644 --- a/UoFiddler/Localization/Dictionaries/zh-CN.json +++ b/UoFiddler/Localization/Dictionaries/zh-CN.json @@ -5,6 +5,10 @@ "Forms": { "MainForm": { "Title": "UOFiddler", + "ExitConfirmDialog": { + "Title": "未保存更改", + "Message": "确定要退出吗?\r\n\r\n存在未保存的文件:\r\n{0}" + }, "Tabs": { "StartTab": "开始", "MultisTab": "多重组件", @@ -87,6 +91,9 @@ "Compare AnimData": "对比动画数据", "Compare RadarCol": "对比雷达颜色", "Compare TileData": "对比图块数据" + }, + "ContextMenu": { + "UnDock": "取消停靠" } }, "LoadProfileForm": { @@ -727,6 +734,10 @@ "asTiffToolStripMenuItem2": "导出为 TIFF", "asJpgToolStripMenuItem2": "导出为 JPG", "asPngToolStripMenuItem": "导出为 PNG", + "ExportDialog": { + "Title": "保存", + "Message": "{0} 已保存到 {1}" + }, "ContextMenu": { "exportAllThumbnailsToolStripMenuItem": "导出所有缩略图..", "asBmpToolStripMenuItem3": "导出为 BMP", @@ -1532,6 +1543,85 @@ "ColumnName": "技能名称", "FileSavedMessage": "技能已保存成功", "FileSavedTitle": "保存" + }, + "AnimDataControl": { + "PreviewGroupBox": "预览", + "DataGroupBox": "数据", + "FramesGroupBox": "帧", + "StartDelayLabel": "开始延迟", + "FrameDelayLabel": "帧延迟", + "AddButton": "添加", + "RemoveButton": "移除", + "SaveButton": "保存", + "ImportButton": "导入...", + "ExportButton": "导出...", + "AddMenuItem": "添加", + "RemoveMenuItem": "移除", + "HueMenuItem": "色调", + "AnimateMenuItem": "播放动画", + "ShowFrameBoundsMenuItem": "显示帧边界", + "ExportGifMenuItem": "导出为动画 GIF", + "ExportGifDialog": { + "Title": "保存", + "Message": "已保存到 {0}" + }, + "IndexLabel": "索引:", + "SettingsButton": "设置", + "RelativeCheckBox": "相对坐标", + "BaseGraphicLabel": "基础图形:", + "GraphicLabel": "图形:", + "HueLabel": "色调:" + }, + "HuePopUpForm": { + "Title": "色调拾取器", + "OkButton": "确定", + "ClearButton": "清除", + "HueOnlyGrayCheckBox": "仅灰色色调 (+0x8000)" + }, + "HuesControl": { + "HueIndexToolStripLabel": "索引:", + "HueNameToolStripLabel": "名称:", + "SearchNameToolStripButton": "查找下一个", + "IndexOffsetButton": "显示游戏内编号", + "saveToolStripMenuItem": "保存", + "replaceToolStripMenuItem": "替换为..", + "exportToolStripMenuItem": "导出..", + "importToolStripMenuItem": "导入..", + "exportAllHueNamesListToolStripMenuItem": "导出所有色调名称列表" + }, + "AnimDataExportForm": { + "Title": "导出动画数据", + "lblAnimationsToExport": "导出动画:", + "btnExport": "导出", + "ExportSelection": { + "All": "全部(默认、蓝色、红色条目)", + "IncludeMissing": "包含缺失动画标志(默认和蓝色条目)", + "OnlyValid": "仅有效动画(默认条目)" + }, + "ExportSuccessMessage": "已导出 {0} 条 animdata 记录到:{1}", + "ExportErrorTitle": "AnimData 导出错误", + "ExportErrorMessage": "导出 animdata 时出错:{0}" + }, + "AnimDataImportForm": { + "Title": "导入动画数据", + "label5": "导入来源:", + "btnImport": "导入", + "label1": "冲突时:", + "cbErase": "导入前清空动画数据", + "ConflictAction": { + "Skip": "跳过", + "Overwrite": "覆盖" + }, + "ImportSuccessTitle": "导入成功", + "ImportSuccessMessage": "已从 {0} 成功导入 {1} 条动画数据\n\n请不要忘记保存您的更改!", + "ImportErrorTitle": "导入错误", + "ImportErrorMessage": "导入动画数据时出错: {0}" + }, + "FileSavedDialog": { + "Title": "文件已保存", + "SaveSuccess": "文件保存成功。", + "OpenFolder": "打开文件夹", + "OK": "确定" } }, "Ultima": { From a479983048572b2bb22c9b66c6da35edf561b88a Mon Sep 17 00:00:00 2001 From: nbyaya Date: Wed, 7 Oct 2026 21:16:59 +0800 Subject: [PATCH 72/76] =?UTF-8?q?=E6=B1=89=E5=8C=96=E5=9C=B0=E5=BD=A2?= =?UTF-8?q?=E5=9B=BE=E5=9D=97=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 - 32 个菜单项、标签、按钮汉化 - FileSavedDialog 标题、按钮汉化 - FolderBrowserDialog 描述文本汉化 - 共 5 个新 JSON 词条 --- .../UserControls/LandTilesControl.cs | 10 +++-- UoFiddler/Forms/MainForm.cs | 1 + .../Localization/Dictionaries/zh-CN.json | 41 +++++++++++++++++++ 3 files changed, 48 insertions(+), 4 deletions(-) diff --git a/UoFiddler.Controls/UserControls/LandTilesControl.cs b/UoFiddler.Controls/UserControls/LandTilesControl.cs index 0557c052..a42566d9 100644 --- a/UoFiddler.Controls/UserControls/LandTilesControl.cs +++ b/UoFiddler.Controls/UserControls/LandTilesControl.cs @@ -803,7 +803,9 @@ private void ExportMultipleLandTileImages(List ids, ImageFormat imageFormat } } - FileSavedDialog.Show(FindForm(), Options.OutputPath, $"{ids.Count} land tiles saved successfully."); + string message = _localizationGetter?.Invoke("Forms.LandTilesControl.Messages.AllLandTilesSavedSuccessfully") + ?? $"{ids.Count} land tiles saved successfully."; + FileSavedDialog.Show(FindForm(), Options.OutputPath, message, null, _localizationGetter); } private void ExportLandTileImage(int index, ImageFormat imageFormat) @@ -917,7 +919,7 @@ private void ExportAllLandTiles(ImageFormat imageFormat) using (FolderBrowserDialog dialog = new FolderBrowserDialog()) { - dialog.Description = "Select directory"; + dialog.Description = _localizationGetter?.Invoke("Forms.LandTilesControl.Messages.SelectDirectoryDescription") ?? "Select directory"; dialog.ShowNewFolderButton = true; if (dialog.ShowDialog() != DialogResult.OK) { @@ -947,7 +949,7 @@ private void ExportAllLandTiles(ImageFormat imageFormat) } } - FileSavedDialog.Show(FindForm(), dialog.SelectedPath, "All land tiles saved successfully."); + FileSavedDialog.Show(FindForm(), dialog.SelectedPath, _localizationGetter?.Invoke("Forms.LandTilesControl.Messages.AllLandTilesSavedSuccessfully") ?? "All land tiles saved successfully.", null, _localizationGetter); } } @@ -1109,7 +1111,7 @@ private static bool IsIndexValid(int index) private void OnClickReplaceFromFolder(object sender, EventArgs e) { using FolderBrowserDialog dialog = new FolderBrowserDialog(); - dialog.Description = "Select folder containing images to replace"; + dialog.Description = _localizationGetter?.Invoke("Forms.LandTilesControl.Messages.SelectFolderForReplaceDescription") ?? "Select folder containing images to replace"; if (dialog.ShowDialog() != DialogResult.OK) { diff --git a/UoFiddler/Forms/MainForm.cs b/UoFiddler/Forms/MainForm.cs index 7516fc29..fa0636b9 100644 --- a/UoFiddler/Forms/MainForm.cs +++ b/UoFiddler/Forms/MainForm.cs @@ -75,6 +75,7 @@ public MainForm(ILogger logger) speechControl.SetLocalization(key => LocalizationService.GetString(key)); skillsControl.SetLocalization(key => LocalizationService.GetString(key)); animdataControl.SetLocalization(key => LocalizationService.GetString(key)); + landTilesControl.SetLocalization(key => LocalizationService.GetString(key)); // 为 ItemsControl 设置汉化(通过遍历 TabPage 找到) foreach (TabPage tab in TabPanel.TabPages) diff --git a/UoFiddler/Localization/Dictionaries/zh-CN.json b/UoFiddler/Localization/Dictionaries/zh-CN.json index 4dc2678a..5cb328a9 100644 --- a/UoFiddler/Localization/Dictionaries/zh-CN.json +++ b/UoFiddler/Localization/Dictionaries/zh-CN.json @@ -1617,6 +1617,47 @@ "ImportErrorTitle": "导入错误", "ImportErrorMessage": "导入动画数据时出错: {0}" }, + "LandTilesControl": { + "showFreeSlotsToolStripMenuItem": "显示空闲槽位", + "findNextFreeSlotToolStripMenuItem": "查找下一个空闲槽位", + "changeBackgroundColorToolStripMenuItem": "更改背景颜色", + "exportImageToolStripMenuItem": "导出图像..", + "asBmpToolStripMenuItem": "导出为 BMP", + "asTiffToolStripMenuItem": "导出为 TIFF", + "asJpgToolStripMenuItem1": "导出为 JPG", + "asPngToolStripMenuItem": "导出为 PNG", + "selectInTileDataTabToolStripMenuItem": "在图块数据标签中选择", + "selectInRadarColorTabToolStripMenuItem": "在雷达颜色标签中选择", + "selectInTexturesTabToolStripMenuItem": "在纹理标签中选择", + "copyImageToolStripMenuItem": "复制图像", + "pasteImageToolStripMenuItem": "粘贴图像", + "replaceToolStripMenuItem": "替换", + "replaceStartingFromToolStripMenuItem": "从..开始替换", + "replaceFromFolderToolStripMenuItem": "从文件夹替换...", + "insertAtToolStripMenuItem": "在..处插入", + "removeToolStripMenuItem": "移除", + "saveToolStripMenuItem": "保存", + "IndexToolStripLabel": "索引:", + "NameToolStripLabel": "名称:", + "searchByNameToolStripButton": "查找下一个", + "MiscToolStripDropDownButton": "杂项", + "exportAllToolStripMenuItem": "全部导出..", + "ExportAllAsBmp": "导出为 BMP", + "ExportAllAsTiff": "导出为 TIFF", + "asJpgToolStripMenuItem": "导出为 JPG", + "asPngToolStripMenuItem1": "导出为 PNG", + "SaveButton": "保存", + "NameLabel": "名称:", + "GraphicLabel": "图形:", + "FlagsLabel": "标志:", + "Messages": { + "LandtileSavedTo": "地形图块已保存到", + "Saved": "已保存", + "AllLandTilesSavedSuccessfully": "所有地形图块保存成功。", + "SelectDirectoryDescription": "选择目录", + "SelectFolderForReplaceDescription": "选择包含要替换的图像的文件夹" + } + }, "FileSavedDialog": { "Title": "文件已保存", "SaveSuccess": "文件保存成功。", From 6a73eb95b75f086a1df48d6199c70023a678d5ca Mon Sep 17 00:00:00 2001 From: nbyaya Date: Wed, 7 Oct 2026 21:28:38 +0800 Subject: [PATCH 73/76] =?UTF-8?q?=E6=B1=89=E5=8C=96=E5=A4=9A=E9=87=8D?= =?UTF-8?q?=E5=9C=B0=E5=9B=BE/=E4=BD=8D=E9=9D=A2=E7=AA=97=E5=8F=A3?= =?UTF-8?q?=E5=86=85=E5=AE=B9?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../UserControls/MultiMapControl.cs | 78 +++++++++++++++++-- UoFiddler/Forms/MainForm.cs | 1 + .../Localization/Dictionaries/zh-CN.json | 30 +++++++ 3 files changed, 101 insertions(+), 8 deletions(-) diff --git a/UoFiddler.Controls/UserControls/MultiMapControl.cs b/UoFiddler.Controls/UserControls/MultiMapControl.cs index cbcf3b27..331f08b5 100644 --- a/UoFiddler.Controls/UserControls/MultiMapControl.cs +++ b/UoFiddler.Controls/UserControls/MultiMapControl.cs @@ -41,6 +41,7 @@ public MultiMapControl() private Point _movingPoint; private bool _loaded; + private Func? _localizationGetter; /// /// ReLoads if loaded @@ -195,6 +196,41 @@ private void OnFilePathChangeEvent() Reload(); } + public void SetLocalization(Func getLocalized) + { + _localizationGetter = getLocalized; + ApplyLocalization(); + } + + private void ApplyLocalization() + { + if (_localizationGetter == null) return; + + // 工具栏按钮 + toolStripDropDownButton1.Text = _localizationGetter("Forms.MultiMapControl.loadButton") ?? "Load.."; + toolStripDropDownButton2.Text = _localizationGetter("Forms.MultiMapControl.generateButton") ?? "Generate.."; + toolStripDropDownButton3.Text = _localizationGetter("Forms.MultiMapControl.exportButton") ?? "Export.."; + + // 加载菜单项 + multiMapToolStripMenuItem.Text = _localizationGetter("Forms.MultiMapControl.Menus.multiMap") ?? "MultiMap"; + facet00ToolStripMenuItem.Text = _localizationGetter("Forms.MultiMapControl.Menus.facet00") ?? "Facet00"; + facet01ToolStripMenuItem.Text = _localizationGetter("Forms.MultiMapControl.Menus.facet01") ?? "Facet01"; + facet02ToolStripMenuItem.Text = _localizationGetter("Forms.MultiMapControl.Menus.facet02") ?? "Facet02"; + facet03ToolStripMenuItem.Text = _localizationGetter("Forms.MultiMapControl.Menus.facet03") ?? "Facet03"; + facet04ToolStripMenuItem.Text = _localizationGetter("Forms.MultiMapControl.Menus.facet04") ?? "Facet04"; + facet05ToolStripMenuItem.Text = _localizationGetter("Forms.MultiMapControl.Menus.facet05") ?? "Facet05"; + + // 生成菜单项 + multiMapFromImageToolStripMenuItem.Text = _localizationGetter("Forms.MultiMapControl.Menus.multiMapFromImage") ?? "MultiMap from Image"; + facetFromImageToolStripMenuItem.Text = _localizationGetter("Forms.MultiMapControl.Menus.facetFromImage") ?? "Facet from Image"; + + // 导出菜单项 + asBmpToolStripMenuItem1.Text = _localizationGetter("Forms.MultiMapControl.Menus.asBmp") ?? "As Bmp.."; + asTiffToolStripMenuItem1.Text = _localizationGetter("Forms.MultiMapControl.Menus.asTiff") ?? "As Tiff.."; + asPngToolStripMenuItem.Text = _localizationGetter("Forms.MultiMapControl.Menus.asJpg") ?? "As Jpg.."; + asPngToolStripMenuItem1.Text = _localizationGetter("Forms.MultiMapControl.Menus.asPng") ?? "As Png.."; + } + private void OnClickExportBmp(object sender, EventArgs e) { ExportMultiMapImage(ImageFormat.Bmp); @@ -222,7 +258,12 @@ private void ExportMultiMapImage(ImageFormat imageFormat) pictureBox.Image.Save(fileName, imageFormat); - FileSavedDialog.Show(FindForm(), fileName, $"{CheckedToString()} saved successfully."); + string successMessage = _localizationGetter?.Invoke("Forms.MultiMapControl.Messages.multiMapSavedSuccess") + ?? $"{CheckedToString()} saved successfully."; + if (_localizationGetter != null) + FileSavedDialog.Show(FindForm(), fileName, successMessage, null, _localizationGetter); + else + FileSavedDialog.Show(FindForm(), fileName, successMessage); } private string CheckedToString() @@ -300,7 +341,8 @@ private void OnClickGenerateRLE(object sender, EventArgs e) { using (OpenFileDialog dialog = new OpenFileDialog()) { - dialog.Title = "Select Image to convert"; + dialog.Title = _localizationGetter?.Invoke("Forms.MultiMapControl.Dialogs.selectImageTitle") + ?? "Select Image to convert"; if (dialog.ShowDialog() != DialogResult.OK) { return; @@ -314,7 +356,10 @@ private void OnClickGenerateRLE(object sender, EventArgs e) if (image.Height != 2048 || image.Width != 2560) { - MessageBox.Show("Invalid image height or width", "Error", MessageBoxButtons.OK, MessageBoxIcon.Error, MessageBoxDefaultButton.Button1); + string errorTitle = _localizationGetter?.Invoke("Forms.MultiMapControl.Dialogs.errorTitle") ?? "Error"; + string errorMsg = _localizationGetter?.Invoke("Forms.MultiMapControl.Messages.invalidImageSize") + ?? "Invalid image height or width"; + MessageBox.Show(errorMsg, errorTitle, MessageBoxButtons.OK, MessageBoxIcon.Error, MessageBoxDefaultButton.Button1); return; } @@ -326,12 +371,20 @@ private void OnClickGenerateRLE(object sender, EventArgs e) Ultima.MultiMap.SaveMultiMap(image, bin); } - FileSavedDialog.Show(FindForm(), fileName, "MultiMap saved successfully."); + string successMsg = _localizationGetter?.Invoke("Forms.MultiMapControl.Messages.multiMapSavedSuccess") + ?? "MultiMap saved successfully."; + if (_localizationGetter != null) + FileSavedDialog.Show(FindForm(), fileName, successMsg, null, _localizationGetter); + else + FileSavedDialog.Show(FindForm(), fileName, successMsg); } } catch (FileNotFoundException) { - MessageBox.Show("No image found", "Error", MessageBoxButtons.OK, MessageBoxIcon.Error, + string errorTitle = _localizationGetter?.Invoke("Forms.MultiMapControl.Dialogs.errorTitle") ?? "Error"; + string errorMsg = _localizationGetter?.Invoke("Forms.MultiMapControl.Messages.imageNotFound") + ?? "No image found"; + MessageBox.Show(errorMsg, errorTitle, MessageBoxButtons.OK, MessageBoxIcon.Error, MessageBoxDefaultButton.Button1); } } @@ -341,7 +394,8 @@ private void OnClickGenerateFacetFromImage(object sender, EventArgs e) { using (var dialog = new OpenFileDialog()) { - dialog.Title = "Select Image to convert"; + dialog.Title = _localizationGetter?.Invoke("Forms.MultiMapControl.Dialogs.selectImageTitle") + ?? "Select Image to convert"; if (dialog.ShowDialog() != DialogResult.OK) { return; @@ -356,12 +410,20 @@ private void OnClickGenerateFacetFromImage(object sender, EventArgs e) string fileName = Path.Combine(path, "facet.mul"); Ultima.MultiMap.SaveFacetImage(fileName, image); - FileSavedDialog.Show(FindForm(), fileName, "Facet saved successfully."); + string successMsg = _localizationGetter?.Invoke("Forms.MultiMapControl.Messages.facetSavedSuccess") + ?? "Facet saved successfully."; + if (_localizationGetter != null) + FileSavedDialog.Show(FindForm(), fileName, successMsg, null, _localizationGetter); + else + FileSavedDialog.Show(FindForm(), fileName, successMsg); } } catch (FileNotFoundException) { - MessageBox.Show("No image found", "Error", MessageBoxButtons.OK, MessageBoxIcon.Error, + string errorTitle = _localizationGetter?.Invoke("Forms.MultiMapControl.Dialogs.errorTitle") ?? "Error"; + string errorMsg = _localizationGetter?.Invoke("Forms.MultiMapControl.Messages.imageNotFound") + ?? "No image found"; + MessageBox.Show(errorMsg, errorTitle, MessageBoxButtons.OK, MessageBoxIcon.Error, MessageBoxDefaultButton.Button1); } } diff --git a/UoFiddler/Forms/MainForm.cs b/UoFiddler/Forms/MainForm.cs index fa0636b9..472b20af 100644 --- a/UoFiddler/Forms/MainForm.cs +++ b/UoFiddler/Forms/MainForm.cs @@ -75,6 +75,7 @@ public MainForm(ILogger logger) speechControl.SetLocalization(key => LocalizationService.GetString(key)); skillsControl.SetLocalization(key => LocalizationService.GetString(key)); animdataControl.SetLocalization(key => LocalizationService.GetString(key)); + multimapControl.SetLocalization(key => LocalizationService.GetString(key)); landTilesControl.SetLocalization(key => LocalizationService.GetString(key)); // 为 ItemsControl 设置汉化(通过遍历 TabPage 找到) diff --git a/UoFiddler/Localization/Dictionaries/zh-CN.json b/UoFiddler/Localization/Dictionaries/zh-CN.json index 5cb328a9..792c8a89 100644 --- a/UoFiddler/Localization/Dictionaries/zh-CN.json +++ b/UoFiddler/Localization/Dictionaries/zh-CN.json @@ -1658,6 +1658,36 @@ "SelectFolderForReplaceDescription": "选择包含要替换的图像的文件夹" } }, + "MultiMapControl": { + "loadButton": "加载..", + "generateButton": "生成..", + "exportButton": "导出..", + "Menus": { + "multiMap": "多重地图", + "facet00": "位面 00", + "facet01": "位面 01", + "facet02": "位面 02", + "facet03": "位面 03", + "facet04": "位面 04", + "facet05": "位面 05", + "multiMapFromImage": "从图像生成多重地图", + "facetFromImage": "从图像生成位面", + "asBmp": "导出为 BMP..", + "asTiff": "导出为 TIFF..", + "asJpg": "导出为 JPG..", + "asPng": "导出为 PNG.." + }, + "Dialogs": { + "selectImageTitle": "选择要转换的图像", + "errorTitle": "错误" + }, + "Messages": { + "invalidImageSize": "图像高度或宽度无效", + "imageNotFound": "未找到图像", + "multiMapSavedSuccess": "多重地图保存成功。", + "facetSavedSuccess": "位面保存成功。" + } + }, "FileSavedDialog": { "Title": "文件已保存", "SaveSuccess": "文件保存成功。", From 6cd9a842c3ab8a6853b926959d6b8a122ab97478 Mon Sep 17 00:00:00 2001 From: nbyaya Date: Wed, 7 Oct 2026 21:52:40 +0800 Subject: [PATCH 74/76] =?UTF-8?q?=E6=B1=89=E5=8C=96Verdata=E8=A1=A5?= =?UTF-8?q?=E4=B8=81=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 --- .../UserControls/VerdataControl.cs | 67 ++++++++++++++++--- UoFiddler/Forms/MainForm.cs | 1 + .../Localization/Dictionaries/zh-CN.json | 20 ++++++ 3 files changed, 78 insertions(+), 10 deletions(-) diff --git a/UoFiddler.Controls/UserControls/VerdataControl.cs b/UoFiddler.Controls/UserControls/VerdataControl.cs index 65d3f7c3..697588ec 100644 --- a/UoFiddler.Controls/UserControls/VerdataControl.cs +++ b/UoFiddler.Controls/UserControls/VerdataControl.cs @@ -33,9 +33,44 @@ public VerdataControl() private int _currentAnimBody = -1; private bool _suppressAnimEvents; private Entry5D[] _customPatches; + private Func? _localizationGetter; private Entry5D[] ActivePatches => _customPatches ?? Verdata.Patches; + public void SetLocalization(Func getLocalized) + { + _localizationGetter = getLocalized; + ApplyLocalization(); + } + + private void ApplyLocalization() + { + if (_localizationGetter == null) return; + + // 工具栏按钮 + buttonReload.Text = _localizationGetter("Forms.VerdataControl.buttonReload") ?? "Reload"; + buttonLoadFile.Text = _localizationGetter("Forms.VerdataControl.buttonLoadFile") ?? "Load File…"; + + // 标签 + labelType.Text = _localizationGetter("Forms.VerdataControl.labelType") ?? "Patch Type:"; + labelCount.Text = _localizationGetter("Forms.VerdataControl.labelCount") ?? "Patches:"; + labelActions.Text = _localizationGetter("Forms.VerdataControl.labelActions") ?? "Actions:"; + labelDir.Text = _localizationGetter("Forms.VerdataControl.labelDir") ?? "Direction:"; + + // 标签页 + if (tabControlMulti.TabCount > 0) + { + tabControlMulti.TabPages[0].Text = _localizationGetter("Forms.VerdataControl.tabPageMultiPreview") ?? "Preview"; + } + if (tabControlMulti.TabCount > 1) + { + tabControlMulti.TabPages[1].Text = _localizationGetter("Forms.VerdataControl.tabPageMultiComponents") ?? "Components"; + } + + // 菜单项 + changeBackgroundColorToolStripMenuItem.Text = _localizationGetter("Forms.VerdataControl.changeBackgroundColor") ?? "Change background color"; + } + // Action names by body type — mirrors AnimationListControl.GetActionNames // [0] Monster (body 0–199): 22 actions // [1] Animal (body 200–399): 13 actions @@ -145,7 +180,8 @@ private void Populate() if (patches.Length == 0) { - labelCount.Text = "No patches found"; + string noPatchesText = _localizationGetter?.Invoke("Forms.VerdataControl.noPatchesFound") ?? "No patches found"; + labelCount.Text = noPatchesText; listBoxType.EndUpdate(); return; } @@ -196,7 +232,8 @@ private void OnTypeSelected(object sender, EventArgs e) listBoxPatches.Items.Add(new PatchItem(patch)); } - labelCount.Text = $"Patches: {group.Patches.Count}"; + string patchesLabel = _localizationGetter?.Invoke("Forms.VerdataControl.labelCount") ?? "Patches:"; + labelCount.Text = $"{patchesLabel} {group.Patches.Count}"; listBoxPatches.EndUpdate(); ClearPreview(); @@ -346,7 +383,9 @@ private void OnClickPlayStop(object sender, EventArgs e) } animatedPictureBox.Animate = !animatedPictureBox.Animate; - buttonPlayStop.Text = animatedPictureBox.Animate ? "Stop" : "Play"; + string stopText = _localizationGetter?.Invoke("Forms.VerdataControl.buttonStop") ?? "Stop"; + string playText = _localizationGetter?.Invoke("Forms.VerdataControl.buttonPlay") ?? "Play"; + buttonPlayStop.Text = animatedPictureBox.Animate ? stopText : playText; } private void OnActionSelected(object sender, EventArgs e) @@ -634,17 +673,24 @@ private void ShowNoPreview(int fileId, string message) private void ClearPreview() { - labelFile.Text = "File:"; - labelIndex.Text = "Index:"; - labelLookup.Text = "Lookup:"; - labelLength.Text = "Length:"; - labelExtra.Text = "Extra:"; + string fileLabel = _localizationGetter?.Invoke("Forms.VerdataControl.labelFile") ?? "File:"; + string indexLabel = _localizationGetter?.Invoke("Forms.VerdataControl.labelIndex") ?? "Index:"; + string lookupLabel = _localizationGetter?.Invoke("Forms.VerdataControl.labelLookup") ?? "Lookup:"; + string lengthLabel = _localizationGetter?.Invoke("Forms.VerdataControl.labelLength") ?? "Length:"; + string extraLabel = _localizationGetter?.Invoke("Forms.VerdataControl.labelExtra") ?? "Extra:"; + string playText = _localizationGetter?.Invoke("Forms.VerdataControl.buttonPlay") ?? "Play"; + + labelFile.Text = fileLabel; + labelIndex.Text = indexLabel; + labelLookup.Text = lookupLabel; + labelLength.Text = lengthLabel; + labelExtra.Text = extraLabel; labelDecoded.Text = string.Empty; _currentAnimBody = -1; animatedPictureBox.Animate = false; animatedPictureBox.Frames = null; panelAnimation.Visible = false; - buttonPlayStop.Text = "Play"; + buttonPlayStop.Text = playText; panelMulti.Visible = false; pictureBoxMulti.Image = null; richTextBoxMultiComponents.Text = string.Empty; @@ -656,9 +702,10 @@ private void ClearPreview() private void OnClickLoadFile(object sender, EventArgs e) { + string dialogTitle = _localizationGetter?.Invoke("Forms.VerdataControl.openVerdataTitle") ?? "Open verdata.mul"; using var dialog = new OpenFileDialog { - Title = "Open verdata.mul", + Title = dialogTitle, Filter = "verdata.mul|verdata.mul|MUL files (*.mul)|*.mul|All files (*.*)|*.*", FilterIndex = 1 }; diff --git a/UoFiddler/Forms/MainForm.cs b/UoFiddler/Forms/MainForm.cs index 472b20af..2b43129f 100644 --- a/UoFiddler/Forms/MainForm.cs +++ b/UoFiddler/Forms/MainForm.cs @@ -77,6 +77,7 @@ public MainForm(ILogger logger) animdataControl.SetLocalization(key => LocalizationService.GetString(key)); multimapControl.SetLocalization(key => LocalizationService.GetString(key)); landTilesControl.SetLocalization(key => LocalizationService.GetString(key)); + verdataControl.SetLocalization(key => LocalizationService.GetString(key)); // 为 ItemsControl 设置汉化(通过遍历 TabPage 找到) foreach (TabPage tab in TabPanel.TabPages) diff --git a/UoFiddler/Localization/Dictionaries/zh-CN.json b/UoFiddler/Localization/Dictionaries/zh-CN.json index 792c8a89..92d3108d 100644 --- a/UoFiddler/Localization/Dictionaries/zh-CN.json +++ b/UoFiddler/Localization/Dictionaries/zh-CN.json @@ -1688,6 +1688,26 @@ "facetSavedSuccess": "位面保存成功。" } }, + "VerdataControl": { + "buttonReload": "重新加载", + "buttonLoadFile": "加载文件…", + "buttonPlay": "播放", + "buttonStop": "停止", + "labelType": "补丁类型:", + "labelCount": "补丁:", + "labelFile": "文件:", + "labelIndex": "索引:", + "labelLookup": "查询:", + "labelLength": "长度:", + "labelExtra": "额外:", + "labelActions": "动作:", + "labelDir": "方向:", + "tabPageMultiPreview": "预览", + "tabPageMultiComponents": "组件", + "changeBackgroundColor": "更改背景颜色", + "openVerdataTitle": "打开 verdata.mul", + "noPatchesFound": "未找到补丁" + }, "FileSavedDialog": { "Title": "文件已保存", "SaveSuccess": "文件保存成功。", From 9f2e08b6e89b261f2510e475498fe48965e69ff7 Mon Sep 17 00:00:00 2001 From: nbyaya Date: Wed, 7 Oct 2026 22:09:55 +0800 Subject: [PATCH 75/76] =?UTF-8?q?=E6=B1=89=E5=8C=96=E6=8A=80=E8=83=BD?= =?UTF-8?q?=E7=BB=84=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 --- .../UserControls/SkillGroupControl.cs | 37 +++++++++++++++++-- UoFiddler/Forms/MainForm.cs | 1 + .../Localization/Dictionaries/zh-CN.json | 11 ++++++ 3 files changed, 46 insertions(+), 3 deletions(-) diff --git a/UoFiddler.Controls/UserControls/SkillGroupControl.cs b/UoFiddler.Controls/UserControls/SkillGroupControl.cs index aa593beb..40faf30c 100644 --- a/UoFiddler.Controls/UserControls/SkillGroupControl.cs +++ b/UoFiddler.Controls/UserControls/SkillGroupControl.cs @@ -31,6 +31,31 @@ public SkillGroupControl() private bool _loaded; private TreeNode _sourceNode; + private Func? _localizationGetter; + + /// + /// 设置本地化(从 MainForm 调用) + /// + public void SetLocalization(Func getLocalized) + { + _localizationGetter = getLocalized; + ApplyLocalization(); + } + + /// + /// 应用菜单项汉化 + /// + private void ApplyLocalization() + { + if (_localizationGetter == null) return; + + // 菜单项汉化 + addToolStripMenuItem.Text = _localizationGetter("Forms.SkillGroupControl.AddButton") ?? "Add"; + removeToolStripMenuItem.Text = _localizationGetter("Forms.SkillGroupControl.RemoveButton") ?? "Remove"; + renameToolStripMenuItem.Text = _localizationGetter("Forms.SkillGroupControl.RenameButton") ?? "Rename"; + toolStripMenuItem1.Text = _localizationGetter("Forms.SkillGroupControl.SkillIDLabel") ?? "SkillID"; + saveToolStripMenuItem.Text = _localizationGetter("Forms.SkillGroupControl.SaveButton") ?? "Save"; + } /// /// ReLoads if loaded @@ -145,7 +170,9 @@ private void OnClickSave(object sender, EventArgs e) SkillGroups.Save(Options.OutputPath); Options.ChangedUltimaClass["SkillGrp"] = false; - FileSavedDialog.Show(FindForm(), Options.OutputPath, "SkillGrp saved successfully."); + string message = _localizationGetter?.Invoke("Forms.SkillGroupControl.FileSavedMessage") ?? "SkillGrp saved successfully."; + string title = _localizationGetter?.Invoke("Forms.FileSavedDialog.Title") ?? "File Saved"; + FileSavedDialog.Show(FindForm(), Options.OutputPath, message, title, key => _localizationGetter?.Invoke(key)); } private void OnItemDrag(object sender, ItemDragEventArgs e) @@ -254,10 +281,14 @@ private void AfterLabelEdit(object sender, NodeLabelEditEventArgs e) return; } + string editFormTitle = _localizationGetter?.Invoke("Forms.SkillGroupControl.EditFormTitle") ?? "SkillGroup Edit"; + string invalidNameReserved = _localizationGetter?.Invoke("Forms.SkillGroupControl.InvalidNameReserved") ?? "Invalid name. Name is reserved."; + string invalidNameEmpty = _localizationGetter?.Invoke("Forms.SkillGroupControl.InvalidNameEmpty") ?? "Invalid name. Name cannot be empty."; + if (string.Equals("Misc", e.Label)) { e.CancelEdit = true; - MessageBox.Show("Invalid name. Name is reserved.", "SkillGroup Edit"); + MessageBox.Show(invalidNameReserved, editFormTitle); e.Node.BeginEdit(); } else if (e.Label.Length > 0) @@ -267,7 +298,7 @@ private void AfterLabelEdit(object sender, NodeLabelEditEventArgs e) else { e.CancelEdit = true; - MessageBox.Show("Invalid name. Name cannot be empty.", "SkillGroup Edit"); + MessageBox.Show(invalidNameEmpty, editFormTitle); e.Node.BeginEdit(); } treeView1.LabelEdit = false; diff --git a/UoFiddler/Forms/MainForm.cs b/UoFiddler/Forms/MainForm.cs index 2b43129f..4a5d09f6 100644 --- a/UoFiddler/Forms/MainForm.cs +++ b/UoFiddler/Forms/MainForm.cs @@ -78,6 +78,7 @@ public MainForm(ILogger logger) multimapControl.SetLocalization(key => LocalizationService.GetString(key)); landTilesControl.SetLocalization(key => LocalizationService.GetString(key)); verdataControl.SetLocalization(key => LocalizationService.GetString(key)); + skillGroupControl.SetLocalization(key => LocalizationService.GetString(key)); // 为 ItemsControl 设置汉化(通过遍历 TabPage 找到) foreach (TabPage tab in TabPanel.TabPages) diff --git a/UoFiddler/Localization/Dictionaries/zh-CN.json b/UoFiddler/Localization/Dictionaries/zh-CN.json index 92d3108d..0bba5819 100644 --- a/UoFiddler/Localization/Dictionaries/zh-CN.json +++ b/UoFiddler/Localization/Dictionaries/zh-CN.json @@ -1708,6 +1708,17 @@ "openVerdataTitle": "打开 verdata.mul", "noPatchesFound": "未找到补丁" }, + "SkillGroupControl": { + "AddButton": "添加", + "RemoveButton": "删除", + "RenameButton": "重命名", + "SkillIDLabel": "技能ID", + "SaveButton": "保存", + "InvalidNameReserved": "无效的名称。该名称是保留的。", + "InvalidNameEmpty": "无效的名称。名称不能为空。", + "EditFormTitle": "技能组编辑", + "FileSavedMessage": "技能组保存成功。" + }, "FileSavedDialog": { "Title": "文件已保存", "SaveSuccess": "文件保存成功。", From a00b76b14621eaf9db9eed29815546dc8b427a28 Mon Sep 17 00:00:00 2001 From: nbyaya Date: Wed, 7 Oct 2026 22:39:30 +0800 Subject: [PATCH 76/76] =?UTF-8?q?=E6=B1=89=E5=8C=96=E8=A3=85=E6=89=AE?= =?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 --- .../UserControls/DressControl.cs | 102 ++++++++++-- UoFiddler/Forms/MainForm.cs | 1 + .../Localization/Dictionaries/zh-CN.json | 146 ++++++------------ 3 files changed, 134 insertions(+), 115 deletions(-) diff --git a/UoFiddler.Controls/UserControls/DressControl.cs b/UoFiddler.Controls/UserControls/DressControl.cs index d3ae25ec..e6984672 100644 --- a/UoFiddler.Controls/UserControls/DressControl.cs +++ b/UoFiddler.Controls/UserControls/DressControl.cs @@ -44,6 +44,9 @@ public DressControl() private int[] _displayedItems = Array.Empty(); private Color[] _displayedColors = Array.Empty(); + // Localization support + private Func? _localizationGetter; + private int GetSelectedObjType() { return listViewItems.SelectedIndices.Count > 0 @@ -181,6 +184,58 @@ public void SetHue(int index, int color) _hues[index] = color; } + /// + /// Sets the localization getter and applies localized text. + /// + public void SetLocalization(Func? getLocalized) + { + _localizationGetter = getLocalized; + ApplyLocalization(); + } + + /// + /// Applies localized text to UI elements. + /// + private void ApplyLocalization() + { + if (_localizationGetter == null) return; + + // Buttons and Labels + FindNextItemButton.Text = _localizationGetter("Forms.DressControl.FindNextItemButton") ?? "Find next"; + button1.Text = _localizationGetter("Forms.DressControl.ExportReportButton") ?? "Export Report"; + LayerSort.Text = _localizationGetter("Forms.DressControl.LayerSort") ?? "Layer Sort"; + buttonDress.Text = _localizationGetter("Forms.DressControl.DressItemButton") ?? "Dress Item"; + checkBoxfemale.Text = _localizationGetter("Forms.DressControl.FemaleCheckBox") ?? "Female"; + checkBoxHuman.Text = _localizationGetter("Forms.DressControl.HumanRadio") ?? "Human"; + checkBoxElve.Text = _localizationGetter("Forms.DressControl.ElfRadio") ?? "Elf"; + checkBoxGargoyle.Text = _localizationGetter("Forms.DressControl.GargoyleRadio") ?? "Gargoyle"; + groupBox1.Text = _localizationGetter("Forms.DressControl.MountGroupBox") ?? "Mount"; + groupBoxAnimate.Text = _localizationGetter("Forms.DressControl.FacingActionGroupBox") ?? "Facing/Action"; + listViewItemsColumn.Text = _localizationGetter("Forms.DressControl.ItemColumnHeader") ?? "Item"; + + // Context Menu 1 (Wear List) + unDressToolStripMenuItem.Text = _localizationGetter("Forms.DressControl.UnDress") ?? "UnDress"; + huToolStripMenuItem.Text = _localizationGetter("Forms.DressControl.Hue") ?? "Hue"; + hueToolStripMenuItem.Text = _localizationGetter("Forms.DressControl.HueEllipsis") ?? "Hue.."; + unDressAllToolStripMenuItem.Text = _localizationGetter("Forms.DressControl.UnDressAll") ?? "UnDress All"; + + // Context Menu 2 (Picture) + showAnimationToolStripMenuItem.Text = _localizationGetter("Forms.DressControl.ShowAnimation") ?? "Show Animation"; + animateToolStripMenuItem.Text = _localizationGetter("Forms.DressControl.Animate") ?? "Animate"; + extractImageToolStripMenuItem.Text = _localizationGetter("Forms.DressControl.ExportImage") ?? "Export Image.."; + asBmpToolStripMenuItem.Text = _localizationGetter("Forms.DressControl.AsBmp") ?? "As Bmp"; + asTiffToolStripMenuItem.Text = _localizationGetter("Forms.DressControl.AsTiff") ?? "As Tiff"; + asJpgToolStripMenuItem.Text = _localizationGetter("Forms.DressControl.AsJpg") ?? "As Jpg"; + asPngToolStripMenuItem.Text = _localizationGetter("Forms.DressControl.AsPng") ?? "As Png"; + extractAnimationToolStripMenuItem.Text = _localizationGetter("Forms.DressControl.ExportAnimation") ?? "Export Animation.."; + asBmpToolStripMenuItem1.Text = _localizationGetter("Forms.DressControl.AsBmp") ?? "As Bmp"; + asTiffToolStripMenuItem1.Text = _localizationGetter("Forms.DressControl.AsTiff") ?? "As Tiff"; + asJpgToolStripMenuItem1.Text = _localizationGetter("Forms.DressControl.AsJpg") ?? "As Jpg"; + asPngToolStripMenuItem1.Text = _localizationGetter("Forms.DressControl.AsPng") ?? "As Png"; + asAnimatedGifToolStripMenuItem.Text = _localizationGetter("Forms.DressControl.AsAnimatedGifLooping") ?? "As animated Gif (looping)"; + asAnimatedGifnoLoopingToolStripMenuItem.Text = _localizationGetter("Forms.DressControl.AsAnimatedGifNoLooping") ?? "As animated Gif (no looping)"; + } + /// /// Reload when loaded /// @@ -798,14 +853,25 @@ private void UpdateSelection(int objType) pictureBoxDress.Invalidate(); TextBox.Clear(); + + // Get localized labels + string objTypeLabel = _localizationGetter?.Invoke("Forms.DressControl.InfoLabels.ObjType") ?? "Objtype"; + string layerLabel = _localizationGetter?.Invoke("Forms.DressControl.InfoLabels.Layer") ?? "Layer"; + string gumpIdLabel = _localizationGetter?.Invoke("Forms.DressControl.InfoLabels.GumpID") ?? "GumpID"; + string hueLabel = _localizationGetter?.Invoke("Forms.DressControl.InfoLabels.Hue") ?? "Hue"; + string animationLabel = _localizationGetter?.Invoke("Forms.DressControl.InfoLabels.Animation") ?? "Animation"; + string validGumpLabel = _localizationGetter?.Invoke("Forms.DressControl.InfoLabels.ValidGump") ?? "ValidGump"; + string validAnimLabel = _localizationGetter?.Invoke("Forms.DressControl.InfoLabels.ValidAnim") ?? "ValidAnim"; + string validLayerLabel = _localizationGetter?.Invoke("Forms.DressControl.InfoLabels.ValidLayer") ?? "ValidLayer"; + TextBox.AppendText( - $"Objtype: 0x{objType:X4}\nLayer: 0x{TileData.ItemTable[objType].Quality:X2}\n"); - TextBox.AppendText($"GumpID: 0x{gump:X4} (0x{gumpOrig:X4})\nHue: {hue + 1}\n"); - TextBox.AppendText($"Animation: 0x{ani:X4} (0x{TileData.ItemTable[objType].Animation:X4})\n"); + $"{objTypeLabel}: 0x{objType:X4}\n{layerLabel}: 0x{TileData.ItemTable[objType].Quality:X2}\n"); + TextBox.AppendText($"{gumpIdLabel}: 0x{gump:X4} (0x{gumpOrig:X4})\n{hueLabel}: {hue + 1}\n"); + TextBox.AppendText($"{animationLabel}: 0x{ani:X4} (0x{TileData.ItemTable[objType].Animation:X4})\n"); TextBox.AppendText( - $"ValidGump: {Gumps.IsValidIndex(gump)}\nValidAnim: {Animations.IsActionDefined(ani, 0, 0)}\n"); + $"{validGumpLabel}: {Gumps.IsValidIndex(gump)}\n{validAnimLabel}: {Animations.IsActionDefined(ani, 0, 0)}\n"); TextBox.AppendText( - $"ValidLayer: {Array.IndexOf(_drawOrder, TileData.ItemTable[objType].Quality) != -1}"); + $"{validLayerLabel}: {Array.IndexOf(_drawOrder, TileData.ItemTable[objType].Quality) != -1}"); } private void OnClick_Animate(object sender, EventArgs e) @@ -988,13 +1054,13 @@ private void OnClick_ChangeDisplay(object sender, EventArgs e) { groupBoxAnimate.Visible = false; animateToolStripMenuItem.Visible = false; - showAnimationToolStripMenuItem.Text = "Show Animation"; + showAnimationToolStripMenuItem.Text = _localizationGetter?.Invoke("Forms.DressControl.ShowAnimation") ?? "Show Animation"; } else { groupBoxAnimate.Visible = true; animateToolStripMenuItem.Visible = true; - showAnimationToolStripMenuItem.Text = "Show Paperdoll"; + showAnimationToolStripMenuItem.Text = _localizationGetter?.Invoke("Forms.DressControl.ShowPaperdoll") ?? "Show Paperdoll"; } RefreshDrawing(); @@ -1346,7 +1412,9 @@ private void ExportImage(ImageFormat imageFormat) string fileName = Path.Combine(outputPath, $"Dress PD.{fileExtension}"); DressPic.Image.Save(fileName, imageFormat); - FileSavedDialog.Show(FindForm(), fileName, "Paperdoll saved successfully."); + string message = _localizationGetter?.Invoke("Forms.DressControl.ExportMessages.PaperdollSaved") ?? "Paperdoll saved successfully."; + string title = _localizationGetter?.Invoke("Forms.FileSavedDialog.Title") ?? "Saved"; + FileSavedDialog.Show(FindForm(), fileName, message, title, key => _localizationGetter?.Invoke(key)); } else { @@ -1360,8 +1428,9 @@ private void ExportImage(ImageFormat imageFormat) DressPic.Image.Save(fileName, imageFormat); } - - FileSavedDialog.Show(FindForm(), fileName, "InGame saved successfully."); + string message = _localizationGetter?.Invoke("Forms.DressControl.ExportMessages.InGameSaved") ?? "InGame saved successfully."; + string title = _localizationGetter?.Invoke("Forms.FileSavedDialog.Title") ?? "Saved"; + FileSavedDialog.Show(FindForm(), fileName, message, title, key => _localizationGetter?.Invoke(key)); } } @@ -1397,7 +1466,9 @@ private void ExportAnimation(ImageFormat imageFormat) _animation[i].Save(Path.Combine(path, $"{fileName}-{i}.{fileExtension}"), imageFormat); } - FileSavedDialog.Show(FindForm(), path, "InGame Anim saved successfully."); + string message = _localizationGetter?.Invoke("Forms.DressControl.ExportMessages.AnimSaved") ?? "InGame Anim saved successfully."; + string title = _localizationGetter?.Invoke("Forms.FileSavedDialog.Title") ?? "Saved"; + FileSavedDialog.Show(FindForm(), path, message, title, key => _localizationGetter?.Invoke(key)); } private void ExportAnimatedGif(bool looping) @@ -1432,7 +1503,9 @@ private void ExportAnimatedGif(bool looping) stream.WriteByte(0); } - FileSavedDialog.Show(FindForm(), outputFile, "InGame Anim saved successfully."); + string message = _localizationGetter?.Invoke("Forms.DressControl.ExportMessages.AnimSaved") ?? "InGame Anim saved successfully."; + string title = _localizationGetter?.Invoke("Forms.FileSavedDialog.Title") ?? "Saved"; + FileSavedDialog.Show(FindForm(), outputFile, message, title, key => _localizationGetter?.Invoke(key)); } private void OnClickExtractAnimGifLooping(object sender, EventArgs e) { @@ -1706,7 +1779,10 @@ private void OnClickBuildAnimationList(object sender, EventArgs e) tex.WriteLine(" "); } - FileSavedDialog.Show(FindForm(), fileName, "Report saved successfully."); + FileSavedDialog.Show(FindForm(), fileName, + _localizationGetter?.Invoke("Forms.DressControl.ExportMessages.ReportSaved") ?? "Report saved successfully.", + _localizationGetter?.Invoke("Forms.FileSavedDialog.Title") ?? "Saved", + key => _localizationGetter?.Invoke(key)); } private void MountTextBoxOnKeyDown(object sender, KeyEventArgs e) diff --git a/UoFiddler/Forms/MainForm.cs b/UoFiddler/Forms/MainForm.cs index 4a5d09f6..60b3cb83 100644 --- a/UoFiddler/Forms/MainForm.cs +++ b/UoFiddler/Forms/MainForm.cs @@ -79,6 +79,7 @@ public MainForm(ILogger logger) landTilesControl.SetLocalization(key => LocalizationService.GetString(key)); verdataControl.SetLocalization(key => LocalizationService.GetString(key)); skillGroupControl.SetLocalization(key => LocalizationService.GetString(key)); + dressControl.SetLocalization(key => LocalizationService.GetString(key)); // 为 ItemsControl 设置汉化(通过遍历 TabPage 找到) foreach (TabPage tab in TabPanel.TabPages) diff --git a/UoFiddler/Localization/Dictionaries/zh-CN.json b/UoFiddler/Localization/Dictionaries/zh-CN.json index 0bba5819..c03cbe2e 100644 --- a/UoFiddler/Localization/Dictionaries/zh-CN.json +++ b/UoFiddler/Localization/Dictionaries/zh-CN.json @@ -394,17 +394,6 @@ "chkMultiSelect": "多选", "applyHue1ToHue2": "应用色调到左侧" }, - "HuesControl": { - "saveToolStripMenuItem": "保存", - "replaceToolStripMenuItem": "替换为..", - "exportToolStripMenuItem": "导出..", - "importToolStripMenuItem": "导入..", - "exportAllHueNamesListToolStripMenuItem": "导出所有色调名称列表", - "HueIndexToolStripLabel": "索引:", - "HueNameToolStripLabel": "名称:", - "SearchNameToolStripButton": "查找下一个", - "IndexOffsetButton": "显示游戏内数字" - }, "HueEditForm": { "Title": "色调编辑", "ColorPickerButton": "颜色拾取器", @@ -896,39 +885,6 @@ "legendLabelDifferent": "不同值", "legendLabelIdentical": "相同" }, - "LandTilesControl": { - "Title": "地形图块", - "MenuItems": { - "addLandTile": "添加地形图块", - "removeLandTile": "删除地形图块", - "copyLandTile": "复制地形图块", - "pasteLandTile": "粘贴地形图块", - "exportLandTileImage": "导出地形图块图像", - "importLandTileImage": "导入地形图块图像", - "selectAllLandTiles": "全选" - }, - "Labels": { - "detailLabel": "详情", - "idLabel": "ID: ", - "nameLabel": "名称: ", - "graphicLabel": "纹理ID: ", - "flagsLabel": "标志: ", - "statusLabel": "就绪" - }, - "Messages": { - "removeConfirmSingle": "确定要删除该地形图块吗?", - "removeConfirmMultiple": "确定要删除这些地形图块吗?", - "pasteConfirm": "是否确认粘贴?这将覆盖当前条目。", - "SaveConfirmation": "是否保存更改?", - "SaveTitle": "保存确认", - "LandtileSavedTo": "地形图块已保存至", - "Saved": "已保存" - }, - "DetailTextBoxContextMenu": { - "Copy": "复制", - "SelectAll": "全选" - } - }, "CompareTileDataControl": { "btnCopyLandSelected": "复制选定项", "btnCopyLandAllDiff": "复制所有差异", @@ -1128,12 +1084,6 @@ "ImportNoEntriesChanged": "没有条目被更改。" } }, - "FileSavedDialog": { - "Title": "文件已保存", - "SaveSuccess": "文件已成功保存。", - "OpenFolder": "打开文件夹", - "OK": "确定" - }, "TileDataSyncPreviewForm": { "Title": "从 TileData 同步 — 预览", "ColumnAction": "操作", @@ -1147,58 +1097,6 @@ "ApplyButton": "应用", "CancelButton": "取消" }, - "MapControl": { - "ZoomPlus": "+缩放", - "ZoomMinus": "-缩放", - "GetMapInfo": "获取地图信息", - "InsertMarker": "插入标记", - "Goto": "跳转...", - "SendClientToPos": "发送客户端到位置", - "Felucca": "Felucca", - "Trammel": "Trammel", - "Ilshenar": "Ilshenar", - "Malas": "Malas", - "Tokuno": "Tokuno", - "TerMur": "TerMur", - "ExtractMap": "导出地图..", - "AsBmp": "为 BMP", - "AsTiff": "为 TIFF", - "AsJpg": "为 JPG", - "AsPng": "为 PNG", - "GotoMarker": "跳转", - "RemoveMarker": "移除", - "SwitchVisibility": "切换可见性", - "View": "视图", - "ShowStatics": "显示静态物体", - "ShowCenterCross": "显示中心十字", - "ShowMarkers": "显示标记", - "ShowClientCross": "显示客户端十字", - "AltitudeModeNormal": "正常", - "AltitudeModeNormalWithAltitude": "正常 + 高度", - "AltitudeModeAltitude": "高度地图", - "ClientInteract": "客户端交互", - "ShowClientLoc": "显示客户端位置", - "GotoClientLoc": "跳转到客户端位置", - "SendClientToCenter": "发送客户端到中心", - "PreloadMap": "预加载地图", - "Misc": "杂项", - "DefragStatics": "整理静态物体...", - "FreezeStatics": "冻结静态物体..(在内存中)", - "MeltStatics": "融化静态物体..(在内存中)", - "ClearStatics": "清除静态物体..(在内存中)", - "ReportStaticsUnderMap": "报告地图下方的静态物体(可能不可见)", - "ReportInvalidMapIDs": "报告无效地图 ID", - "RewriteMap": "重写地图", - "MapAndStaticsCopy": "地图和静态物体复制...", - "DiffToMapCopy": "差异到地图复制...", - "ReplaceTiles": "替换图块..", - "CoordsLabel": "坐标:", - "ClientLocLabel": "客户端位置:", - "ZoomLabel": "缩放:", - "CoordinatePrefix": "坐标:{0},{1}", - "ClientLocPrefix": "客户端位置:{0},{1}", - "ZoomPrefix": "缩放:{0}%" - }, "MapMarkerForm": { "Title": "添加地图标记", "TextLabel": "文本", @@ -1724,6 +1622,50 @@ "SaveSuccess": "文件保存成功。", "OpenFolder": "打开文件夹", "OK": "确定" + }, + "DressControl": { + "AsJpg": "JPG 格式", + "ExportMessages": { + "PaperdollSaved": "人物模型已成功保存。", + "InGameSaved": "游戏内图像已成功保存。", + "AnimSaved": "动画已成功保存。", + "ReportSaved": "报告已成功保存。" + }, + "FacingActionGroupBox": "方向/动作", + "DressItemButton": "穿戴物品", + "UnDress": "卸下", + "AsTiff": "TIFF 格式", + "ShowAnimation": "显示动画", + "UnDressAll": "卸下全部", + "FindNextItemButton": "查找下一个", + "ItemColumnHeader": "物品", + "FemaleCheckBox": "女性", + "ElfRadio": "精灵", + "ExportAnimation": "导出动画...", + "ExportImage": "导出图像...", + "HumanRadio": "人类", + "ExportReportButton": "导出报告", + "AsAnimatedGifNoLooping": "动画 GIF(非循环)", + "Animate": "动画", + "AsBmp": "BMP 格式", + "MountGroupBox": "坐骑", + "HueEllipsis": "色调...", + "AsPng": "PNG 格式", + "LayerSort": "按层排序", + "AsAnimatedGifLooping": "动画 GIF(循环)", + "Hue": "色调", + "GargoyleRadio": "石像鬼", + "ShowPaperdoll": "显示纸娃娃", + "InfoLabels": { + "ValidGump": "有效Gump", + "ValidAnim": "有效动画", + "ValidLayer": "有效层", + "ObjType": "对象类型", + "Animation": "动画", + "Hue": "色调", + "Layer": "层", + "GumpID": "Gump ID" + } } }, "Ultima": {