
在當今全球化的軟體開發浪潮中,應用程式的國際化(i18n)與本地化(L10n)顯得尤為重要。Avalonia UI 作為一款強大的跨平台 UI 框架,為開發者提供了多種實現國際化的途徑。其中,使用傳統的 Resx 資源檔案進行國際化處理,不僅相容於原 Winform、WPF、ASP.NET Core 等開發場景下的使用習慣,還藉助一些實用工具和特定的開發流程,讓國際化的實現變得高效且有條理。
1. 引言:Resx 資源檔案與 Avalonia UI 國際化的邂逅
在軟體開發領域,國際化是確保應用程式能夠跨越語言和文化邊界,觸達全球使用者的關鍵。Avalonia UI 以其靈活的架構和豐富的功能,在跨平台應用程式開發中嶄露頭角。而 Resx 資源檔案,作為一種久經考驗的本地化資源管理方式,在 Avalonia UI 中也找到了新的用武之地。透過將兩者結合,開發者能夠在熟悉的開發模式下,為應用程式賦予多語言支援的能力,輕鬆應對不同地區使用者的需求。
下圖是使用VS延伸模組 ResXManager 對 Resx 資源檔案進行管理的截圖:

2. 詳細使用步驟:建構多語言應用的基石
2.1. Resx 資源檔案的精心佈局
2.1.1. 專案目錄規劃與基礎資源檔案建立
開啟您的 Avalonia UI 專案之旅,無論是已有的成熟專案還是全新建立的專案,首先在專案中加入一個用於存放國際化資源的目錄,這裡我們命名為 I18n(您可根據專案實際情況自訂目錄名)。在這個目錄下,建立預設的英文語言資源檔案 Resource.resx。這個檔案將作為整個國際化資源體系的基礎,承載著應用程式在英文環境下的所有文字資源。

2.1.2. 多語言資源檔案的拓展
- 當英文資源檔案就緒後,我們可以進一步拓展其他語言的資源檔案。以中文簡體、中文繁體和日語為例,它們的檔名需要遵循特定的命名規則:檔名前綴與預設語言資源檔案名保持一致,即
Resource,並添加對應的CultureName後綴。例如,中文簡體對應的資源檔案名為Resource.zh-CN.resx,中文繁體為Resource.zh-Hant.resx,日語則是Resource.ja-JP.resx。這樣的命名方式有助於 Avalonia UI 在執行階段準確識別並載入不同語言的資源。 - 藉助強大的 ResXManager 工具,我們可以方便地開啟這些資源檔案進行多語言文字的編輯。在編輯過程中,需要特別注意語言 Key 的命名,它必須滿足 C# 變數語法,因為後續的開發流程會依據這些 Key 生成對應的語言 Key 類別,確保在程式碼層面能夠精準地引用和操作這些資源。
2.2. NuGet 套件的引入:增強國際化功能的得力助手
Install-Package AvaloniaExtensions.Axaml
這個套件為我們的專案帶來了一系列實用的 API,包括多語言切換功能、便捷的獲取 Key 對應翻譯字串的方法,以及在 axaml 前端介面中對語言標記的支援。這些功能將極大地簡化我們在國際化開發過程中的程式碼編寫和介面設計工作。
2.3. T4 檔案:從資源檔案到強型別資源類別的橋樑
2.3.1. T4 檔案的建立與設定
有了資源檔案後,雖然已經能夠在一定程度上實現國際化功能,但直接使用字串 Key 在程式碼中進行資源引用既容易出錯又不夠直觀。因此,我們引入 T4 檔案來根據資源檔案生成強型別的資源類別。在之前建立的 I18n 目錄下,加入一個 T4 檔案,例如 Language.tt(檔案名可根據專案需求靈活調整)。

2.3.2. T4 檔案的內容解析與生成邏輯
開啟 Language.tt 檔案,其內容包含了一系列的指令和程式碼片段。首先,透過 #import 指令引入了多個命名空間,這些命名空間為後續的程式碼操作提供了必要的功能支援,如處理 XML 資料、檔案操作等。
<#@ template debug="false" hostspecific="true" language="C#" #>
<#@ assembly name="System.Core" #>
<#@ assembly name="System.Xml" #>
<#@ assembly name="System.Xml.Linq" #>
<#@ import namespace="System.Linq" #>
<#@ import namespace="System.Text" #>
<#@ import namespace="System.Collections.Generic" #>
<#@ import namespace="System.Xml.Linq" #>
<#@ import namespace="System.IO" #>
<#@ output extension=".cs" #>
//------------------------------------------------------------------------------
// <auto-generated>
// This code was generated by a tool.
// Changes to this file may cause incorrect behavior and will be lost if
// the code is regenerated.
// </auto-generated>
//------------------------------------------------------------------------------
<#
const string ResourceFileName = "Resources.resx";
#>
namespace <#=System.Runtime.Remoting.Messaging.CallContext.LogicalGetData("NamespaceHint").ToString()#>;
public static class Language
{
<#
var resourceKeys = XElement.Load(this.Host.ResolvePath(ResourceFileName))
.Elements("data")
.Select(item => item.Attribute("name")?.Value)
.Where(item => item != null);
var resourceDesignerName = Path.GetFileNameWithoutExtension(ResourceFileName);
foreach (string resourceKey in resourceKeys)
{
#>
public static readonly string <#= resourceKey #> = "<#= resourceKey #>";
<#
}
#>
}
其中,ResourceFileName 變數指定了前面建立的預設 Resx 資源檔案名,這是 T4 檔案生成強型別資源類別的依據。在 T4 檔案的主體部分,透過 XElement.Load 方法載入指定的資源檔案,並使用 LINQ 查詢運算式從資源檔案的 XML 結構中提取出所有的語言 Key。然後,針對每個提取到的 Key,生成一個對應的公用靜態唯讀字串欄位,欄位名與 Key 相同,初始值也為 Key。這樣,當 T4 檔案執行儲存操作(通常透過 Ctrl + S)時,就會在相同目錄下生成一個名為 Language.cs 的 C# 檔案,其中包含了強型別的資源類別。例如:
//------------------------------------------------------------------------------
// <auto-generated>
// This code was generated by a tool.
// Changes to this file may cause incorrect behavior and will be lost if
// the code is regenerated.
// </auto-generated>
//------------------------------------------------------------------------------
namespace CodeWF.Toolbox.I18n;
public static class Language
{
public static readonly string AppName = "AppName";
public static readonly string Home = "Home";
public static readonly string SearchToolTip = "SearchToolTip";
public static readonly string Setting = "Setting";
public static readonly string DesiredAvailabilityNotification = "DesiredAvailabilityNotification";
public static readonly string AccessToolbox = "AccessToolbox";
public static readonly string MissingTool = "MissingTool";
public static readonly string InterfaceStyleSettings = "InterfaceStyleSettings";
public static readonly string GeneralSettings = "GeneralSettings";
public static readonly string Theme = "Theme";
public static readonly string FollowingSystem = "FollowingSystem";
public static readonly string LightMode = "LightMode";
public static readonly string DarkMode = "DarkMode";
public static readonly string LanguageKey = "LanguageKey";
public static readonly string AutoOpenToolboxAtStartup = "AutoOpenToolboxAtStartup";
public static readonly string HideTrayIconOnClose = "HideTrayIconOnClose";
public static readonly string TurnOn = "TurnOn";
public static readonly string TurnOff = "TurnOff";
public static readonly string Exit = "Exit";
public static readonly string SureExit = "SureExit";
public static readonly string FindInTrayIcon = "FindInTrayIcon";
public static readonly string ShowMainWindow = "ShowMainWindow";
public static readonly string DisplayPromptWhenClosing = "DisplayPromptWhenClosing";
public static readonly string NoMorePrompts = "NoMorePrompts";
public static readonly string About = "About";
public static readonly string AboutMessage = "AboutMessage";
}
這個生成的資源類別使得我們在程式碼中能夠以強型別的方式引用資源 Key,大大提高了程式碼的可讀性和可維護性。
2.4. 在專案中的具體應用:讓多語言功能鮮活起來
2.4.1. 程式碼中的資源引用
在 C# 程式碼中,我們可以藉助 I18nManager 類別來獲取指定語言 Key 對應的翻譯字串。例如:
I18nManager.GetString(Language.Setting)
這裡的 Language.Setting 就是透過 T4 檔案生成的強型別資源類別中的欄位,透過這種方式,我們能夠在程式碼的任何地方方便地獲取並使用多語言資源,確保應用程式在不同語言環境下的正確顯示。
2.4.2. Axaml 介面中的語言繫結
在 axaml 前端介面中,我們首先需要引入相應的命名空間:
xmlns:i18n="https://codewf.com"
xmlns:language="clr-namespace:CodeWF.Toolbox.I18n"
然後,透過資料繫結的方式將介面元素的文字屬性與語言資源關聯起來。例如:
<TextBlock Text="{i18n:I18n {x:Static language:Language.AppName}}" />
這樣,當應用程式的語言環境發生變化時,介面元素的文字會自動更新為對應的翻譯文字,實現了介面的動態國際化。
- 語言切換的實現
實現語言切換功能也非常簡單,只需呼叫 I18nManager.Instance.Culture 屬性,並傳入目標語言的 CultureInfo 物件即可。例如:
I18nManager.Instance.Culture = new CultureInfo(language);
這裡的 language 變數可以是任何有效的語言代碼,如 zh-CN、ja-JP 等。當設定了新的語言文化後,整個應用程式的語言顯示會立即更新,為使用者提供無縫的多語言切換體驗。
3. 總結:Resx 資源檔案國際化方案的優劣剖析
透過 Resx 資源檔案實現 Avalonia UI 應用程式的國際化,無疑為傳統開發者提供了一條熟悉且便捷的道路。它充分利用了已有的開發經驗和工具生態,如 ResXManager 和 T4 檔案技術,使得國際化的開發過程能夠高效地融入現有的專案流程中。然而,這種方式也並非完美無缺。其對於普通使用者側的維護來說,可能存在一定的難度。普通使用者可能不熟悉 Resx 檔案的結構和編輯方式,也難以理解 T4 檔案生成程式碼的邏輯。這就要求在專案的設計和實施過程中,開發者需要充分考慮到後續的維護成本,可能需要為普通使用者提供一些簡單易用的介面或工具來輔助他們進行國際化資源的更新和管理。但總體而言,對於具有一定技術基礎的開發團隊和專案來說,Resx 資源檔案的國際化方案仍然是一種值得推薦的選擇,它在功能、效率和相容性方面都有著出色的表現。
希望本文能夠為廣大 Avalonia UI 開發者在國際化實踐中提供有益的參考和指導,讓您的應用程式能夠在全球舞台上綻放光彩。
彩蛋:下篇文章介紹XML檔案實現國際化