Menerapkan pelokalan dengan generator kode Sumber

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








All Articles