From 509dff5b29bbc965507385d7f637fae280d21efb Mon Sep 17 00:00:00 2001 From: nbyaya Date: Sat, 3 Oct 2026 13:34:23 +0800 Subject: [PATCH 01/81] 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/81] 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/81] 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/81] 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/81] 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/81] 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/81] 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/81] 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/81] 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/81] 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/81] 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/81] 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/81] =?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/81] =?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/81] 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/81] 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/81] =?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/81] =?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/81] =?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/81] =?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/81] =?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/81] =?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/81] =?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/81] =?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/81] =?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/81] =?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/81] =?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/81] =?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/81] =?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/81] =?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/81] =?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/81] =?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/81] =?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/81] =?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/81] =?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/81] =?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/81] =?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/81] =?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/81] =?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/81] =?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/81] =?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/81] =?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/81] =?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/81] =?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/81] =?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/81] =?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/81] =?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/81] =?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/81] =?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/81] =?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/81] =?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/81] =?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/81] =?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/81] =?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/81] =?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/81] =?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/81] =?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/81] =?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/81] =?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/81] =?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/81] =?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/81] =?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/81] =?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/81] =?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/81] =?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/81] =?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/81] =?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/81] =?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/81] =?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/81] =?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/81] =?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/81] =?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/81] =?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/81] =?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/81] =?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/81] =?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": { From 8855f34651d592b3abe698b7243e5f72c9719a06 Mon Sep 17 00:00:00 2001 From: nbyaya Date: Thu, 8 Oct 2026 09:33:51 +0800 Subject: [PATCH 77/81] =?UTF-8?q?=E6=B1=89=E5=8C=96=E9=9B=B7=E8=BE=BE?= =?UTF-8?q?=E9=A2=9C=E8=89=B2=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 - UI 元素、MessageBox、下拉菜单、按钮、文本框 - 独立窗口 StrategyHelpForm 完整汉化 - 布局调整 --- .../RadarColorControl.Designer.cs | 2 +- .../UserControls/RadarColorControl.cs | 263 +++++++++++++++--- .../UserControls/RadarColorControl.resx | 3 - UoFiddler/Forms/MainForm.cs | 1 + .../Localization/Dictionaries/zh-CN.json | 95 +++++++ 5 files changed, 328 insertions(+), 36 deletions(-) diff --git a/UoFiddler.Controls/UserControls/RadarColorControl.Designer.cs b/UoFiddler.Controls/UserControls/RadarColorControl.Designer.cs index e046dfbe..cc8a3423 100644 --- a/UoFiddler.Controls/UserControls/RadarColorControl.Designer.cs +++ b/UoFiddler.Controls/UserControls/RadarColorControl.Designer.cs @@ -549,7 +549,7 @@ private void InitializeComponent() // // numericUpDownShortCol // - numericUpDownShortCol.Location = new System.Drawing.Point(50, 22); + numericUpDownShortCol.Location = new System.Drawing.Point(100, 22); numericUpDownShortCol.Margin = new System.Windows.Forms.Padding(4); numericUpDownShortCol.Maximum = new decimal(new int[] { 32767, 0, 0, 0 }); numericUpDownShortCol.Name = "numericUpDownShortCol"; diff --git a/UoFiddler.Controls/UserControls/RadarColorControl.cs b/UoFiddler.Controls/UserControls/RadarColorControl.cs index 7ba310b0..9a7d8b78 100644 --- a/UoFiddler.Controls/UserControls/RadarColorControl.cs +++ b/UoFiddler.Controls/UserControls/RadarColorControl.cs @@ -71,6 +71,9 @@ public RadarColorControl() private ushort _currentColor; private static RadarColorControl _refMarker; private bool _updating; + + // 汉化字段 + private Func? _localizationGetter; private readonly Dictionary _originalItemColors = []; private readonly Dictionary _originalLandColors = []; private Timer _debounceTimer; @@ -488,6 +491,110 @@ private void Reload() } } + // 汉化支持 + public void SetLocalization(Func getLocalized) + { + _localizationGetter = getLocalized; + ApplyLocalization(); + } + + private void ApplyLocalization() + { + if (_localizationGetter == null) return; + + // GroupBox 标题 + groupColor.Text = _localizationGetter("Forms.RadarColorControl.groupColor") ?? "Color preview"; + groupColorValue.Text = _localizationGetter("Forms.RadarColorControl.groupColorValue") ?? "Color value"; + groupSingleTile.Text = _localizationGetter("Forms.RadarColorControl.groupSingleTile") ?? "Single tile"; + groupBatch.Text = _localizationGetter("Forms.RadarColorControl.groupBatch") ?? "Batch"; + groupFile.Text = _localizationGetter("Forms.RadarColorControl.groupFile") ?? "File"; + + // TabPage 标题 + tabPage3.Text = _localizationGetter("Forms.RadarColorControl.tabPageItems") ?? "Items"; + tabPage4.Text = _localizationGetter("Forms.RadarColorControl.tabPageLand") ?? "Land Tiles"; + + // 标签文本 + labelHex.Text = _localizationGetter("Forms.RadarColorControl.labelHex") ?? "Hex:"; + labelRgb.Text = _localizationGetter("Forms.RadarColorControl.labelRgb") ?? "RGB:"; + label1.Text = _localizationGetter("Forms.RadarColorControl.labelItemsProgress") ?? "Items:"; + label2.Text = _localizationGetter("Forms.RadarColorControl.labelLandProgress") ?? "Land:"; + + // 按钮文本 + buttonMean.Text = _localizationGetter("Forms.RadarColorControl.buttonMean") ?? "Average Color"; + buttonRevert.Text = _localizationGetter("Forms.RadarColorControl.buttonRevert") ?? "Revert"; + buttonSaveColor.Text = _localizationGetter("Forms.RadarColorControl.buttonSaveColor") ?? "Save Color"; + buttonSaveFile.Text = _localizationGetter("Forms.RadarColorControl.buttonSaveFile") ?? "Save File"; + buttonRevertAll.Text = _localizationGetter("Forms.RadarColorControl.buttonRevertAll") ?? "Revert All"; + buttonExport.Text = _localizationGetter("Forms.RadarColorControl.buttonExport") ?? "Export.."; + buttonImport.Text = _localizationGetter("Forms.RadarColorControl.buttonImport") ?? "Import.."; + buttonAverageAll.Text = _localizationGetter("Forms.RadarColorControl.buttonAverageAll") ?? "Auto-fill empty entries"; + buttonSelectAllItems.Text = _localizationGetter("Forms.RadarColorControl.buttonSelectAllItems") ?? "Select All"; + buttonSelectNoneItems.Text = _localizationGetter("Forms.RadarColorControl.buttonSelectNoneItems") ?? "Select None"; + buttonSelectAllLand.Text = _localizationGetter("Forms.RadarColorControl.buttonSelectAllLand") ?? "Select All"; + buttonSelectNoneLand.Text = _localizationGetter("Forms.RadarColorControl.buttonSelectNoneLand") ?? "Select None"; + + // 注意:以下三个按钮的文本会在 Selection/Range 模式切换时动态改变 + // 初始化时先设置为 Selection 模式,但会立即被 ApplyBatchButtonLocalization() 覆盖 + buttonCurrentToRangeAverage.Text = _localizationGetter("Forms.RadarColorControl.DynamicButtonTexts.buttonCurrentToRangeAverage_selection") ?? "Current tile to selection average"; + buttonRangeToIndividualAverage.Text = _localizationGetter("Forms.RadarColorControl.DynamicButtonTexts.buttonRangeToIndividualAverage_selection") ?? "Selected tiles to individual average"; + buttonRangeToRangeAverage.Text = _localizationGetter("Forms.RadarColorControl.DynamicButtonTexts.buttonRangeToRangeAverage_selection") ?? "Selected tiles to selection average"; + + // 单选框文本 + radioUseSelection.Text = _localizationGetter("Forms.RadarColorControl.radioUseSelection") ?? "Selection / Checked tiles"; + radioUseRange.Text = _localizationGetter("Forms.RadarColorControl.radioUseRange") ?? "Range:"; + + // 动态按钮文本(初始化为 Selection 模式) + bool useSelection = radioUseSelection.Checked; + ApplyBatchButtonLocalization(useSelection); + + // 菜单项文本 + selectInItemsTabToolStripMenuItem.Text = _localizationGetter("Forms.RadarColorControl.selectInItemsTabToolStripMenuItem") ?? "Select in Items tab"; + selectInTiledataTabToolStripMenuItem.Text = _localizationGetter("Forms.RadarColorControl.selectInTiledataTabToolStripMenuItem") ?? "Select in Tiledata tab"; + setAsRangeFromToolStripMenuItem.Text = _localizationGetter("Forms.RadarColorControl.setAsRangeFromToolStripMenuItem") ?? "Set as Range \"from\""; + setAsRangeToToolStripMenuItem.Text = _localizationGetter("Forms.RadarColorControl.setAsRangeToToolStripMenuItem") ?? "Set as Range \"to\""; + toolStripMenuItem1.Text = _localizationGetter("Forms.RadarColorControl.toolStripMenuItem1") ?? "Select in Landtiles tab"; + toolStripMenuItem2.Text = _localizationGetter("Forms.RadarColorControl.toolStripMenuItem2") ?? "Select in Tiledata tab"; + setAsRangeFromToolStripMenuItem1.Text = _localizationGetter("Forms.RadarColorControl.setAsRangeFromToolStripMenuItem1") ?? "Set as Range \"from\""; + setAsRangeToToolStripMenuItem1.Text = _localizationGetter("Forms.RadarColorControl.setAsRangeToToolStripMenuItem1") ?? "Set as Range \"to\""; + changeBackgroundColorToolStripMenuItem.Text = _localizationGetter("Forms.RadarColorControl.changeBackgroundColorToolStripMenuItem") ?? "Change background color"; + + // 文本框占位符 + textBoxMeanFrom.PlaceholderText = _localizationGetter("Forms.RadarColorControl.textBoxMeanFromPlaceholder") ?? "from"; + textBoxMeanTo.PlaceholderText = _localizationGetter("Forms.RadarColorControl.textBoxMeanToPlaceholder") ?? "to"; + + // Filter 文本框占位符 + textFilterItems.PlaceholderText = _localizationGetter("Forms.RadarColorControl.textFilterItems") ?? "Filter"; + textFilterLand.PlaceholderText = _localizationGetter("Forms.RadarColorControl.textFilterLand") ?? "Filter"; + + // Tooltip + toolTip.SetToolTip(buttonStrategyHelp, + _localizationGetter("Forms.RadarColorControl.toolTipStrategyHelp") ?? "About these averaging strategies"); + } + + private void ApplyBatchButtonLocalization(bool useSelection) + { + if (_localizationGetter == null) return; + + if (useSelection) + { + buttonCurrentToRangeAverage.Text = _localizationGetter("Forms.RadarColorControl.DynamicButtonTexts.buttonCurrentToRangeAverage_selection") + ?? "Current tile to selection average"; + buttonRangeToIndividualAverage.Text = _localizationGetter("Forms.RadarColorControl.DynamicButtonTexts.buttonRangeToIndividualAverage_selection") + ?? "Selected tiles to individual average"; + buttonRangeToRangeAverage.Text = _localizationGetter("Forms.RadarColorControl.DynamicButtonTexts.buttonRangeToRangeAverage_selection") + ?? "Selected tiles to selection average"; + } + else + { + buttonCurrentToRangeAverage.Text = _localizationGetter("Forms.RadarColorControl.DynamicButtonTexts.buttonCurrentToRangeAverage_range") + ?? "Current tile to range average"; + buttonRangeToIndividualAverage.Text = _localizationGetter("Forms.RadarColorControl.DynamicButtonTexts.buttonRangeToIndividualAverage_range") + ?? "Range tiles to individual average"; + buttonRangeToRangeAverage.Text = _localizationGetter("Forms.RadarColorControl.DynamicButtonTexts.buttonRangeToRangeAverage_range") + ?? "Range tiles to range average"; + } + } + public void OnLoad(object sender, EventArgs e) { if (IsAncestorSiteInDesignMode || FormsDesignerHelper.IsInDesignMode()) @@ -539,7 +646,7 @@ private void PopulateMeanStrategyCombo() comboMeanStrategy.BeginUpdate(); foreach (RadarAveragingStrategy s in RadarColorAveraging.All) { - comboMeanStrategy.Items.Add(new MeanStrategyItem(s)); + comboMeanStrategy.Items.Add(new MeanStrategyItem(s, _localizationGetter)); } // Select the persisted/runtime strategy. for (int i = 0; i < comboMeanStrategy.Items.Count; ++i) @@ -560,8 +667,29 @@ private void PopulateMeanStrategyCombo() private sealed class MeanStrategyItem { public RadarAveragingStrategy Strategy { get; } - public MeanStrategyItem(RadarAveragingStrategy s) { Strategy = s; } - public override string ToString() => RadarColorAveraging.DisplayName(Strategy); + private readonly Func? _localizationGetter; + + public MeanStrategyItem(RadarAveragingStrategy s, Func? localizationGetter = null) + { + Strategy = s; + _localizationGetter = localizationGetter; + } + + public override string ToString() + { + // DEBUG: 打印枚举名称用于调试 + string enumName = Strategy.ToString(); + + if (_localizationGetter != null) + { + string localizedName = _localizationGetter($"Forms.RadarColorControl.AveragingStrategies.{enumName}"); + if (!string.IsNullOrEmpty(localizedName)) + { + return localizedName; + } + } + return RadarColorAveraging.DisplayName(Strategy); + } } private RadarAveragingStrategy CurrentStrategy => @@ -577,7 +705,7 @@ private void OnSelectedMeanStrategyChanged(object sender, EventArgs e) private void OnClickStrategyHelp(object sender, EventArgs e) { - using var dlg = new StrategyHelpForm(); + using var dlg = new StrategyHelpForm(_localizationGetter); dlg.ShowDialog(FindForm()); } @@ -586,9 +714,13 @@ private void OnClickStrategyHelp(object sender, EventArgs e) // to the code that defines the strategies. private sealed class StrategyHelpForm : Form { - public StrategyHelpForm() + private readonly Func? _localizationGetter; + + public StrategyHelpForm(Func? localizationGetter = null) { - Text = "Radar color — averaging strategies"; + _localizationGetter = localizationGetter; + + Text = _localizationGetter?.Invoke("Forms.StrategyHelpForm.Title") ?? "Radar color — averaging strategies"; FormBorderStyle = FormBorderStyle.Sizable; StartPosition = FormStartPosition.CenterParent; MinimumSize = new Size(560, 400); @@ -605,12 +737,12 @@ public StrategyHelpForm() WordWrap = true, Dock = DockStyle.Fill, Font = new Font(FontFamily.GenericSansSerif, 9f), - Text = HelpText, + Text = GetHelpText(), TabStop = false, }; var ok = new Button { - Text = "Close", + Text = _localizationGetter?.Invoke("Forms.StrategyHelpForm.CloseButton") ?? "Close", DialogResult = DialogResult.OK, Dock = DockStyle.Bottom, Height = 32, @@ -640,6 +772,19 @@ protected override void OnShown(EventArgs e) } } + private string GetHelpText() + { + if (_localizationGetter != null) + { + var helpText = _localizationGetter("Forms.StrategyHelpForm.HelpText"); + if (!string.IsNullOrEmpty(helpText)) + { + return helpText; + } + } + return HelpText; + } + private const string HelpText = "Radar color averaging strategies\r\n" + "================================\r\n\r\n" + @@ -860,7 +1005,10 @@ private void OnClickSaveFile(object sender, EventArgs e) Options.ChangedUltimaClass["RadarCol"] = false; - FileSavedDialog.Show(FindForm(), fileName, "RadarCol saved successfully."); + string message = _localizationGetter("Forms.RadarColorControl.Messages.RadarColSaved") + ?? "RadarCol saved successfully."; + string title = _localizationGetter("Forms.FileSavedDialog.Title") ?? "Saved"; + FileSavedDialog.Show(FindForm(), fileName, message, title, key => _localizationGetter(key)); } private void SaveColor() @@ -900,11 +1048,12 @@ private void SaveColor(int index, ushort color, bool isItemTile) private void OnClickRevertAll(object sender, EventArgs e) { - DialogResult result = MessageBox.Show( - "Do you want to revert all changes to items and land tiles?", - "Revert All", - MessageBoxButtons.YesNo - ); + string message = _localizationGetter("Forms.RadarColorControl.Messages.ConfirmRevertAll") + ?? "Do you want to revert all changes to items and land tiles?"; + string title = _localizationGetter("Forms.RadarColorControl.MessageBoxTitles.RevertAll") + ?? "Revert All"; + + DialogResult result = MessageBox.Show(message, title, MessageBoxButtons.YesNo); if (result != DialogResult.Yes) { @@ -1076,7 +1225,11 @@ private IEnumerable GetValidSequence() if (!Utils.ConvertStringToInt(textBoxMeanFrom.Text, out int from, 0, maxIndex) || !Utils.ConvertStringToInt(textBoxMeanTo.Text, out int to, 0, maxIndex)) { - MessageBox.Show($"Invalid parameters. Expected [to, from] between [0, {maxIndex} (0x{maxIndex:X4})]", "Error", MessageBoxButtons.OK); + string message = _localizationGetter("Forms.RadarColorControl.Messages.InvalidParametersRange") + ?? $"Invalid parameters. Expected [to, from] between [0, {maxIndex} (0x{maxIndex:X4})]"; + string title = _localizationGetter("Forms.RadarColorControl.MessageBoxTitles.Error") + ?? "Error"; + MessageBox.Show(string.Format(message, maxIndex), title, MessageBoxButtons.OK); return null; } @@ -1092,7 +1245,11 @@ private IEnumerable GetValidSequence() var sequence = isItem ? _selectedItems : _selectedLand; if (sequence.Count == 0) { - MessageBox.Show("Invalid parameters. No tiles selected/checked.", "Error", MessageBoxButtons.OK); + string message = _localizationGetter("Forms.RadarColorControl.Messages.InvalidParametersNoSelection") + ?? "Invalid parameters. No tiles selected/checked."; + string title = _localizationGetter("Forms.RadarColorControl.MessageBoxTitles.Error") + ?? "Error"; + MessageBox.Show(message, title, MessageBoxButtons.OK); return null; } return sequence; @@ -1228,7 +1385,11 @@ private void OnClickSelectItemsTab(object sender, EventArgs e) var found = ItemsControl.SearchGraphic(index); if (!found) { - MessageBox.Show("You need to load Items tab first.", "Information"); + string message = _localizationGetter("Forms.RadarColorControl.Messages.ItemsTabNotLoaded") + ?? "You need to load Items tab first."; + string title = _localizationGetter("Forms.RadarColorControl.MessageBoxTitles.Information") + ?? "Information"; + MessageBox.Show(message, title); } } @@ -1254,7 +1415,11 @@ private void OnClickSelectLandTilesTab(object sender, EventArgs e) var found = LandTilesControl.SearchGraphic(index); if (!found) { - MessageBox.Show("You need to load LandTiles tab first.", "Information"); + string message = _localizationGetter("Forms.RadarColorControl.Messages.LandTilesTabNotLoaded") + ?? "You need to load LandTiles tab first."; + string title = _localizationGetter("Forms.RadarColorControl.MessageBoxTitles.Information") + ?? "Information"; + MessageBox.Show(message, title); } } @@ -1309,16 +1474,20 @@ private void OnClickExport(object sender, EventArgs e) string fileName = Path.Combine(path, "RadarColor.csv"); RadarCol.ExportToCSV(fileName); - FileSavedDialog.Show(FindForm(), fileName, "RadarColor saved successfully."); + string message = _localizationGetter("Forms.RadarColorControl.Messages.RadarColorSaved") + ?? "RadarColor saved successfully."; + string title = _localizationGetter("Forms.FileSavedDialog.Title") ?? "Saved"; + FileSavedDialog.Show(FindForm(), fileName, message, title, key => _localizationGetter(key)); } private void OnClickMeanColorAll(object sender, EventArgs e) { - DialogResult result = MessageBox.Show( - "Do you want to calculate and set new radar color values for all items and land tiles entries where current color is black or missing?", - "Average All", - MessageBoxButtons.YesNo - ); + string message = _localizationGetter("Forms.RadarColorControl.Messages.ConfirmAutoFillEmpty") + ?? "Do you want to calculate and set new radar color values for all items and land tiles entries where current color is black or missing?"; + string title = _localizationGetter("Forms.RadarColorControl.MessageBoxTitles.AverageAll") + ?? "Average All"; + + DialogResult result = MessageBox.Show(message, title, MessageBoxButtons.YesNo); if (result != DialogResult.Yes) { @@ -1384,7 +1553,10 @@ private void OnClickMeanColorAll(object sender, EventArgs e) } } - MessageBox.Show("Done!", "Average All"); + MessageBox.Show( + _localizationGetter("Forms.RadarColorControl.Messages.OperationDone") ?? "Done!", + _localizationGetter("Forms.RadarColorControl.MessageBoxTitles.AverageAll") ?? "Average All" + ); progressBar1.Value = 0; progressBar2.Value = 0; @@ -1515,18 +1687,44 @@ private void OnCheckedChangeUseSelection(object sender, EventArgs e) { textBoxMeanFrom.Enabled = false; textBoxMeanTo.Enabled = false; - buttonRangeToRangeAverage.Text = "Selected tiles to selection average"; - buttonRangeToIndividualAverage.Text = "Selected tiles to individual average"; - buttonCurrentToRangeAverage.Text = "Current tile to selection average"; + + if (_localizationGetter != null) + { + buttonRangeToRangeAverage.Text = _localizationGetter("Forms.RadarColorControl.DynamicButtonTexts.buttonRangeToRangeAverage_selection") + ?? "Selected tiles to selection average"; + buttonRangeToIndividualAverage.Text = _localizationGetter("Forms.RadarColorControl.DynamicButtonTexts.buttonRangeToIndividualAverage_selection") + ?? "Selected tiles to individual average"; + buttonCurrentToRangeAverage.Text = _localizationGetter("Forms.RadarColorControl.DynamicButtonTexts.buttonCurrentToRangeAverage_selection") + ?? "Current tile to selection average"; + } + else + { + buttonRangeToRangeAverage.Text = "Selected tiles to selection average"; + buttonRangeToIndividualAverage.Text = "Selected tiles to individual average"; + buttonCurrentToRangeAverage.Text = "Current tile to selection average"; + } } private void OnCheckedChangeUseRange(object sender, EventArgs e) { textBoxMeanFrom.Enabled = true; textBoxMeanTo.Enabled = true; - buttonRangeToRangeAverage.Text = "Range tiles to range average"; - buttonRangeToIndividualAverage.Text = "Range tiles to individual average"; - buttonCurrentToRangeAverage.Text = "Current tile to range average"; + + if (_localizationGetter != null) + { + buttonRangeToRangeAverage.Text = _localizationGetter("Forms.RadarColorControl.DynamicButtonTexts.buttonRangeToRangeAverage_range") + ?? "Range tiles to range average"; + buttonRangeToIndividualAverage.Text = _localizationGetter("Forms.RadarColorControl.DynamicButtonTexts.buttonRangeToIndividualAverage_range") + ?? "Range tiles to individual average"; + buttonCurrentToRangeAverage.Text = _localizationGetter("Forms.RadarColorControl.DynamicButtonTexts.buttonCurrentToRangeAverage_range") + ?? "Current tile to range average"; + } + else + { + buttonRangeToRangeAverage.Text = "Range tiles to range average"; + buttonRangeToIndividualAverage.Text = "Range tiles to individual average"; + buttonCurrentToRangeAverage.Text = "Current tile to range average"; + } } private void OnClickSelectAllLand(object sender, EventArgs e) @@ -1659,7 +1857,8 @@ private void OnClickAlgorithmBenchmark(object sender, EventArgs e) $" item : {item.Exact[bestIdx]}/{item.Counted[bestIdx]} " + $"({(item.Counted[bestIdx] == 0 ? 0 : 100.0 * item.Exact[bestIdx] / item.Counted[bestIdx]):F2}%)\n\n" + $"Full report: {outPath}"; - MessageBox.Show(FindForm(), summary, "Algorithm benchmark"); + MessageBox.Show(FindForm(), summary, + _localizationGetter("Forms.RadarColorControl.MessageBoxTitles.AlgorithmBenchmark") ?? "Algorithm benchmark"); } private sealed class BenchStats diff --git a/UoFiddler.Controls/UserControls/RadarColorControl.resx b/UoFiddler.Controls/UserControls/RadarColorControl.resx index f7497ab1..699e61c6 100644 --- a/UoFiddler.Controls/UserControls/RadarColorControl.resx +++ b/UoFiddler.Controls/UserControls/RadarColorControl.resx @@ -129,9 +129,6 @@ 17, 17 - - 17, 17 - 316, 17 diff --git a/UoFiddler/Forms/MainForm.cs b/UoFiddler/Forms/MainForm.cs index 60b3cb83..cc0211ad 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)); + radarColControl.SetLocalization(key => LocalizationService.GetString(key)); skillGroupControl.SetLocalization(key => LocalizationService.GetString(key)); dressControl.SetLocalization(key => LocalizationService.GetString(key)); diff --git a/UoFiddler/Localization/Dictionaries/zh-CN.json b/UoFiddler/Localization/Dictionaries/zh-CN.json index c03cbe2e..fad92d5c 100644 --- a/UoFiddler/Localization/Dictionaries/zh-CN.json +++ b/UoFiddler/Localization/Dictionaries/zh-CN.json @@ -1666,6 +1666,101 @@ "Layer": "层", "GumpID": "Gump ID" } + }, + "RadarColorControl": { + "selectInItemsTabToolStripMenuItem": "在 Items 标签页中选择", + "selectInTiledataTabToolStripMenuItem": "在 TileData 标签页中选择", + "setAsRangeFromToolStripMenuItem": "设置为范围\"起点\"", + "setAsRangeToToolStripMenuItem": "设置为范围\"终点\"", + "toolStripMenuItem1": "在 LandTiles 标签页中选择", + "toolStripMenuItem2": "在 TileData 标签页中选择", + "changeBackgroundColorToolStripMenuItem": "更改背景颜色", + "buttonSelectAllItems": "全选", + "buttonSelectNoneItems": "取消全选", + "buttonMean": "平均颜色", + "buttonRevert": "恢复", + "buttonStrategyHelp": "帮助", + "buttonSaveColor": "保存颜色", + "buttonCurrentToRangeAverage": "当前图形 → 选中集合平均", + "buttonRangeToIndividualAverage": "选中图形 → 单个平均", + "buttonRangeToRangeAverage": "选中图形 → 集合平均", + "buttonSaveFile": "保存文件", + "buttonRevertAll": "全部恢复", + "buttonExport": "导出...", + "buttonImport": "导入...", + "buttonAverageAll": "自动填充空项", + "groupColor": "颜色预览", + "groupColorValue": "颜色值", + "groupSingleTile": "单个图形", + "groupBatch": "批量处理", + "groupFile": "文件", + "labelHex": "十六进制:", + "labelRgb": "RGB:", + "label4": "→", + "labelItemsProgress": "物品:", + "labelLandProgress": "地形:", + "tabPageItems": "物品", + "tabPageLand": "地形", + "textFilterItems": "筛选", + "textFilterLand": "筛选", + "textBoxMeanFrom": "从", + "textBoxMeanTo": "至", + "textBoxMeanFromPlaceholder": "从", + "textBoxMeanToPlaceholder": "至", + "radioUseSelection": "选中的图形", + "radioUseRange": "范围:", + "toolTipStrategyHelp": "关于这些平均策略", + "Messages": { + "InvalidParametersRange": "参数无效。期望 [终点, 起点] 在 [0, {0}] 之间", + "InvalidParametersNoSelection": "参数无效。未选中任何图形。", + "ItemsTabNotLoaded": "需要先加载 Items 标签页。", + "LandTilesTabNotLoaded": "需要先加载 LandTiles 标签页。", + "ConfirmRevertAll": "确定要恢复所有物品和地形图形的修改吗?", + "ConfirmAutoFillEmpty": "确定要为所有黑色或缺失颜色的物品和地形图形条目计算并设置新的雷达颜色吗?", + "OperationDone": "完成!", + "RadarColorSaved": "雷达颜色保存成功。", + "RadarColSaved": "RadarCol 保存成功。" + }, + "AveragingStrategies": { + "Mean5": "均值 (5 位)", + "Mean8Shift": "均值 (8 位, >>3 打包)", + "Mean5Rounded": "均值 (5 位, 四舍五入)", + "Mean5RoundedIncludeAlpha": "均值 (5 位, 四舍五入, 含透明)", + "Mean5BankersRound": "均值 (5 位, 银行家舍入)", + "Mean5RoundedNoOutline": "均值 (5 位, 四舍五入, 无轮廓)", + "SnapToLandPalette": "对齐地形调色板", + "SnapToItemPalette": "对齐物品调色板", + "MeanRounded": "均值 (8 位, 四舍五入打包)", + "MeanLinear": "均值 (线性光)", + "Mode16": "众数 (主导像素)", + "MedianPerChannel": "每通道中位数", + "MeanNoOutline": "均值 (无轮廓)", + "Legacy": "旧版 (UOFiddler)" + }, + "DynamicButtonTexts": { + "buttonCurrentToRangeAverage_selection": "当前图形 → 选中集合平均", + "buttonCurrentToRangeAverage_range": "当前图形 → 范围平均", + "buttonRangeToIndividualAverage_selection": "选中图形 → 单个平均", + "buttonRangeToIndividualAverage_range": "范围内图形 → 单个平均", + "buttonRangeToRangeAverage_selection": "选中图形 → 集合平均", + "buttonRangeToRangeAverage_range": "范围内图形 → 范围平均" + }, + "MessageBoxTitles": { + "Error": "错误", + "Information": "信息", + "RevertAll": "全部恢复", + "AverageAll": "自动填充", + "AlgorithmBenchmark": "算法基准测试" + }, + "buttonSelectAllLand": "全选", + "buttonSelectNoneLand": "取消全选", + "setAsRangeFromToolStripMenuItem1": "设置为范围\"起点\"", + "setAsRangeToToolStripMenuItem1": "设置为范围\"终点\"" + }, + "StrategyHelpForm": { + "Title": "雷达颜色 — 平均策略", + "CloseButton": "关闭", + "HelpText": "雷达颜色平均策略\r\n================================\r\n\r\nradarcol.mul 中的每个条目都是一个 16 位 (RGB555) 颜色,用于渲染世界地图。当你点击\"平均颜色\"时,UOFiddler 会从图块的像素计算该颜色。有多种方法来计算平均值;它们在四舍五入、源像素选择和色彩空间方面有所不同。\r\n\r\n基准测试的发现\r\n-------------------------------\r\n每种策略都针对 radarcol.mul 中的值进行了评分。发现如下:\r\n\r\n - 产生文件值的 24->15 位缩放使用位移 (>>3),而不是旧版本 UOFiddler 使用的 *31/255 四舍五入。\r\n\r\n - 对于物品 (静态):值可以通过对图块 5 位像素的按通道算术平均(四舍五入)再现。\"均值 (5 位, 银行家舍入)\" 在约 96.6% 的 13,771 个物品条目上与文件逐字节匹配;余数是小于 1 步的误差。\r\n\r\n - 对于地形图块:4,239 个活跃条目总共只使用约 103 个独特颜色。这是手工调整的地形调色板,不是计算结果。没有像素平均算法与超过约 10% 的地形条目匹配。\"对齐地形调色板\"从文件中已有的颜色中选择最接近的,保持地形的连贯性。\r\n\r\n黄金标准 (推荐默认值)\r\n------------------------------------\r\n - 物品标签页 -> 均值 (5 位, 银行家舍入) [实际默认值]\r\n - 地形标签页 -> 对齐地形调色板\r\n\r\n切换标签页时手动切换下拉列表;选择在此会话中保持不变。\r\n\r\n详细策略\r\n--------------------\r\n\r\n均值 (5 位)\r\n 提取每个非透明像素的 5 位 R/G/B,求和,除以计数(截断)。简单但每通道有约半步的深色偏差。物品匹配约 13%。\r\n\r\n均值 (5 位, 四舍五入)\r\n 与均值 (5 位) 相同,但使用四舍五入 ((sum + n/2) / n)。物品匹配 96.4%。\r\n\r\n均值 (5 位, 银行家舍入) [默认]\r\n 相同,但使用银行家舍入 (四舍五入到最近的偶数)。经验上的赢家:物品匹配 96.6%。\r\n\r\n均值 (5 位, 四舍五入, 含透明)\r\n 在除数中包含透明像素 (值 0)。将平均值拖向 0;仅用于诊断。\r\n\r\n均值 (8 位, >>3 打包)\r\n 将每个 5 位像素扩展到 8 位 (通过 (c<<3)|(c>>2)),在 8 位空间中平均,然后用位移打包回 555。中间结果:物品匹配约 42%。\r\n\r\n均值 (8 位, 四舍五入打包)\r\n 与均值 (8 位) 相同,但用 ((c*31+127)/255) 打包。匹配约 69%。\r\n\r\n均值 (5 位, 四舍五入, 无轮廓)\r\n 在平均前排除接近黑色的像素 (5 位 Y < 2)。测试 90 年代精灵的常见技巧。实际上比四舍五入平均值更差 (约 44%)。\r\n\r\n均值 (线性光)\r\n 将 sRGB 伽马校正为线性 (x*x),平均,然后回到 sRGB。对照组;1997 年的美术管道几乎肯定没有伽马感知。低匹配率 (约 11%)。\r\n\r\n众数 (主导像素)\r\n 返回最常见的单个非透明像素。对于非常均匀的图块很有用,其他地方则很嘈杂。匹配约 5%。\r\n\r\n每通道中位数\r\n 在 5 位空间中独立的每通道中位数。对异常值稳健,但与文件值不匹配 (约 15%)。\r\n\r\n均值 (无轮廓)\r\n 纯 5 位截断平均值,带轮廓拒绝。(约 19%。)\r\n\r\n对齐地形调色板\r\n 计算银行家舍入 5 位平均值,然后将结果对齐到 radarcol.mul 中已有的约 103 个地形颜色中最接近的一个 (5 位欧几里得距离)。当你希望新的/编辑的地形图块看起来像邻近图块而不是产生自由形式颜色时的正确选择。\r\n\r\n对齐物品调色板\r\n 类似于对齐地形调色板,但使用约 2,200 个独特物品颜色。对物品的用处较小 (它们的值是真正计算出来的);为对称而保留。\r\n\r\n旧版 (UOFiddler)\r\n 逐位再现 UOFiddler 的早期行为:在 *31/255 截断 8 位空间中平均,用相同的截断重新打包。仅与约 1.9% 的文件值匹配。为了与较旧的 UOFiddler 版本保持连续性而保留。\r\n\r\n透明度和限制\r\n-----------------------\r\n所有策略 (除了\"含透明\") 都跳过等于 0 的像素 (透明)。限制规则应用于输出:如果所有分量缩放为 0 但输入非零,强制该通道为 1。纯黑不透明像素不能在 24->15 位缩放中幸存;它们在运行时和我们的平均中都显示为透明。\r\n\r\n工具\r\n-----\r\n - 在调试版本中,此控件上的\"算法基准 (CSV)\"按钮针对加载的 radarcol.mul 运行每个策略,并将每个策略的报告写入 Options.OutputPath\\radarcol_eval.csv。\r\n" } }, "Ultima": { From 797c12b6add6a4b5f1e37b4960488f4039be9c2d Mon Sep 17 00:00:00 2001 From: nbyaya Date: Thu, 8 Oct 2026 12:03:25 +0800 Subject: [PATCH 78/81] =?UTF-8?q?=E6=B1=89=E5=8C=96=20TileDataControl=20?= =?UTF-8?q?=E5=8F=8A=E7=9B=B8=E5=85=B3=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 - TileDataControl 汉化(60+ 项:菜单、标签、工具栏、消息) - TileDataHelpForm 汉化(63 个标志项 + 描述) - TileDataFilterForm 汉化(14 个过滤字段标签) - 总计 90+ 条目,测试通过 --- .../Forms/TileDataFilterForm.cs | 131 +++- UoFiddler.Controls/Forms/TileDataHelpForm.cs | 299 ++++----- .../Localization/Dictionaries/zh-CN.json | 565 ++++++++++++++++++ 3 files changed, 858 insertions(+), 137 deletions(-) diff --git a/UoFiddler.Controls/Forms/TileDataFilterForm.cs b/UoFiddler.Controls/Forms/TileDataFilterForm.cs index 830d2c78..278d9209 100644 --- a/UoFiddler.Controls/Forms/TileDataFilterForm.cs +++ b/UoFiddler.Controls/Forms/TileDataFilterForm.cs @@ -10,6 +10,7 @@ ***************************************************************************/ using System; +using System.Collections.Generic; using System.Windows.Forms; using Ultima; using UoFiddler.Controls.Classes; @@ -20,6 +21,7 @@ public partial class TileDataFilterForm : Form { private readonly Action _applyItemFilterAction; private readonly Action _applyLandFilterAction; + private Func? _localizationGetter; public TileDataFilterForm(Action applyItemFilterAction, Action applyLandFilterAction) { @@ -32,6 +34,125 @@ public TileDataFilterForm(Action applyItemFilterAction, Action + /// 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.TileDataFilterForm.Title"); + if (title != null) + Text = title; + + // Localize tab pages - look for TabPage controls named tabPageItems and tabPageLand + foreach (TabPage page in tabcontrol.TabPages) + { + if (page.Name == "tabPageItems") + { + var itemsTab = _localizationGetter("Forms.TileDataFilterForm.ItemsTab"); + if (itemsTab != null) + page.Text = itemsTab; + } + else if (page.Name == "tabPageLand") + { + var landTab = _localizationGetter("Forms.TileDataFilterForm.LandTab"); + if (landTab != null) + page.Text = landTab; + } + } + + // Map textbox names to their corresponding label names and JSON keys + // The label names are defined in Designer.cs (e.g., label1, label2, etc.) + var textboxToLabelName = new Dictionary + { + { "textBoxName", ("label1", "Forms.TileDataFilterForm.Labels.Name") }, + { "textBoxAnim", ("label2", "Forms.TileDataFilterForm.Labels.Anim") }, + { "textBoxWeight", ("label3", "Forms.TileDataFilterForm.Labels.Weight") }, + { "textBoxQuality", ("label4", "Forms.TileDataFilterForm.Labels.Quality") }, + { "textBoxQuantity", ("label5", "Forms.TileDataFilterForm.Labels.Quantity") }, + { "textBoxHue", ("label8", "Forms.TileDataFilterForm.Labels.Hue") }, + { "textBoxStackOff", ("label7", "Forms.TileDataFilterForm.Labels.StackOff") }, + { "textBoxValue", ("label6", "Forms.TileDataFilterForm.Labels.Value") }, + { "textBoxHeigth", ("label11", "Forms.TileDataFilterForm.Labels.Height") }, // label11.Text = "Heigth" (typo in Designer) + { "textBoxUnk1", ("label10", "Forms.TileDataFilterForm.Labels.MiscData") }, + { "textBoxUnk2", ("label9", "Forms.TileDataFilterForm.Labels.Unk2") }, + { "textBoxUnk3", ("label12", "Forms.TileDataFilterForm.Labels.Unk3") }, + { "textBoxNameLand", ("label23", "Forms.TileDataFilterForm.Labels.NameLand") }, + { "textBoxTexID", ("label24", "Forms.TileDataFilterForm.Labels.TexID") } + }; + + // Create a map of label names to controls for quick lookup + var labelMap = new Dictionary(); + foreach (Control control in GetAllControls(this)) + { + if (control is Label && !string.IsNullOrEmpty(control.Name)) + { + labelMap[control.Name] = control; + } + } + + // Now apply localizations to each label based on its mapped textbox + foreach (var textbox in textboxToLabelName) + { + if (labelMap.TryGetValue(textbox.Value.labelName, out Control? labelControl)) + { + if (labelControl is Label label) + { + var localized = _localizationGetter(textbox.Value.jsonKey); + if (localized != null) + label.Text = localized; + } + } + } + + // Localize buttons + foreach (Control control in GetAllControls(this)) + { + if (control is Button button) + { + if (button.Text == "Apply Filter" || button.Text == "应用过滤器") + { + var applyButton = _localizationGetter("Forms.TileDataFilterForm.ApplyButton"); + if (applyButton != null) + button.Text = applyButton; + } + else if (button.Text == "Reset Filter" || button.Text == "重置过滤器") + { + var resetButton = _localizationGetter("Forms.TileDataFilterForm.ResetButton"); + if (resetButton != null) + button.Text = resetButton; + } + } + } + + // Re-initialize flag checkboxes with localized names + InitFlagCheckBoxes(); + } + + /// + /// Helper method to recursively get all controls. + /// + private IEnumerable GetAllControls(Control container) + { + foreach (Control control in container.Controls) + { + yield return control; + foreach (Control child in GetAllControls(control)) + yield return child; + } + } + private void InitFlagCheckBoxes() { string[] enumNames = Enum.GetNames(typeof(TileFlag)); @@ -42,7 +163,10 @@ private void InitFlagCheckBoxes() checkedListBox1.Items.Clear(); for (int i = 1; i < maxLength; ++i) { - checkedListBox1.Items.Add(enumNames[i], false); + string flagName = enumNames[i]; + // 获取汉化文本,如果没有就用原始英文 + string displayName = _localizationGetter?.Invoke($"Forms.TileDataControl.TileFlags.{flagName}") ?? flagName; + checkedListBox1.Items.Add(displayName, false); } checkedListBox1.EndUpdate(); @@ -51,7 +175,10 @@ private void InitFlagCheckBoxes() checkedListBox2.Items.Clear(); for (int i = 1; i < maxLength; ++i) { - checkedListBox2.Items.Add(enumNames[i], false); + string flagName = enumNames[i]; + // 获取汉化文本,如果没有就用原始英文 + string displayName = _localizationGetter?.Invoke($"Forms.TileDataControl.TileFlags.{flagName}") ?? flagName; + checkedListBox2.Items.Add(displayName, false); } checkedListBox2.EndUpdate(); } diff --git a/UoFiddler.Controls/Forms/TileDataHelpForm.cs b/UoFiddler.Controls/Forms/TileDataHelpForm.cs index dc4bbf60..1f3ab14a 100644 --- a/UoFiddler.Controls/Forms/TileDataHelpForm.cs +++ b/UoFiddler.Controls/Forms/TileDataHelpForm.cs @@ -9,6 +9,7 @@ * ***************************************************************************/ +using System; using System.Drawing; using System.Text; using System.Windows.Forms; @@ -18,155 +19,183 @@ namespace UoFiddler.Controls.Forms { public partial class TileDataHelpForm : Form { + private Func? _localizationGetter; + public TileDataHelpForm() { InitializeComponent(); PopulateFields(); } + public void SetLocalization(Func getLocalized) + { + _localizationGetter = getLocalized; + ApplyLocalization(); + } + + private void ApplyLocalization() + { + if (_localizationGetter == null) return; + + this.Text = _localizationGetter("Forms.TileDataHelpForm.Title") ?? "TileData Help"; + + // Localize column header + var fieldHeader = _localizationGetter("Forms.TileDataHelpForm.FieldColumnHeader") ?? "Field"; + _columnField.Text = fieldHeader; + + // Localize Close button + var closeButton = _localizationGetter("Forms.TileDataHelpForm.CloseButton") ?? "Close"; + _btnClose.Text = closeButton; + + // Clear and re-populate with localized content + _listView.Items.Clear(); + PopulateFields(); + } + private void PopulateFields() { - AddHeader("Editing many entries"); - Add("Multi-select", - "Ctrl+click and Shift+click select several entries at once. The right hand pane keeps showing the entry " - + "you picked last, and 'Save Changes' writes to every selected entry.", + // Helper function to get localized text + Func GetLocalized = (string key) => + { + return _localizationGetter?.Invoke(key) ?? null; + }; + + // Editing many entries section + AddHeader(GetLocalized("Forms.TileDataHelpForm.EditingManyEntries.Title") ?? "Editing many entries"); + Add(GetLocalized("Forms.TileDataHelpForm.EditingManyEntries.MultiSelect.Title") ?? "Multi-select", + GetLocalized("Forms.TileDataHelpForm.EditingManyEntries.MultiSelect.Description") + ?? "Ctrl+click and Shift+click select several entries at once. The right hand pane keeps showing the entry you picked last, and 'Save Changes' writes to every selected entry.", "multi"); - Add("Empty boxes", - "With more than one entry selected, a box the entries disagree on comes up empty, and an empty box is " - + "left alone when you save - the entries keep their own values. Fill it in to give them all the same " - + "value. Because empty means 'leave alone', a name cannot be cleared across a multi-selection; select " - + "the entry on its own to do that.", + Add(GetLocalized("Forms.TileDataHelpForm.EditingManyEntries.EmptyBoxes.Title") ?? "Empty boxes", + GetLocalized("Forms.TileDataHelpForm.EditingManyEntries.EmptyBoxes.Description") + ?? "With more than one entry selected, a box the entries disagree on comes up empty, and an empty box is left alone when you save - the entries keep their own values. Fill it in to give them all the same value. Because empty means 'leave alone', a name cannot be cleared across a multi-selection; select the entry on its own to do that.", "multi"); - Add("Greyed flags", - "A flag that is set on some of the selected entries but not all shows greyed, and a greyed flag is left " - + "alone when you save. Clicking it cycles leave alone -> set on all -> clear on all. A flag they all " - + "already agree on just toggles.", + Add(GetLocalized("Forms.TileDataHelpForm.EditingManyEntries.GreyedFlags.Title") ?? "Greyed flags", + GetLocalized("Forms.TileDataHelpForm.EditingManyEntries.GreyedFlags.Description") + ?? "A flag that is set on some of the selected entries but not all shows greyed, and a greyed flag is left alone when you save. Clicking it cycles leave alone -> set on all -> clear on all. A flag they all already agree on just toggles.", "multi"); - Add("Copy / Paste special", - "Right-click an entry and choose 'Copy tile data' to remember it, then select any number of entries and " - + "choose 'Paste special...' to pick which of the copied fields and flags to write onto them.", + Add(GetLocalized("Forms.TileDataHelpForm.EditingManyEntries.CopyPasteSpecial.Title") ?? "Copy / Paste special", + GetLocalized("Forms.TileDataHelpForm.EditingManyEntries.CopyPasteSpecial.Description") + ?? "Right-click an entry and choose 'Copy tile data' to remember it, then select any number of entries and choose 'Paste special...' to pick which of the copied fields and flags to write onto them.", "multi"); - Add("Undo", - "Misc -> 'Undo last bulk apply' puts back the values the entries had before the last apply. Only the " - + "most recent apply is kept, and it is forgotten when tiledata is reloaded.", + Add(GetLocalized("Forms.TileDataHelpForm.EditingManyEntries.Undo.Title") ?? "Undo", + GetLocalized("Forms.TileDataHelpForm.EditingManyEntries.Undo.Description") + ?? "Misc -> 'Undo last bulk apply' puts back the values the entries had before the last apply. Only the most recent apply is kept, and it is forgotten when tiledata is reloaded.", "multi"); - AddHeader("Items"); - Add("Name", "This field is for the name of the item, which can be a maximum of 20 characters.", "items"); - Add("Animation", "This field is for the animation ID associated with the item.", "items"); - Add("Weight", "This field is for the weight of the item.", "items"); - Add("Layer", new StringBuilder() - .AppendLine("This field is for the layer of the item:") - .AppendLine("") - .AppendLine("1 One handed weapon") - .AppendLine("2 Two handed weapon, shield, or misc.") - .AppendLine("3 Shoes") - .AppendLine("4 Pants") - .AppendLine("5 Shirt") - .AppendLine("6 Helm / Line") - .AppendLine("7 Gloves") - .AppendLine("8 Ring") - .AppendLine("9 Talisman") - .AppendLine("10 Neck") - .AppendLine("11 Hair") - .AppendLine("12 Waist (half apron)") - .AppendLine("13 Torso (inner) (chest armor)") - .AppendLine("14 Bracelet") - .AppendLine("15 Unused (but backpackers for backpackers go to 21)") - .AppendLine("16 Facial Hair") - .AppendLine("17 Torso (middle) (surcoat, tunic, full apron, sash)") - .AppendLine("18 Earrings") - .AppendLine("19 Arms") - .AppendLine("20 Back (cloak)") - .AppendLine("21 Backpack") - .AppendLine("22 Torso (outer) (robe)") - .AppendLine("23 Legs (outer) (skirt / kilt)") - .AppendLine("24 Legs (inner) (leg armor)") - .AppendLine("25 Mount (horse, ostard, etc)") - .AppendLine("26 NPC Buy Restock container") - .AppendLine("27 NPC Buy no restock container") - .Append("28 NPC Sell container") - .ToString(), "items"); - Add("Quantity", "This field is for the quantity of the item.", "items"); - Add("Value", "This field is for the value of the item.", "items"); - Add("Stacking Offset", new StringBuilder() - .AppendLine("StackOff refers to the stacking offset in pixels when multiple items are stacked.") - .Append("A higher StackOff value means the items will appear further apart from each other within the stack.") - .ToString(), "items"); - Add("Hue", "This field is for the hue (color) of the item.", "items"); - Add("Unknown 2", "This field is for the second unknown value.", "items"); - Add("Misc Data", "Old UO Demo weapon template definition", "items"); - Add("Height", "This field is for the height of the item.", "items"); - Add("Unknown 3", "This field is for the third unknown value.", "items"); - - AddHeader("Land Tiles"); - Add("Name", "This field is for the name of the land tile, which can be a maximum of 20 characters.", "land"); - Add("Texture ID", "This field is for the texture ID associated with the land tile.", "land"); - - AddHeader("Flags"); - Add("Background", "Not yet documented.", "flags"); - Add("Weapon", "Not yet documented.", "flags"); - Add("Transparent", "Not yet documented.", "flags"); - Add("Translucent", "The tile is rendered with partial alpha-transparency.", "flags"); - Add("Wall", "The tile is a wall.", "flags"); - Add("Damaging", "The tile can cause damage when moved over.", "flags"); - Add("Impassable", "The tile may not be moved over or through.", "flags"); - Add("Wet", "Not yet documented.", "flags"); - Add("Unknown1", "Unknown.", "flags"); - Add("Surface", "The tile is a surface. It may be moved over, but not through.", "flags"); - Add("Bridge", "The tile is a stair, ramp, or ladder.", "flags"); - Add("Generic", "The tile is stackable.", "flags"); - Add("Window", "The tile is a window. Like NoShoot, tiles with this flag block line of sight.", "flags"); - Add("NoShoot", "The tile blocks line of sight.", "flags"); - Add("ArticleA", "For single-amount tiles, the string \"a \" should be prepended to the tile name.", "flags"); - Add("ArticleAn", "For single-amount tiles, the string \"an \" should be prepended to the tile name.", "flags"); - Add("ArticleThe", "Probably article \"The\" prepended to the tile name.", "flags"); - Add("Foliage", "The tile becomes translucent when walked behind. Boat masts also have this flag.", "flags"); - Add("PartialHue", "Only gray pixels will be hued.", "flags"); - Add("NoHouse", "NoHouse or Unknown. Needs further research.", "flags"); - Add("Map", "The tile is a map in the cartography sense. Unknown usage.", "flags"); - Add("Container", "The tile is a container.", "flags"); - Add("Wearable", "The tile may be equipped.", "flags"); - Add("LightSource", "The tile gives off light.", "flags"); - Add("Animation", "The tile is animated.", "flags"); - Add("HoverOver", "Gargoyles can fly over, or NoDiagonal.", "flags"); - Add("NoDiagonal", "NoDiagonal (Unknown3).", "flags"); - Add("Armor", "Not yet documented.", "flags"); - Add("Roof", "The tile is a slanted roof.", "flags"); - Add("Door", "The tile is a door. Tiles with this flag can be moved through by ghosts and GMs.", "flags"); - Add("StairBack", "Not yet documented.", "flags"); - Add("StairRight", "Not yet documented.", "flags"); - Add("AlphaBlend", "Blend Alphas, tile blending.", "flags"); - Add("UseNewArt", "Uses new art style? Something related to the nodraw tile?", "flags"); - Add("ArtUsed", "Has art being used?", "flags"); - Add("Unused8", "Unused or unknown yet.", "flags"); - Add("NoShadow", "Disallow shadow on this tile, light source? lava?", "flags"); - Add("PixelBleed", "Let pixels bleed in to other tiles? Is this Disabling Texture Clamp?", "flags"); - Add("PlayAnimOnce", "Play tile animation once.", "flags"); - Add("MultiMovable", "Movable multi? Cool ships and vehicles etc? Something related to the masts.", "flags"); - Add("Unused10", "Unused or unknown yet.", "flags"); - Add("Unused11", "Unused or unknown yet.", "flags"); - Add("Unused12", "Unused or unknown yet.", "flags"); - Add("Unused13", "Unused or unknown yet.", "flags"); - Add("Unused14", "Unused or unknown yet.", "flags"); - Add("Unused15", "Unused or unknown yet.", "flags"); - Add("Unused16", "Unused or unknown yet.", "flags"); - Add("Unused17", "Unused or unknown yet.", "flags"); - Add("Unused18", "Unused or unknown yet.", "flags"); - Add("Unused19", "Unused or unknown yet.", "flags"); - Add("Unused20", "Unused or unknown yet.", "flags"); - Add("Unused21", "Unused or unknown yet.", "flags"); - Add("Unused22", "Unused or unknown yet.", "flags"); - Add("Unused23", "Unused or unknown yet.", "flags"); - Add("Unused24", "Unused or unknown yet.", "flags"); - Add("Unused25", "Unused or unknown yet.", "flags"); - Add("Unused26", "Unused or unknown yet.", "flags"); - Add("Unused27", "Unused or unknown yet.", "flags"); - Add("Unused28", "Unused or unknown yet.", "flags"); - Add("Unused29", "Unused or unknown yet.", "flags"); - Add("Unused30", "Unused or unknown yet.", "flags"); - Add("Unused31", "Unused or unknown yet.", "flags"); - Add("Unused32", "Unused or unknown yet.", "flags"); + // Items section + AddHeader(GetLocalized("Forms.TileDataHelpForm.Items.Title") ?? "Items"); + Add(GetLocalized("Forms.TileDataHelpForm.Items.Name.Title") ?? "Name", + GetLocalized("Forms.TileDataHelpForm.Items.Name.Description") + ?? "This field is for the name of the item, which can be a maximum of 20 characters.", "items"); + Add(GetLocalized("Forms.TileDataHelpForm.Items.Animation.Title") ?? "Animation", + GetLocalized("Forms.TileDataHelpForm.Items.Animation.Description") + ?? "This field is for the animation ID associated with the item.", "items"); + Add(GetLocalized("Forms.TileDataHelpForm.Items.Weight.Title") ?? "Weight", + GetLocalized("Forms.TileDataHelpForm.Items.Weight.Description") + ?? "This field is for the weight of the item.", "items"); + Add(GetLocalized("Forms.TileDataHelpForm.Items.Layer.Title") ?? "Layer", + GetLocalized("Forms.TileDataHelpForm.Items.Layer.Description") + ?? "This field is for the layer of the item:\n\n1 One handed weapon\n2 Two handed weapon, shield, or misc.\n3 Shoes\n4 Pants\n5 Shirt\n6 Helm / Line\n7 Gloves\n8 Ring\n9 Talisman\n10 Neck\n11 Hair\n12 Waist (half apron)\n13 Torso (inner) (chest armor)\n14 Bracelet\n15 Unused (but backpackers for backpackers go to 21)\n16 Facial Hair\n17 Torso (middle) (surcoat, tunic, full apron, sash)\n18 Earrings\n19 Arms\n20 Back (cloak)\n21 Backpack\n22 Torso (outer) (robe)\n23 Legs (outer) (skirt / kilt)\n24 Legs (inner) (leg armor)\n25 Mount (horse, ostard, etc)\n26 NPC Buy Restock container\n27 NPC Buy no restock container\n28 NPC Sell container", "items"); + Add(GetLocalized("Forms.TileDataHelpForm.Items.Quantity.Title") ?? "Quantity", + GetLocalized("Forms.TileDataHelpForm.Items.Quantity.Description") + ?? "This field is for the quantity of the item.", "items"); + Add(GetLocalized("Forms.TileDataHelpForm.Items.Value.Title") ?? "Value", + GetLocalized("Forms.TileDataHelpForm.Items.Value.Description") + ?? "This field is for the value of the item.", "items"); + Add(GetLocalized("Forms.TileDataHelpForm.Items.StackingOffset.Title") ?? "Stacking Offset", + GetLocalized("Forms.TileDataHelpForm.Items.StackingOffset.Description") + ?? "StackOff refers to the stacking offset in pixels when multiple items are stacked.\nA higher StackOff value means the items will appear further apart from each other within the stack.", "items"); + Add(GetLocalized("Forms.TileDataHelpForm.Items.Hue.Title") ?? "Hue", + GetLocalized("Forms.TileDataHelpForm.Items.Hue.Description") + ?? "This field is for the hue (color) of the item.", "items"); + Add(GetLocalized("Forms.TileDataHelpForm.Items.Unknown2.Title") ?? "Unknown 2", + GetLocalized("Forms.TileDataHelpForm.Items.Unknown2.Description") + ?? "This field is for the second unknown value.", "items"); + Add(GetLocalized("Forms.TileDataHelpForm.Items.MiscData.Title") ?? "Misc Data", + GetLocalized("Forms.TileDataHelpForm.Items.MiscData.Description") + ?? "Old UO Demo weapon template definition", "items"); + Add(GetLocalized("Forms.TileDataHelpForm.Items.Height.Title") ?? "Height", + GetLocalized("Forms.TileDataHelpForm.Items.Height.Description") + ?? "This field is for the height of the item.", "items"); + Add(GetLocalized("Forms.TileDataHelpForm.Items.Unknown3.Title") ?? "Unknown 3", + GetLocalized("Forms.TileDataHelpForm.Items.Unknown3.Description") + ?? "This field is for the third unknown value.", "items"); + + // Land Tiles section + AddHeader(GetLocalized("Forms.TileDataHelpForm.LandTiles.Title") ?? "Land Tiles"); + Add(GetLocalized("Forms.TileDataHelpForm.LandTiles.Name.Title") ?? "Name", + GetLocalized("Forms.TileDataHelpForm.LandTiles.Name.Description") + ?? "This field is for the name of the land tile, which can be a maximum of 20 characters.", "land"); + Add(GetLocalized("Forms.TileDataHelpForm.LandTiles.TextureID.Title") ?? "Texture ID", + GetLocalized("Forms.TileDataHelpForm.LandTiles.TextureID.Description") + ?? "This field is for the texture ID associated with the land tile.", "land"); + + // Flags section + AddHeader(GetLocalized("Forms.TileDataHelpForm.Flags.Title") ?? "Flags"); + Add(GetLocalized("Forms.TileDataHelpForm.Flags.Background.Title") ?? "Background", GetLocalized("Forms.TileDataHelpForm.Flags.Background.Description") ?? "Not yet documented.", "flags"); + Add(GetLocalized("Forms.TileDataHelpForm.Flags.Weapon.Title") ?? "Weapon", GetLocalized("Forms.TileDataHelpForm.Flags.Weapon.Description") ?? "Not yet documented.", "flags"); + Add(GetLocalized("Forms.TileDataHelpForm.Flags.Transparent.Title") ?? "Transparent", GetLocalized("Forms.TileDataHelpForm.Flags.Transparent.Description") ?? "Not yet documented.", "flags"); + Add(GetLocalized("Forms.TileDataHelpForm.Flags.Translucent.Title") ?? "Translucent", GetLocalized("Forms.TileDataHelpForm.Flags.Translucent.Description") ?? "The tile is rendered with partial alpha-transparency.", "flags"); + Add(GetLocalized("Forms.TileDataHelpForm.Flags.Wall.Title") ?? "Wall", GetLocalized("Forms.TileDataHelpForm.Flags.Wall.Description") ?? "The tile is a wall.", "flags"); + Add(GetLocalized("Forms.TileDataHelpForm.Flags.Damaging.Title") ?? "Damaging", GetLocalized("Forms.TileDataHelpForm.Flags.Damaging.Description") ?? "The tile can cause damage when moved over.", "flags"); + Add(GetLocalized("Forms.TileDataHelpForm.Flags.Impassable.Title") ?? "Impassable", GetLocalized("Forms.TileDataHelpForm.Flags.Impassable.Description") ?? "The tile may not be moved over or through.", "flags"); + Add(GetLocalized("Forms.TileDataHelpForm.Flags.Wet.Title") ?? "Wet", GetLocalized("Forms.TileDataHelpForm.Flags.Wet.Description") ?? "Not yet documented.", "flags"); + Add(GetLocalized("Forms.TileDataHelpForm.Flags.Unknown1.Title") ?? "Unknown1", GetLocalized("Forms.TileDataHelpForm.Flags.Unknown1.Description") ?? "Unknown.", "flags"); + Add(GetLocalized("Forms.TileDataHelpForm.Flags.Surface.Title") ?? "Surface", GetLocalized("Forms.TileDataHelpForm.Flags.Surface.Description") ?? "The tile is a surface. It may be moved over, but not through.", "flags"); + Add(GetLocalized("Forms.TileDataHelpForm.Flags.Bridge.Title") ?? "Bridge", GetLocalized("Forms.TileDataHelpForm.Flags.Bridge.Description") ?? "The tile is a stair, ramp, or ladder.", "flags"); + Add(GetLocalized("Forms.TileDataHelpForm.Flags.Generic.Title") ?? "Generic", GetLocalized("Forms.TileDataHelpForm.Flags.Generic.Description") ?? "The tile is stackable.", "flags"); + Add(GetLocalized("Forms.TileDataHelpForm.Flags.Window.Title") ?? "Window", GetLocalized("Forms.TileDataHelpForm.Flags.Window.Description") ?? "The tile is a window. Like NoShoot, tiles with this flag block line of sight.", "flags"); + Add(GetLocalized("Forms.TileDataHelpForm.Flags.NoShoot.Title") ?? "NoShoot", GetLocalized("Forms.TileDataHelpForm.Flags.NoShoot.Description") ?? "The tile blocks line of sight.", "flags"); + Add(GetLocalized("Forms.TileDataHelpForm.Flags.ArticleA.Title") ?? "ArticleA", GetLocalized("Forms.TileDataHelpForm.Flags.ArticleA.Description") ?? "For single-amount tiles, the string \"a \" should be prepended to the tile name.", "flags"); + Add(GetLocalized("Forms.TileDataHelpForm.Flags.ArticleAn.Title") ?? "ArticleAn", GetLocalized("Forms.TileDataHelpForm.Flags.ArticleAn.Description") ?? "For single-amount tiles, the string \"an \" should be prepended to the tile name.", "flags"); + Add(GetLocalized("Forms.TileDataHelpForm.Flags.ArticleThe.Title") ?? "ArticleThe", GetLocalized("Forms.TileDataHelpForm.Flags.ArticleThe.Description") ?? "Probably article \"The\" prepended to the tile name.", "flags"); + Add(GetLocalized("Forms.TileDataHelpForm.Flags.Foliage.Title") ?? "Foliage", GetLocalized("Forms.TileDataHelpForm.Flags.Foliage.Description") ?? "The tile becomes translucent when walked behind. Boat masts also have this flag.", "flags"); + Add(GetLocalized("Forms.TileDataHelpForm.Flags.PartialHue.Title") ?? "PartialHue", GetLocalized("Forms.TileDataHelpForm.Flags.PartialHue.Description") ?? "Only gray pixels will be hued.", "flags"); + Add(GetLocalized("Forms.TileDataHelpForm.Flags.NoHouse.Title") ?? "NoHouse", GetLocalized("Forms.TileDataHelpForm.Flags.NoHouse.Description") ?? "NoHouse or Unknown. Needs further research.", "flags"); + Add(GetLocalized("Forms.TileDataHelpForm.Flags.Map.Title") ?? "Map", GetLocalized("Forms.TileDataHelpForm.Flags.Map.Description") ?? "The tile is a map in the cartography sense. Unknown usage.", "flags"); + Add(GetLocalized("Forms.TileDataHelpForm.Flags.Container.Title") ?? "Container", GetLocalized("Forms.TileDataHelpForm.Flags.Container.Description") ?? "The tile is a container.", "flags"); + Add(GetLocalized("Forms.TileDataHelpForm.Flags.Wearable.Title") ?? "Wearable", GetLocalized("Forms.TileDataHelpForm.Flags.Wearable.Description") ?? "The tile may be equipped.", "flags"); + Add(GetLocalized("Forms.TileDataHelpForm.Flags.LightSource.Title") ?? "LightSource", GetLocalized("Forms.TileDataHelpForm.Flags.LightSource.Description") ?? "The tile gives off light.", "flags"); + Add(GetLocalized("Forms.TileDataHelpForm.Flags.Animation.Title") ?? "Animation", GetLocalized("Forms.TileDataHelpForm.Flags.Animation.Description") ?? "The tile is animated.", "flags"); + Add(GetLocalized("Forms.TileDataHelpForm.Flags.HoverOver.Title") ?? "HoverOver", GetLocalized("Forms.TileDataHelpForm.Flags.HoverOver.Description") ?? "Gargoyles can fly over, or NoDiagonal.", "flags"); + Add(GetLocalized("Forms.TileDataHelpForm.Flags.NoDiagonal.Title") ?? "NoDiagonal", GetLocalized("Forms.TileDataHelpForm.Flags.NoDiagonal.Description") ?? "NoDiagonal (Unknown3).", "flags"); + Add(GetLocalized("Forms.TileDataHelpForm.Flags.Armor.Title") ?? "Armor", GetLocalized("Forms.TileDataHelpForm.Flags.Armor.Description") ?? "Not yet documented.", "flags"); + Add(GetLocalized("Forms.TileDataHelpForm.Flags.Roof.Title") ?? "Roof", GetLocalized("Forms.TileDataHelpForm.Flags.Roof.Description") ?? "The tile is a slanted roof.", "flags"); + Add(GetLocalized("Forms.TileDataHelpForm.Flags.Door.Title") ?? "Door", GetLocalized("Forms.TileDataHelpForm.Flags.Door.Description") ?? "The tile is a door. Tiles with this flag can be moved through by ghosts and GMs.", "flags"); + Add(GetLocalized("Forms.TileDataHelpForm.Flags.StairBack.Title") ?? "StairBack", GetLocalized("Forms.TileDataHelpForm.Flags.StairBack.Description") ?? "Not yet documented.", "flags"); + Add(GetLocalized("Forms.TileDataHelpForm.Flags.StairRight.Title") ?? "StairRight", GetLocalized("Forms.TileDataHelpForm.Flags.StairRight.Description") ?? "Not yet documented.", "flags"); + Add(GetLocalized("Forms.TileDataHelpForm.Flags.AlphaBlend.Title") ?? "AlphaBlend", GetLocalized("Forms.TileDataHelpForm.Flags.AlphaBlend.Description") ?? "Blend Alphas, tile blending.", "flags"); + Add(GetLocalized("Forms.TileDataHelpForm.Flags.UseNewArt.Title") ?? "UseNewArt", GetLocalized("Forms.TileDataHelpForm.Flags.UseNewArt.Description") ?? "Uses new art style? Something related to the nodraw tile?", "flags"); + Add(GetLocalized("Forms.TileDataHelpForm.Flags.ArtUsed.Title") ?? "ArtUsed", GetLocalized("Forms.TileDataHelpForm.Flags.ArtUsed.Description") ?? "Has art being used?", "flags"); + Add(GetLocalized("Forms.TileDataHelpForm.Flags.Unused8.Title") ?? "Unused8", GetLocalized("Forms.TileDataHelpForm.Flags.Unused8.Description") ?? "Unused or unknown yet.", "flags"); + Add(GetLocalized("Forms.TileDataHelpForm.Flags.NoShadow.Title") ?? "NoShadow", GetLocalized("Forms.TileDataHelpForm.Flags.NoShadow.Description") ?? "Disallow shadow on this tile, light source? lava?", "flags"); + Add(GetLocalized("Forms.TileDataHelpForm.Flags.PixelBleed.Title") ?? "PixelBleed", GetLocalized("Forms.TileDataHelpForm.Flags.PixelBleed.Description") ?? "Let pixels bleed in to other tiles? Is this Disabling Texture Clamp?", "flags"); + Add(GetLocalized("Forms.TileDataHelpForm.Flags.PlayAnimOnce.Title") ?? "PlayAnimOnce", GetLocalized("Forms.TileDataHelpForm.Flags.PlayAnimOnce.Description") ?? "Play tile animation once.", "flags"); + Add(GetLocalized("Forms.TileDataHelpForm.Flags.MultiMovable.Title") ?? "MultiMovable", GetLocalized("Forms.TileDataHelpForm.Flags.MultiMovable.Description") ?? "Movable multi? Cool ships and vehicles etc? Something related to the masts.", "flags"); + Add(GetLocalized("Forms.TileDataHelpForm.Flags.Unused10.Title") ?? "Unused10", GetLocalized("Forms.TileDataHelpForm.Flags.Unused10.Description") ?? "Unused or unknown yet.", "flags"); + Add(GetLocalized("Forms.TileDataHelpForm.Flags.Unused11.Title") ?? "Unused11", GetLocalized("Forms.TileDataHelpForm.Flags.Unused11.Description") ?? "Unused or unknown yet.", "flags"); + Add(GetLocalized("Forms.TileDataHelpForm.Flags.Unused12.Title") ?? "Unused12", GetLocalized("Forms.TileDataHelpForm.Flags.Unused12.Description") ?? "Unused or unknown yet.", "flags"); + Add(GetLocalized("Forms.TileDataHelpForm.Flags.Unused13.Title") ?? "Unused13", GetLocalized("Forms.TileDataHelpForm.Flags.Unused13.Description") ?? "Unused or unknown yet.", "flags"); + Add(GetLocalized("Forms.TileDataHelpForm.Flags.Unused14.Title") ?? "Unused14", GetLocalized("Forms.TileDataHelpForm.Flags.Unused14.Description") ?? "Unused or unknown yet.", "flags"); + Add(GetLocalized("Forms.TileDataHelpForm.Flags.Unused15.Title") ?? "Unused15", GetLocalized("Forms.TileDataHelpForm.Flags.Unused15.Description") ?? "Unused or unknown yet.", "flags"); + Add(GetLocalized("Forms.TileDataHelpForm.Flags.Unused16.Title") ?? "Unused16", GetLocalized("Forms.TileDataHelpForm.Flags.Unused16.Description") ?? "Unused or unknown yet.", "flags"); + Add(GetLocalized("Forms.TileDataHelpForm.Flags.Unused17.Title") ?? "Unused17", GetLocalized("Forms.TileDataHelpForm.Flags.Unused17.Description") ?? "Unused or unknown yet.", "flags"); + Add(GetLocalized("Forms.TileDataHelpForm.Flags.Unused18.Title") ?? "Unused18", GetLocalized("Forms.TileDataHelpForm.Flags.Unused18.Description") ?? "Unused or unknown yet.", "flags"); + Add(GetLocalized("Forms.TileDataHelpForm.Flags.Unused19.Title") ?? "Unused19", GetLocalized("Forms.TileDataHelpForm.Flags.Unused19.Description") ?? "Unused or unknown yet.", "flags"); + Add(GetLocalized("Forms.TileDataHelpForm.Flags.Unused20.Title") ?? "Unused20", GetLocalized("Forms.TileDataHelpForm.Flags.Unused20.Description") ?? "Unused or unknown yet.", "flags"); + Add(GetLocalized("Forms.TileDataHelpForm.Flags.Unused21.Title") ?? "Unused21", GetLocalized("Forms.TileDataHelpForm.Flags.Unused21.Description") ?? "Unused or unknown yet.", "flags"); + Add(GetLocalized("Forms.TileDataHelpForm.Flags.Unused22.Title") ?? "Unused22", GetLocalized("Forms.TileDataHelpForm.Flags.Unused22.Description") ?? "Unused or unknown yet.", "flags"); + Add(GetLocalized("Forms.TileDataHelpForm.Flags.Unused23.Title") ?? "Unused23", GetLocalized("Forms.TileDataHelpForm.Flags.Unused23.Description") ?? "Unused or unknown yet.", "flags"); + Add(GetLocalized("Forms.TileDataHelpForm.Flags.Unused24.Title") ?? "Unused24", GetLocalized("Forms.TileDataHelpForm.Flags.Unused24.Description") ?? "Unused or unknown yet.", "flags"); + Add(GetLocalized("Forms.TileDataHelpForm.Flags.Unused25.Title") ?? "Unused25", GetLocalized("Forms.TileDataHelpForm.Flags.Unused25.Description") ?? "Unused or unknown yet.", "flags"); + Add(GetLocalized("Forms.TileDataHelpForm.Flags.Unused26.Title") ?? "Unused26", GetLocalized("Forms.TileDataHelpForm.Flags.Unused26.Description") ?? "Unused or unknown yet.", "flags"); + Add(GetLocalized("Forms.TileDataHelpForm.Flags.Unused27.Title") ?? "Unused27", GetLocalized("Forms.TileDataHelpForm.Flags.Unused27.Description") ?? "Unused or unknown yet.", "flags"); + Add(GetLocalized("Forms.TileDataHelpForm.Flags.Unused28.Title") ?? "Unused28", GetLocalized("Forms.TileDataHelpForm.Flags.Unused28.Description") ?? "Unused or unknown yet.", "flags"); + Add(GetLocalized("Forms.TileDataHelpForm.Flags.Unused29.Title") ?? "Unused29", GetLocalized("Forms.TileDataHelpForm.Flags.Unused29.Description") ?? "Unused or unknown yet.", "flags"); + Add(GetLocalized("Forms.TileDataHelpForm.Flags.Unused30.Title") ?? "Unused30", GetLocalized("Forms.TileDataHelpForm.Flags.Unused30.Description") ?? "Unused or unknown yet.", "flags"); + Add(GetLocalized("Forms.TileDataHelpForm.Flags.Unused31.Title") ?? "Unused31", GetLocalized("Forms.TileDataHelpForm.Flags.Unused31.Description") ?? "Unused or unknown yet.", "flags"); + Add(GetLocalized("Forms.TileDataHelpForm.Flags.Unused32.Title") ?? "Unused32", GetLocalized("Forms.TileDataHelpForm.Flags.Unused32.Description") ?? "Unused or unknown yet.", "flags"); if (_listView.Items.Count > 0) { diff --git a/UoFiddler/Localization/Dictionaries/zh-CN.json b/UoFiddler/Localization/Dictionaries/zh-CN.json index fad92d5c..d2d3f408 100644 --- a/UoFiddler/Localization/Dictionaries/zh-CN.json +++ b/UoFiddler/Localization/Dictionaries/zh-CN.json @@ -1757,6 +1757,571 @@ "setAsRangeFromToolStripMenuItem1": "设置为范围\"起点\"", "setAsRangeToToolStripMenuItem1": "设置为范围\"终点\"" }, + "TileDataControl": { + "TabPages": { + "tabPageItems": "物品", + "tabPageLand": "地形磁贴" + }, + "Labels": { + "nameLabel": "名称", + "animLabel": "动画", + "weightLabel": "重量", + "layerLabel": "层级", + "quantityLabel": "数量", + "valueLabel": "价值", + "stackOffLabel": "堆叠偏移", + "hueLabel": "色调", + "unknown2Label": "未知值2", + "miscDataLabel": "杂项数据", + "heightLabel": "高度", + "unknown3Label": "未知值3", + "landNameLabel": "名称", + "landTexIdLabel": "纹理 ID" + }, + "Toolbar": { + "toolStripLabel1": "索引:", + "toolStripLabel2": "名称:", + "searchByNameToolStripButton": "查找下一个", + "toolStripButton1": "导出为 CSV", + "toolStripButton5": "从 CSV 导入", + "toolStripButton4": "保存更改", + "toolStripButton3": "保存 TileData", + "helpToolStripButton": "帮助" + }, + "MiscMenu": { + "memorySaveWarning": "内存保存警告", + "saveDirectlyOnChanges": "更改时直接保存", + "setFilter": "设置过滤器", + "undoBulkApply": "撤销上次批量应用", + "setTextureOnDoubleClick": "双击时设置 TexID", + "setTextures": "设置纹理" + }, + "ItemsContextMenu": { + "copyTileData": "复制图块数据", + "pasteSpecial": "粘贴特殊...", + "selectInItems": "在物品标签中选择", + "selectInRadarColor": "在雷达颜色标签中选择", + "selectInGumpsMale": "在 Gumps 中选择 (男)", + "selectInGumpsFemale": "在 Gumps 中选择 (女)", + "selectInAnimData": "在动画数据标签中选择" + }, + "LandContextMenu": { + "copyTileData": "复制图块数据", + "pasteSpecial": "粘贴特殊...", + "selectInLandTiles": "在地形标签中选择", + "selectInRadarColor": "在雷达颜色标签中选择" + }, + "PictureBoxMenu": { + "changeBackgroundColor": "改变背景颜色" + }, + "FileDialogs": { + "importCsvTitle": "选择要导入的 csv 文件", + "importCsvFilter": "csv 文件 (*.csv)|*.csv", + "tileDataSavedMessage": "TileData 已成功保存。", + "itemDataSavedMessage": "ItemData 已成功保存。", + "landDataSavedMessage": "LandData 已成功保存。" + }, + "MessageBoxes": { + "SetTextures": { + "Title": "设置纹理", + "ConfirmMessage": "您想为所有地形设置 TexID 吗?\n\n此操作假设地形图块索引值等于纹理索引值。\n\n它只考虑 TexID 为 0 的地形磁贴。\n\n继续?", + "SuccessMessage": "已更新 {0} 个地形。", + "NothingUpdated": "未更新任何内容。" + }, + "BulkApply": { + "Title": "应用到选择", + "ConfirmMessage": "应用 {0} 到 {1} 项?", + "EmptyFieldsMessage": "没有要应用的内容 - 所有框都为空,所有标志保持不变。" + }, + "BulkApplyResult": { + "Title": "已保存", + "Message": "已在内存中应用 {0} 到 {1} 项。\r\n\r\n单击'保存 TileData'写入文件。" + }, + "MemorySaveWarning": { + "Title": "信息", + "ItemMessage": "编辑 0x{0:X4} ({0}) 已保存到内存。单击'保存 TileData'写入文件。", + "LandMessage": "编辑 0x{0:X4} ({0}) 已保存到内存。单击'保存 TileData'写入文件。" + }, + "UndoBulkApply": { + "Title": "撤销批量应用", + "ConfirmMessage": "将 {0} 项恢复到应用'{1}'之前的值?" + }, + "TabNotLoaded": { + "ItemsTabMessage": "您需要先加载物品标签页。", + "LandTabMessage": "您需要先加载地形标签页。" + }, + "SelectionError": { + "NoItemSelected": "您需要先选择一个物品。", + "NoLandSelected": "您需要先选择一个地形。", + "NothingToPaste": "您需要先复制某些内容才能粘贴。" + }, + "Messages": { + "emptyApply": "没有要应用的内容 - 所有框都为空,所有标志保持不变。", + "applyToSelection": "应用到选择", + "saved": "已保存", + "applyToMany": "应用 {0} 到 {1} 项?", + "appliedToMany": "已在内存中应用 {0} 到 {1} 项。\r\n\r\n单击'保存 TileData'写入文件。", + "undoConfirm": "将 {0} 项恢复到应用'{1}'之前的值?", + "undoBulkApply": "撤销批量应用", + "needLoadItems": "您需要先加载物品标签页。", + "needLoadLand": "您需要先加载地形标签页。", + "setTextures": "设置纹理", + "texturesUpdated": "已更新 {0} 个地形。", + "texturesNothing": "未更新任何内容。", + "information": "信息", + "setTexturesConfirm": "您想为所有地形设置 TexID 吗?\n\n此操作假设地形图块索引值等于纹理索引值。\n\n它只考虑 TexID 为 0 的地形磁贴。\n\n继续?" + } + }, + "TileFlags": { + "Background": "背景", + "Weapon": "武器", + "Transparent": "透明", + "Translucent": "半透明", + "Wall": "墙壁", + "Damaging": "伤害性", + "Impassable": "不可通行", + "Wet": "潮湿", + "Unknown1": "未知值1", + "Surface": "表面", + "Bridge": "桥梁", + "Generic": "通用", + "Window": "窗户", + "NoShoot": "不可射击", + "ArticleA": "冠词A", + "ArticleAn": "冠词An", + "ArticleThe": "冠词The", + "Foliage": "树叶", + "PartialHue": "部分色调", + "NoHouse": "不可建造房屋", + "Map": "地图", + "Container": "容器", + "Wearable": "可穿戴", + "LightSource": "光源", + "Animation": "动画", + "HoverOver": "悬停", + "NoDiagonal": "不可对角线", + "Armor": "护甲", + "Roof": "屋顶", + "Door": "门", + "StairBack": "后楼梯", + "StairRight": "右楼梯", + "AlphaBlend": "透明混合", + "UseNewArt": "使用新美术", + "ArtUsed": "已使用美术", + "Unused8": "未使用8", + "NoShadow": "无阴影", + "PixelBleed": "像素渗漏", + "PlayAnimOnce": "播放一次动画", + "MultiMovable": "多部件可移动", + "Unused10": "未使用10", + "Unused11": "未使用11", + "Unused12": "未使用12", + "Unused13": "未使用13", + "Unused14": "未使用14", + "Unused15": "未使用15", + "Unused16": "未使用16", + "Unused17": "未使用17", + "Unused18": "未使用18", + "Unused19": "未使用19", + "Unused20": "未使用20", + "Unused21": "未使用21", + "Unused22": "未使用22", + "Unused23": "未使用23", + "Unused24": "未使用24", + "Unused25": "未使用25", + "Unused26": "未使用26", + "Unused27": "未使用27", + "Unused28": "未使用28", + "Unused29": "未使用29", + "Unused30": "未使用30", + "Unused31": "未使用31", + "Unused32": "未使用32" + }, + "Tooltips": { + "name": "此字段用于物品名称,最多可为20个字符。", + "anim": "此字段用于与物品关联的动画ID。", + "weight": "此字段用于物品的重量。", + "layer": "此字段用于物品的层级:\n\n1 单手武器\n2 双手武器、盾牌或杂项\n3 鞋类\n4 裤子\n5 衬衣\n6 头盔/衣领\n7 手套\n8 戒指\n9 护身符\n10 项链\n11 头发\n12 腰部(半围裙)\n13 躯干(内侧)(胸甲)\n14 手镯\n15 未使用(但背包使用第21层)\n16 面部毛发\n17 躯干(中间)(超衣、束腰外衣、满围裙、腰带)\n18 耳环\n19 手臂\n20 背部(斗篷)\n21 背包\n22 躯干(外侧)(长袍)\n23 腿部(外侧)(裙子/短裙)\n24 腿部(内侧)(腿甲)\n25 坐骑(马、鸵鸟等)\n26 NPC购买补货容器\n27 NPC购买无补货容器\n28 NPC销售容器", + "quantity": "此字段用于物品的数量。", + "value": "此字段用于物品的价值。", + "stackOff": "堆叠偏移是指多个物品堆叠时以像素为单位的堆叠偏移。\n更高的堆叠偏移值意味着物品在堆栈中出现的距离会更远。", + "hue": "此字段用于物品的色调(颜色)。", + "unknown2": "此字段用于第二个未知值。", + "miscData": "旧UO演示武器模板定义", + "height": "此字段用于物品的高度。", + "unknown3": "此字段用于第三个未知值。", + "landName": "此字段用于地形图块名称,最多可为20个字符。", + "landTexId": "此字段用于与地形图块关联的纹理ID。" + } + }, + "TileDataFilterForm": { + "Title": "设置过滤器", + "ItemsTab": "物品过滤器", + "LandTab": "地形过滤器", + "ApplyButton": "应用过滤器", + "ResetButton": "重置过滤器", + "Labels": { + "Name": "名称", + "Anim": "动画", + "Weight": "重量", + "Quality": "品质", + "Quantity": "数量", + "Hue": "色调", + "StackOff": "堆叠偏移", + "Value": "价值", + "Height": "高度", + "MiscData": "杂项数据", + "Unk2": "未知值2", + "Unk3": "未知值3", + "NameLand": "名称", + "TexID": "纹理ID" + } + }, + "TileDataHelpForm": { + "Title": "TileData 帮助", + "FieldColumnHeader": "字段", + "CloseButton": "关闭", + "EditingManyEntries": { + "Title": "编辑多个条目", + "MultiSelect": { + "Title": "多选", + "Description": "Ctrl+点击和Shift+点击可以一次选择多个条目。右侧窗格保持显示您最后选择的条目,'保存更改'会写入到每个选定的条目。" + }, + "EmptyBoxes": { + "Title": "空框", + "Description": "选择多个条目时,条目之间不一致的框会显示为空。保存时会忽略空框——条目保留自己的值。填充它可以给它们全部相同的值。因为空意味着'保留不变',在多选中不能清除名称;单独选择条目来执行该操作。" + }, + "GreyedFlags": { + "Title": "灰化标志", + "Description": "在某些选定条目上设置但不是全部的标志显示为灰化。保存时灰化标志保留不变。单击它会循环:保留不变 -> 全部打开 -> 全部关闭。它们都已同意的标志只是切换。" + }, + "CopyPasteSpecial": { + "Title": "复制/特殊粘贴", + "Description": "右键单击条目并选择'复制图块数据'以记住它,然后选择任意数量的条目并选择'特殊粘贴...'来选择复制的字段和标志中的哪些写入它们。" + }, + "Undo": { + "Title": "撤销", + "Description": "杂项 -> '撤销最后批量应用'会恢复条目在最后应用前的值。仅保留最近的应用,当重新加载tiledata时会忘记。" + } + }, + "Items": { + "Title": "物品", + "Name": { + "Title": "名称", + "Description": "此字段用于物品名称,最多可为20个字符。" + }, + "Animation": { + "Title": "动画", + "Description": "此字段用于与物品关联的动画ID。" + }, + "Weight": { + "Title": "重量", + "Description": "此字段用于物品的重量。" + }, + "Layer": { + "Title": "层级", + "Description": "此字段用于物品的层级:\n\n1 单手武器\n2 双手武器、盾牌或杂项\n3 鞋类\n4 裤子\n5 衬衫\n6 头盔/颈部\n7 手套\n8 戒指\n9 护身符\n10 项链\n11 头发\n12 腰部(半围裙)\n13 躯干(内侧)(胸甲)\n14 手镯\n15 未使用(但背包使用第21层)\n16 面部毛发\n17 躯干(中间)(超衣、束腰外衣、满围裙、腰带)\n18 耳环\n19 手臂\n20 背部(斗篷)\n21 背包\n22 躯干(外侧)(长袍)\n23 腿部(外侧)(裙子/短裙)\n24 腿部(内侧)(腿甲)\n25 坐骑(马、鸵鸟等)\n26 NPC购买补货容器\n27 NPC购买无补货容器\n28 NPC销售容器" + }, + "Quantity": { + "Title": "数量", + "Description": "此字段用于物品的数量。" + }, + "Value": { + "Title": "价值", + "Description": "此字段用于物品的价值。" + }, + "StackingOffset": { + "Title": "堆叠偏移", + "Description": "堆叠偏移是指多个物品堆叠时以像素为单位的堆叠偏移。\n更高的堆叠偏移值意味着物品在堆栈中出现的距离会更远。" + }, + "Hue": { + "Title": "色调", + "Description": "此字段用于物品的色调(颜色)。" + }, + "Unknown2": { + "Title": "未知值2", + "Description": "此字段用于第二个未知值。" + }, + "MiscData": { + "Title": "杂项数据", + "Description": "旧UO演示武器模板定义" + }, + "Height": { + "Title": "高度", + "Description": "此字段用于物品的高度。" + }, + "Unknown3": { + "Title": "未知值3", + "Description": "此字段用于第三个未知值。" + } + }, + "LandTiles": { + "Title": "地形图块", + "Name": { + "Title": "名称", + "Description": "此字段用于地形图块名称,最多可为20个字符。" + }, + "TextureID": { + "Title": "纹理ID", + "Description": "此字段用于与地形图块关联的纹理ID。" + } + }, + "Flags": { + "Title": "标志", + "Background": { + "Description": "尚未记录。", + "Title": "背景" + }, + "Weapon": { + "Description": "尚未记录。", + "Title": "武器" + }, + "Transparent": { + "Description": "尚未记录。", + "Title": "透明" + }, + "Translucent": { + "Description": "图块以部分透明度渲染。", + "Title": "半透明" + }, + "Wall": { + "Description": "图块是墙。", + "Title": "墙" + }, + "Damaging": { + "Description": "图块在移动时可能造成伤害。", + "Title": "伤害" + }, + "Impassable": { + "Description": "图块不可移动或穿过。", + "Title": "不可通行" + }, + "Wet": { + "Description": "尚未记录。", + "Title": "湿润" + }, + "Unknown1": { + "Description": "未知。", + "Title": "未知1" + }, + "Surface": { + "Description": "图块是表面。它可以被移动,但不能穿过。", + "Title": "表面" + }, + "Bridge": { + "Description": "图块是楼梯、坡道或梯子。", + "Title": "桥梁" + }, + "Generic": { + "Description": "图块是可堆叠的。", + "Title": "通用" + }, + "Window": { + "Description": "图块是窗口。与NoShoot一样,带有此标志的图块阻挡视线。", + "Title": "窗户" + }, + "NoShoot": { + "Description": "图块阻挡视线。", + "Title": "不穿透" + }, + "ArticleA": { + "Description": "对于单数量图块,应在图块名称前加上\"一个 \"。", + "Title": "冠词A" + }, + "ArticleAn": { + "Description": "对于单数量图块,应在图块名称前加上\"一个 \"。", + "Title": "冠词An" + }, + "ArticleThe": { + "Description": "可能在图块名称前加上\"该\"。", + "Title": "冠词The" + }, + "Foliage": { + "Description": "走在后面时图块变为半透明。船桅也有此标志。", + "Title": "树叶" + }, + "PartialHue": { + "Description": "仅灰色像素会被着色。", + "Title": "部分着色" + }, + "NoHouse": { + "Description": "NoHouse或未知。需要进一步研究。", + "Title": "非房屋" + }, + "Map": { + "Description": "图块在制图学意义上是地图。未知用途。", + "Title": "地图" + }, + "Container": { + "Description": "图块是容器。", + "Title": "容器" + }, + "Wearable": { + "Description": "图块可以被装备。", + "Title": "可穿戴" + }, + "LightSource": { + "Description": "图块发出光。", + "Title": "光源" + }, + "Animation": { + "Description": "图块是动画的。", + "Title": "动画" + }, + "HoverOver": { + "Description": "石像鬼可以飞过,或NoDiagonal。", + "Title": "悬停通过" + }, + "NoDiagonal": { + "Description": "NoDiagonal(未知3)。", + "Title": "无对角线" + }, + "Armor": { + "Description": "尚未记录。", + "Title": "护甲" + }, + "Roof": { + "Description": "图块是斜面屋顶。", + "Title": "屋顶" + }, + "Door": { + "Description": "图块是门。带有此标志的图块可以被幽灵和GM穿过。", + "Title": "门" + }, + "StairBack": { + "Description": "尚未记录。", + "Title": "后楼梯" + }, + "StairRight": { + "Description": "尚未记录。", + "Title": "右楼梯" + }, + "AlphaBlend": { + "Description": "混合Alphas,图块混合。", + "Title": "透明混合" + }, + "UseNewArt": { + "Description": "使用新美术风格?与nodraw图块相关?", + "Title": "使用新美术" + }, + "ArtUsed": { + "Description": "有美术被使用?", + "Title": "已使用美术" + }, + "Unused8": { + "Description": "未使用或未知。", + "Title": "未使用8" + }, + "NoShadow": { + "Description": "不允许此图块上的阴影,光源?熔岩?", + "Title": "无阴影" + }, + "PixelBleed": { + "Description": "让像素渗透到其他图块?这是禁用纹理夹具?", + "Title": "像素渗漏" + }, + "PlayAnimOnce": { + "Description": "播放一次图块动画。", + "Title": "播放一次动画" + }, + "MultiMovable": { + "Description": "可移动多重部件?很酷的船和车辆等?与桅杆相关的东西?", + "Title": "多部件可移动" + }, + "Unused10": { + "Description": "未使用或未知。", + "Title": "未使用10" + }, + "Unused11": { + "Description": "未使用或未知。", + "Title": "未使用11" + }, + "Unused12": { + "Description": "未使用或未知。", + "Title": "未使用12" + }, + "Unused13": { + "Description": "未使用或未知。", + "Title": "未使用13" + }, + "Unused14": { + "Description": "未使用或未知。", + "Title": "未使用14" + }, + "Unused15": { + "Description": "未使用或未知。", + "Title": "未使用15" + }, + "Unused16": { + "Description": "未使用或未知。", + "Title": "未使用16" + }, + "Unused17": { + "Description": "未使用或未知。", + "Title": "未使用17" + }, + "Unused18": { + "Description": "未使用或未知。", + "Title": "未使用18" + }, + "Unused19": { + "Description": "未使用或未知。", + "Title": "未使用19" + }, + "Unused20": { + "Description": "未使用或未知。", + "Title": "未使用20" + }, + "Unused21": { + "Description": "未使用或未知。", + "Title": "未使用21" + }, + "Unused22": { + "Description": "未使用或未知。", + "Title": "未使用22" + }, + "Unused23": { + "Description": "未使用或未知。", + "Title": "未使用23" + }, + "Unused24": { + "Description": "未使用或未知。", + "Title": "未使用24" + }, + "Unused25": { + "Description": "未使用或未知。", + "Title": "未使用25" + }, + "Unused26": { + "Description": "未使用或未知。", + "Title": "未使用26" + }, + "Unused27": { + "Description": "未使用或未知。", + "Title": "未使用27" + }, + "Unused28": { + "Description": "未使用或未知。", + "Title": "未使用28" + }, + "Unused29": { + "Description": "未使用或未知。", + "Title": "未使用29" + }, + "Unused30": { + "Description": "未使用或未知。", + "Title": "未使用30" + }, + "Unused31": { + "Description": "未使用或未知。", + "Title": "未使用31" + }, + "Unused32": { + "Description": "未使用或未知。", + "Title": "未使用32" + } + } + }, "StrategyHelpForm": { "Title": "雷达颜色 — 平均策略", "CloseButton": "关闭", From f8c51bba0e2d66f07956f221c1769210e71e5aa4 Mon Sep 17 00:00:00 2001 From: nbyaya Date: Thu, 8 Oct 2026 13:35:06 +0800 Subject: [PATCH 79/81] =?UTF-8?q?=E6=B1=89=E5=8C=96=E9=80=89=E6=8B=A9?= =?UTF-8?q?=E9=85=8D=E7=BD=AE=E6=96=87=E4=BB=B6=E7=AA=97=E5=8F=A3?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit - LoadProfileForm UI 文本汉化 - 修复名称为空时应用启动异常 - 添加 null 检查防止崩溃 --- UoFiddler/FiddlerAppContext.cs | 10 ++++++- UoFiddler/Forms/LoadProfileForm.cs | 30 +++++++++++++++++-- .../Localization/Dictionaries/zh-CN.json | 6 +++- 3 files changed, 41 insertions(+), 5 deletions(-) diff --git a/UoFiddler/FiddlerAppContext.cs b/UoFiddler/FiddlerAppContext.cs index 0a8309dd..553f4a11 100644 --- a/UoFiddler/FiddlerAppContext.cs +++ b/UoFiddler/FiddlerAppContext.cs @@ -17,6 +17,7 @@ using UoFiddler.Controls.Classes; using UoFiddler.Controls.UserControls; using UoFiddler.Forms; +using UoFiddler.Localization; using Ultima.Helpers; namespace UoFiddler @@ -47,6 +48,7 @@ internal FiddlerAppContext(IServiceProvider services) _logger.LogInformation("Starting loading profile form..."); var profile = new LoadProfileForm(services.GetRequiredService>()) { TopMost = true }; + profile.SetLocalization(LocalizationService.GetString); var profileResult = profile.ShowDialog(); if (profileResult == DialogResult.Cancel) { @@ -80,9 +82,15 @@ internal FiddlerAppContext(IServiceProvider services) } _logger.LogInformation("Starting main form..."); + + // 确保 Options.ProfileName 有有效值 + string profileDisplayName = string.IsNullOrEmpty(Options.ProfileName) + ? "Default" + : Options.ProfileName.Replace("Options_", "").Replace(".xml", ""); + MainForm = new MainForm(services.GetRequiredService>()) { - Text = $"{Application.ProductName} (Profile: {Options.ProfileName.Replace("Options_", "").Replace(".xml", "")})" + Text = $"{Application.ProductName} (Profile: {profileDisplayName})" }; MainForm.Show(); } diff --git a/UoFiddler/Forms/LoadProfileForm.cs b/UoFiddler/Forms/LoadProfileForm.cs index 93f5c915..3e4194ea 100644 --- a/UoFiddler/Forms/LoadProfileForm.cs +++ b/UoFiddler/Forms/LoadProfileForm.cs @@ -24,6 +24,7 @@ public partial class LoadProfileForm : Form { private readonly string[] _profiles; private readonly ILogger _log; + private Func? _localizationGetter; public LoadProfileForm() : this(AppLog.For()) { } @@ -46,8 +47,27 @@ public LoadProfileForm(ILogger logger) comboBoxLoad.SelectedIndex = 0; comboBoxBasedOn.SelectedIndex = 0; - // 应用中文汉化 - LocalizationService.LocalizeForm(this); + // 汉化 getter 在 SetLocalization() 时才初始化 + // 这样确保 LocalizationService 已完全初始化 + } + + public void SetLocalization(Func getLocalized) + { + if (getLocalized == null) return; + _localizationGetter = getLocalized; + ApplyLocalization(); + } + + private void ApplyLocalization() + { + if (_localizationGetter == null) return; + + this.Text = _localizationGetter("Forms.LoadProfileForm.Title") ?? "Choose Profile"; + groupBox1.Text = _localizationGetter("Forms.LoadProfileForm.groupBox1") ?? "Load"; + groupBox2.Text = _localizationGetter("Forms.LoadProfileForm.groupBox2") ?? "Create"; + button1.Text = _localizationGetter("Forms.LoadProfileForm.button1") ?? "Load Profile"; + button2.Text = _localizationGetter("Forms.LoadProfileForm.button2") ?? "Create Profile"; + label1.Text = _localizationGetter("Forms.LoadProfileForm.label1") ?? "Based On"; } private static string[] GetProfiles() @@ -87,7 +107,11 @@ private void OnClickCreate(object sender, EventArgs e) { if (string.IsNullOrEmpty(textBoxCreate.Text)) { - MessageBox.Show("Profile name is missing", "New Profile", MessageBoxButtons.OK, MessageBoxIcon.Error); + string message = _localizationGetter?.Invoke("Forms.LoadProfileForm.Messages.ProfileNameMissing") ?? "Profile name is missing"; + string title = _localizationGetter?.Invoke("Forms.LoadProfileForm.Messages.NewProfileTitle") ?? "New Profile"; + MessageBox.Show(message, title, MessageBoxButtons.OK, MessageBoxIcon.Error); + // 不关闭对话框,让用户重新输入 + textBoxCreate.Focus(); return; } diff --git a/UoFiddler/Localization/Dictionaries/zh-CN.json b/UoFiddler/Localization/Dictionaries/zh-CN.json index d2d3f408..78f85b6f 100644 --- a/UoFiddler/Localization/Dictionaries/zh-CN.json +++ b/UoFiddler/Localization/Dictionaries/zh-CN.json @@ -102,7 +102,11 @@ "groupBox2": "创建", "button1": "加载配置文件", "button2": "创建配置文件", - "label1": "基于" + "label1": "基于", + "Messages": { + "ProfileNameMissing": "配置文件名称不能为空", + "NewProfileTitle": "新配置文件" + } }, "OptionsForm": { "Title": "选项", From 039a93e6ba333eb5d54d357a1c0709cff9589cb7 Mon Sep 17 00:00:00 2001 From: nbyaya Date: Thu, 8 Oct 2026 13:58:17 +0800 Subject: [PATCH 80/81] =?UTF-8?q?=E6=B1=89=E5=8C=96=E5=A4=9A=E9=87=8D?= =?UTF-8?q?=E7=BB=84=E4=BB=B6=E7=AA=97=E5=8F=A3=E5=AF=BC=E5=87=BA=E5=92=8C?= =?UTF-8?q?=E4=BF=9D=E5=AD=98=E5=8A=9F=E8=83=BD?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit - 为 MultisControl 导出功能添加汉化支持(BMP/TIFF/JPG/PNG、文本/UOA/WSC/CSV/UOX3 等格式) - 为 FileSavedDialog 添加多重组件专用的汉化消息 - 为 ClientFileSaveCommand 添加保存确认对话框的汉化 - JSON 中添加了 MultiSavedMessage、AllMultisSavedMessage、AllUopMultisSavedMessage 等 7 个汉化条目 --- .../Classes/ClientFileSaveCommand.cs | 50 +++++++++++++++- .../UserControls/MultisControl.cs | 59 +++++++++++-------- .../Localization/Dictionaries/zh-CN.json | 14 +++++ 3 files changed, 98 insertions(+), 25 deletions(-) diff --git a/UoFiddler.Controls/Classes/ClientFileSaveCommand.cs b/UoFiddler.Controls/Classes/ClientFileSaveCommand.cs index 232c24ae..6fbad45a 100644 --- a/UoFiddler.Controls/Classes/ClientFileSaveCommand.cs +++ b/UoFiddler.Controls/Classes/ClientFileSaveCommand.cs @@ -161,7 +161,35 @@ private static bool ConfirmPreflight(Control owner, FileType type, ContainerForm sb.AppendLine().AppendLine().Append("Save anyway?"); - return MessageBox.Show(owner?.FindForm(), sb.ToString(), "Save", MessageBoxButtons.YesNo, + // 尝试获取汉化文本 + string confirmTitle = "Save"; + string confirmQuestion = "Save anyway?"; + 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) + { + var localizedTitle = getStringMethod.Invoke(null, new object[] { "Forms.ClientFileSaveCommand.SaveConfirmTitle" }); + if (localizedTitle is string title) + confirmTitle = title; + + var localizedQuestion = getStringMethod.Invoke(null, new object[] { "Forms.ClientFileSaveCommand.SaveAnywayQuestion" }); + if (localizedQuestion is string question) + confirmQuestion = question; + } + } + } + catch { } + + // 替换英文问题为汉化版本 + sb.Length -= "Save anyway?".Length; + sb.Append(confirmQuestion); + + return MessageBox.Show(owner?.FindForm(), sb.ToString(), confirmTitle, MessageBoxButtons.YesNo, MessageBoxIcon.Warning, MessageBoxDefaultButton.Button2) == DialogResult.Yes; } @@ -211,7 +239,25 @@ private static void ShowError(Control owner, FileType type, Exception error) sb.AppendLine(where); } - MessageBox.Show(owner?.FindForm(), sb.ToString(), "Save failed", MessageBoxButtons.OK, + string errorTitle = "Save failed"; + 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) + { + var localizedTitle = getStringMethod.Invoke(null, new object[] { "Forms.ClientFileSaveCommand.SaveFailedTitle" }); + if (localizedTitle is string title) + errorTitle = title; + } + } + } + catch { } + + MessageBox.Show(owner?.FindForm(), sb.ToString(), errorTitle, MessageBoxButtons.OK, MessageBoxIcon.Error); } diff --git a/UoFiddler.Controls/UserControls/MultisControl.cs b/UoFiddler.Controls/UserControls/MultisControl.cs index af403d09..39ed87a4 100644 --- a/UoFiddler.Controls/UserControls/MultisControl.cs +++ b/UoFiddler.Controls/UserControls/MultisControl.cs @@ -538,7 +538,7 @@ private void ExtractMultiImage(ImageFormat imageFormat, Color backgroundColor) string floorSuffix = HeightChangeMulti.Value > 0 ? $"_Z{HeightChangeMulti.Value:000}" : string.Empty; string fileName = Path.Combine(Options.OutputPath, $"Multi {Utils.FormatExportId(GetSelectedMulId())}{floorSuffix}.{fileExtension}"); SaveImage(_mulBitmap, fileName, imageFormat, backgroundColor); - FileSavedDialog.Show(FindForm(), fileName, "Multi saved successfully."); + ShowFileSavedDialog(fileName, _localizationGetter?.Invoke("Forms.FileSavedDialog.MultiSavedMessage") ?? "Multi saved successfully."); } private static void SaveImage(Image sourceImage, string fileName, ImageFormat imageFormat, Color backgroundColor) @@ -578,7 +578,7 @@ private void OnExportTextFile(object sender, EventArgs e) string fileName = Path.Combine(path, $"Multi {Utils.FormatExportId(id)}.txt"); multi.ExportToTextFile(fileName); - FileSavedDialog.Show(FindForm(), fileName, "Multi saved successfully."); + ShowFileSavedDialog(fileName, _localizationGetter?.Invoke("Forms.FileSavedDialog.MultiSavedMessage") ?? "Multi saved successfully."); } private void OnExportWscFile(object sender, EventArgs e) @@ -599,7 +599,7 @@ private void OnExportWscFile(object sender, EventArgs e) string fileName = Path.Combine(path, $"Multi {Utils.FormatExportId(id)}.wsc"); multi.ExportToWscFile(fileName); - FileSavedDialog.Show(FindForm(), fileName, "Multi saved successfully."); + ShowFileSavedDialog(fileName, _localizationGetter?.Invoke("Forms.FileSavedDialog.MultiSavedMessage") ?? "Multi saved successfully."); } private void OnExportUOAFile(object sender, EventArgs e) @@ -620,7 +620,7 @@ private void OnExportUOAFile(object sender, EventArgs e) string fileName = Path.Combine(path, $"Multi {Utils.FormatExportId(id)}.uoa"); multi.ExportToUOAFile(fileName); - FileSavedDialog.Show(FindForm(), fileName, "Multi saved successfully."); + ShowFileSavedDialog(fileName, _localizationGetter?.Invoke("Forms.FileSavedDialog.MultiSavedMessage") ?? "Multi saved successfully."); } private void OnClickSave(object sender, EventArgs e) @@ -741,7 +741,7 @@ private void ExportAllMultis(ImageFormat imageFormat, Color backgroundColor) } } - FileSavedDialog.Show(FindForm(), dialog.SelectedPath, "All Multis saved successfully."); + ShowFileSavedDialog(dialog.SelectedPath, _localizationGetter?.Invoke("Forms.FileSavedDialog.AllMultisSavedMessage") ?? "All Multis saved successfully."); } } @@ -774,7 +774,7 @@ private void OnClick_SaveAllText(object sender, EventArgs e) multi.ExportToTextFile(fileName); } - FileSavedDialog.Show(FindForm(), dialog.SelectedPath, "All Multis saved successfully."); + ShowFileSavedDialog(dialog.SelectedPath, _localizationGetter?.Invoke("Forms.FileSavedDialog.AllMultisSavedMessage") ?? "All Multis saved successfully."); } } @@ -807,7 +807,7 @@ private void OnClick_SaveAllUOA(object sender, EventArgs e) multi.ExportToUOAFile(fileName); } - FileSavedDialog.Show(FindForm(), dialog.SelectedPath, "All Multis saved successfully."); + ShowFileSavedDialog(dialog.SelectedPath, _localizationGetter?.Invoke("Forms.FileSavedDialog.AllMultisSavedMessage") ?? "All Multis saved successfully."); } } @@ -840,7 +840,7 @@ private void OnClick_SaveAllWSC(object sender, EventArgs e) multi.ExportToWscFile(fileName); } - FileSavedDialog.Show(FindForm(), dialog.SelectedPath, "All Multis saved successfully."); + ShowFileSavedDialog(dialog.SelectedPath, _localizationGetter?.Invoke("Forms.FileSavedDialog.AllMultisSavedMessage") ?? "All Multis saved successfully."); } } @@ -873,7 +873,7 @@ private void OnClick_SaveAllCSV(object sender, EventArgs e) multi.ExportToCsvFile(fileName); } - FileSavedDialog.Show(FindForm(), dialog.SelectedPath, "All Multis saved successfully."); + ShowFileSavedDialog(dialog.SelectedPath, _localizationGetter?.Invoke("Forms.FileSavedDialog.AllMultisSavedMessage") ?? "All Multis saved successfully."); } } @@ -906,7 +906,7 @@ private void OnClick_SaveAllUox3(object sender, EventArgs e) multi.ExportToUox3File(fileName); } - FileSavedDialog.Show(FindForm(), dialog.SelectedPath, "All Multis saved successfully."); + ShowFileSavedDialog(dialog.SelectedPath, _localizationGetter?.Invoke("Forms.FileSavedDialog.AllMultisSavedMessage") ?? "All Multis saved successfully."); } } @@ -927,7 +927,7 @@ private void OnExportCsvFile(object sender, EventArgs e) string path = Options.OutputPath; string fileName = Path.Combine(path, $"{id:D4}.csv"); multi.ExportToCsvFile(fileName); - FileSavedDialog.Show(FindForm(), fileName, "Multi saved successfully."); + ShowFileSavedDialog(fileName, _localizationGetter?.Invoke("Forms.FileSavedDialog.MultiSavedMessage") ?? "Multi saved successfully."); } private void OnExportUox3File(object sender, EventArgs e) @@ -947,7 +947,7 @@ private void OnExportUox3File(object sender, EventArgs e) string path = Options.OutputPath; string fileName = Path.Combine(path, $"Multi {Utils.FormatExportId(id)}.uox3"); multi.ExportToUox3File(fileName); - FileSavedDialog.Show(FindForm(), fileName, "Multi saved successfully."); + ShowFileSavedDialog(fileName, _localizationGetter?.Invoke("Forms.FileSavedDialog.MultiSavedMessage") ?? "Multi saved successfully."); } private void ChangeBackgroundColorToolStripMenuItem_Click(object sender, EventArgs e) @@ -1370,7 +1370,7 @@ private void ExtractUopMultiImage(ImageFormat imageFormat, Color backgroundColor int id = GetSelectedUopId(); string fileName = Path.Combine(Options.OutputPath, $"UopMulti {Utils.FormatExportId(id)}{floorSuffix}.{fileExtension}"); SaveImage(_uopBitmap, fileName, imageFormat, backgroundColor); - FileSavedDialog.Show(FindForm(), fileName, "Multi saved successfully."); + ShowFileSavedDialog(fileName, _localizationGetter?.Invoke("Forms.FileSavedDialog.MultiSavedMessage") ?? "Multi saved successfully."); } private void OnUopExportTextFile(object sender, EventArgs e) @@ -1387,7 +1387,7 @@ private void OnUopExportTextFile(object sender, EventArgs e) } string fileName = Path.Combine(Options.OutputPath, $"UopMulti {Utils.FormatExportId(id)}.txt"); multi.ExportToTextFile(fileName); - FileSavedDialog.Show(FindForm(), fileName, "Multi saved successfully."); + ShowFileSavedDialog(fileName, _localizationGetter?.Invoke("Forms.FileSavedDialog.MultiSavedMessage") ?? "Multi saved successfully."); } private void OnUopExportUOAFile(object sender, EventArgs e) @@ -1404,7 +1404,7 @@ private void OnUopExportUOAFile(object sender, EventArgs e) } string fileName = Path.Combine(Options.OutputPath, $"UopMulti {Utils.FormatExportId(id)}.uoa"); multi.ExportToUOAFile(fileName); - FileSavedDialog.Show(FindForm(), fileName, "Multi saved successfully."); + ShowFileSavedDialog(fileName, _localizationGetter?.Invoke("Forms.FileSavedDialog.MultiSavedMessage") ?? "Multi saved successfully."); } private void OnUopExportWscFile(object sender, EventArgs e) @@ -1421,7 +1421,7 @@ private void OnUopExportWscFile(object sender, EventArgs e) } string fileName = Path.Combine(Options.OutputPath, $"UopMulti {Utils.FormatExportId(id)}.wsc"); multi.ExportToWscFile(fileName); - FileSavedDialog.Show(FindForm(), fileName, "Multi saved successfully."); + ShowFileSavedDialog(fileName, _localizationGetter?.Invoke("Forms.FileSavedDialog.MultiSavedMessage") ?? "Multi saved successfully."); } private void OnUopExportCsvFile(object sender, EventArgs e) @@ -1438,7 +1438,7 @@ private void OnUopExportCsvFile(object sender, EventArgs e) } string fileName = Path.Combine(Options.OutputPath, $"{id:D4}_uop.csv"); multi.ExportToCsvFile(fileName); - FileSavedDialog.Show(FindForm(), fileName, "Multi saved successfully."); + ShowFileSavedDialog(fileName, _localizationGetter?.Invoke("Forms.FileSavedDialog.MultiSavedMessage") ?? "Multi saved successfully."); } private void OnUopClick_SaveAllBmp(object sender, EventArgs e) => @@ -1485,7 +1485,7 @@ private void ExportAllUopMultis(ImageFormat imageFormat, Color backgroundColor) } } - FileSavedDialog.Show(FindForm(), dialog.SelectedPath, "All UOP Multis saved successfully."); + ShowFileSavedDialog(dialog.SelectedPath, _localizationGetter?.Invoke("Forms.FileSavedDialog.AllUopMultisSavedMessage") ?? "All UOP Multis saved successfully."); } private void OnUopClick_SaveAllText(object sender, EventArgs e) @@ -1513,7 +1513,7 @@ private void OnUopClick_SaveAllText(object sender, EventArgs e) multi.ExportToTextFile(Path.Combine(dialog.SelectedPath, $"UopMulti {Utils.FormatExportId(index)}.txt")); } - FileSavedDialog.Show(FindForm(), dialog.SelectedPath, "All UOP Multis saved successfully."); + ShowFileSavedDialog(dialog.SelectedPath, _localizationGetter?.Invoke("Forms.FileSavedDialog.AllUopMultisSavedMessage") ?? "All UOP Multis saved successfully."); } private void OnUopClick_SaveAllUOA(object sender, EventArgs e) @@ -1541,7 +1541,7 @@ private void OnUopClick_SaveAllUOA(object sender, EventArgs e) multi.ExportToUOAFile(Path.Combine(dialog.SelectedPath, $"UopMulti {Utils.FormatExportId(index)}.uoa")); } - FileSavedDialog.Show(FindForm(), dialog.SelectedPath, "All UOP Multis saved successfully."); + ShowFileSavedDialog(dialog.SelectedPath, _localizationGetter?.Invoke("Forms.FileSavedDialog.AllUopMultisSavedMessage") ?? "All UOP Multis saved successfully."); } private void OnUopClick_SaveAllWSC(object sender, EventArgs e) @@ -1569,7 +1569,7 @@ private void OnUopClick_SaveAllWSC(object sender, EventArgs e) multi.ExportToWscFile(Path.Combine(dialog.SelectedPath, $"UopMulti {Utils.FormatExportId(index)}.wsc")); } - FileSavedDialog.Show(FindForm(), dialog.SelectedPath, "All UOP Multis saved successfully."); + ShowFileSavedDialog(dialog.SelectedPath, _localizationGetter?.Invoke("Forms.FileSavedDialog.AllUopMultisSavedMessage") ?? "All UOP Multis saved successfully."); } private void OnUopClick_SaveAllCSV(object sender, EventArgs e) @@ -1597,7 +1597,7 @@ private void OnUopClick_SaveAllCSV(object sender, EventArgs e) multi.ExportToCsvFile(Path.Combine(dialog.SelectedPath, $"{index:D4}_uop.csv")); } - FileSavedDialog.Show(FindForm(), dialog.SelectedPath, "All UOP Multis saved successfully."); + ShowFileSavedDialog(dialog.SelectedPath, _localizationGetter?.Invoke("Forms.FileSavedDialog.AllUopMultisSavedMessage") ?? "All UOP Multis saved successfully."); } private void OnClick_SaveAllToXML(object sender, EventArgs e) @@ -1668,7 +1668,7 @@ private void OnClick_SaveAllToXML(object sender, EventArgs e) groupWriter.WriteEndDocument(); } - FileSavedDialog.Show(FindForm(), fileName, "All Multis saved successfully."); + ShowFileSavedDialog(fileName, _localizationGetter?.Invoke("Forms.FileSavedDialog.AllMultisSavedMessage") ?? "All Multis saved successfully."); } /// @@ -1680,6 +1680,17 @@ public void SetLocalization(Func getLocalized) ApplyLocalization(); } + /// + /// 显示文件保存成功对话框,支持汉化 + /// + private void ShowFileSavedDialog(string filePath, string message) + { + if (_localizationGetter != null) + FileSavedDialog.Show(FindForm(), filePath, message, null, _localizationGetter); + else + FileSavedDialog.Show(FindForm(), filePath, message); + } + private void ApplyLocalization() { if (_localizationGetter == null) return; @@ -1823,3 +1834,5 @@ private static bool IsOver(Control c, Point screenPt) } } } + + diff --git a/UoFiddler/Localization/Dictionaries/zh-CN.json b/UoFiddler/Localization/Dictionaries/zh-CN.json index 78f85b6f..9ba97565 100644 --- a/UoFiddler/Localization/Dictionaries/zh-CN.json +++ b/UoFiddler/Localization/Dictionaries/zh-CN.json @@ -108,6 +108,20 @@ "NewProfileTitle": "新配置文件" } }, + "ClientFileSaveCommand": { + "SaveConfirmTitle": "保存", + "SaveAnywayQuestion": "仍然保存吗?", + "SaveFailedTitle": "保存失败" + }, + "FileSavedDialog": { + "Title": "已保存", + "SaveSuccess": "保存成功", + "OpenFolder": "打开文件夹", + "OK": "确定", + "MultiSavedMessage": "多重组件保存成功", + "AllMultisSavedMessage": "所有多重组件保存成功", + "AllUopMultisSavedMessage": "所有 UOP 多重组件保存成功" + }, "OptionsForm": { "Title": "选项", "groupBox1": "物品标签页", From 447755f3fb752d07e5fca9731c8500c43273fd95 Mon Sep 17 00:00:00 2001 From: nbyaya Date: Thu, 8 Oct 2026 15:16:33 +0800 Subject: [PATCH 81/81] =?UTF-8?q?=E6=B1=89=E5=8C=96=E5=8A=A8=E7=94=BB?= =?UTF-8?q?=E7=AA=97=E5=8F=A3=E4=B8=AD=E7=9A=84=E5=86=85=E5=AE=B9=EF=BC=9A?= =?UTF-8?q?=E9=87=8D=E5=86=99XML=E3=80=81=E7=AA=97=E5=8F=A3=E3=80=81?= =?UTF-8?q?=E5=B0=9D=E8=AF=95=E6=9F=A5=E6=89=BE=E6=96=B0=E5=9B=BE=E5=BD=A2?= =?UTF-8?q?=E3=80=81=E5=8A=A8=E7=94=BB=E7=BC=96=E8=BE=91=E7=AD=89?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit - 动画编辑窗口:标题、标签页、右键菜单、编辑器功能区域 - 状态栏功能:保存、导出相关操作 - UI 元素:颜色列表、对话框标题和消息 - Bug 修复:播放按钮图标显示问题 --- .../Forms/AnimationEditForm.Designer.cs | 4 +- UoFiddler.Controls/Forms/AnimationEditForm.cs | 109 ++++++++++++++- .../Forms/AnimationListNewEntriesForm.cs | 30 +++- .../UserControls/AnimationListControl.cs | 69 ++++++++-- .../Localization/Dictionaries/zh-CN.json | 128 ++++++++++++++++++ 5 files changed, 325 insertions(+), 15 deletions(-) diff --git a/UoFiddler.Controls/Forms/AnimationEditForm.Designer.cs b/UoFiddler.Controls/Forms/AnimationEditForm.Designer.cs index b0a1642f..24187b16 100644 --- a/UoFiddler.Controls/Forms/AnimationEditForm.Designer.cs +++ b/UoFiddler.Controls/Forms/AnimationEditForm.Designer.cs @@ -1089,7 +1089,7 @@ private void InitializeComponent() // SecondAnimColorComboBox // SecondAnimColorComboBox.DropDownStyle = System.Windows.Forms.ComboBoxStyle.DropDownList; - SecondAnimColorComboBox.Items.AddRange(new object[] { "Original", "Green", "Magenta", "Cyan", "Red", "Custom…" }); + SecondAnimColorComboBox.Items.AddRange(new object[] { "原始", "绿色", "洋红色", "青色", "红色", "自定义…" }); SecondAnimColorComboBox.Location = new System.Drawing.Point(9, 98); SecondAnimColorComboBox.Name = "SecondAnimColorComboBox"; SecondAnimColorComboBox.Size = new System.Drawing.Size(172, 23); @@ -1211,7 +1211,7 @@ private void InitializeComponent() // AnimationSpeedTrackBar // AnimationSpeedTrackBar.AutoSize = false; - AnimationSpeedTrackBar.Location = new System.Drawing.Point(48, 22); + AnimationSpeedTrackBar.Location = new System.Drawing.Point(48, 35); AnimationSpeedTrackBar.Margin = new System.Windows.Forms.Padding(4, 3, 4, 3); AnimationSpeedTrackBar.Maximum = 14; AnimationSpeedTrackBar.Name = "AnimationSpeedTrackBar"; diff --git a/UoFiddler.Controls/Forms/AnimationEditForm.cs b/UoFiddler.Controls/Forms/AnimationEditForm.cs index 89006bfc..020347ca 100644 --- a/UoFiddler.Controls/Forms/AnimationEditForm.cs +++ b/UoFiddler.Controls/Forms/AnimationEditForm.cs @@ -38,6 +38,8 @@ public partial class AnimationEditForm : Form private float _zoomFactor = 1.0f; + private Func? _localizationGetter; + // Second-animation overlay state private bool _secondAnimActivated; private int _secondAnimId; @@ -114,8 +116,109 @@ public AnimationEditForm() _loaded = false; } + public void SetLocalization(Func? getLocalized) + { + _localizationGetter = getLocalized; + ApplyLocalization(); + } + + private void ApplyLocalization() + { + if (_localizationGetter == null) return; + + // Tab pages + FramePage.Text = _localizationGetter("Forms.AnimationEditForm.Tabs.Frame") ?? "Frame"; + AnimationEditPage.Text = _localizationGetter("Forms.AnimationEditForm.Tabs.PreviewEdit") ?? "Preview/Edit"; + GalleryPage.Text = _localizationGetter("Forms.AnimationEditForm.Tabs.Gallery") ?? "Gallery"; + + // TreeView context menu + addToolStripMenuItem.Text = _localizationGetter("Forms.AnimationEditForm.TreeViewContextMenu.Replace") ?? "Replace"; + removeToolStripMenuItem.Text = _localizationGetter("Forms.AnimationEditForm.TreeViewContextMenu.Remove") ?? "Remove"; + extractImagesToolStripMenuItem1.Text = _localizationGetter("Forms.AnimationEditForm.TreeViewContextMenu.ExtractImages") ?? "Extract Images.."; + asBmpToolStripMenuItem.Text = _localizationGetter("Forms.AnimationEditForm.TreeViewContextMenu.ExtractAsFormats.Bmp") ?? "As Bmp"; + asTiffToolStripMenuItem.Text = _localizationGetter("Forms.AnimationEditForm.TreeViewContextMenu.ExtractAsFormats.Tiff") ?? "As Tiff"; + asJpgToolStripMenuItem.Text = _localizationGetter("Forms.AnimationEditForm.TreeViewContextMenu.ExtractAsFormats.Jpg") ?? "As Jpg"; + asPngToolStripMenuItem.Text = _localizationGetter("Forms.AnimationEditForm.TreeViewContextMenu.ExtractAsFormats.Png") ?? "As Png"; + importToolStripMenuItem1.Text = _localizationGetter("Forms.AnimationEditForm.TreeViewContextMenu.Import") ?? "Import.."; + fromvdToolStripMenuItem.Text = _localizationGetter("Forms.AnimationEditForm.TreeViewContextMenu.ImportFromVD") ?? "From .vd"; + exportToolStripMenuItem1.Text = _localizationGetter("Forms.AnimationEditForm.TreeViewContextMenu.Export") ?? "Export.."; + tovdToolStripMenuItem.Text = _localizationGetter("Forms.AnimationEditForm.TreeViewContextMenu.ExportToVD") ?? "To .vd"; + + // Palette context menu + exportToolStripMenuItem.Text = _localizationGetter("Forms.AnimationEditForm.PaletteContextMenu.Export") ?? "Export.."; + bmpToolStripMenuItem.Text = _localizationGetter("Forms.AnimationEditForm.PaletteContextMenu.ExportBmp") ?? "Bmp"; + tiffToolStripMenuItem.Text = _localizationGetter("Forms.AnimationEditForm.PaletteContextMenu.ExportTiff") ?? "Tiff"; + textToolStripMenuItem.Text = _localizationGetter("Forms.AnimationEditForm.PaletteContextMenu.ExportText") ?? "Text"; + importToolStripMenuItem.Text = _localizationGetter("Forms.AnimationEditForm.PaletteContextMenu.Import") ?? "Import.."; + fromTxtToolStripMenuItem.Text = _localizationGetter("Forms.AnimationEditForm.PaletteContextMenu.ImportFromTxt") ?? "From Txt"; + fromGifToolStripMenuItem.Text = _localizationGetter("Forms.AnimationEditForm.PaletteContextMenu.ImportFromGif") ?? "From Gif"; + fromImageToolStripMenuItem.Text = _localizationGetter("Forms.AnimationEditForm.PaletteContextMenu.ImportFromImage") ?? "From Image"; + + // Frames list view context menu + allDirectionsAddToolStripMenuItem.Text = _localizationGetter("Forms.AnimationEditForm.FramesListViewContextMenu.AllDirectionsAdd") ?? "All directions add"; + allDirectionsAddWithCanvasToolStripMenuItem.Text = _localizationGetter("Forms.AnimationEditForm.FramesListViewContextMenu.AllDirectionsAddWithCanvas") ?? "All directions add with Canvas"; + addDirectionsAddWithCanvasUniqueImageToolStripMenuItem.Text = _localizationGetter("Forms.AnimationEditForm.FramesListViewContextMenu.AllDirectionsAddWithCanvasCv5GifStyle") ?? "All directions add with Canvas ( CV5 Gif Style )"; + allDirectionsAddWithCanvasKRframeEditorColorCorrectorToolStripMenuItem.Text = _localizationGetter("Forms.AnimationEditForm.FramesListViewContextMenu.AllDirectionsAddWithCanvasKRColorCorrector") ?? "All directions add with Canvas ( KRframeViewer Color Corrector)"; + addToolStripMenuItem1.Text = _localizationGetter("Forms.AnimationEditForm.FramesListViewContextMenu.Add") ?? "Add"; + addWithCanvasToolStripMenuItem.Text = _localizationGetter("Forms.AnimationEditForm.FramesListViewContextMenu.AddWithCanvas") ?? "Add with Canvas"; + replaceToolStripMenuItem.Text = _localizationGetter("Forms.AnimationEditForm.FramesListViewContextMenu.Replace") ?? "Replace"; + removeToolStripMenuItem1.Text = _localizationGetter("Forms.AnimationEditForm.FramesListViewContextMenu.Remove") ?? "Remove"; + + // Frame page controls + groupBox1.Text = _localizationGetter("Forms.AnimationEditForm.FramePage.ExtraBackground") ?? "Extra background"; + BackgroundRedLabel.Text = _localizationGetter("Forms.AnimationEditForm.FramePage.BackgroundRed") ?? "R"; + BackgroundGreenLabel.Text = _localizationGetter("Forms.AnimationEditForm.FramePage.BackgroundGreen") ?? "G"; + BackgroundBlueLabel.Text = _localizationGetter("Forms.AnimationEditForm.FramePage.BackgroundBlue") ?? "B"; + groupBox2.Text = _localizationGetter("Forms.AnimationEditForm.FramePage.PaletteConverter") ?? "Palette converter"; + SetPalleteButton.Text = _localizationGetter("Forms.AnimationEditForm.FramePage.SetPallete") ?? "Set"; + rbRGB.Text = _localizationGetter("Forms.AnimationEditForm.FramePage.ColorModes.RGB") ?? "RGB"; + rbRBG.Text = _localizationGetter("Forms.AnimationEditForm.FramePage.ColorModes.RBG") ?? "RBG"; + rbGRB.Text = _localizationGetter("Forms.AnimationEditForm.FramePage.ColorModes.GRB") ?? "GRB"; + rbGBR.Text = _localizationGetter("Forms.AnimationEditForm.FramePage.ColorModes.GBR") ?? "GBR"; + rbBGR.Text = _localizationGetter("Forms.AnimationEditForm.FramePage.ColorModes.BGR") ?? "BGR"; + rbBRG.Text = _localizationGetter("Forms.AnimationEditForm.FramePage.ColorModes.BRG") ?? "BRG"; + groupBox3.Text = _localizationGetter("Forms.AnimationEditForm.FramePage.ColorBalance") ?? "Color balance"; + ColorRedLabel.Text = _localizationGetter("Forms.AnimationEditForm.FramePage.ColorRed") ?? "R"; + ColorGreenLabel.Text = _localizationGetter("Forms.AnimationEditForm.FramePage.ColorGreen") ?? "G"; + ColorBlueLabel.Text = _localizationGetter("Forms.AnimationEditForm.FramePage.ColorBlue") ?? "B"; + ApplyButton.Text = _localizationGetter("Forms.AnimationEditForm.FramePage.ApplyButton") ?? "Apply"; + LockColorControlsCheckBox.Text = _localizationGetter("Forms.AnimationEditForm.FramePage.LockColorControls") ?? "Lock"; + + // Animation Edit page controls + ZoomLabel.Text = _localizationGetter("Forms.AnimationEditForm.AnimationEditPage.Zoom") ?? "Zoom:"; + DrawFullRectangleToolStripButton.ToolTipText = _localizationGetter("Forms.AnimationEditForm.AnimationEditPage.DrawFullRectangle") ?? "Draw Full Rectangle"; + DrawEmptyRectangleToolStripButton.ToolTipText = _localizationGetter("Forms.AnimationEditForm.AnimationEditPage.DrawEmptyRectangle") ?? "Draw Empty Rectangle"; + DrawReferencialPointToolStripButton.ToolTipText = _localizationGetter("Forms.AnimationEditForm.AnimationEditPage.DrawReferencialPoint") ?? "Draw Referencial Point"; + SecondAnimGroupBox.Text = _localizationGetter("Forms.AnimationEditForm.AnimationEditPage.SecondAnimOverlay") ?? "Second Animation Overlay"; + SecondAnimCheckBox.Text = _localizationGetter("Forms.AnimationEditForm.AnimationEditPage.ShowOverlay") ?? "Show overlay"; + SecondAnimIdLabel.Text = _localizationGetter("Forms.AnimationEditForm.AnimationEditPage.SecondAnimFileId") ?? "ID"; + SecondAnimOpacityLabel.Text = _localizationGetter("Forms.AnimationEditForm.AnimationEditPage.SecondAnimOpacity") ?? "Opacity"; + SecondAnimInFrontCheckBox.Text = _localizationGetter("Forms.AnimationEditForm.AnimationEditPage.OnTop") ?? "On top"; + SecondAnimBoxCheckBox.Text = _localizationGetter("Forms.AnimationEditForm.AnimationEditPage.Box") ?? "Box"; + FramesGroupBox.Text = _localizationGetter("Forms.AnimationEditForm.AnimationEditPage.AnimationFrames") ?? "Animation Frames"; + SpeedGroupBox.Text = _localizationGetter("Forms.AnimationEditForm.AnimationEditPage.AnimationSpeed") ?? "Animation Speed"; + LocationCenterGroupBox.Text = _localizationGetter("Forms.AnimationEditForm.AnimationEditPage.LocationCenter") ?? "Location Center"; + CenterXLabel.Text = _localizationGetter("Forms.AnimationEditForm.AnimationEditPage.CenterX") ?? "X"; + CenterYLabel.Text = _localizationGetter("Forms.AnimationEditForm.AnimationEditPage.CenterY") ?? "Y"; + SameCenterButton.Text = _localizationGetter("Forms.AnimationEditForm.AnimationEditPage.SameCenter") ?? "Same Center"; + ReferencialPointGroupBox.Text = _localizationGetter("Forms.AnimationEditForm.AnimationEditPage.ReferencialPoint") ?? "Referencial Point"; + RefXLabel.Text = _localizationGetter("Forms.AnimationEditForm.AnimationEditPage.RefX") ?? "X"; + RefYLabel.Text = _localizationGetter("Forms.AnimationEditForm.AnimationEditPage.RefY") ?? "Y"; + ToolStripLockButton.Text = _localizationGetter("Forms.AnimationEditForm.AnimationEditPage.LockButton") ?? "Lock"; + CoordinatesGroupBox.Text = _localizationGetter("Forms.AnimationEditForm.AnimationEditPage.Coordinates") ?? "Coordinates"; + SetCoordinatesButton.Text = _localizationGetter("Forms.AnimationEditForm.AnimationEditPage.SetCoordinates") ?? "Set"; + SaveCoordinatesCheckBox.Text = _localizationGetter("Forms.AnimationEditForm.AnimationEditPage.SaveCoordinates") ?? "Save"; + + // Status bar items + SaveToolStripMenuItem.Text = _localizationGetter("Forms.AnimationEditForm.StatusBar.SaveMenuItem") ?? "Save"; + ShowOnlyValidToolStripMenuItem.Text = _localizationGetter("Forms.AnimationEditForm.StatusBar.ShowOnlyValidMenuItem") ?? "Show Only Valid"; + ExportAllToVDToolStripMenuItem.Text = _localizationGetter("Forms.AnimationEditForm.StatusBar.ExportAllToVD") ?? "Export All Valid To VD"; + MiscToolStripButton.Text = _localizationGetter("Forms.AnimationEditForm.StatusBar.MiscButton") ?? "Misc"; + } + // Indexed by MobType enum: Monster=0, Sea=1, Animal=2, Human=3, Equipment=4. // Equipment composites onto a humanoid and shares the human action set. + private readonly string[][] _animNames = { new[] // Monster (22) @@ -1313,7 +1416,7 @@ private void OnClickSave(object sender, EventArgs e) AnimationEdit.Save(_fileType, Options.OutputPath); Options.ChangedUltimaClass["Animations"] = false; - MessageBox.Show($"AnimationFile saved to {Options.OutputPath}", "Saved", MessageBoxButtons.OK, + MessageBox.Show($"动画文件已保存到 {Options.OutputPath}", "已保存", MessageBoxButtons.OK, MessageBoxIcon.Information, MessageBoxDefaultButton.Button1); } @@ -2806,8 +2909,8 @@ private void OnClickExportAllToVD(object sender, EventArgs e) AnimationEdit.ExportToVD(_fileType, index, fileName); } - MessageBox.Show($"All Animations saved to {dialog.SelectedPath}", - "Export", MessageBoxButtons.OK, MessageBoxIcon.Information, MessageBoxDefaultButton.Button1); + MessageBox.Show($"所有动画已保存到 {dialog.SelectedPath}", + "全部导出到VD", MessageBoxButtons.OK, MessageBoxIcon.Information, MessageBoxDefaultButton.Button1); } } diff --git a/UoFiddler.Controls/Forms/AnimationListNewEntriesForm.cs b/UoFiddler.Controls/Forms/AnimationListNewEntriesForm.cs index 3668631f..cfe5cac6 100644 --- a/UoFiddler.Controls/Forms/AnimationListNewEntriesForm.cs +++ b/UoFiddler.Controls/Forms/AnimationListNewEntriesForm.cs @@ -26,6 +26,7 @@ public partial class AnimationListNewEntriesForm : Form private readonly string[][] _actionNames; private readonly Func _isAlreadyDefinedCallback; private readonly Action _addGraphicAction; + private readonly Func _localizationGetter; private int _currentSelect; private int _facing = 1; @@ -35,8 +36,10 @@ public partial class AnimationListNewEntriesForm : Form private AnimationFrame[] _animation; public AnimationListNewEntriesForm(Func isAlreadyDefinedCallback, - Action addGraphicAction, string[][] actionNames) + Action addGraphicAction, string[][] actionNames, Func localizationGetter = null) { + _localizationGetter = localizationGetter; + InitializeComponent(); Icon = Options.GetFiddlerIcon(); @@ -190,6 +193,31 @@ private void OnLoad(object sender, EventArgs e) } tvAnimationList.EndUpdate(); + + // 应用汉化 + ApplyLocalization(); + } + + private void ApplyLocalization() + { + if (_localizationGetter == null) + return; + + Text = _localizationGetter("Forms.AnimationListControl.NewEntriesForm.Title") ?? "Animationlist New Entries"; + toolStripButton1.Text = _localizationGetter("Forms.AnimationListControl.NewEntriesForm.AddButton") ?? "Add"; + animateToolStripMenuItem.Text = _localizationGetter("Forms.AnimationListControl.NewEntriesForm.AnimateMenuitem") ?? "Animate"; + + // 更新下拉框选项 + string[] actionTypes = new[] + { + _localizationGetter("Forms.AnimationListControl.NewEntriesForm.ActionTypes.Monster") ?? "Monster", + _localizationGetter("Forms.AnimationListControl.NewEntriesForm.ActionTypes.SeaMonster") ?? "Sea Monster", + _localizationGetter("Forms.AnimationListControl.NewEntriesForm.ActionTypes.Animal") ?? "Animal", + _localizationGetter("Forms.AnimationListControl.NewEntriesForm.ActionTypes.HumanEquipment") ?? "Human/Equipment" + }; + + ComboBoxActionType.Items.Clear(); + ComboBoxActionType.Items.AddRange(actionTypes); } private void ProcessBodyConverterTable(IEnumerable table) diff --git a/UoFiddler.Controls/UserControls/AnimationListControl.cs b/UoFiddler.Controls/UserControls/AnimationListControl.cs index 3d0fa585..fb235d33 100644 --- a/UoFiddler.Controls/UserControls/AnimationListControl.cs +++ b/UoFiddler.Controls/UserControls/AnimationListControl.cs @@ -987,6 +987,7 @@ private void OnClickAnimationEdit(object sender, EventArgs e) _animEditFormEntry = new AnimationEditForm(); //animEditEntry.TopMost = true; // TODO: should it be topMost? + _animEditFormEntry.SetLocalization(_localizationGetter); _animEditFormEntry.Show(); } @@ -999,7 +1000,7 @@ private void OnClickFindNewEntries(object sender, EventArgs e) return; } - _animNewEntryForm = new AnimationListNewEntriesForm(IsAlreadyDefined, AddGraphic, GetActionNames) + _animNewEntryForm = new AnimationListNewEntriesForm(IsAlreadyDefined, AddGraphic, GetActionNames, _localizationGetter) { TopMost = true }; @@ -1060,7 +1061,9 @@ private void RewriteXml(object sender, EventArgs e) dom.Save(fileName); } - MessageBox.Show("XML saved", "Rewrite", MessageBoxButtons.OK, MessageBoxIcon.Information, + string message = _localizationGetter?.Invoke("Forms.AnimationListControl.Messages.RewriteMessage") ?? "XML saved"; + string title = _localizationGetter?.Invoke("Forms.AnimationListControl.Messages.RewriteTitle") ?? "Rewrite"; + MessageBox.Show(message, title, MessageBoxButtons.OK, MessageBoxIcon.Information, MessageBoxDefaultButton.Button1); } @@ -1149,8 +1152,12 @@ private void ExtractImage(ImageFormat imageFormat) newBitmap.Save(fileName, imageFormat); } - MessageBox.Show($"{what} saved to {fileName}", "Saved", MessageBoxButtons.OK, MessageBoxIcon.Information, - MessageBoxDefaultButton.Button1); + // 获取汉化标题和消息 + string title = _localizationGetter?.Invoke("Forms.AnimationListControl.Messages.ExportSingleFrameTitle") ?? "Saved"; + string messageTemplate = _localizationGetter?.Invoke("Forms.AnimationListControl.Messages.ExportSingleFrameMessage") ?? "{0} saved to {1}"; + string message = string.Format(messageTemplate, what, fileName); + + MessageBox.Show(message, title, MessageBoxButtons.OK, MessageBoxIcon.Information, MessageBoxDefaultButton.Button1); } private void OnClickExtractAnimBmp(object sender, EventArgs e) @@ -1200,7 +1207,18 @@ private void ExportAnimationFrames(ImageFormat imageFormat) } } - FileSavedDialog.Show(FindForm(), Options.OutputPath, $"Files with following format {fileName}-X.{fileExtension} saved successfully."); + string message = _localizationGetter?.Invoke("Forms.AnimationListControl.Messages.ExportFramesMessage") + ?? $"Files with following format {fileName}-X.{fileExtension} saved successfully."; + + if (_localizationGetter != null) + { + string title = _localizationGetter("Forms.FileSavedDialog.Title") ?? "Saved"; + FileSavedDialog.Show(FindForm(), Options.OutputPath, message, title, _localizationGetter); + } + else + { + FileSavedDialog.Show(FindForm(), Options.OutputPath, message); + } } private void OnClickExportFrameBmp(object sender, EventArgs e) @@ -1237,7 +1255,7 @@ private void ExportSingleFrame(ImageFormat imageFormat) } string fileExtension = Utils.GetFileExtensionFor(imageFormat); - string fileName = Path.Combine(Options.OutputPath, $"{what} {Utils.FormatExportId(_currentSelect)}"); + string fileName = Path.Combine(Options.OutputPath, $"{what} {Utils.FormatExportId(_currentSelect)}-{(int)listView1.SelectedItems[0].Tag}.{fileExtension}"); Bitmap bit = MainPictureBox.Frames[(int)listView1.SelectedItems[0].Tag].Bitmap; using (Bitmap newBitmap = new Bitmap(bit.Width, bit.Height)) @@ -1249,8 +1267,15 @@ private void ExportSingleFrame(ImageFormat imageFormat) newGraph.Save(); } - newBitmap.Save($"{fileName}-{(int)listView1.SelectedItems[0].Tag}.{fileExtension}", imageFormat); + newBitmap.Save(fileName, imageFormat); } + + // 获取汉化标题和消息 + string title = _localizationGetter?.Invoke("Forms.AnimationListControl.Messages.ExportSingleFrameTitle") ?? "Saved"; + string messageTemplate = _localizationGetter?.Invoke("Forms.AnimationListControl.Messages.ExportSingleFrameMessage") ?? "{0} saved to {1}"; + string message = string.Format(messageTemplate, what, fileName); + + MessageBox.Show(message, title, MessageBoxButtons.OK, MessageBoxIcon.Information, MessageBoxDefaultButton.Button1); } private void OnClickExportAllThumbnailsBmp(object sender, EventArgs e) @@ -1339,7 +1364,20 @@ private void ExportAllThumbnails(ImageFormat imageFormat) } } - FileSavedDialog.Show(FindForm(), thumbnailPath, "All thumbnails saved successfully."); + // Localize message and title + string message = _localizationGetter?.Invoke("Forms.AnimationListControl.Messages.ExportAllThumbnailsMessage") + ?? "All thumbnails saved successfully."; + string title = _localizationGetter?.Invoke("Forms.AnimationListControl.Messages.ExportAllThumbnailsTitle") + ?? "Saved"; + + if (_localizationGetter != null) + { + FileSavedDialog.Show(FindForm(), thumbnailPath, message, title, _localizationGetter); + } + else + { + FileSavedDialog.Show(FindForm(), thumbnailPath, message); + } } private void ExportAnimatedGif(bool looping) @@ -1352,7 +1390,20 @@ private void ExportAnimatedGif(bool looping) var outputFile = Path.Combine(Options.OutputPath, $"{(_displayType == 1 ? "Equipment" : "Mob")} {_currentSelect}.gif"); MainPictureBox.Frames.ToGif(outputFile, looping: looping, delay: 150, showFrameBounds: MainPictureBox.ShowFrameBounds); - FileSavedDialog.Show(FindForm(), outputFile, "InGame Anim saved successfully."); + // Localize message and title + string message = _localizationGetter?.Invoke("Forms.AnimationListControl.Messages.ExportAnimatedGifMessage") + ?? "InGame Anim saved successfully."; + string title = _localizationGetter?.Invoke("Forms.AnimationListControl.Messages.ExportAnimatedGifTitle") + ?? "Saved"; + + if (_localizationGetter != null) + { + FileSavedDialog.Show(FindForm(), outputFile, message, title, _localizationGetter); + } + else + { + FileSavedDialog.Show(FindForm(), outputFile, message); + } } /// diff --git a/UoFiddler/Localization/Dictionaries/zh-CN.json b/UoFiddler/Localization/Dictionaries/zh-CN.json index 9ba97565..7a68e9f6 100644 --- a/UoFiddler/Localization/Dictionaries/zh-CN.json +++ b/UoFiddler/Localization/Dictionaries/zh-CN.json @@ -824,6 +824,134 @@ "Bow_Lesser_01": "鞠躬_较小_01", "Salute_Armed1h_01": "敬礼_持单手_01", "Ingest_Eat_01": "进食_进食_01" + }, + "Messages": { + "ExportFramesMessage": "文件已成功保存", + "ExportFrameMessage": "{0} 已保存到 {1}", + "ExportFrameTitle": "已保存", + "ExportSingleFrameMessage": "{0} 已保存到 {1}", + "ExportSingleFrameTitle": "已保存", + "ExportAllThumbnailsMessage": "所有缩略图已成功保存", + "ExportAllThumbnailsTitle": "已保存", + "ExportAnimatedGifMessage": "动画已成功保存", + "ExportAnimatedGifTitle": "已保存", + "RewriteTitle": "重写", + "RewriteMessage": "XML 已保存" + }, + "NewEntriesForm": { + "Title": "动画列表新条目", + "AddButton": "添加", + "AnimateMenuitem": "播放动画", + "ActionTypes": { + "Monster": "怪物", + "SeaMonster": "海怪", + "Animal": "动物", + "HumanEquipment": "人类/装备" + } + } + }, + "AnimationEditForm": { + "Title": "动画编辑", + "Tabs": { + "Frame": "帧", + "PreviewEdit": "预览/编辑", + "Gallery": "画廊" + }, + "TreeViewContextMenu": { + "Replace": "替换", + "Remove": "移除", + "ExtractImages": "导出图像..", + "ExtractAsFormats": { + "Bmp": "导出为 BMP", + "Tiff": "导出为 TIFF", + "Jpg": "导出为 JPG", + "Png": "导出为 PNG" + }, + "Import": "导入..", + "ImportFromVD": "从 .vd 导入", + "Export": "导出..", + "ExportToVD": "导出到 .vd" + }, + "FileSelector": "选择动画文件", + "PaletteContextMenu": { + "Export": "导出..", + "ExportBmp": "BMP", + "ExportTiff": "TIFF", + "ExportText": "文本", + "Import": "导入..", + "ImportFromTxt": "从 TXT 导入", + "ImportFromGif": "从 GIF 导入", + "ImportFromImage": "从图像导入" + }, + "FramesListViewContextMenu": { + "AllDirectionsAdd": "添加全部方向", + "AllDirectionsAddWithCanvas": "添加全部方向(带画布)", + "AllDirectionsAddWithCanvasCv5GifStyle": "添加全部方向(带画布,CV5 GIF 风格)", + "AllDirectionsAddWithCanvasKRColorCorrector": "添加全部方向(带画布,KR 颜色校正)", + "Add": "添加", + "AddWithCanvas": "添加(带画布)", + "Replace": "替换", + "Remove": "移除" + }, + "FramePage": { + "ColorBalance": "色彩平衡", + "BackgroundRed": "R", + "BackgroundGreen": "G", + "BackgroundBlue": "B", + "ApplyButton": "应用", + "PaletteConverter": "调色板转换器", + "SetPallete": "设置", + "ColorModes": { + "RGB": "RGB", + "RBG": "RBG", + "GRB": "GRB", + "GBR": "GBR", + "BGR": "BGR", + "BRG": "BRG" + }, + "ExtraBackground": "额外背景", + "ColorRed": "R", + "ColorGreen": "G", + "ColorBlue": "B", + "LockColorControls": "锁定颜色控制" + }, + "AnimationEditPage": { + "Zoom": "缩放:", + "DrawFullRectangle": "绘制完整矩形", + "DrawEmptyRectangle": "绘制空矩形", + "DrawReferencialPoint": "绘制参考点", + "SecondAnimOverlay": "第二动画叠加层", + "ShowOverlay": "显示叠加层", + "SecondAnimFileId": "ID", + "SecondAnimOpacity": "不透明度", + "OnTop": "在顶部", + "Box": "方框", + "WarningLabel": "警告", + "AnimationFrames": "动画帧", + "AnimationSpeed": "动画速度", + "PlayButton": "播放", + "LocationCenter": "位置中心", + "CenterX": "X", + "CenterY": "Y", + "SameCenter": "相同中心", + "ReferencialPoint": "参考点", + "RefX": "X", + "RefY": "Y", + "LockButton": "锁定", + "Coordinates": "坐标", + "SetCoordinates": "设置", + "SaveCoordinates": "保存" + }, + "StatusBar": { + "MiscButton": "杂项", + "SaveMenuItem": "保存", + "ShowOnlyValidMenuItem": "仅显示有效", + "ExportAllToVD": "全部导出到 VD" + }, + "Tooltips": { + "AllDirectionsAddToolTip": "依次选择 5 个 GIF,分别添加到不同方向", + "AllDirectionsAddWithCanvasToolTip": "依次选择 5 个 GIF,分别添加到不同方向(使用画布收缩算法)", + "AllDirectionsAddWithCanvasKRToolTip": "添加图像时移除所有绿色" } }, "CompareGumpControl": {