Skip to content
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
81 commits
Select commit Hold shift + click to select a range
509dff5
feat: Add non-invasive Chinese localization system for UOFiddler 4.24.0
nbyaya Oct 3, 2026
e2136ee
fix: Correct tab names in zh-CN.json to match actual control names
nbyaya Oct 3, 2026
78552f6
fix: Add support for ToolStrip menu localization
nbyaya Oct 3, 2026
1075e40
feat: Add LoadProfileForm localization support
nbyaya Oct 3, 2026
d95802d
fix: Support both .Text suffix and direct control name keys in Locali…
nbyaya Oct 3, 2026
f1d6f1a
feat: Add OptionsForm complete localization with all controls and labels
nbyaya Oct 3, 2026
5c94700
feat: Add PathSettingsForm localization
nbyaya Oct 3, 2026
2833dcd
fix: Add ToolStripButton localization support
nbyaya Oct 3, 2026
4e042f2
feat: Add ManageToolsForm localization and update ExternTools menu
nbyaya Oct 3, 2026
bfb89fd
fix: Localize dynamic ExternTools menu items (Manage.., Start) in Mai…
nbyaya Oct 3, 2026
552d95e
feat: Localize ManagePluginsForm, AboutBoxForm, and ExceptionForm
nbyaya Oct 3, 2026
3d81550
feat: Localize ManagePluginsForm plugin names with display-data separ…
nbyaya Oct 3, 2026
2a09683
fix: 修复插件多标签页汉化问题 - 支持 Compare 插件的 10 个标签页
nbyaya Oct 3, 2026
17e2153
feat: 汉化批量导入插件窗口
nbyaya Oct 3, 2026
eb70af4
feat: Localize MultiEditor and OptionsForm UI and tooltips
nbyaya Oct 3, 2026
a31fb77
feat: Localize AboutBoxForm changelog
nbyaya Oct 3, 2026
cc38bec
汉化 SendItem 插件
nbyaya Oct 4, 2026
96837e2
汉化 PluginTest 插件
nbyaya Oct 4, 2026
5855316
更新汉化字典
nbyaya Oct 4, 2026
ffe4161
汉化:Compare插件词条补充
nbyaya Oct 4, 2026
1d2c4ef
完善:CompareTileDataControl汉化实现
nbyaya Oct 4, 2026
0a2cc42
完善:Compare所有控制汉化模式
nbyaya Oct 4, 2026
ba1e5c5
汉化 GumpControl 菜单项和完善 Ctrl 多选导出功能
nbyaya Oct 4, 2026
a071e75
实施 Shift+Click 范围选择和导出功能
nbyaya Oct 4, 2026
ef2b4de
汉化 GumpControl 提示信息和对话框文本
nbyaya Oct 4, 2026
3f49895
feat: 汉化 HuesControl 和 HueEditForm,修复 Load 事件重复调用陷阱
nbyaya Oct 4, 2026
0d653d7
汉化 MultisControl 标签项多重组件窗口内容
nbyaya Oct 4, 2026
422ee50
汉化 MultisControl 状态栏和帮助窗口 - JSON 词条
nbyaya Oct 4, 2026
7c751e0
汉化 MultisControl - 状态文本和帮助窗口
nbyaya Oct 4, 2026
1f6f9c5
汉化 MultisHelpForm - 帮助窗口
nbyaya Oct 4, 2026
d248e34
汉化 AnimationListControl 动作名称列表
nbyaya Oct 4, 2026
cef7206
汉化 AnimationListControl 缩略图菜单
nbyaya Oct 4, 2026
0536a78
补充:MainForm 中调用 AnimationListControl.SetLocalization
nbyaya Oct 4, 2026
54253f9
汉化 ItemsControl 右键菜单及插件菜单 (Type 12/13/14)
nbyaya Oct 6, 2026
084b639
汉化 ItemsControl 状态栏标签 (Type 8)
nbyaya Oct 6, 2026
d020ad1
汉化 ItemsControl Save 按钮
nbyaya Oct 6, 2026
9bad393
汉化 ItemsControl 保存确认提示 (Type 6)
nbyaya Oct 6, 2026
7399bdc
汉化 LandTilesControl 地形图块窗口内容
nbyaya Oct 6, 2026
ce7b1d5
汉化 TexturesControl 纹理窗口
nbyaya Oct 6, 2026
7f29eb5
统一菜单项中的标签名汉化
nbyaya Oct 6, 2026
bd43e0d
汉化音效窗口内容
nbyaya Oct 6, 2026
ac7af67
汉化字体窗口内容
nbyaya Oct 6, 2026
38054a5
汉化 CliLocControl 标签页
nbyaya Oct 6, 2026
98dd8e0
汉化 TileDataSyncPreviewForm 窗口
nbyaya Oct 6, 2026
6c00878
汉化 MapControl 地图查看器窗口
nbyaya Oct 6, 2026
5500fa9
汉化 MapClearStaticsForm 清除静态物品表单
nbyaya Oct 6, 2026
ba39848
汉化 MapDefragStaticsForm 整理静态物品表单
nbyaya Oct 6, 2026
cb294c0
汉化 MapDefragStaticsResultForm 整理结果表单
nbyaya Oct 6, 2026
0bcfc6e
汉化 MapDetailsForm 地图详情表单
nbyaya Oct 6, 2026
717ad6e
汉化差异到地图复制工作流
nbyaya Oct 6, 2026
b6b276e
补充汉化 MapDetailsForm 内容标签
nbyaya Oct 6, 2026
8c9c9ff
补充汉化 MapDefragStaticsForm 动态消息标签
nbyaya Oct 6, 2026
66b4bec
汉化 MapMarkerForm 地图标记窗口
nbyaya Oct 6, 2026
21e1f97
汉化 MapMeltStaticsForm 融化静态物品窗口
nbyaya Oct 6, 2026
fbbc9a1
汉化 MapReplaceTilesForm 替换地块窗口
nbyaya Oct 6, 2026
867e41c
汉化 MapRegionCopyResultForm 地图区域复制结果窗口
nbyaya Oct 6, 2026
a9ca54d
汉化 MapReplaceForm 地图和静态物品复制窗口
nbyaya Oct 6, 2026
c4fff40
补充汉化 MapReplaceForm ComboBox 动态项
nbyaya Oct 7, 2026
1c79b18
补充汉化 MapReplaceForm 预览消息提示文本
nbyaya Oct 7, 2026
cef728e
修复 MapReplaceForm 预览消息汉化 - 在 ApplyLocalization 中刷新动态文本
nbyaya Oct 7, 2026
d246c7e
根本修复 MapReplaceForm 动态文本汉化 - 延迟初始化到 SetLocalization 之后
nbyaya Oct 7, 2026
7ff970f
汉化 Map 窗口状态栏标签(坐标、客户端位置、缩放)
nbyaya Oct 7, 2026
35336e2
汉化 MapReplaceForm 地图和静态物品复制窗口
nbyaya Oct 7, 2026
3f3c754
汉化 MapDefragStaticsForm 整理静态物体窗口
nbyaya Oct 7, 2026
8475922
为地图报告对话框添加汉化支持
nbyaya Oct 7, 2026
28e3dab
地图重写功能添加汉化支持
nbyaya Oct 7, 2026
40db7fa
汉化 MapControl 高度模式菜单项(Sharp/Normal/Soft、Subtle/Normal/Strong Intensity)
nbyaya Oct 7, 2026
2f942ee
汉化 LightControl 窗口和对话框
nbyaya Oct 7, 2026
3138738
汉化 SpeechControl 窗口(语音)标签页的汉化
nbyaya Oct 7, 2026
dd66422
汉化 SkillsControl 窗口(技能)标签页
nbyaya Oct 7, 2026
3379049
汉化 动画数据窗口内容
nbyaya Oct 7, 2026
a479983
汉化地形图块窗口内容
nbyaya Oct 7, 2026
6a73eb9
汉化多重地图/位面窗口内容
nbyaya Oct 7, 2026
6cd9a84
汉化Verdata补丁窗口内容
nbyaya Oct 7, 2026
9f2e08b
汉化技能组窗口内容
nbyaya Oct 7, 2026
a00b76b
汉化装扮窗口内容
nbyaya Oct 7, 2026
8855f34
汉化雷达颜色窗口内容
nbyaya Oct 8, 2026
797c12b
汉化 TileDataControl 及相关窗口内容
nbyaya Oct 8, 2026
f8c51bb
汉化选择配置文件窗口
nbyaya Oct 8, 2026
039a93e
汉化多重组件窗口导出和保存功能
nbyaya Oct 8, 2026
447755f
汉化动画窗口中的内容:重写XML、窗口、尝试查找新图形、动画编辑等
nbyaya Oct 8, 2026
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
30 changes: 20 additions & 10 deletions Ultima/Maps/MapSizes.cs
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,17 @@

namespace Ultima.Maps
{
/// <summary>
/// Static helper for localizing map detection messages.
/// </summary>
public static class MapSizesLocalization
{
/// <summary>
/// Optional localization getter for error messages (set by main application).
/// </summary>
public static Func<string, string>? LocalizationGetter { get; set; }
}

public readonly struct MapSize : IEquatable<MapSize>
{
public MapSize(int width, int height)
Expand Down Expand Up @@ -135,9 +146,9 @@ private static bool TryDetect(Func<string, string> 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;
}

Expand All @@ -149,17 +160,16 @@ private static bool TryDetect(Func<string, string> 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;
}

Expand Down
80 changes: 77 additions & 3 deletions UoFiddler.Controls/Classes/ClientFileSaveCommand.cs
Original file line number Diff line number Diff line change
Expand Up @@ -91,7 +91,35 @@ public static bool Run(Control owner, FileType type, Action<string> writeMul, st
Options.ChangedUltimaClass[dirtyKey] = false;
}

FileSavedDialog.Show(owner?.FindForm(), outputDirectory, BuildMessage(result));
// 尝试通过反射访问 LocalizationService 来获取汉化
Func<string, string?> 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;
}
Expand Down Expand Up @@ -133,7 +161,35 @@ private static bool ConfirmPreflight(Control owner, FileType type, ContainerForm

sb.AppendLine().AppendLine().Append("Save anyway?");

return MessageBox.Show(owner?.FindForm(), sb.ToString(), "Save", MessageBoxButtons.YesNo,
// 尝试获取汉化文本
string confirmTitle = "Save";
string confirmQuestion = "Save anyway?";
try
{
var localizationServiceType = Type.GetType("UoFiddler.Localization.LocalizationService, UoFiddler");
if (localizationServiceType != null)
{
var getStringMethod = localizationServiceType.GetMethod("GetString",
System.Reflection.BindingFlags.Public | System.Reflection.BindingFlags.Static);
if (getStringMethod != null)
{
var localizedTitle = getStringMethod.Invoke(null, new object[] { "Forms.ClientFileSaveCommand.SaveConfirmTitle" });
if (localizedTitle is string title)
confirmTitle = title;

var localizedQuestion = getStringMethod.Invoke(null, new object[] { "Forms.ClientFileSaveCommand.SaveAnywayQuestion" });
if (localizedQuestion is string question)
confirmQuestion = question;
}
}
}
catch { }

// 替换英文问题为汉化版本
sb.Length -= "Save anyway?".Length;
sb.Append(confirmQuestion);

return MessageBox.Show(owner?.FindForm(), sb.ToString(), confirmTitle, MessageBoxButtons.YesNo,
MessageBoxIcon.Warning, MessageBoxDefaultButton.Button2) == DialogResult.Yes;
}

Expand Down Expand Up @@ -183,7 +239,25 @@ private static void ShowError(Control owner, FileType type, Exception error)
sb.AppendLine(where);
}

MessageBox.Show(owner?.FindForm(), sb.ToString(), "Save failed", MessageBoxButtons.OK,
string errorTitle = "Save failed";
try
{
var localizationServiceType = Type.GetType("UoFiddler.Localization.LocalizationService, UoFiddler");
if (localizationServiceType != null)
{
var getStringMethod = localizationServiceType.GetMethod("GetString",
System.Reflection.BindingFlags.Public | System.Reflection.BindingFlags.Static);
if (getStringMethod != null)
{
var localizedTitle = getStringMethod.Invoke(null, new object[] { "Forms.ClientFileSaveCommand.SaveFailedTitle" });
if (localizedTitle is string title)
errorTitle = title;
}
}
}
catch { }

MessageBox.Show(owner?.FindForm(), sb.ToString(), errorTitle, MessageBoxButtons.OK,
MessageBoxIcon.Error);
}

Expand Down
37 changes: 35 additions & 2 deletions UoFiddler.Controls/Forms/AnimDataExportForm.cs
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,8 @@ namespace UoFiddler.Controls.Forms
{
public partial class AnimDataExportForm : Form
{
private Func<string, string?>? _localizationGetter;

public AnimDataExportForm()
{
InitializeComponent();
Expand All @@ -18,6 +20,30 @@ public AnimDataExportForm()
};
}

public void SetLocalization(Func<string, string?> 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<string>
{
_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";
Expand Down Expand Up @@ -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);
}
}
}
Expand Down
42 changes: 39 additions & 3 deletions UoFiddler.Controls/Forms/AnimDataImportForm.cs
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,8 @@ namespace UoFiddler.Controls.Forms
{
public partial class AnimDataImportForm : Form
{
private Func<string, string?>? _localizationGetter;

[DesignerSerializationVisibility(DesignerSerializationVisibility.Hidden)]
public Action OnAfterImport { get; set; }

Expand All @@ -18,13 +20,40 @@ public AnimDataImportForm()
cboConflictAction.SelectedItem = "skip";
}

public void SetLocalization(Func<string, string?> 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.
Expand All @@ -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);
}
}

Expand Down
4 changes: 2 additions & 2 deletions UoFiddler.Controls/Forms/AnimationEditForm.Designer.cs

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

Loading