From f5ea5df8f3eef8e84d5495e372ec90dfaaa57873 Mon Sep 17 00:00:00 2001 From: Nikolaj Geisle <70372949+Zeegaan@users.noreply.github.com> Date: Wed, 10 Nov 2021 11:48:09 +0100 Subject: [PATCH] v9: Don't load all translation files (#11576) * Update systemInformation.ts * Added lazy loading * Update systemInformation.ts * Update systemInformation.ts * Use CharArrays.ForwardSlash instead of hardcoded string * Align braces Co-authored-by: Nikolaj Geisle Co-authored-by: Elitsa Marinovska --- .../Implement/LocalizedTextService.cs | 175 +++++++++++++----- .../Services/LocalizedTextServiceTests.cs | 44 ++--- 2 files changed, 148 insertions(+), 71 deletions(-) diff --git a/src/Umbraco.Infrastructure/Services/Implement/LocalizedTextService.cs b/src/Umbraco.Infrastructure/Services/Implement/LocalizedTextService.cs index 68fa4c37a5..24c37fbf76 100644 --- a/src/Umbraco.Infrastructure/Services/Implement/LocalizedTextService.cs +++ b/src/Umbraco.Infrastructure/Services/Implement/LocalizedTextService.cs @@ -8,63 +8,85 @@ using Microsoft.Extensions.Logging; namespace Umbraco.Cms.Core.Services.Implement { + /// public class LocalizedTextService : ILocalizedTextService { private readonly ILogger _logger; private readonly Lazy _fileSources; - private IDictionary>> _dictionarySource => _dictionarySourceLazy.Value; - private IDictionary> _noAreaDictionarySource => _noAreaDictionarySourceLazy.Value; - private readonly Lazy>>> _dictionarySourceLazy; - private readonly Lazy>> _noAreaDictionarySourceLazy; - private readonly char[] _splitter = new[] { '/' }; + + private IDictionary>>> _dictionarySource => + _dictionarySourceLazy.Value; + + private IDictionary>> _noAreaDictionarySource => + _noAreaDictionarySourceLazy.Value; + + private readonly Lazy>>>> + _dictionarySourceLazy; + + private readonly Lazy>>> _noAreaDictionarySourceLazy; + /// /// Initializes with a file sources instance /// /// /// - public LocalizedTextService(Lazy fileSources, ILogger logger) + public LocalizedTextService(Lazy fileSources, + ILogger logger) { if (logger == null) throw new ArgumentNullException(nameof(logger)); _logger = logger; if (fileSources == null) throw new ArgumentNullException(nameof(fileSources)); - _dictionarySourceLazy = new Lazy>>>(() => FileSourcesToAreaDictionarySources(fileSources.Value)); - _noAreaDictionarySourceLazy = new Lazy>>(() => FileSourcesToNoAreaDictionarySources(fileSources.Value)); + _dictionarySourceLazy = + new Lazy>>>>(() => + FileSourcesToAreaDictionarySources(fileSources.Value)); + _noAreaDictionarySourceLazy = + new Lazy>>>(() => + FileSourcesToNoAreaDictionarySources(fileSources.Value)); _fileSources = fileSources; } - private IDictionary> FileSourcesToNoAreaDictionarySources(LocalizedTextServiceFileSources fileSources) + private IDictionary>> FileSourcesToNoAreaDictionarySources( + LocalizedTextServiceFileSources fileSources) { var xmlSources = fileSources.GetXmlSources(); return XmlSourceToNoAreaDictionary(xmlSources); } - private IDictionary> XmlSourceToNoAreaDictionary(IDictionary> xmlSources) + private IDictionary>> XmlSourceToNoAreaDictionary( + IDictionary> xmlSources) { - var cultureNoAreaDictionary = new Dictionary>(); + var cultureNoAreaDictionary = new Dictionary>>(); foreach (var xmlSource in xmlSources) { - var noAreaAliasValue = GetNoAreaStoredTranslations(xmlSources, xmlSource.Key); + var noAreaAliasValue = + new Lazy>(() => GetNoAreaStoredTranslations(xmlSources, xmlSource.Key)); cultureNoAreaDictionary.Add(xmlSource.Key, noAreaAliasValue); } + return cultureNoAreaDictionary; } - private IDictionary>> FileSourcesToAreaDictionarySources(LocalizedTextServiceFileSources fileSources) + private IDictionary>>> + FileSourcesToAreaDictionarySources(LocalizedTextServiceFileSources fileSources) { var xmlSources = fileSources.GetXmlSources(); return XmlSourcesToAreaDictionary(xmlSources); } - private IDictionary>> XmlSourcesToAreaDictionary(IDictionary> xmlSources) + private IDictionary>>> + XmlSourcesToAreaDictionary(IDictionary> xmlSources) { - var cultureDictionary = new Dictionary>>(); + var cultureDictionary = + new Dictionary>>>(); foreach (var xmlSource in xmlSources) { - var areaAliaValue = GetAreaStoredTranslations(xmlSources, xmlSource.Key); + var areaAliaValue = + new Lazy>>(() => + GetAreaStoredTranslations(xmlSources, xmlSource.Key)); cultureDictionary.Add(xmlSource.Key, areaAliaValue); - } + return cultureDictionary; } @@ -73,14 +95,18 @@ namespace Umbraco.Cms.Core.Services.Implement /// /// /// - public LocalizedTextService(IDictionary> source, ILogger logger) + public LocalizedTextService(IDictionary> source, + ILogger logger) { if (source == null) throw new ArgumentNullException(nameof(source)); _logger = logger ?? throw new ArgumentNullException(nameof(logger)); - _dictionarySourceLazy = new Lazy>>>(() => XmlSourcesToAreaDictionary(source)); - _noAreaDictionarySourceLazy = new Lazy>>(() => XmlSourceToNoAreaDictionary(source)); - + _dictionarySourceLazy = + new Lazy>>>>(() => + XmlSourcesToAreaDictionary(source)); + _noAreaDictionarySourceLazy = + new Lazy>>>(() => + XmlSourceToNoAreaDictionary(source)); } @@ -89,29 +115,44 @@ namespace Umbraco.Cms.Core.Services.Implement /// /// /// - public LocalizedTextService(IDictionary>> source, ILogger logger) + public LocalizedTextService( + IDictionary>>> source, + ILogger logger) { var dictionarySource = source ?? throw new ArgumentNullException(nameof(source)); - _dictionarySourceLazy = new Lazy>>>(() => dictionarySource); + _dictionarySourceLazy = + new Lazy>>>>(() => + dictionarySource); _logger = logger ?? throw new ArgumentNullException(nameof(logger)); - var cultureNoAreaDictionary = new Dictionary>(); + var cultureNoAreaDictionary = new Dictionary>>(); foreach (var cultureDictionary in dictionarySource) { var areaAliaValue = GetAreaStoredTranslations(source, cultureDictionary.Key); - var aliasValue = new Dictionary(); - foreach (var area in areaAliaValue) + + cultureNoAreaDictionary.Add(cultureDictionary.Key, + new Lazy>(() => GetAliasValues(areaAliaValue))); + } + + _noAreaDictionarySourceLazy = + new Lazy>>>(() => cultureNoAreaDictionary); + } + + private static Dictionary GetAliasValues( + Dictionary> areaAliaValue) + { + var aliasValue = new Dictionary(); + foreach (var area in areaAliaValue) + { + foreach (var alias in area.Value) { - foreach (var alias in area.Value) + if (!aliasValue.ContainsKey(alias.Key)) { - if (!aliasValue.ContainsKey(alias.Key)) - { - aliasValue.Add(alias.Key, alias.Value); - } + aliasValue.Add(alias.Key, alias.Value); } } - cultureNoAreaDictionary.Add(cultureDictionary.Key, aliasValue); } - _noAreaDictionarySourceLazy = new Lazy>>(() => cultureNoAreaDictionary); + + return aliasValue; } public string Localize(string key, CultureInfo culture, IDictionary tokens = null) @@ -122,12 +163,14 @@ namespace Umbraco.Cms.Core.Services.Implement if (string.IsNullOrEmpty(key)) return string.Empty; - var keyParts = key.Split(_splitter, StringSplitOptions.RemoveEmptyEntries); + var keyParts = key.Split(Constants.CharArrays.ForwardSlash, StringSplitOptions.RemoveEmptyEntries); var area = keyParts.Length > 1 ? keyParts[0] : null; var alias = keyParts.Length > 1 ? keyParts[1] : keyParts[0]; return Localize(area, alias, culture, tokens); } - public string Localize(string area, string alias, CultureInfo culture, IDictionary tokens = null) + + public string Localize(string area, string alias, CultureInfo culture, + IDictionary tokens = null) { if (culture == null) throw new ArgumentNullException(nameof(culture)); @@ -153,12 +196,15 @@ namespace Umbraco.Cms.Core.Services.Implement if (_dictionarySource.ContainsKey(culture) == false) { - _logger.LogWarning("The culture specified {Culture} was not found in any configured sources for this service", culture); + _logger.LogWarning( + "The culture specified {Culture} was not found in any configured sources for this service", + culture); return new Dictionary(0); } + IDictionary result = new Dictionary(); //convert all areas + keys to a single key with a '/' - foreach (var area in _dictionarySource[culture]) + foreach (var area in _dictionarySource[culture].Value) { foreach (var key in area.Value) { @@ -170,10 +216,12 @@ namespace Umbraco.Cms.Core.Services.Implement } } } + return result; } - private Dictionary> GetAreaStoredTranslations(IDictionary> xmlSource, CultureInfo cult) + private IDictionary> GetAreaStoredTranslations( + IDictionary> xmlSource, CultureInfo cult) { var overallResult = new Dictionary>(StringComparer.InvariantCulture); var areas = xmlSource[cult].Value.XPathSelectElements("//area"); @@ -189,6 +237,7 @@ namespace Umbraco.Cms.Core.Services.Implement if (result.ContainsKey(dictionaryKey) == false) result.Add(dictionaryKey, key.Value); } + overallResult.Add(area.Attribute("alias").Value, result); } @@ -199,11 +248,13 @@ namespace Umbraco.Cms.Core.Services.Implement var enUS = xmlSource[englishCulture].Value.XPathSelectElements("//area"); foreach (var area in enUS) { - IDictionary result = new Dictionary(StringComparer.InvariantCulture); + IDictionary + result = new Dictionary(StringComparer.InvariantCulture); if (overallResult.ContainsKey(area.Attribute("alias").Value)) { result = overallResult[area.Attribute("alias").Value]; } + var keys = area.XPathSelectElements("./key"); foreach (var key in keys) { @@ -213,15 +264,19 @@ namespace Umbraco.Cms.Core.Services.Implement if (result.ContainsKey(dictionaryKey) == false) result.Add(dictionaryKey, key.Value); } + if (!overallResult.ContainsKey(area.Attribute("alias").Value)) { overallResult.Add(area.Attribute("alias").Value, result); } } } + return overallResult; } - private Dictionary GetNoAreaStoredTranslations(IDictionary> xmlSource, CultureInfo cult) + + private Dictionary GetNoAreaStoredTranslations( + IDictionary> xmlSource, CultureInfo cult) { var result = new Dictionary(StringComparer.InvariantCulture); var keys = xmlSource[cult].Value.XPathSelectElements("//key"); @@ -250,14 +305,18 @@ namespace Umbraco.Cms.Core.Services.Implement result.Add(dictionaryKey, key.Value); } } + return result; } - private Dictionary> GetAreaStoredTranslations(IDictionary>> dictionarySource, CultureInfo cult) + + private Dictionary> GetAreaStoredTranslations( + IDictionary>>> dictionarySource, + CultureInfo cult) { var overallResult = new Dictionary>(StringComparer.InvariantCulture); var areaDict = dictionarySource[cult]; - foreach (var area in areaDict) + foreach (var area in areaDict.Value) { var result = new Dictionary(StringComparer.InvariantCulture); var keys = area.Value.Keys; @@ -267,8 +326,10 @@ namespace Umbraco.Cms.Core.Services.Implement if (result.ContainsKey(key) == false) result.Add(key, area.Value[key]); } + overallResult.Add(area.Key, result); } + return overallResult; } @@ -306,11 +367,14 @@ namespace Umbraco.Cms.Core.Services.Implement return attempt ? attempt.Result : currentCulture; } - private string GetFromDictionarySource(CultureInfo culture, string area, string key, IDictionary tokens) + private string GetFromDictionarySource(CultureInfo culture, string area, string key, + IDictionary tokens) { if (_dictionarySource.ContainsKey(culture) == false) { - _logger.LogWarning("The culture specified {Culture} was not found in any configured sources for this service", culture); + _logger.LogWarning( + "The culture specified {Culture} was not found in any configured sources for this service", + culture); return "[" + key + "]"; } @@ -318,17 +382,18 @@ namespace Umbraco.Cms.Core.Services.Implement string found = null; if (string.IsNullOrWhiteSpace(area)) { - _noAreaDictionarySource[culture].TryGetValue(key, out found); + _noAreaDictionarySource[culture].Value.TryGetValue(key, out found); } else { - if (_dictionarySource[culture].TryGetValue(area, out var areaDictionary)) + if (_dictionarySource[culture].Value.TryGetValue(area, out var areaDictionary)) { areaDictionary.TryGetValue(key, out found); } + if (found == null) { - _noAreaDictionarySource[culture].TryGetValue(key, out found); + _noAreaDictionarySource[culture].Value.TryGetValue(key, out found); } } @@ -341,6 +406,7 @@ namespace Umbraco.Cms.Core.Services.Implement //NOTE: Based on how legacy works, the default text does not contain the area, just the key return "[" + key + "]"; } + /// /// Parses the tokens in the value /// @@ -370,20 +436,29 @@ namespace Umbraco.Cms.Core.Services.Implement return value; } + /// + /// Returns all key/values in storage for the given culture + /// + /// public IDictionary> GetAllStoredValuesByAreaAndAlias(CultureInfo culture) { - if (culture == null) throw new ArgumentNullException("culture"); + if (culture == null) + { + throw new ArgumentNullException("culture"); + } // TODO: Hack, see notes on ConvertToSupportedCultureWithRegionCode culture = ConvertToSupportedCultureWithRegionCode(culture); if (_dictionarySource.ContainsKey(culture) == false) { - _logger.LogWarning("The culture specified {Culture} was not found in any configured sources for this service", culture); + _logger.LogWarning( + "The culture specified {Culture} was not found in any configured sources for this service", + culture); return new Dictionary>(0); } - return _dictionarySource[culture]; + return _dictionarySource[culture].Value; } } } diff --git a/tests/Umbraco.Tests.UnitTests/Umbraco.Infrastructure/Services/LocalizedTextServiceTests.cs b/tests/Umbraco.Tests.UnitTests/Umbraco.Infrastructure/Services/LocalizedTextServiceTests.cs index ea4c043aa2..497af66d63 100644 --- a/tests/Umbraco.Tests.UnitTests/Umbraco.Infrastructure/Services/LocalizedTextServiceTests.cs +++ b/tests/Umbraco.Tests.UnitTests/Umbraco.Infrastructure/Services/LocalizedTextServiceTests.cs @@ -23,10 +23,10 @@ namespace Umbraco.Cms.Tests.UnitTests.Umbraco.Infrastructure.Services { var culture = CultureInfo.GetCultureInfo("en-US"); var txtService = new LocalizedTextService( - new Dictionary>> + new Dictionary>>> { { - culture, new Dictionary> + culture, new Lazy>>(() => new Dictionary> { { "testArea1", new Dictionary @@ -42,7 +42,7 @@ namespace Umbraco.Cms.Tests.UnitTests.Umbraco.Infrastructure.Services { "blah2", "blahValue2" } } }, - } + }) } }, s_loggerFactory.CreateLogger()); @@ -119,10 +119,10 @@ namespace Umbraco.Cms.Tests.UnitTests.Umbraco.Infrastructure.Services { var culture = CultureInfo.GetCultureInfo("en-US"); var txtService = new LocalizedTextService( - new Dictionary>> + new Dictionary>>> { { - culture, new Dictionary> + culture, new Lazy>>(() => new Dictionary> { { "testArea", new Dictionary @@ -130,7 +130,7 @@ namespace Umbraco.Cms.Tests.UnitTests.Umbraco.Infrastructure.Services { "testKey", "testValue" } } } - } + }) } }, s_loggerFactory.CreateLogger()); @@ -144,10 +144,10 @@ namespace Umbraco.Cms.Tests.UnitTests.Umbraco.Infrastructure.Services { var culture = CultureInfo.GetCultureInfo("en-US"); var txtService = new LocalizedTextService( - new Dictionary>> + new Dictionary>>> { { - culture, new Dictionary> + culture, new Lazy>>(() => new Dictionary> { { "testArea", new Dictionary @@ -155,7 +155,8 @@ namespace Umbraco.Cms.Tests.UnitTests.Umbraco.Infrastructure.Services { "testKey", "testValue" } } } - } + }) + } }, s_loggerFactory.CreateLogger()); @@ -169,10 +170,10 @@ namespace Umbraco.Cms.Tests.UnitTests.Umbraco.Infrastructure.Services { var culture = CultureInfo.GetCultureInfo("en-US"); var txtService = new LocalizedTextService( - new Dictionary>> + new Dictionary>>> { { - culture, new Dictionary> + culture, new Lazy>>(() => new Dictionary> { { "testArea", new Dictionary @@ -180,7 +181,7 @@ namespace Umbraco.Cms.Tests.UnitTests.Umbraco.Infrastructure.Services { "testKey", "testValue" } } } - } + }) } }, s_loggerFactory.CreateLogger()); @@ -195,10 +196,10 @@ namespace Umbraco.Cms.Tests.UnitTests.Umbraco.Infrastructure.Services { var culture = CultureInfo.GetCultureInfo("en-US"); var txtService = new LocalizedTextService( - new Dictionary>> + new Dictionary>>> { { - culture, new Dictionary> + culture, new Lazy>>(() => new Dictionary> { { "testArea", new Dictionary @@ -206,7 +207,7 @@ namespace Umbraco.Cms.Tests.UnitTests.Umbraco.Infrastructure.Services { "testKey", "testValue" } } } - } + }) } }, s_loggerFactory.CreateLogger()); @@ -220,10 +221,10 @@ namespace Umbraco.Cms.Tests.UnitTests.Umbraco.Infrastructure.Services { var culture = CultureInfo.GetCultureInfo("en-US"); var txtService = new LocalizedTextService( - new Dictionary>> + new Dictionary>>> { { - culture, new Dictionary> + culture, new Lazy>>(() => new Dictionary> { { "testArea", new Dictionary @@ -231,7 +232,8 @@ namespace Umbraco.Cms.Tests.UnitTests.Umbraco.Infrastructure.Services { "testKey", "Hello %0%, you are such a %1% %2%" } } } - } + }) + } }, s_loggerFactory.CreateLogger()); @@ -350,10 +352,10 @@ namespace Umbraco.Cms.Tests.UnitTests.Umbraco.Infrastructure.Services { var culture = CultureInfo.GetCultureInfo("en-US"); var txtService = new LocalizedTextService( - new Dictionary>> + new Dictionary>>> { { - culture, new Dictionary> + culture, new Lazy>>(() => new Dictionary> { { "testArea", new Dictionary @@ -361,7 +363,7 @@ namespace Umbraco.Cms.Tests.UnitTests.Umbraco.Infrastructure.Services { "testKey", "testValue" } } } - } + }) } }, s_loggerFactory.CreateLogger());