
今日のグローバルなソフトウェア開発の波の中で、アプリケーションの国際化(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 ツールを使用すると、これらのリソースファイルを簡単に開いて多言語テキストを編集できます。編集時には、言語キーの命名に特に注意が必要です。これは C# の変数構文に従わなければなりません。なぜなら、後の開発フローでこれらのキーに基づいて対応する言語キークラスが生成され、コードレベルで正確にリソースを参照・操作できるようにするためです。
2.2. NuGet パッケージの導入:国際化機能を強化する頼もしい助っ人
Install-Package AvaloniaExtensions.Axaml
このパッケージは、多言語切り替え機能、キーに対応する翻訳文字列を便利に取得するメソッド、そして axaml フロントエンド UI での言語マークのサポートなど、一連の実用的な API をプロジェクトにもたらします。これらの機能により、国際化開発の過程でのコード記述と UI 設計作業が大幅に簡素化されます。
2.3. T4 ファイル:リソースファイルから強型リソースクラスへの橋渡し
2.3.1. T4 ファイルの作成と設定
リソースファイルができたことで、ある程度の国際化機能は実現できますが、コード内で直接文字列キーを使用してリソースを参照するのは、エラーが発生しやすく直感的でもありません。そこで、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 構造からすべての言語キーを抽出します。そして、抽出された各キーに対して、対応するパブリック静的読み取り専用文字列フィールドを生成します。フィールド名はキーと同じで、初期値もキーです。このようにして、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";
}
この生成されたリソースクラスにより、コード内でリソースキーを強型で参照できるようになり、コードの可読性と保守性が大幅に向上します。
2.4. プロジェクトでの具体的な応用:多言語機能を活き活きとさせる
2.4.1. コード内でのリソース参照
C# コードでは、I18nManager クラスを使用して、指定された言語キーに対応する翻訳文字列を取得できます。例えば:
I18nManager.GetString(Language.Setting)
ここでの Language.Setting は、T4 ファイルで生成された強型リソースクラスのフィールドです。この方法により、コード内の任意の場所で多言語リソースを簡単に取得・使用でき、異なる言語環境での正しい表示を確保できます。
2.4.2. Axaml UI での言語バインディング
axaml フロントエンド UI では、まず対応する名前空間をインポートする必要があります:
xmlns:i18n="https://codewf.com"
xmlns:language="clr-namespace:CodeWF.Toolbox.I18n"
その後、データバインディングを使用して UI 要素のテキストプロパティを言語リソースに関連付けます。例えば:
<TextBlock Text="{i18n:I18n {x:Static language:Language.AppName}}" />
これにより、アプリの言語環境が変わると、UI 要素のテキストが自動的に対応する翻訳テキストに更新され、UI の動的な国際化が実現します。
- 言語切り替えの実装
言語切り替え機能の実装も非常に簡単で、I18nManager.Instance.Culture プロパティを呼び出し、対象言語の CultureInfo オブジェクトを渡すだけです。例えば:
I18nManager.Instance.Culture = new CultureInfo(language);
ここでの language 変数は、zh-CN や ja-JP などの有効な言語コードであれば何でもかまいません。新しい言語文化を設定すると、アプリ全体の言語表示が即座に更新され、ユーザーにシームレスな多言語切り替え体験を提供します。
3. まとめ:Resx リソースファイル国際化方式のメリットとデメリットの分析
Resx リソースファイルを使用した Avalonia UI アプリケーションの国際化は、従来の開発者にとって馴染み深く便利な道を提供します。ResXManager や T4 ファイル技術などの既存の開発経験とツールエコシステムを最大限に活用し、国際化開発プロセスを既存のプロジェクトフローに効率良く統合できます。しかし、この方式は完璧ではありません。一般のユーザー側でのメンテナンスにはある程度の難しさが伴う可能性があります。一般のユーザーは Resx ファイルの構造や編集方法に馴染みがなく、T4 ファイルがコードを生成するロジックを理解するのも難しいかもしれません。そのため、プロジェクトの設計と実装において、開発者はその後のメンテナンスコストを十分に考慮し、一般ユーザーが国際化リソースを更新・管理しやすいように、シンプルな UI やツールを提供する必要があるかもしれません。しかし総合的に見ると、一定の技術基盤を持つ開発チームとプロジェクトにとって、Resx リソースファイルによる国際化方式は依然として推奨できる選択肢であり、機能、効率、互換性の面で優れたパフォーマンスを発揮します。
本記事が、多くの Avalonia UI 開発者の国際化実践において有益な参考と指針となり、あなたのアプリケーションがグローバルな舞台で輝く一助となれば幸いです。
おまけ:次回の記事では XML ファイルによる国際化を紹介します。