Kürzlich bin ich auf das Problem der Lokalisierung meiner Anwendung gestoßen und habe darüber nachgedacht, sie zu lösen.
Der erste, der mir in den Sinn kommt, ist der naheliegendste und einfachste Weg - ein Wörterbuch, das jedoch sofort abgelehnt wurde, da zum Zeitpunkt der Kompilierung nicht überprüft werden kann, ob eine Zeichenfolge im Wörterbuch vorhanden ist.
Eine viel elegantere Lösung besteht darin, eine Klassenhierarchie wie diese zu erstellen:
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;}
}
Dann können Sie xml'ku einfach serialisieren / deserialisieren.
Es gibt nur ein "aber". Das Erstellen dieser Klassenhierarchie kann lange dauern, insbesondere wenn das Projekt groß ist. Warum also nicht aus einer XML-Datei generieren? Das werden wir tun.
Lass uns anfangen
Lassen Sie uns zunächst ein Projekt für unseren Generator erstellen und die erforderlichen Pakete hinzufügen.
dotnet new classlib -o LocalizationSourceGenerator -f netstandard2.0 dotnet add package Microsoft.CodeAnalysis.CSharp dotnet add package Microsoft.CodeAnalysis.Analyzers
Wichtig! Das Ziel-Framework des Projekts muss netstandard2.0 sein
Als nächstes fügen wir die Klasse unseres Generators hinzu
Es muss die ISourceGenerator-Schnittstelle implementieren und mit dem Generator-Attribut gekennzeichnet sein
Als Nächstes fügen wir die ILocalizationGenerator-Schnittstelle und die XmlLocalizationGenerator-Klasse hinzu, die sie implementiert:
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());
}
}
Es gibt wenig zu tun. Es ist notwendig, die Klasse des Generators selbst zu implementieren
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)
{
// ,
//
}
}
Das ist alles! Jetzt müssen Sie nur noch unseren Generator überprüfen. Erstellen Sie dazu ein Konsolenanwendungsprojekt
dotnet new console -o Test
Fügen Sie die Vorlage und die Lokalisierungsdatei hinzu
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>
Lassen Sie uns die Projektdatei bearbeiten
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>
Und der Programmcode
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-And-Happiness / LocalizationSourceGenerator (github.com) - Generator-Repository