diff options
Diffstat (limited to 'Emby.Server.Implementations/Localization/LocalizationManager.cs')
| -rw-r--r-- | Emby.Server.Implementations/Localization/LocalizationManager.cs | 400 |
1 files changed, 210 insertions, 190 deletions
diff --git a/Emby.Server.Implementations/Localization/LocalizationManager.cs b/Emby.Server.Implementations/Localization/LocalizationManager.cs index efbccaa5b..220e423bf 100644 --- a/Emby.Server.Implementations/Localization/LocalizationManager.cs +++ b/Emby.Server.Implementations/Localization/LocalizationManager.cs @@ -25,19 +25,19 @@ namespace Emby.Server.Implementations.Localization private static readonly Assembly _assembly = typeof(LocalizationManager).Assembly; private static readonly string[] _unratedValues = { "n/a", "unrated", "not rated" }; + private readonly IServerConfigurationManager _configurationManager; + private readonly ILogger<LocalizationManager> _logger; + private readonly Dictionary<string, Dictionary<string, ParentalRating>> _allParentalRatings = new Dictionary<string, Dictionary<string, ParentalRating>>(StringComparer.OrdinalIgnoreCase); - private readonly IServerConfigurationManager _configurationManager; - private readonly ConcurrentDictionary<string, Dictionary<string, string>> _dictionaries = new ConcurrentDictionary<string, Dictionary<string, string>>(StringComparer.OrdinalIgnoreCase); - private readonly JsonSerializerOptions _jsonOptions = JsonDefaults.Options; - private readonly ILogger<LocalizationManager> _logger; - private List<CultureDto> _cultures; + private readonly JsonSerializerOptions _jsonOptions = JsonDefaults.Options; + /// <summary> /// Initializes a new instance of the <see cref="LocalizationManager" /> class. /// </summary> @@ -52,12 +52,119 @@ namespace Emby.Server.Implementations.Localization } /// <summary> + /// Loads all resources into memory. + /// </summary> + /// <returns><see cref="Task" />.</returns> + public async Task LoadAll() + { + const string RatingsResource = "Emby.Server.Implementations.Localization.Ratings."; + + // Extract from the assembly + foreach (var resource in _assembly.GetManifestResourceNames()) + { + if (!resource.StartsWith(RatingsResource, StringComparison.Ordinal)) + { + continue; + } + + string countryCode = resource.Substring(RatingsResource.Length, 2); + var dict = new Dictionary<string, ParentalRating>(StringComparer.OrdinalIgnoreCase); + + using (var str = _assembly.GetManifestResourceStream(resource)) + using (var reader = new StreamReader(str)) + { + await foreach (var line in reader.ReadAllLinesAsync().ConfigureAwait(false)) + { + if (string.IsNullOrWhiteSpace(line)) + { + continue; + } + + string[] parts = line.Split(','); + if (parts.Length == 2 + && int.TryParse(parts[1], NumberStyles.Integer, CultureInfo.InvariantCulture, out var value)) + { + var name = parts[0]; + dict.Add(name, new ParentalRating(name, value)); + } +#if DEBUG + else + { + _logger.LogWarning("Malformed line in ratings file for country {CountryCode}", countryCode); + } +#endif + } + } + + _allParentalRatings[countryCode] = dict; + } + + await LoadCultures().ConfigureAwait(false); + } + + /// <summary> /// Gets the cultures. /// </summary> /// <returns><see cref="IEnumerable{CultureDto}" />.</returns> public IEnumerable<CultureDto> GetCultures() => _cultures; + private async Task LoadCultures() + { + List<CultureDto> list = new List<CultureDto>(); + + const string ResourcePath = "Emby.Server.Implementations.Localization.iso6392.txt"; + + using (var stream = _assembly.GetManifestResourceStream(ResourcePath)) + using (var reader = new StreamReader(stream)) + { + await foreach (var line in reader.ReadAllLinesAsync().ConfigureAwait(false)) + { + if (string.IsNullOrWhiteSpace(line)) + { + continue; + } + + var parts = line.Split('|'); + + if (parts.Length == 5) + { + string name = parts[3]; + if (string.IsNullOrWhiteSpace(name)) + { + continue; + } + + string twoCharName = parts[2]; + if (string.IsNullOrWhiteSpace(twoCharName)) + { + continue; + } + + string[] threeletterNames; + if (string.IsNullOrWhiteSpace(parts[1])) + { + threeletterNames = new[] { parts[0] }; + } + else + { + threeletterNames = new[] { parts[0], parts[1] }; + } + + list.Add(new CultureDto + { + DisplayName = name, + Name = name, + ThreeLetterISOLanguageNames = threeletterNames, + TwoLetterISOLanguageName = twoCharName + }); + } + } + } + + _cultures = list; + } + /// <inheritdoc /> public CultureDto FindLanguageInfo(string language) => GetCultures() @@ -79,6 +186,34 @@ namespace Emby.Server.Implementations.Localization public IEnumerable<ParentalRating> GetParentalRatings() => GetParentalRatingsDictionary().Values; + /// <summary> + /// Gets the parental ratings dictionary. + /// </summary> + /// <returns><see cref="Dictionary{String, ParentalRating}" />.</returns> + private Dictionary<string, ParentalRating> GetParentalRatingsDictionary() + { + var countryCode = _configurationManager.Configuration.MetadataCountryCode; + + if (string.IsNullOrEmpty(countryCode)) + { + countryCode = "us"; + } + + return GetRatings(countryCode) ?? GetRatings("us"); + } + + /// <summary> + /// Gets the ratings. + /// </summary> + /// <param name="countryCode">The country code.</param> + /// <returns>The ratings.</returns> + private Dictionary<string, ParentalRating> GetRatings(string countryCode) + { + _allParentalRatings.TryGetValue(countryCode, out var value); + + return value; + } + /// <inheritdoc /> public int? GetRatingLevel(string rating) { @@ -115,7 +250,7 @@ namespace Emby.Server.Implementations.Localization var index = rating.IndexOf(':', StringComparison.Ordinal); if (index != -1) { - rating = rating.Substring(index + 1).Trim(); + rating = rating.Substring(index).TrimStart(':').Trim(); if (!string.IsNullOrWhiteSpace(rating)) { @@ -128,6 +263,20 @@ namespace Emby.Server.Implementations.Localization } /// <inheritdoc /> + public bool HasUnicodeCategory(string value, UnicodeCategory category) + { + foreach (var chr in value) + { + if (char.GetUnicodeCategory(chr) == category) + { + return true; + } + } + + return false; + } + + /// <inheritdoc /> public string GetLocalizedString(string phrase) { return GetLocalizedString(phrase, _configurationManager.Configuration.UICulture); @@ -156,179 +305,6 @@ namespace Emby.Server.Implementations.Localization return phrase; } - /// <inheritdoc /> - public IEnumerable<LocalizationOption> GetLocalizationOptions() - { - yield return new LocalizationOption("Arabic", "ar"); - yield return new LocalizationOption("Bulgarian (Bulgaria)", "bg-BG"); - yield return new LocalizationOption("Catalan", "ca"); - yield return new LocalizationOption("Chinese Simplified", "zh-CN"); - yield return new LocalizationOption("Chinese Traditional", "zh-TW"); - yield return new LocalizationOption("Croatian", "hr"); - yield return new LocalizationOption("Czech", "cs"); - yield return new LocalizationOption("Danish", "da"); - yield return new LocalizationOption("Dutch", "nl"); - yield return new LocalizationOption("English (United Kingdom)", "en-GB"); - yield return new LocalizationOption("English (United States)", "en-US"); - yield return new LocalizationOption("French", "fr"); - yield return new LocalizationOption("French (Canada)", "fr-CA"); - yield return new LocalizationOption("German", "de"); - yield return new LocalizationOption("Greek", "el"); - yield return new LocalizationOption("Hebrew", "he"); - yield return new LocalizationOption("Hungarian", "hu"); - yield return new LocalizationOption("Italian", "it"); - yield return new LocalizationOption("Kazakh", "kk"); - yield return new LocalizationOption("Korean", "ko"); - yield return new LocalizationOption("Lithuanian", "lt-LT"); - yield return new LocalizationOption("Malay", "ms"); - yield return new LocalizationOption("Norwegian Bokmål", "nb"); - yield return new LocalizationOption("Persian", "fa"); - yield return new LocalizationOption("Polish", "pl"); - yield return new LocalizationOption("Portuguese (Brazil)", "pt-BR"); - yield return new LocalizationOption("Portuguese (Portugal)", "pt-PT"); - yield return new LocalizationOption("Russian", "ru"); - yield return new LocalizationOption("Slovak", "sk"); - yield return new LocalizationOption("Slovenian (Slovenia)", "sl-SI"); - yield return new LocalizationOption("Spanish", "es"); - yield return new LocalizationOption("Spanish (Argentina)", "es-AR"); - yield return new LocalizationOption("Spanish (Mexico)", "es-MX"); - yield return new LocalizationOption("Swedish", "sv"); - yield return new LocalizationOption("Swiss German", "gsw"); - yield return new LocalizationOption("Turkish", "tr"); - yield return new LocalizationOption("Tiếng Việt", "vi"); - } - - /// <summary> - /// Loads all resources into memory. - /// </summary> - /// <returns><see cref="Task" />.</returns> - public async Task LoadAll() - { - const string RatingsResource = "Emby.Server.Implementations.Localization.Ratings."; - - // Extract from the assembly - foreach (var resource in _assembly.GetManifestResourceNames()) - { - if (!resource.StartsWith(RatingsResource, StringComparison.Ordinal)) - { - continue; - } - - string countryCode = resource.Substring(RatingsResource.Length, 2); - var dict = new Dictionary<string, ParentalRating>(StringComparer.OrdinalIgnoreCase); - - await using var str = _assembly.GetManifestResourceStream(resource); - using var reader = new StreamReader(str); - await foreach (var line in reader.ReadAllLinesAsync().ConfigureAwait(false)) - { - if (string.IsNullOrWhiteSpace(line)) - { - continue; - } - - string[] parts = line.Split(','); - if (parts.Length == 2 - && int.TryParse(parts[1], NumberStyles.Integer, CultureInfo.InvariantCulture, out var value)) - { - var name = parts[0]; - dict.Add(name, new ParentalRating(name, value)); - } -#if DEBUG - else - { - _logger.LogWarning("Malformed line in ratings file for country {CountryCode}", countryCode); - } -#endif - } - - _allParentalRatings[countryCode] = dict; - } - - await LoadCultures().ConfigureAwait(false); - } - - private async Task LoadCultures() - { - List<CultureDto> list = new List<CultureDto>(); - - const string ResourcePath = "Emby.Server.Implementations.Localization.iso6392.txt"; - - await using var stream = _assembly.GetManifestResourceStream(ResourcePath); - using var reader = new StreamReader(stream); - await foreach (var line in reader.ReadAllLinesAsync().ConfigureAwait(false)) - { - if (string.IsNullOrWhiteSpace(line)) - { - continue; - } - - var parts = line.Split('|'); - - if (parts.Length == 5) - { - string name = parts[3]; - if (string.IsNullOrWhiteSpace(name)) - { - continue; - } - - string twoCharName = parts[2]; - if (string.IsNullOrWhiteSpace(twoCharName)) - { - continue; - } - - string[] threeletterNames; - if (string.IsNullOrWhiteSpace(parts[1])) - { - threeletterNames = new[] { parts[0] }; - } - else - { - threeletterNames = new[] { parts[0], parts[1] }; - } - - list.Add(new CultureDto - { - DisplayName = name, - Name = name, - ThreeLetterISOLanguageNames = threeletterNames, - TwoLetterISOLanguageName = twoCharName - }); - } - } - - _cultures = list; - } - - /// <summary> - /// Gets the parental ratings dictionary. - /// </summary> - /// <returns><see cref="Dictionary{String, ParentalRating}" />.</returns> - private Dictionary<string, ParentalRating> GetParentalRatingsDictionary() - { - var countryCode = _configurationManager.Configuration.MetadataCountryCode; - - if (string.IsNullOrEmpty(countryCode)) - { - countryCode = "us"; - } - - return GetRatings(countryCode) ?? GetRatings("us"); - } - - /// <summary> - /// Gets the ratings. - /// </summary> - /// <param name="countryCode">The country code.</param> - /// <returns>The ratings.</returns> - private Dictionary<string, ParentalRating> GetRatings(string countryCode) - { - _allParentalRatings.TryGetValue(countryCode, out var value); - - return value; - } - private Dictionary<string, string> GetLocalizationDictionary(string culture) { if (string.IsNullOrEmpty(culture)) @@ -340,7 +316,7 @@ namespace Emby.Server.Implementations.Localization return _dictionaries.GetOrAdd( culture, - _ => GetDictionary(Prefix, culture, DefaultCulture + ".json").GetAwaiter().GetResult()); + f => GetDictionary(Prefix, culture, DefaultCulture + ".json").GetAwaiter().GetResult()); } private async Task<Dictionary<string, string>> GetDictionary(string prefix, string culture, string baseFilename) @@ -362,21 +338,23 @@ namespace Emby.Server.Implementations.Localization private async Task CopyInto(IDictionary<string, string> dictionary, string resourcePath) { - await using var stream = _assembly.GetManifestResourceStream(resourcePath); - // If a Culture doesn't have a translation the stream will be null and it defaults to en-us further up the chain - if (stream != null) + using (var stream = _assembly.GetManifestResourceStream(resourcePath)) { - var dict = await JsonSerializer.DeserializeAsync<Dictionary<string, string>>(stream, _jsonOptions).ConfigureAwait(false); + // If a Culture doesn't have a translation the stream will be null and it defaults to en-us further up the chain + if (stream != null) + { + var dict = await JsonSerializer.DeserializeAsync<Dictionary<string, string>>(stream, _jsonOptions).ConfigureAwait(false); - foreach (var key in dict.Keys) + foreach (var key in dict.Keys) + { + dictionary[key] = dict[key]; + } + } + else { - dictionary[key] = dict[key]; + _logger.LogError("Missing translation/culture resource: {ResourcePath}", resourcePath); } } - else - { - _logger.LogError("Missing translation/culture resource: {ResourcePath}", resourcePath); - } } private static string GetResourceFilename(string culture) @@ -394,5 +372,47 @@ namespace Emby.Server.Implementations.Localization return culture + ".json"; } + + /// <inheritdoc /> + public IEnumerable<LocalizationOption> GetLocalizationOptions() + { + yield return new LocalizationOption("Arabic", "ar"); + yield return new LocalizationOption("Bulgarian (Bulgaria)", "bg-BG"); + yield return new LocalizationOption("Catalan", "ca"); + yield return new LocalizationOption("Chinese Simplified", "zh-CN"); + yield return new LocalizationOption("Chinese Traditional", "zh-TW"); + yield return new LocalizationOption("Croatian", "hr"); + yield return new LocalizationOption("Czech", "cs"); + yield return new LocalizationOption("Danish", "da"); + yield return new LocalizationOption("Dutch", "nl"); + yield return new LocalizationOption("English (United Kingdom)", "en-GB"); + yield return new LocalizationOption("English (United States)", "en-US"); + yield return new LocalizationOption("French", "fr"); + yield return new LocalizationOption("French (Canada)", "fr-CA"); + yield return new LocalizationOption("German", "de"); + yield return new LocalizationOption("Greek", "el"); + yield return new LocalizationOption("Hebrew", "he"); + yield return new LocalizationOption("Hungarian", "hu"); + yield return new LocalizationOption("Italian", "it"); + yield return new LocalizationOption("Kazakh", "kk"); + yield return new LocalizationOption("Korean", "ko"); + yield return new LocalizationOption("Lithuanian", "lt-LT"); + yield return new LocalizationOption("Malay", "ms"); + yield return new LocalizationOption("Norwegian Bokmål", "nb"); + yield return new LocalizationOption("Persian", "fa"); + yield return new LocalizationOption("Polish", "pl"); + yield return new LocalizationOption("Portuguese (Brazil)", "pt-BR"); + yield return new LocalizationOption("Portuguese (Portugal)", "pt-PT"); + yield return new LocalizationOption("Russian", "ru"); + yield return new LocalizationOption("Slovak", "sk"); + yield return new LocalizationOption("Slovenian (Slovenia)", "sl-SI"); + yield return new LocalizationOption("Spanish", "es"); + yield return new LocalizationOption("Spanish (Argentina)", "es-AR"); + yield return new LocalizationOption("Spanish (Mexico)", "es-MX"); + yield return new LocalizationOption("Swedish", "sv"); + yield return new LocalizationOption("Swiss German", "gsw"); + yield return new LocalizationOption("Turkish", "tr"); + yield return new LocalizationOption("Tiếng Việt", "vi"); + } } } |
