From 845deb43d60147603ec31fe4ae5fd7d747556d8c Mon Sep 17 00:00:00 2001 From: Jesse Plamondon-Willard Date: Tue, 1 Oct 2019 21:27:49 -0400 Subject: add support for core translation files --- src/SMAPI/Framework/Translator.cs | 128 ++++++++++++++++++++++++++++++++++++++ 1 file changed, 128 insertions(+) create mode 100644 src/SMAPI/Framework/Translator.cs (limited to 'src/SMAPI/Framework/Translator.cs') diff --git a/src/SMAPI/Framework/Translator.cs b/src/SMAPI/Framework/Translator.cs new file mode 100644 index 00000000..f2738633 --- /dev/null +++ b/src/SMAPI/Framework/Translator.cs @@ -0,0 +1,128 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using StardewValley; + +namespace StardewModdingAPI.Framework +{ + /// Encapsulates access to arbitrary translations. Translations are fetched with locale fallback, so missing translations are filled in from broader locales (like pt-BR.json < pt.json < default.json). + internal class Translator + { + /********* + ** Fields + *********/ + /// The translations for each locale. + private readonly IDictionary> All = new Dictionary>(StringComparer.InvariantCultureIgnoreCase); + + /// The translations for the current locale, with locale fallback taken into account. + private IDictionary ForLocale; + + + /********* + ** Accessors + *********/ + /// The current locale. + public string Locale { get; private set; } + + /// The game's current language code. + public LocalizedContentManager.LanguageCode LocaleEnum { get; private set; } + + + /********* + ** Public methods + *********/ + /// Construct an instance. + public Translator() + { + this.SetLocale(string.Empty, LocalizedContentManager.LanguageCode.en); + } + + /// Set the current locale and precache translations. + /// The current locale. + /// The game's current language code. + public void SetLocale(string locale, LocalizedContentManager.LanguageCode localeEnum) + { + this.Locale = locale.ToLower().Trim(); + this.LocaleEnum = localeEnum; + + this.ForLocale = new Dictionary(StringComparer.InvariantCultureIgnoreCase); + foreach (string next in this.GetRelevantLocales(this.Locale)) + { + // skip if locale not defined + if (!this.All.TryGetValue(next, out IDictionary translations)) + continue; + + // add missing translations + foreach (var pair in translations) + { + if (!this.ForLocale.ContainsKey(pair.Key)) + this.ForLocale.Add(pair.Key, new Translation(this.Locale, pair.Key, pair.Value)); + } + } + } + + /// Get all translations for the current locale. + public IEnumerable GetTranslations() + { + return this.ForLocale.Values.ToArray(); + } + + /// Get a translation for the current locale. + /// The translation key. + public Translation Get(string key) + { + this.ForLocale.TryGetValue(key, out Translation translation); + return translation ?? new Translation(this.Locale, key, null); + } + + /// Get a translation for the current locale. + /// The translation key. + /// An object containing token key/value pairs. This can be an anonymous object (like new { value = 42, name = "Cranberries" }), a dictionary, or a class instance. + public Translation Get(string key, object tokens) + { + return this.Get(key).Tokens(tokens); + } + + /// Set the translations to use. + /// The translations to use. + internal Translator SetTranslations(IDictionary> translations) + { + // reset translations + this.All.Clear(); + foreach (var pair in translations) + this.All[pair.Key] = new Dictionary(pair.Value, StringComparer.InvariantCultureIgnoreCase); + + // rebuild cache + this.SetLocale(this.Locale, this.LocaleEnum); + + return this; + } + + + /********* + ** Private methods + *********/ + /// Get the locales which can provide translations for the given locale, in precedence order. + /// The locale for which to find valid locales. + private IEnumerable GetRelevantLocales(string locale) + { + // given locale + yield return locale; + + // broader locales (like pt-BR => pt) + while (true) + { + int dashIndex = locale.LastIndexOf('-'); + if (dashIndex <= 0) + break; + + locale = locale.Substring(0, dashIndex); + yield return locale; + } + + // default + if (locale != "default") + yield return "default"; + } + } +} -- cgit