| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204 |
- using Ryujinx.Ava.UI.ViewModels;
- using Ryujinx.Common;
- using Ryujinx.Common.Logging;
- using Ryujinx.Common.Utilities;
- using Ryujinx.UI.Common.Configuration;
- using System;
- using System.Collections.Concurrent;
- using System.Collections.Generic;
- using System.Globalization;
- using System.IO;
- using System.Linq;
- using System.Text.Encodings.Web;
- using System.Text.Json;
- using System.Text.Json.Serialization;
- using System.Text.Unicode;
- namespace Ryujinx.Ava.Common.Locale
- {
- class LocaleManager : BaseModel
- {
- private const string DefaultLanguageCode = "en_US";
- private readonly Dictionary<LocaleKeys, string> _localeStrings;
- private Dictionary<LocaleKeys, string> _localeDefaultStrings;
- private readonly ConcurrentDictionary<LocaleKeys, object[]> _dynamicValues;
- private string _localeLanguageCode;
- public static LocaleManager Instance { get; } = new();
- public event Action LocaleChanged;
- public LocaleManager()
- {
- _localeStrings = new Dictionary<LocaleKeys, string>();
- _localeDefaultStrings = new Dictionary<LocaleKeys, string>();
- _dynamicValues = new ConcurrentDictionary<LocaleKeys, object[]>();
- Load();
- }
- private void Load()
- {
- var localeLanguageCode = !string.IsNullOrEmpty(ConfigurationState.Instance.UI.LanguageCode.Value) ?
- ConfigurationState.Instance.UI.LanguageCode.Value : CultureInfo.CurrentCulture.Name.Replace('-', '_');
- // Load en_US as default, if the target language translation is missing or incomplete.
- LoadDefaultLanguage();
- LoadLanguage(localeLanguageCode);
- // Save whatever we ended up with.
- if (Program.PreviewerDetached)
- {
- ConfigurationState.Instance.UI.LanguageCode.Value = _localeLanguageCode;
- ConfigurationState.Instance.ToFileFormat().SaveConfig(Program.ConfigurationPath);
- }
- }
- public string this[LocaleKeys key]
- {
- get
- {
- // Check if the locale contains the key.
- if (_localeStrings.TryGetValue(key, out string value))
- {
- // Check if the localized string needs to be formatted.
- if (_dynamicValues.TryGetValue(key, out var dynamicValue))
- try
- {
- return string.Format(value, dynamicValue);
- }
- catch
- {
- // If formatting failed use the default text instead.
- if (_localeDefaultStrings.TryGetValue(key, out value))
- try
- {
- return string.Format(value, dynamicValue);
- }
- catch
- {
- // If formatting the default text failed return the key.
- return key.ToString();
- }
- }
- return value;
- }
- // If the locale doesn't contain the key return the default one.
- return _localeDefaultStrings.TryGetValue(key, out string defaultValue)
- ? defaultValue
- : key.ToString(); // If the locale text doesn't exist return the key.
- }
- set
- {
- _localeStrings[key] = value;
- OnPropertyChanged();
- }
- }
- public bool IsRTL() =>
- _localeLanguageCode switch
- {
- "ar_SA" or "he_IL" => true,
- _ => false
- };
- public static string FormatDynamicValue(LocaleKeys key, params object[] values)
- => Instance.UpdateAndGetDynamicValue(key, values);
- public string UpdateAndGetDynamicValue(LocaleKeys key, params object[] values)
- {
- _dynamicValues[key] = values;
- OnPropertyChanged("Item");
- return this[key];
- }
- private void LoadDefaultLanguage()
- {
- _localeDefaultStrings = LoadJsonLanguage(DefaultLanguageCode);
- }
- public void LoadLanguage(string languageCode)
- {
- var locale = LoadJsonLanguage(languageCode);
- if (locale == null)
- {
- _localeLanguageCode = DefaultLanguageCode;
- locale = _localeDefaultStrings;
- }
- else
- {
- _localeLanguageCode = languageCode;
- }
- foreach ((LocaleKeys key, string val) in locale)
- {
- _localeStrings[key] = val;
- }
- OnPropertyChanged("Item");
- LocaleChanged?.Invoke();
- }
- private static Dictionary<LocaleKeys, string> LoadJsonLanguage(string languageCode)
- {
- var localeStrings = new Dictionary<LocaleKeys, string>();
- string fileData = EmbeddedResources.ReadAllText($"Ryujinx/Assets/locales.json");
- if (fileData == null)
- {
- // We were unable to find file for that language code.
- return null;
- }
- LocalesJson json = JsonHelper.Deserialize(fileData, LocalesJsonContext.Default.LocalesJson);
- foreach (LocalesEntry locale in json.Locales)
- {
- if (locale.Translations.Count != json.Languages.Count)
- {
- Logger.Error?.Print(LogClass.UI, $"Locale key {{{locale.ID}}} is missing languages!");
- throw new Exception("Missing locale data!");
- }
- if (Enum.TryParse<LocaleKeys>(locale.ID, out var localeKey))
- {
- if (locale.Translations.TryGetValue(languageCode, out string val) && val != "")
- {
- localeStrings[localeKey] = val;
- }
- else
- {
- locale.Translations.TryGetValue("en_US", out val);
- localeStrings[localeKey] = val;
- }
- }
- }
- return localeStrings;
- }
- }
- public struct LocalesJson
- {
- public List<string> Languages { get; set; }
- public List<LocalesEntry> Locales { get; set; }
- }
- public struct LocalesEntry
- {
- public string ID { get; set; }
- public Dictionary<string, string> Translations { get; set; }
- }
- [JsonSourceGenerationOptions(WriteIndented = true)]
- [JsonSerializable(typeof(LocalesJson))]
- internal partial class LocalesJsonContext : JsonSerializerContext { }
- }
|