在软件开发日益全球化的今天,Avalonia 的国际化实现策略成为了众多开发者关注的焦点。继上一篇 Avalonia 国际化之路:Resx 资源文件的深度应用与探索[1]之后,本文将引领大家深入探究如何运用自定义 XML 文件来达成 Avalonia 国际化的目标,开启一段全新的技术探索之旅。1.1. 突破维护局限,拥抱用户定制摘要:在软件开发日益全球化的今天,Avalonia 的国际化实现策略成为了众多开发者关注的焦点。继上一篇 Avalonia 国际化之路:Resx 资源文件的深度应用与探索
Resx 资源文件往往将维护权限局限于开发端,而自定义 XML 语言文件则以其独特的灵活性脱颖而出。它能够与可执行程序一同输出,这一特性为用户侧的语言文件修改开辟了广阔的空间。用户不仅可以根据自身需求对已有语言内容进行调整,还能够轻松地扩展更多语言种类,使软件的国际化适应能力得到极大的提升,真正实现了从开发主导到用户参与的转变。
1.2. 命名空间加持,结构清晰有序自定义 XML 文件采用命名空间的方式来组织语言内容,这一设计理念与类的结构形成了精准的对应关系。通过这种方式,整个翻译文件的架构变得清晰明了,易于管理与维护。无论是在大型项目中进行团队协作开发,还是在后期的代码维护与升级过程中,都能够显著提高工作效率,减少因结构混乱而可能引发的错误与困扰。
1.3. AI 翻译便捷,助力语言转换在当今人工智能蓬勃发展的时代,XML 文件在 AI 翻译方面展现出了得天独厚的优势。借助特定的工具或平台,我们可以方便地利用 AI 技术对 XML 翻译文件进行处理。例如,只需提供简单的提示词,就能快速获取多种语言版本的翻译结果,为跨语言交流与软件全球化推广提供了强有力的支持。
下图为输出的XML语言文件:
2.1. 精心规划语言文件夹首先,我们需要创建一个专门用于存放语言文件的文件夹,例如命名为 “i18n”。在这个过程中,需要特别注意的是,相同输出路径下不同模块的 XML 文件名必须保持唯一性。因为在程序编译输出时,如果存在同名的 XML 文件,将会导致文件替换,进而造成语言信息的丢失,这无疑会给国际化进程带来严重的阻碍。
文件前缀可以工程名命名(方便区分),后缀为语言文化名
以下是创建语言文件夹后的工程结构示例图:
编译输出后文件列表如下:
AIModule.en-US.xmlAIModule.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文件内容(
AI
智能问答助手
一键提问,即刻获取答案,智能问答助手为您解惑。
AI一键多语种翻译神器
轻松实现一键翻译,支持多种语言互译,让沟通无界限!
AI一键转URL Slug
轻松将中文、英文等文章标题一键转换成英文URL Slug。
语言
可选择的
已选择
XML 文件的内容结构遵循一定的规范与层次。推荐采用三层结构来组织信息:
2.2.1. 第一层:Localization 节点此节点包含三个重要的子属性:
language:用于明确指定语言的名称,例如 “Chinese (Simplified)” 表示简体中文。
description:对该语言的简要描述,如 “中文简体”,以便于开发者和用户快速了解语言的基本特征。
cultureName:语言的文化名,这是一个在国际化处理中非常关键的标识,例如 “zh-CN” 代表简体中文的文化区域。如果对文化名不太清楚,可以通过百度搜索等方式获取准确信息。
以下是一个基本的 XML 文件框架示例:
2.2.2. 第二层:功能名或类名节点
这一层以功能名或类名来命名节点,其目的在于对翻译文件进行有效的功能归类。例如,在一个包含 AI 模块、转换模块等的项目中,可以分别创建 “AIModule”、“ConverterModule” 等节点,将与各个模块相关的翻译内容分别放置在对应的节点下,使整个文件的结构更加清晰,便于管理与查找。
以下是一个包含多个模块节点的 XML 文件示例:
2.2.3. 第三层:语言 Key 节点
最后一层为语言 Key 节点,这些节点直接存储了具体的翻译文本内容。例如:
AI
智能问答助手
一键提问,即刻获取答案,智能问答助手为您解惑。
在实际应用中,虽然推荐采用三层结构,但 XML 节点的嵌套层数并没有严格的限制,开发者可以根据项目的实际需求和复杂程度进行灵活调整。例如:
AI
智能问答助手
一键提问,即刻获取答案,智能问答助手为您解惑。
AI一键多语种翻译神器
轻松实现一键翻译,支持多种语言互译,让沟通无界限!
为了在代码中更加方便、高效地使用 XML 翻译文件,我们采用 T4 文件将 XML 转换为 C# 的强类型。具体操作如下:
在 “i18n” 目录下创建一个 T4 文件,例如命名为 “Language.tt”,并在其中填入以下代码:
//
//
// This code was generated by a tool.
// Changes to this file may cause incorrect behavior and will be lost if
// the code is regenerated.
//
<#
string templatedirectory = Path.GetDirectoryName(Host.TemplateFile);
string xmlFilePath = Directory.GetFiles(templateDirectory, "*.xml").FirstOrDefault;
if (xmlFilePath!= )
{
XDocument xdoc = XDocument.Load(xmlFilePath);
var classNodes = xdoc.Nodes.OfType.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";
}
}
{
public static class AskBotView
{
public static readonly string Title = "Localization.AskBotView.Title";
public static readonly string Description = "Localization.AskBotView.Description";
}
}
//...
这些生成的强类型类将为我们在后续的代码编写中提供极大的便利,使我们能够更加准确、便捷地获取和使用翻译文本。
4.1. 安装必备 NuGet 包Install-Package AvaloniaXmlTranslator这一步骤将为我们的项目引入必要的功能组件,为后续的国际化操作奠定基础。
4.2. 动态获取语言列表在 Avalonia 应用中,动态获取程序配置的语言列表是实现国际化界面切换的关键步骤之一。通过以下代码,我们可以轻松地获取语言列表:
List languages = I18nManager.Instance.Resources.Select(kvp => kvp.Value).ToList;其中,“LocalizationLanguage” 类定义如下:
public class LocalizationLanguage{
public string Language { get; set; } = (string) ;
public string Description { get; set; } = (string) ;
public string CultureName { get; set; } = (string) ;
//...
}
获取到语言列表后,我们可以将其用于界面绑定,例如在下拉菜单中显示可供用户选择的语言选项,或者在其他需要展示语言信息的界面元素中进行数据绑定。
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 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 进行关联。
以下是在控件中使用翻译文本的示例:
来源:opendotnet