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/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/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/FileSavedDialog.cs b/UoFiddler.Controls/Forms/FileSavedDialog.cs
index aebcb92d..52711bf1 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
@@ -74,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/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/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/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/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 1223bdcf..5e254045 100644
--- a/UoFiddler.Controls/Forms/MapDefragStaticsForm.cs
+++ b/UoFiddler.Controls/Forms/MapDefragStaticsForm.cs
@@ -32,6 +32,10 @@ public sealed partial class MapDefragStaticsForm : Form
private const string DefaultCollapseIds = "0x1797-0x179C";
private readonly Map _map;
+ private Func? _localizationGetter;
+
+ private string[] _idCeilingOptions;
+ private string[] _outOfBlockOptions;
private CancellationTokenSource _cancellation;
private bool _lastRunUsedFilters;
@@ -45,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;
@@ -66,6 +74,70 @@ 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";
+
+ // 汉化下拉菜单项 - 保存选中的原始值
+ 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();
+ }
+
///
/// 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
@@ -78,11 +150,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;
@@ -99,7 +177,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();
@@ -110,10 +190,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;
@@ -121,16 +200,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);
}
}
@@ -301,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;
}
@@ -316,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);
}
@@ -375,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;
}
@@ -388,6 +469,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.Controls/Forms/MapDetailsForm.cs b/UoFiddler.Controls/Forms/MapDetailsForm.cs
index ae323bbd..8af894cb 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,10 @@ namespace UoFiddler.Controls.Forms
{
public partial class MapDetailsForm : Form
{
+ private Func? _localizationGetter;
+ private Map _currentMap;
+ private Point _point;
+
public MapDetailsForm(Map currentMap, Point point)
{
InitializeComponent();
@@ -25,17 +30,50 @@ 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");
+ _currentMap = currentMap;
+ _point = point;
+
+ // 先生成英文内容
+ GenerateContent();
+ }
+
+ public void SetLocalization(Func getLocalized)
+ {
+ _localizationGetter = getLocalized;
+ ApplyLocalization();
+ }
+
+ 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} Hue: {@static.Hue} Altitude: {@static.Z}\n");
+ 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.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/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/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/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.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 4c6c7674..a5f13425 100644
--- a/UoFiddler.Controls/Forms/MapReplaceForm.cs
+++ b/UoFiddler.Controls/Forms/MapReplaceForm.cs
@@ -31,6 +31,8 @@ namespace UoFiddler.Controls.Forms
public partial class MapReplaceForm : Form
{
private readonly Map _workingMap;
+ private Func? _localizationGetter;
+ private bool _initialized = false;
private CancellationTokenSource _cancellation;
private MapSize _detectedSize;
@@ -58,6 +60,82 @@ public partial class MapReplaceForm : Form
private ZSurveyRequest _zPending;
private CancellationTokenSource _zCancellation;
+ public void SetLocalization(Func getLocalized)
+ {
+ _localizationGetter = getLocalized;
+ ApplyLocalization();
+ CompleteInitialization(); // 完成初始化,确保动态消息被汉化
+ }
+
+ 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";
+
+ // 汉化 ComboBox 项(类型 2 - 动态列表项汉化)
+ ApplyComboBoxLocalization();
+
+ // 刷新预览消息,应用动态文本汉化(类型 8 - 运行时动态文本)
+ UpdatePreview();
+ }
+
+ 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)
{
InitializeComponent();
@@ -115,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;
@@ -173,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
})
@@ -248,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();
@@ -326,7 +440,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;
}
@@ -356,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();
@@ -406,7 +527,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;
}
@@ -519,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();
@@ -623,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);
@@ -642,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}",
@@ -682,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;
}
@@ -719,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);
}
@@ -787,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)
@@ -803,27 +951,47 @@ 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))
{
+ // 通过反射尝试获取 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);
}
}
@@ -887,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.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/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)
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/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/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.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 3cc2df5c..3d0fa585 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 });
}
}
}
@@ -858,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();
}
@@ -1345,6 +1355,95 @@ 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";
+
+ // 导出所有缩略图菜单
+ 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";
+ 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.Controls/UserControls/ClilocControl.cs b/UoFiddler.Controls/UserControls/ClilocControl.cs
index 794489d5..e2d2ce7f 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);
}
}
}
@@ -673,6 +793,7 @@ private void TileDataToolStripMenuItem_Click(object sender, EventArgs e)
}
preview = new TileDataSyncPreviewForm(changes);
+ preview.SetLocalization(_localizationGetter);
}
catch
{
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("