From 350f4cd7a5bd6c971477eea19bd72eecdb74cc0b Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Sitko=2C=20Micha=C5=82?= Date: Tue, 29 Aug 2023 16:32:43 +0200 Subject: [PATCH] Added support for nesting formats in LocalizationFormatter --- .../Extensions/LocalizationFormatterTests.cs | 42 +++++++++++++------ .../Localization/LocTest1.de.resx | 6 +++ .../Localization/LocTest1.es.resx | 6 +++ .../Localization/LocTest1.fr.resx | 6 +++ .../Localization/LocTest1.resx | 6 +++ .../Extensions/LocalizationFormatter.cs | 21 +++++++--- 6 files changed, 69 insertions(+), 18 deletions(-) diff --git a/src/SmartFormat.Tests/Extensions/LocalizationFormatterTests.cs b/src/SmartFormat.Tests/Extensions/LocalizationFormatterTests.cs index f623f481..71f38d40 100644 --- a/src/SmartFormat.Tests/Extensions/LocalizationFormatterTests.cs +++ b/src/SmartFormat.Tests/Extensions/LocalizationFormatterTests.cs @@ -1,4 +1,9 @@ -using System; +// +// Copyright SmartFormat Project maintainers and contributors. +// Licensed under the MIT license. +// + +using System; using System.Globalization; using NUnit.Framework; using SmartFormat.Core.Formatting; @@ -14,17 +19,17 @@ public class LocalizationFormatterTests { private static SmartFormatter GetFormatterWithRegisteredResource(CaseSensitivityType caseSensitivity = CaseSensitivityType.CaseSensitive, FormatErrorAction formatErrorAction = FormatErrorAction.ThrowError) { - var localizationFormatter = new LocalizationFormatter {CanAutoDetect = false}; + var localizationFormatter = new LocalizationFormatter { CanAutoDetect = false }; var smart = Smart.CreateDefaultSmartFormat(new SmartSettings - { - CaseSensitivity = caseSensitivity, - Localization = + { + CaseSensitivity = caseSensitivity, + Localization = { LocalizationProvider = new LocalizationProvider(true, LocTest1.ResourceManager) { FallbackCulture = null, ReturnNameIfNotFound = false } }, - Formatter = { ErrorAction = formatErrorAction } - }) + Formatter = { ErrorAction = formatErrorAction } + }) .AddExtensions(localizationFormatter) .AddExtensions(new PluralLocalizationFormatter()); @@ -89,7 +94,7 @@ public void No_Localized_String_Found(FormatErrorAction errorAction) public void No_Localized_String_Found_With_Name_Fallback() { var smart = GetFormatterWithRegisteredResource(); - ((LocalizationProvider)smart.GetFormatterExtension()!.LocalizationProvider!) + ((LocalizationProvider) smart.GetFormatterExtension()!.LocalizationProvider!) .ReturnNameIfNotFound = true; var actual = smart.Format("{:L(es):NonExisting}"); Assert.That(actual, Is.EqualTo("NonExisting")); @@ -171,9 +176,9 @@ public void TextWithPlaceholder_CultureByFormatString(string format, string expe { var smart = GetFormatterWithRegisteredResource(CaseSensitivityType.CaseSensitive); // number should be localized - expected = string.Format(CultureInfo.GetCultureInfo(culture), expected, new {City = new { Name = "X-City", Inhabitants = 8900000}}, "X-City", 8900000); + expected = string.Format(CultureInfo.GetCultureInfo(culture), expected, new { City = new { Name = "X-City", Inhabitants = 8900000 } }, "X-City", 8900000); - var actual = smart.Format(format, "X-City", 8900000, new {City = new { Name = "X-City", Inhabitants = 8900000}}); + var actual = smart.Format(format, "X-City", 8900000, new { City = new { Name = "X-City", Inhabitants = 8900000 } }); Assert.That(actual, Is.EqualTo(expected)); } @@ -191,7 +196,7 @@ public void Combine_With_ConditionalFormatter(string format, int count, string c var actual = smart.Format(CultureInfo.GetCultureInfo(cultureName), format, count); Assert.That(actual, Is.EqualTo(expected)); } - + [TestCase("{0:plural:{:L:{} item}|{:L:{} items}}", 0, "en", "0 items")] [TestCase("{0:plural:{:L:{} item}|{:L:{} items}}", 1, "en", "1 item")] [TestCase("{0:plural:{:L:{} item}|{:L:{} items}}", 200, "de", "200 Elemente")] @@ -204,4 +209,17 @@ public void Combine_With_PluralLocalizationFormatter(string format, int count, s var actual = smart.Format(CultureInfo.GetCultureInfo(cultureName), format, count); Assert.That(actual, Is.EqualTo(expected)); } -} \ No newline at end of file + + [TestCase("{:L:{ProductType}}", "en", "paper", "Paper")] + [TestCase("{:L:{ProductType}}", "de", "paper", "das Papier")] + [TestCase("{:L:{ProductType}}", "fr", "paper", "Papier")] + [TestCase("{:L:{ProductType}}", "en", "pen", "Pen")] + [TestCase("{:L:{ProductType}}", "de", "pen", "der Kugelschreiber")] + [TestCase("{:L:{ProductType}}", "fr", "pen", "Bic")] + public void Combine_With_Nesting(string format, string cultureName, string productType, string expected) + { + var smart = GetFormatterWithRegisteredResource(); + var actual = smart.Format(CultureInfo.GetCultureInfo(cultureName), format, new { ProductType = productType }); + Assert.That(actual, Is.EqualTo(expected)); + } +} diff --git a/src/SmartFormat.Tests/Localization/LocTest1.de.resx b/src/SmartFormat.Tests/Localization/LocTest1.de.resx index 4e96db01..406f5111 100644 --- a/src/SmartFormat.Tests/Localization/LocTest1.de.resx +++ b/src/SmartFormat.Tests/Localization/LocTest1.de.resx @@ -132,4 +132,10 @@ {} Elemente + + das Papier + + + der Kugelschreiber + \ No newline at end of file diff --git a/src/SmartFormat.Tests/Localization/LocTest1.es.resx b/src/SmartFormat.Tests/Localization/LocTest1.es.resx index 291f4e82..2a11b578 100644 --- a/src/SmartFormat.Tests/Localization/LocTest1.es.resx +++ b/src/SmartFormat.Tests/Localization/LocTest1.es.resx @@ -132,4 +132,10 @@ {} elementos + + Papel + + + Bolígrafo + \ No newline at end of file diff --git a/src/SmartFormat.Tests/Localization/LocTest1.fr.resx b/src/SmartFormat.Tests/Localization/LocTest1.fr.resx index cabdf6a4..555217ef 100644 --- a/src/SmartFormat.Tests/Localization/LocTest1.fr.resx +++ b/src/SmartFormat.Tests/Localization/LocTest1.fr.resx @@ -132,4 +132,10 @@ {} éléments + + Papier + + + Bic + \ No newline at end of file diff --git a/src/SmartFormat.Tests/Localization/LocTest1.resx b/src/SmartFormat.Tests/Localization/LocTest1.resx index b5508d4d..12b24031 100644 --- a/src/SmartFormat.Tests/Localization/LocTest1.resx +++ b/src/SmartFormat.Tests/Localization/LocTest1.resx @@ -136,4 +136,10 @@ {} items + + Paper + + + Pen + \ No newline at end of file diff --git a/src/SmartFormat/Extensions/LocalizationFormatter.cs b/src/SmartFormat/Extensions/LocalizationFormatter.cs index f3b93916..37f5d05f 100644 --- a/src/SmartFormat/Extensions/LocalizationFormatter.cs +++ b/src/SmartFormat/Extensions/LocalizationFormatter.cs @@ -1,6 +1,7 @@ -// +// // Copyright SmartFormat Project maintainers and contributors. // Licensed under the MIT license. +// using System; using System.Collections.Generic; @@ -17,7 +18,7 @@ namespace SmartFormat.Extensions; public class LocalizationFormatter : IFormatter, IInitializer { private SmartFormatter? _formatter; - + /// /// Storage for localized versions of s /// to avoid repetitive parsing. @@ -27,7 +28,7 @@ public class LocalizationFormatter : IFormatter, IInitializer /// Obsolete. s only have one unique name. /// [Obsolete("Use property \"Name\" instead", true)] - public string[] Names { get; set; } = {"localize", "L"}; + public string[] Names { get; set; } = { "localize", "L" }; /// public string Name { get; set; } = "L"; @@ -55,7 +56,7 @@ public bool TryEvaluateFormat(IFormattingInfo formattingInfo) throw new LocalizationFormattingException(formattingInfo.Format, new ArgumentException($"'{nameof(formattingInfo.Format)}' for localization must not be null or empty.", nameof(formattingInfo)), 0); } - + if (LocalizationProvider is null) { throw new LocalizationFormattingException(formattingInfo.Format, @@ -68,8 +69,16 @@ public bool TryEvaluateFormat(IFormattingInfo formattingInfo) // Get the localized string var localized = LocalizationProvider!.GetString(formattingInfo.Format!.RawText, cultureInfo); + // Try formatting if localized string was not found, but a format has nested items + if (localized is null && formattingInfo.Format!.HasNested) + { + var formatted = _formatter!.Format(formattingInfo.Format!.RawText, formattingInfo.CurrentValue); + + localized = LocalizationProvider!.GetString(formatted, cultureInfo); + } + if (localized is null) throw new LocalizationFormattingException(formattingInfo.Format, $"No localized string found for '{formattingInfo.Format!.RawText}'", formattingInfo.Format.StartIndex); - + // Use an existing Format from the cache if (LocalizedFormatCache!.TryGetValue(localized, out var format)) { @@ -124,4 +133,4 @@ private static CultureInfo GetCultureInfo(IFormattingInfo formattingInfo) return cultureInfo; } -} \ No newline at end of file +}