Avalonia使用XML檔案實現國際化

Avalonia使用XML檔案實現國際化

本文深入探討了 Avalonia 使用 XML 檔案實現國際化的方法與優勢。透過與 Resx 資源檔案對比,為開發者提供了選擇依據。XML 實現國際化適用於有用戶側修改需求、期望藉助 AI 編輯且追求清晰語言結構管理的場景。文中詳細介紹了從建立語言檔案、強型別產生到具體使用以及語言管理的整套流程,並提供了相關資源連結,如 XML 語言管理套件、案例 Demo 及語言管理工具、Resx 資源管理擴充功能等,有助於開發者快速上手並在實際專案中應用該國際化方案,提升 Avalonia 應用的全球化適配能力與使用者體驗。

最後更新 2024/12/23 下午12:34
沙漠尽头的狼
預計閱讀 19 分鐘
分類
Avalonia UI
標籤
.NET C# Avalonia UI 國際化 本地化

在軟體開發日益全球化的今天,Avalonia 的國際化實現策略成為了眾多開發者關注的焦點。繼上一篇 Avalonia 國際化之路:Resx 資源檔案的深度應用與探索 之後,本文將引領大家深入探究如何運用自訂 XML 檔案來達成 Avalonia 國際化的目標,開啟一段全新的技術探索之旅。

1. XML 實現 Avalonia UI 國際化的優勢剖析

1.1. 突破維護局限,擁抱使用者自訂

Resx 資源檔案往往將維護權限局限於開發端,而自訂 XML 語言檔案則以其獨特的靈活性脫穎而出。它能夠與可執行程式一同輸出,這一特性為使用者側的語言檔案修改開闢了廣闊的空間。使用者不僅可以根據自身需求對既有語言內容進行調整,還能夠輕鬆地擴展更多語言種類,使軟體的國際化適應能力得到極大的提升,真正實現了從開發主導到使用者參與的轉變。

1.2. 命名空間加持,結構清晰有序

自訂 XML 檔案採用命名空間的方式來組織語言內容,這一設計理念與類的結構形成了精準的對應關係。透過這種方式,整個翻譯檔案的架構變得清晰明瞭,易於管理與維護。無論是在大型專案中進行團隊協作開發,還是在後期的程式碼維護與升級過程中,都能夠顯著提高工作效率,減少因結構混亂而可能引發的錯誤與困擾。

1.3. AI 翻譯便捷,助力語言轉換

在當今人工智慧蓬勃發展的時代,XML 檔案在 AI 翻譯方面展現出了得天獨厚的優勢。藉助特定的工具或平台,我們可以方便地利用 AI 技術對 XML 翻譯檔案進行處理。例如,只需提供簡單的提示詞,就能快速獲取多種語言版本的翻譯結果,為跨語言交流與軟體全球化推廣提供了強有力的支援。

下圖為輸出的 XML 語言檔案:

2. XML 檔案的建立與架構設計

2.1. 精心規劃語言資料夾

首先,我們需要建立一個專門用於存放語言檔案的資料夾,例如命名為 “i18n”。在這個過程中,需要特別注意的是,相同輸出路徑下不同模組的 XML 檔案名稱必須保持唯一性。因為在程式編譯輸出時,如果存在同名的 XML 檔案,將會導致檔案替換,進而造成語言資訊的遺失,這無疑會給國際化進程帶來嚴重的阻礙。

檔案前綴可以工程名命名(方便區分),後綴為語言文化名

以下是建立語言資料夾後的工程結構範例圖:

編譯輸出後檔案列表如下:

AIModule.en-US.xml
AIModule.ja-JP.xml
AIModule.zh-CN.xml
AIModule.zh-Hant.xml
ConverterModule.en-US.xml
ConverterModule.ja-JP.xml
ConverterModule.zh-CN.xml
ConverterModule.zh-Hant.xml
DevelopmentModule.en-US.xml
DevelopmentModule.ja-JP.xml
DevelopmentModule.zh-CN.xml
DevelopmentModule.zh-Hant.xml
MainModule.en-US.xml
MainModule.ja-JP.xml
MainModule.zh-CN.xml
MainModule.zh-Hant.xml
XmlTranslatorManagerModule.en-US.xml
XmlTranslatorManagerModule.ja-JP.xml
XmlTranslatorManagerModule.zh-CN.xml
XmlTranslatorManagerModule.zh-Hant.xml

2.2. 嚴謹建構 XML 檔案內容

以下是上面一個 XML 檔案內容(AIModule.zh-CN.xml):

<?xml version="1.0" encoding="utf-8"?>

<Localization language="Chinese (Simplified)" description="中文简体" cultureName="zh-CN">
	<AIModule>
		<Title>AI</Title>
	</AIModule>
	<AskBotView>
		<Title>智能问答助手</Title>
		<Description>一键提问,即刻获取答案,智能问答助手为您解惑。</Description>
	</AskBotView>
	<PolyTranslateView>
		<Title>AI一键多语种翻译神器</Title>
		<Description>轻松实现一键翻译,支持多种语言互译,让沟通无界限!</Description>
	</PolyTranslateView>
	<Title2SlugView>
		<Title>AI一键转URL Slug</Title>
		<Description>轻松将中文、英文等文章标题一键转换成英文URL Slug。</Description>
	</Title2SlugView>
	<ChoiceLanguagesView>
		<LanguageKey>语言</LanguageKey>
		<Selectable>可选择的</Selectable>
		<Selected>已选择</Selected>
	</ChoiceLanguagesView>
</Localization>

XML 檔案的內容結構遵循一定的規範與層次。推薦採用三層結構來組織資訊:

2.2.1. 第一層:Localization 節點

此節點包含三個重要的子屬性:

  • language:用於明確指定語言的名稱,例如 “Chinese (Simplified)” 表示簡體中文。
  • description:對該語言的簡要描述,如 “中文简体”,以便於開發者和使用者快速了解語言的基本特徵。
  • cultureName:語言的文化名,這是一個在國際化處理中非常關鍵的標識,例如 “zh-CN” 代表簡體中文的文化區域。如果對文化名不太清楚,可以透過百度搜尋等方式獲取準確資訊。

以下是一個基本的 XML 檔案框架範例:

<?xml version="1.0" encoding="utf-8"?>

<Localization language="Chinese (Simplified)" description="中文简体" cultureName="zh-CN">
  <!-- 此處將填充具體的模組和語言鍵值對 -->
</Localization>

2.2.2. 第二層:功能名或類別名稱節點

這一層以功能名或類別名稱來命名節點,其目的在於對翻譯檔案進行有效的功能歸類。例如,在一個包含 AI 模組、轉換模組等的專案中,可以分別建立 “AIModule”、“ConverterModule” 等節點,將與各個模組相關的翻譯內容分別放置在對應的節點下,使整個檔案的結構更加清晰,便於管理與查找。

以下是一個包含多個模組節點的 XML 檔案範例:

<?xml version="1.0" encoding="utf-8"?>

<Localization language="Chinese (Simplified)" description="中文简体" cultureName="zh-CN">
  <AIModule>
    <!-- AI 模組相關的翻譯內容 -->
  </AIModule>
  <ConverterModule>
    <!-- 轉換模組相關的翻譯內容 -->
  </ConverterModule>
</Localization>

2.2.3. 第三層:語言 Key 節點

最後一層為語言 Key 節點,這些節點直接儲存了具體的翻譯文字內容。例如:

<?xml version="1.0" encoding="utf-8"?>

<Localization language="Chinese (Simplified)" description="中文简体" cultureName="zh-CN">
  <AIModule>
    <Title>AI</Title>
  </AIModule>
  <AskBotView>
    <Title>智能问答助手</Title>
    <Description>一键提问,即刻获取答案,智能问答助手为您解惑。</Description>
  </AskBotView>
</Localization>

在實際應用中,雖然推薦採用三層結構,但 XML 節點的巢狀層數並沒有嚴格的限制,開發者可以根據專案的實際需求和複雜程度進行靈活調整。例如:

<?xml version="1.0" encoding="utf-8"?>

<Localization language="Chinese (Simplified)" description="中文简体" cultureName="zh-CN">
	<AIModule>
		<Title>AI</Title>
	</AIModule>
    <AI>
        <AskBotView>
            <Title>智能问答助手</Title>
            <Description>一键提问,即刻获取答案,智能问答助手为您解惑。</Description>
        </AskBotView>
    </AI>
    <Translate>
        <Baidu>
            <PolyTranslateView>
                <Title>AI一键多语种翻译神器</Title>
                <Description>轻松实现一键翻译,支持多种语言互译,让沟通无界限!</Description>
            </PolyTranslateView>
        </Baidu>
        <Google>
        	<PolyTranslateView>
                <Title>AI一键多语种翻译神器</Title>
                <Description>轻松实现一键翻译,支持多种语言互译,让沟通无界限!</Description>
            </PolyTranslateView>
        </Google>
    </Translate>
</Localization>

3. 語言檔案的強型別生成策略

為了在程式碼中更加方便、高效地使用 XML 翻譯檔案,我們採用 T4 檔案將 XML 轉換為 C# 的強型別。具體操作如下:

在 “i18n” 目錄下建立一個 T4 檔案,例如命名為 “Language.tt”,並在其中填入以下程式碼:

<#@ 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>
//------------------------------------------------------------------------------
<#
    string templateDirectory = Path.GetDirectoryName(Host.TemplateFile);
    string xmlFilePath = Directory.GetFiles(templateDirectory, "*.xml").FirstOrDefault();
    if (xmlFilePath!= null)
    {
        XDocument xdoc = XDocument.Load(xmlFilePath);
        var classNodes = xdoc.Nodes().OfType<XElement>().DescendantsAndSelf().Where(e => e.Descendants().Count() == 0).Select(e => e.Parent).Distinct().ToList();
        foreach (var classNode in classNodes)
        {
            var namespaceSegments = classNode.Ancestors().Reverse().Select(node => node.Name.LocalName);
            string namespaceName = string.Join(".", namespaceSegments);
            GenerateClasses(classNode, namespaceName);
        }
    }
    else
    {
        Write("XML file not found, please ensure that there is an XML file in the current directory");
    }

    void GenerateClasses(XElement element, string namespaceName)
    {
        string className = element.Name.LocalName;
        StringBuilder classBuilder = new StringBuilder();
        classBuilder.AppendLine($"namespace {namespaceName}");
        classBuilder.AppendLine("{");
        classBuilder.AppendLine($"    public static class {className}");
        classBuilder.AppendLine("    {");
        var fieldNodes = element.Elements();
        foreach (var fieldNode in fieldNodes)
        {
            var propertyName = fieldNode.Name.LocalName;
            var languageKey = $"{namespaceName}.{className}.{propertyName}";
            classBuilder.AppendLine($"        public static readonly string {propertyName} = \"{languageKey}\";");
        }
        classBuilder.AppendLine("    }");
        classBuilder.AppendLine("}");
        Write(classBuilder.ToString());
    }
#>

每次對 XML 檔案進行修改後,只需打開該 T4 檔案並執行一次儲存操作,系統將會自動生成或更新對應的 C# 類別。例如:

//...
namespace Localization
{
    public static class AIModule
    {
        public static readonly string Title = "Localization.AIModule.Title";
    }
}
namespace Localization
{
    public static class AskBotView
    {
        public static readonly string Title = "Localization.AskBotView.Title";
        public static readonly string Description = "Localization.AskBotView.Description";
    }
}
//...

這些生成的強型別類將為我們在後續的程式碼編寫中提供極大的便利,使我們能夠更加準確、便捷地取得和使用翻譯文字。

4. XML 檔案在 Avalonia 中的具體應用實踐

4.1. 安裝必備 NuGet 套件

Install-Package AvaloniaXmlTranslator

這一步驟將為我們的專案引入必要的功能元件,為後續的國際化操作奠定基礎。

4.2. 動態取得語言列表

在 Avalonia 應用中,動態取得程式配置的語言列表是實現國際化介面切換的關鍵步驟之一。透過以下程式碼,我們可以輕鬆地取得語言列表:

List<LocalizationLanguage> languages = I18nManager.Instance.Resources.Select(kvp => kvp.Value).ToList();

其中,“LocalizationLanguage” 類別定義如下:

public class LocalizationLanguage
{
    public string Language { get; set; } = (string) null;

    public string Description { get; set; } = (string) null;

    public string CultureName { get; set; } = (string) null;

    //...
}

取得語言列表後,我們可以將其用於介面繫結,例如在下拉選單中顯示可供使用者選擇的語言選項,或者在其他需要展示語言資訊的介面元素中進行資料繫結。

4.3. 動態切換語言

當使用者在介面中選擇了不同的語言後,我們需要在程式碼中實現語言的動態切換。以下是實現語言切換的程式碼範例:

var culture = new CultureInfo(language);
I18nManager.Instance.Culture = culture;

這裡的 “language” 參數為 “LocalizationLanguage” 類別的 “CultureName” 屬性值,透過設定當前執行緒的文化資訊,我們可以實現介面語言的即時切換,為使用者提供無縫的國際化體驗。

4.4. 程式碼中使用翻譯字串

在程式碼中,我們可以根據強型別 Key 方便地取得當前語言文化的翻譯字串。例如:

var title = I18nManager.GetString(Localization.AskBotView.Title); // 取得當前語言
var titleZhCN = I18nManager.Instance.GetResource(Localization.Main.MainView.Title, "zh-CN");	// 取得中文簡體
var titleEnUS = I18nManager.Instance.GetResource(Localization.Main.MainView.Title, "en-US");	// 取得英文

透過這種方式,我們可以在程式碼的任何地方靈活地使用翻譯文字,確保介面顯示的內容與使用者選擇的語言相匹配。

下面是程式碼中繫結使用:

//...
 var header = item is UserControl { DataContext: ITabItemBase tabItem }
     ? tabItem.TitleKey
     : item?.GetType().ToString();
 var newTabItem = new TabItem { Content = item };
 newTabItem.Bind(TabItem.HeaderProperty, new I18nBinding(header));
 regionTarget.Items.Add(newTabItem);
//...

4.5. Axaml 介面中的應用

在 Axaml 介面中使用 XML 翻譯檔案也非常便捷。首先,需要引入相應的命名空間:

xmlns:language="clr-namespace:Localization"
xmlns:markup="https://codewf.com"

其中,“markup” 為前面安裝的輔助庫命名空間,它提供了 “I18n” 標記擴展幫助類,用於在介面中繫結翻譯文字;“language” 為 T4 檔案生成的 C# 強型別語言 Key 關聯類別命名空間,透過它可以與 XML 語言檔案的語言 Key 進行關聯。

以下是在控制項中使用翻譯文字的範例:

<Button
    Grid.Row="3"
    Grid.Column="1"
    Margin="10,0,0,0"
    HorizontalAlignment="Stretch"
    VerticalAlignment="Center"
    Command="{Binding RaiseChoiceLanguagesCommand}"
    Content="{markup:I18n {x:Static language:ChoiceLanguagesView.LanguageKey}}" />

在上述範例中,“Button” 控制項的 “Content” 屬性透過 “I18n” 標記擴展繫結到了 “ChoiceLanguagesView.LanguageKey” 對應的翻譯文字上。這樣,當介面語言發生變化時,按鈕的顯示文字也會自動更新為相應語言的翻譯內容。

當然也支援指定語言:

<SelectableTextBlock u:FormItem.Label="Current Thread" Text="{markup:I18n {x:Static developModuleLanguage:Title2SlugView.Title}}" />
<SelectableTextBlock u:FormItem.Label="en-US" Text="{markup:I18n {x:Static developModuleLanguage:Title2SlugView.Title}, CultureName=en-US}" />
<SelectableTextBlock u:FormItem.Label="ja-JP" Text="{markup:I18n {x:Static developModuleLanguage:Title2SlugView.Title}, CultureName=ja-JP}" />
<SelectableTextBlock u:FormItem.Label="zh-CN" Text="{markup:I18n {x:Static developModuleLanguage:Title2SlugView.Title}, CultureName=zh-CN}" />
<SelectableTextBlock u:FormItem.Label="zh-Hant" Text="{markup:I18n {x:Static developModuleLanguage:Title2SlugView.Title}, CultureName=zh-Hant}" />

此外,Axaml 介面還支援動態 Key 的繫結,例如:

<u:Banner
    Classes.Bordered="{Binding Bordered}"
    Content="{markup:I18n {Binding SelectedMenuItem.Description}}"
    Header="{markup:I18n {Binding SelectedMenuItem.Name}}"
    Type="{Binding SelectedType}" />

在這個範例中,“Banner” 控制項的 “Content” 和 “Header” 屬性分別繫結到了動態的 “SelectedMenuItem.Description” 和 “SelectedMenuItem.Name” 屬性上,透過 “I18n” 標記擴展實現了動態翻譯文字的顯示。

5. 語言管理功能的深度解析

為了更好地管理 XML 語言檔案,站長開發了部分管理功能,包括多模組 XML 檔案合併與 XML 檔案編輯,可點擊下載 管理工具或自行編譯 工具原始碼,工具程式結構如下:

5.1. 多模組 XML 檔案合併

執行工具箱後,選擇 “XML 國際化管理” 下的 “XML 多模組檔案合併” 節點。預設情況下,將會打開工具箱自己的 “I18n” 目錄(點擊 “A” 可選擇其他語言目錄)。在介面的左側,將會顯示 XML 檔案列表,點擊檔案即可瀏覽其詳細內容。

在 “B” 處輸入合併後的 XML 檔案前綴,預設值為 “Localization”。然後,點擊 “C” 按鈕即可執行檔案合併操作。以下是合併後的效果範例圖:

在進行多模組 XML 檔案合併時,需要特別注意以下幾點:

  1. 合併前務必進行資料備份,以防止因合併操作失誤而導致資料遺失或損壞。
  2. 建議在合併前確保每個 XML 根節點相同,例如都命名為 “Localization”,這樣可以保證合併後的檔案結構更加規範和統一。
  3. 不同模組的 XML 節點應避免重複,否則可能會在合併過程中出現資料衝突或覆蓋的問題。

多模組 XML 檔案合併的原理其實非常簡單,即將相同語言後綴下的 XML 檔案合併到一個根節點下,從而實現語言資料的整合與集中管理。

5.2. XML 檔案編輯

目前,XML 檔案編輯功能相對較為基礎,僅支援對現有的語言進行修改。

在後續的開發計畫中,站長將進一步完善 XML 檔案編輯功能,預計將會支援以下操作:

  1. 可修改 Key:允許使用者對既有的語言 Key 進行修改,以適應專案需求的變化或修正錯誤的 Key 命名。
  2. 可添加 Key、刪除 Key:提供靈活的 Key 管理功能,使用者可以根據實際需要添加新的語言 Key 或刪除不再使用的 Key,使 XML 檔案的內容更加精準和高效。
  3. 可添加語言、刪除語言:除了對 Key 的管理外,還將支援添加新的語言種類以及刪除不再需要的語言,進一步拓展 XML 檔案的國際化支援範圍。
  4. 一鍵翻譯:借助先進的 AI 翻譯技術,實現一鍵將 XML 檔案中的內容翻譯成多種語言,大大提高翻譯效率,減少人工翻譯的工作量和成本。

5.3. AI 翻譯的巧妙應用

在 XML 檔案的翻譯過程中,我們可以巧妙地利用 AI 翻譯技術來提高效率。例如,透過編寫如下提示詞:

幫我將以下的中文簡體 XML 翻譯檔案再翻譯成中文繁體、英文、日語 3 個版本,不用回覆其他文字,謝謝:

```xml
<?xml version="1.0" encoding="utf-8"?>

<Localization language="Chinese (Simplified)" description="中文简体" cultureName="zh-CN">
	<MainModule>
		<Title>碼坊工具箱</Title>
		<SearchToolTip>搜你所想</SearchToolTip>
		<WeChat>聯繫微信號:codewf</WeChat>
		<WeChatPublic>關注微信公眾號:Dotnet9</WeChatPublic>
		<DesiredAvailabilityNotification>想要的都有,沒有請告知。</DesiredAvailabilityNotification>
		<AccessToolbox>訪問線上工具箱</AccessToolbox>
	<AboutView>
		<Title>關於</Title>
		<Description>本項目只用於學習使用</Description>
	</AboutView>
</Localization>
```

將上述 XML 內容提供給 AI,即可獲取相應的中文繁體、英文、日語翻譯版本,為國際化工作提供了快速且便捷的翻譯途徑,效果顯著,如同以下範例圖展示:

6. 總結與展望

在 Avalonia 國際化的征程中,Resx 資源檔案和自訂 XML 檔案是兩種重要的實現方式,開發者應根據具體需求進行合理選擇。

6.1. Resx 資源檔案的適用場景

  1. 當專案無使用者側修改需求時,Resx 資源檔案憑藉其在開發環境中的便捷管理性,可透過 Resx Manager 等工具進行高效操作,是較為理想的選擇。
  2. 對於那些注重開發過程中資源檔案管理效率,且不需要使用者參與語言內容調整的專案,Resx 資源檔案能夠很好地滿足需求,確保專案的國際化進程順利推進。

6.2. 自訂 XML 檔案的優勢領域

  1. 若專案存在使用者側修改需求,自訂 XML 檔案則能夠大放異彩。它允許使用者根據自身使用場景和語言習慣對軟體的語言內容進行靈活調整,極大地提升了使用者體驗和軟體的適應性。
  2. 在需要借助 AI 編輯進行語言處理的情況下,XML 檔案的格式更易於與 AI 工具進行互動,能夠充分利用 AI 技術的優勢,實現高效的翻譯和語言管理。
  3. 對於追求清晰、有序的語言結構管理,以便於團隊協作、程式碼維護和專案擴展的專案,自訂 XML 檔案的命名空間組織方式和靈活的節點結構能夠提供強有力的支援。

本文詳細闡述了 Avalonia 使用自訂 XML 檔案實現國際化的全過程,包括 XML 檔案的建立、強型別生成、在 Avalonia 中的具體應用以及語言管理功能等方面。同時,為開發者提供了豐富的程式碼範例、詳細的操作步驟以及相關的圖片說明,旨在幫助開發者快速上手並熟練運用這一國際化方案。文中涉及的相關資源如下:

展望未來,隨著技術的不斷發展和應用場景的日益豐富,Avalonia 國際化的實現方式也將不斷演進和完善。我們期待能夠看到更多便捷、高效的工具和技術湧現,進一步簡化國際化開發流程,提升軟體的全球化品質,為使用者帶來更加卓越的跨語言使用體驗。無論是 Resx 資源檔案還是自訂 XML 檔案,都將在各自的適用領域繼續發揮重要作用,共同推動 Avalonia 國際化進程的不斷前進。

繼續探索

延伸閱讀

更多文章