Baru-baru ini saya mengalami masalah saat melokalkan aplikasi saya dan berpikir untuk menyelesaikannya.
Yang pertama terlintas dalam pikiran adalah cara yang paling jelas dan paling sederhana - kamus, tetapi segera ditolak, karena tidak ada cara untuk memeriksa apakah suatu string ada di kamus pada saat kompilasi.
Solusi yang jauh lebih elegan adalah membuat hierarki kelas seperti ini:
public class Locale
{
public string Name {get; set;}
public UI UI {get; set;}
}
public class UI
{
public Buttons Buttons {get; set;}
public Messages Messages {get; set;}
}
public class Buttons
{
public string CloseButton {get; set;}
public string DeleteButton {get; set;}
}
public class Messages
{
public string ErrorMessage {get; set;}
}
Kemudian Anda cukup membuat serial / deserialize xml'ku.
Hanya ada satu "tetapi". Perlu waktu lama untuk membuat hierarki kelas ini, terutama jika projectnya besar. Jadi mengapa tidak membuatnya dari file xml? Inilah yang akan kami lakukan.
Mari kita mulai
Pertama, mari buat proyek untuk generator kita dan tambahkan paket yang diperlukan ke dalamnya.
dotnet new classlib -o LocalizationSourceGenerator -f netstandard2.0 dotnet add package Microsoft.CodeAnalysis.CSharp dotnet add package Microsoft.CodeAnalysis.Analyzers
Penting! Kerangka target proyek harus netstandard2.0
Selanjutnya, mari tambahkan kelas generator kita
Ini harus mengimplementasikan antarmuka ISourceGenerator dan ditandai dengan atribut Generator
Selanjutnya, mari tambahkan antarmuka ILocalizationGenerator dan kelas XmlLocalizationGenerator yang mengimplementasikannya:
ILocalizationGenerator.cs
public interface ILocalizationGenerator
{
string GenerateLocalization(string template);
}
XmlLocalizationGenerator.cs
public class XmlLocalizationGenerator : ILocalizationGenerator
{
//
private List<string> classes = new List<string>();
public string GenerateLocalization(string template)
{
// xml
XmlDocument document = new XmlDocument();
document.LoadXml(template);
var root = document.DocumentElement;
//
string namespaceName = root.HasAttribute("namespace") ?
root.GetAttribute("namespace") :
"Localization";
GenClass(root); //
var sb = new StringBuilder();
sb.AppendLine($"namespace {namespaceName}\n{{");
//
foreach(var item in classes)
{
sb.AppendLine(item);
}
sb.Append('}');
return sb.ToString();
}
public void GenClass(XmlElement element)
{
var sb = new StringBuilder();
sb.Append($"public class {element.Name}");
sb.AppendLine("{");
//
foreach (XmlNode item in element.ChildNodes)
{
//
// - -
if (item.ChildNodes.Count == 0
|| (item.ChildNodes.Count == 1
&& item.FirstChild.NodeType==XmlNodeType.Text))
{
sb.AppendLine($"public string {item.Name} {{get; set;}}");
}
else
{
//
//
sb.AppendLine($"public {item.Name} {item.Name} {{get; set;}}");
GenClass(item);
}
}
sb.AppendLine("}");
classes.Add(sb.ToString());
}
}
Ada sedikit yang harus dilakukan. Penting untuk mengimplementasikan kelas generator itu sendiri
LocalizationSourceGenerator.cs
[Generator]
public class LocalizationSourceGenerator : ISourceGenerator
{
public void Execute(GeneratorExecutionContext context)
{
//
var templateFile = context
.AdditionalFiles
.FirstOrDefault(
x => Path.GetExtension(x.Path) == ".xml")
?.Path;
if (!string.IsNullOrWhiteSpace(templateFile))
{
ILocalizationGenerator generator = new XmlLocalizationGenerator();
var s = generator.GenerateLocalization(File.ReadAllText(templateFile));
// ""
//
context.AddSource("Localization",s );
}
}
public void Initialize(GeneratorInitializationContext context)
{
// ,
//
}
}
Itu saja! Sekarang Anda hanya perlu memeriksa generator kami. Untuk melakukan ini, buat proyek aplikasi konsol
dotnet new console -o Test
Tambahkan template dan file pelokalan
template.xml
<Locale namespace="Program.Localization">
<UI>
<Buttons>
<SendButton/>
</Buttons>
</UI>
<Name/>
</Locale>
ru.xml
<Locale>
<UI>
<Buttons>
<SendButton></SendButton>
</Buttons>
</UI>
<Name></Name>
</Locale>
Mari edit file proyek
Test.csproj
<Project Sdk="Microsoft.NET.Sdk">
<PropertyGroup>
<OutputType>Exe</OutputType>
<TargetFramework>net5.0</TargetFramework>
</PropertyGroup>
<ItemGroup>
<ProjectReference
ReferenceOutputAssembly="false"
OutputItemType="Analyzer"
Include="----" />
<!-- -->
<AdditionalFiles Include="template.xml"/>
</ItemGroup>
</Project>
Dan kode programnya
Program.cs
using System;
using System.IO;
using System.Xml.Serialization;
using Program.Localization; //
namespace Program
{
public class Program
{
public static void Main()
{
// Locale
var xs = new XmlSerializer(typeof(Locale));
var locale = xs.Deserialize(File.OpenRead("ru.xml")) as Locale;
Console.WriteLine(locale.Name);
Console.WriteLine(locale.UI.Buttons.SendButton);
}
}
}
Dotnet-Dan-Kebahagiaan / LocalizationSourceGenerator (github.com) - gudang generator