Avalonia's Road to Internationalization: In-depth Application and Exploration of Resx Resource Files

Avalonia's Road to Internationalization: In-depth Application and Exploration of Resx Resource Files

In today's global wave of software development, application internationalization (i18n) and localization (L10n) are particularly important. As a powerful cross-platform UI framework, Avalonia UI provides developers with multiple ways to achieve internationalization. Among them, the use of traditional Resx resource files for internationalization is not only compatible with the usage habits of the original Winform, WPF, ASP.NET Core and other development scenarios, but also uses some utilities and specific development processes to enable the realization of internationalization. Become efficient and organized.

最后更新 12/5/2024 9:34 PM
沙漠尽头的狼
预计阅读 10 分钟
分类
Avalonia UI
标签
.NET C# ASP.NET Core WPF Avalonia UI

In today's global wave of software development, application internationalization (i18n) and localization (L10n) are particularly important. As a powerful cross-platform UI framework, Avalonia UI provides developers with multiple ways to achieve internationalization. Among them, the use of traditional Resx resource files for internationalization is not only compatible with the usage habits of the original Winform, WPF, ASP.NET Core and other development scenarios, but also uses some utilities and specific development processes to enable the realization of internationalization. Become efficient and organized.

1. Introduction: Resx resource documents encounter Avalonia UI internationalization

In software development, internationalization is the key to ensuring that applications can transcend language and cultural boundaries and reach global users. With its flexible architecture and rich functions, Avalonia UI has emerged in cross-platform application development. Resx resource files, as a time-tested and localized resource management method, have also found new use in the Avalonia UI. By combining the two, developers can provide applications with multi-language support capabilities under familiar development models and easily respond to the needs of users in different regions.

下图是使用VS扩展 ResXManager 对Resx资源文件进行管理的截图:

2. Detailed steps: The cornerstone of building multi-language applications

2.1. Careful layout of Resx resource files

2.1.1. Project catalog planning and basic resource file creation

开启您的 Avalonia UI 项目之旅,无论是已有的成熟项目还是全新创建的项目,首先在项目中添加一个用于存放国际化资源的目录,这里我们命名为 I18n(您可根据项目实际情况自定义目录名)。在这个目录下,创建默认的英文语言资源文件 Resource.resx。这个文件将作为整个国际化资源体系的基础,承载着应用在英文环境下的所有文本资源。

2.1.2. Expansion of multilingual resource files

  • 当英文资源文件就绪后,我们可以进一步拓展其他语言的资源文件。以中文简体、中文繁体和日语为例,它们的文件名需要遵循特定的命名规则:文件名前缀与默认语言资源文件名保持一致,即 Resource,并添加对应的 CultureName 后缀。例如,中文简体对应的资源文件名为 Resource.zh-CN.resx,中文繁体为 Resource.zh-Hant.resx,日语则是 Resource.ja-JP.resx。这样的命名方式有助于 Avalonia UI 在运行时准确识别并加载不同语言的资源。
  • 借助强大的 ResXManager 工具,我们可以方便地打开这些资源文件进行多语言文本的编辑。在编辑过程中,需要特别注意语言 Key 的命名,它必须满足 C# 变量语法,因为后续的开发流程会依据这些 Key 生成对应的语言 Key 类,确保在代码层面能够精准地引用和操作这些资源。

2.2. Introduction of NuGet package: A right-hand assistant to enhance internationalization capabilities

Install-Package AvaloniaExtensions.Axaml

这个包为我们的项目带来了一系列实用的 API,包括多语言切换功能、便捷的获取 Key 对应翻译字符串的方法,以及在 axaml 前端界面中对语言标记的支持。这些功能将极大地简化我们在国际化开发过程中的代码编写和界面设计工作。

2.3. T4 File: The Bridge from Resource Files to Strongly Type Resource Classes

2.3.1. Creation and configuration of T4 files

有了资源文件后,虽然已经能够在一定程度上实现国际化功能,但直接使用字符串 Key 在代码中进行资源引用既容易出错又不够直观。因此,我们引入 T4 文件来根据资源文件生成强类型的资源类。在之前创建的 I18n 目录下,添加一个 T4 文件,例如 Language.tt(文件名可根据项目需求灵活调整)。

2.3.2. Content parsing and generation logic of T4 file

打开 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";
}

This generated resource class allows us to reference resource keys in a strongly typed way in our code, which greatly improves the readability and maintainability of the code.

2.4. Specific application in the project: Make multi-language functions come alive

2.4.1. Resource references in code

在 C# 代码中,我们可以借助 I18nManager 类来获取指定语言 Key 对应的翻译字符串。例如:

I18nManager.GetString(Language.Setting)

这里的 Language.Setting 就是通过 T4 文件生成的强类型资源类中的字段,通过这种方式,我们能够在代码的任何地方方便地获取并使用多语言资源,确保应用在不同语言环境下的正确显示。

2.4.2. Language binding in the Axaml interface

axaml 前端界面中,我们首先需要引入相应的命名空间:

xmlns:i18n="https://codewf.com"
xmlns:language="clr-namespace:CodeWF.Toolbox.I18n"

Then, the text attributes of the interface elements are associated with the language resources through data binding. For example:

<TextBlock Text="{i18n:I18n {x:Static language:Language.AppName}}" />

In this way, when the language environment of the application changes, the text of the interface elements will be automatically updated to the corresponding translated text, realizing dynamic internationalization of the interface.

  1. Implementation of language switching

实现语言切换功能也非常简单,只需调用 I18nManager.Instance.Culture 属性,并传入目标语言的 CultureInfo 对象即可。例如:

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

这里的 language 变量可以是任何有效的语言代码,如 zh-CNja-JP 等。当设置了新的语言文化后,整个应用的语言显示会立即更新,为用户提供无缝的多语言切换体验。

3. Summary: An analysis of the advantages and disadvantages of the internationalization plan for Resx resource documents

Internationalization of Avalonia UI applications through Resx resource files undoubtedly provides a familiar and convenient path for traditional developers. It makes full use of existing development experience and tool ecosystems, such as ResXManager and T4 document technology, allowing the international development process to be efficiently integrated into existing project processes. However, this approach is not perfect. It may be difficult for the maintenance of ordinary users. Ordinary users may not be familiar with the structure and editing method of Resx files, and have difficulty understanding the logic of T4 file generation code. This requires developers to fully consider subsequent maintenance costs during the design and implementation of the project, and may need to provide ordinary users with some easy-to-use interfaces or tools to assist them in updating and managing international resources. But overall, for development teams and projects with a certain technical foundation, the internationalization of Resx resource files is still a recommended choice. It has excellent performance in terms of functionality, efficiency and compatibility.

I hope this article can provide useful reference and guidance for Avalonia UI developers in international practice, so that your applications can shine on the global stage.

** Egg: The next article introduces the internationalization of XML files **

Keep Exploring

延伸阅读

更多文章
同分类 / 同标签 9/13/2025

Migration from WPF to Avalonia series: Why I have to migrate WPF programs to Avalonia

In the past few years, our host computer software has been mainly developed using WPF and WinForm. These technologies are really easy to use on the Windows platform, and they have also accompanied us through the stage of small-scale trial production to today's large-scale delivery. However, with the development of business and changes in customer needs, the single Windows technology stack has gradually become a hurdle that we must overcome.

继续阅读