/// <summary> /// This method parses the Watcher Value Translation table from the plugin configuration. /// </summary> /// <param name="root">The root node of the configuration.</param> private void ParseValueTranslationTable(XElement root) { // Search for a value translation node XElement valueTranslationElement = root.Element("ValueTranslation", StringComparison.OrdinalIgnoreCase); if (valueTranslationElement == null) { Trace.TraceInformation("Value translation table does not appear to exist."); return; } Trace.TraceInformation("Found the value translation table."); // Extract the fields whose values will be translated IEnumerable <XElement> watcherFields = valueTranslationElement.Elements("WatcherField", StringComparison.OrdinalIgnoreCase); foreach (XElement watcherField in watcherFields) { // Create a new translation instance, and store the name of the field to translate TranslationEntry entry = new TranslationEntry(); entry.Field = watcherField.AttributeValue("Name", StringComparison.OrdinalIgnoreCase); // Extract the possible values of each field, and what value they should be translated to IEnumerable <XElement> watcherFieldValues = watcherField.Elements("Value", StringComparison.OrdinalIgnoreCase); foreach (XElement watcherFieldValue in watcherFieldValues) { entry.TranslationTable.Add( watcherFieldValue.AttributeValue("From", StringComparison.OrdinalIgnoreCase), watcherFieldValue.AttributeValue("To", StringComparison.OrdinalIgnoreCase) ); } // Add the translation instance to the translation table this.Translation.Add(entry.Field, entry); } }
/// <inheritdoc/> public void Execute(GeneratorExecutionContext context) { try { // get generator options string @namespace = this.ReadOption(context, "Namespace", raw => raw) ?? this.GetRootNamespace(context) ?? "Pathoschild.I18n"; string className = this.ReadOption(context, "ClassName", raw => raw) ?? "I18n"; string classModifiers = this.ReadOption(context, "ClassModifiers", raw => raw) ?? "internal static"; bool addGetByKey = this.ReadOption <bool?>(context, "AddGetByKey", raw => bool.Parse(raw)) ?? false; bool addKeyMap = this.ReadOption <bool?>(context, "AddKeyMap", raw => bool.Parse(raw)) ?? false; // get translations TranslationEntry[] entries = this.ReadTranslationFile(context, new HashSet <string>(this.GetReservedNames(className, addKeyMap))); // build output StringBuilder output = new(); output .AppendLine("#nullable enable") .AppendLine("using System;") .AppendLine("using System.CodeDom.Compiler;"); if (entries.Any(p => p.TokenParameterStyle == TokenParameterStyle.Dictionary)) { output .AppendLine("using System.Collections.Generic;"); } output .AppendLine("using System.Diagnostics.CodeAnalysis;") .AppendLine("using StardewModdingAPI;") .AppendLine() .AppendLine($"namespace {@namespace}") .AppendLine("{") .AppendLine(" /// <summary>Get translations from the mod's <c>i18n</c> folder.</summary>") .AppendLine(" /// <remarks>This is auto-generated from the <c>i18n/default.json</c> file when the project is compiled.</remarks>") .AppendLine(@" [GeneratedCode(""TextTemplatingFileGenerator"", ""1.0.0"")]") .AppendLine(@" [SuppressMessage(""ReSharper"", ""InconsistentNaming"", Justification = ""Deliberately named for consistency and to match translation conventions."")]") .AppendLine($" {classModifiers} class {className}") .AppendLine(" {") .AppendLine(" /*********") .AppendLine(" ** Fields") .AppendLine(" *********/") .AppendLine(" /// <summary>The mod's translation helper.</summary>") .AppendLine(" private static ITranslationHelper? Translations;") .AppendLine() .AppendLine(); if (addKeyMap) { output .AppendLine(" /*********") .AppendLine(" ** Accessors") .AppendLine(" *********/") .AppendLine(" /// <summary>A lookup of available translation keys.</summary>") .AppendLine(@" [SuppressMessage(""ReSharper"", ""MemberHidesStaticFromOuterClass"", Justification = ""Using the same key is deliberate."")]") .AppendLine(" public static class Keys") .AppendLine(" {"); for (int i = 0; i < entries.Length; i++) { TranslationEntry entry = entries[i]; if (i != 0) { output.AppendLine(); } output .AppendLine($@" /// <summary>The unique key for a translation equivalent to ""{entry.GetTranslationTextForXmlDoc()}"".</summary>") .AppendLine($@" public const string {entry.MethodName} = ""{entry.Key}"";"); } output .AppendLine(" }") .AppendLine() .AppendLine(); } output .AppendLine(" /*********") .AppendLine(" ** Public methods") .AppendLine(" *********/") .AppendLine(" /// <summary>Construct an instance.</summary>") .AppendLine(@" /// <param name=""translations"">The mod's translation helper.</param>") .AppendLine(" public static void Init(ITranslationHelper translations)") .AppendLine(" {") .AppendLine($" {className}.Translations = translations;") .AppendLine(" }"); foreach (TranslationEntry entry in entries) { // summary doc output .AppendLine() .AppendLine($@" /// <summary>Get a translation equivalent to ""{entry.GetTranslationTextForXmlDoc()}"".</summary>"); // param docs foreach (var token in entry.Tokens) { output.AppendLine($@" /// <param name=""{this.PrefixIdentifierIfNeeded(token.ParameterName)}"">The value to inject for the <c>{{{{{token.Key}}}}}</c> token.</param>"); } // method { string renderedKey = addKeyMap ? $"Keys.{entry.MethodName}" : $@"""{entry.Key}"""; string renderedArgs = string.Join(", ", entry.Tokens.Select(token => $"object {token.ParameterName}")); string renderedTokenObj = entry.Tokens.Any() ? $", {this.GenerateTokenParameter(entry)}" : ""; output .AppendLine($@" public static string {entry.MethodName}({renderedArgs})") .AppendLine(" {") .AppendLine($@" return {className}.GetByKey({renderedKey}{renderedTokenObj});") .AppendLine(" }"); } } if (addGetByKey) { output.AppendLine(); } else { output .AppendLine() .AppendLine() .AppendLine(" /*********") .AppendLine(" ** Private methods") .AppendLine(" *********/"); } output .AppendLine(" /// <summary>Get a translation by its key.</summary>") .AppendLine(@" /// <param name=""key"">The translation key.</param>") .AppendLine(@" /// <param name=""tokens"">An object containing token key/value pairs. This can be an anonymous object (like <c>new { value = 42, name = ""Cranberries"" }</c>), a dictionary, or a class instance.</param>") .AppendLine($" {(addGetByKey ? "public" : "private")} static Translation GetByKey(string key, object? tokens = null)") .AppendLine(" {") .AppendLine($" if ({className}.Translations == null)") .AppendLine($@" throw new InvalidOperationException($""You must call {{nameof({className})}}.{{nameof({className}.Init)}} from the mod's entry method before reading translations."");") .AppendLine($" return {className}.Translations.Get(key, tokens);") .AppendLine(" }"); output .AppendLine(" }") .AppendLine("}") .AppendLine(); // Add the source code to the compilation context.AddSource($"{className}.generated.cs", output.ToString()); } catch (Exception ex) { this.LogException(context, ex); } }
public void setTranslationValues() { TranslationEntry.Clear(); foreach (var k in TransResult.results) { if (k.lexicalEntries != null) { foreach (var i in k.lexicalEntries) { var trans_item = new TranslateEntry(); trans_item.Type = i.lexicalCategory; trans_item.Examples = "Examples: \n\n"; trans_item.Translations = "Translations: \n\n"; if (i.entries != null) { foreach (var j in i.entries) { if (j.senses != null) { foreach (var y in j.senses) { if (y.translations != null) { foreach (var x in y.translations) { if (!trans_item.Translations.Contains(x.text)) { trans_item.Translations += x.text + "\n"; } } } if (y.examples != null) { foreach (var example in y.examples) { if (example.translations != null) { trans_item.Examples += example.text + "\n" + example.translations.ElementAt(0).text + "\n\n"; } } } if (y.subsenses != null) { foreach (var x in y.subsenses) { if (x.translations != null) { foreach (var trans in x.translations) { if (!trans_item.Translations.Contains(trans.text)) { trans_item.Translations += trans.text + "\n"; } } } if (x.examples != null) { foreach (var example in x.examples) { if (example.translations != null) { trans_item.Examples += example.text + "\n" + example.translations.ElementAt(0).text + "\n\n"; } } } } } } } } } TranslationEntry.Add(trans_item); } } } }