summaryrefslogtreecommitdiff
path: root/src/SMAPI/Framework/Translator.cs
diff options
context:
space:
mode:
authorJesse Plamondon-Willard <Pathoschild@users.noreply.github.com>2019-10-01 21:27:49 -0400
committerJesse Plamondon-Willard <Pathoschild@users.noreply.github.com>2019-10-01 21:27:49 -0400
commit845deb43d60147603ec31fe4ae5fd7d747556d8c (patch)
tree2d96293aef515147b5ca1cd2440f268f886ae6be /src/SMAPI/Framework/Translator.cs
parent673510b3941dd35a127e4f4a8a406f34b72b6a66 (diff)
downloadSMAPI-845deb43d60147603ec31fe4ae5fd7d747556d8c.tar.gz
SMAPI-845deb43d60147603ec31fe4ae5fd7d747556d8c.tar.bz2
SMAPI-845deb43d60147603ec31fe4ae5fd7d747556d8c.zip
add support for core translation files
Diffstat (limited to 'src/SMAPI/Framework/Translator.cs')
-rw-r--r--src/SMAPI/Framework/Translator.cs128
1 files changed, 128 insertions, 0 deletions
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
+{
+ /// <summary>Encapsulates access to arbitrary translations. Translations are fetched with locale fallback, so missing translations are filled in from broader locales (like <c>pt-BR.json</c> &lt; <c>pt.json</c> &lt; <c>default.json</c>).</summary>
+ internal class Translator
+ {
+ /*********
+ ** Fields
+ *********/
+ /// <summary>The translations for each locale.</summary>
+ private readonly IDictionary<string, IDictionary<string, string>> All = new Dictionary<string, IDictionary<string, string>>(StringComparer.InvariantCultureIgnoreCase);
+
+ /// <summary>The translations for the current locale, with locale fallback taken into account.</summary>
+ private IDictionary<string, Translation> ForLocale;
+
+
+ /*********
+ ** Accessors
+ *********/
+ /// <summary>The current locale.</summary>
+ public string Locale { get; private set; }
+
+ /// <summary>The game's current language code.</summary>
+ public LocalizedContentManager.LanguageCode LocaleEnum { get; private set; }
+
+
+ /*********
+ ** Public methods
+ *********/
+ /// <summary>Construct an instance.</summary>
+ public Translator()
+ {
+ this.SetLocale(string.Empty, LocalizedContentManager.LanguageCode.en);
+ }
+
+ /// <summary>Set the current locale and precache translations.</summary>
+ /// <param name="locale">The current locale.</param>
+ /// <param name="localeEnum">The game's current language code.</param>
+ public void SetLocale(string locale, LocalizedContentManager.LanguageCode localeEnum)
+ {
+ this.Locale = locale.ToLower().Trim();
+ this.LocaleEnum = localeEnum;
+
+ this.ForLocale = new Dictionary<string, Translation>(StringComparer.InvariantCultureIgnoreCase);
+ foreach (string next in this.GetRelevantLocales(this.Locale))
+ {
+ // skip if locale not defined
+ if (!this.All.TryGetValue(next, out IDictionary<string, string> 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));
+ }
+ }
+ }
+
+ /// <summary>Get all translations for the current locale.</summary>
+ public IEnumerable<Translation> GetTranslations()
+ {
+ return this.ForLocale.Values.ToArray();
+ }
+
+ /// <summary>Get a translation for the current locale.</summary>
+ /// <param name="key">The translation key.</param>
+ public Translation Get(string key)
+ {
+ this.ForLocale.TryGetValue(key, out Translation translation);
+ return translation ?? new Translation(this.Locale, key, null);
+ }
+
+ /// <summary>Get a translation for the current locale.</summary>
+ /// <param name="key">The translation key.</param>
+ /// <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>
+ public Translation Get(string key, object tokens)
+ {
+ return this.Get(key).Tokens(tokens);
+ }
+
+ /// <summary>Set the translations to use.</summary>
+ /// <param name="translations">The translations to use.</param>
+ internal Translator SetTranslations(IDictionary<string, IDictionary<string, string>> translations)
+ {
+ // reset translations
+ this.All.Clear();
+ foreach (var pair in translations)
+ this.All[pair.Key] = new Dictionary<string, string>(pair.Value, StringComparer.InvariantCultureIgnoreCase);
+
+ // rebuild cache
+ this.SetLocale(this.Locale, this.LocaleEnum);
+
+ return this;
+ }
+
+
+ /*********
+ ** Private methods
+ *********/
+ /// <summary>Get the locales which can provide translations for the given locale, in precedence order.</summary>
+ /// <param name="locale">The locale for which to find valid locales.</param>
+ private IEnumerable<string> 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";
+ }
+ }
+}