Skip to content

Commit

Permalink
Added support for nesting formats in LocalizationFormatter
Browse files Browse the repository at this point in the history
  • Loading branch information
Sitko, Michał committed Aug 29, 2023
1 parent 2bb777c commit 350f4cd
Show file tree
Hide file tree
Showing 6 changed files with 69 additions and 18 deletions.
42 changes: 30 additions & 12 deletions src/SmartFormat.Tests/Extensions/LocalizationFormatterTests.cs
Original file line number Diff line number Diff line change
@@ -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;
Expand All @@ -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());

Expand Down Expand Up @@ -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<LocalizationFormatter>()!.LocalizationProvider!)
((LocalizationProvider) smart.GetFormatterExtension<LocalizationFormatter>()!.LocalizationProvider!)
.ReturnNameIfNotFound = true;
var actual = smart.Format("{:L(es):NonExisting}");
Assert.That(actual, Is.EqualTo("NonExisting"));
Expand Down Expand Up @@ -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));
}

Expand All @@ -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")]
Expand All @@ -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));
}
}

[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));
}
}
6 changes: 6 additions & 0 deletions src/SmartFormat.Tests/Localization/LocTest1.de.resx
Original file line number Diff line number Diff line change
Expand Up @@ -132,4 +132,10 @@
<data name="{} items" xml:space="preserve">
<value>{} Elemente</value>
</data>
<data name="paper" xml:space="preserve">
<value>das Papier</value>
</data>
<data name="pen" xml:space="preserve">
<value>der Kugelschreiber</value>
</data>
</root>
6 changes: 6 additions & 0 deletions src/SmartFormat.Tests/Localization/LocTest1.es.resx
Original file line number Diff line number Diff line change
Expand Up @@ -132,4 +132,10 @@
<data name="{} items" xml:space="preserve">
<value>{} elementos</value>
</data>
<data name="paper" xml:space="preserve">
<value>Papel</value>
</data>
<data name="pen" xml:space="preserve">
<value>Bolígrafo</value>
</data>
</root>
6 changes: 6 additions & 0 deletions src/SmartFormat.Tests/Localization/LocTest1.fr.resx
Original file line number Diff line number Diff line change
Expand Up @@ -132,4 +132,10 @@
<data name="{} items" xml:space="preserve">
<value>{} éléments</value>
</data>
<data name="paper" xml:space="preserve">
<value>Papier</value>
</data>
<data name="pen" xml:space="preserve">
<value>Bic</value>
</data>
</root>
6 changes: 6 additions & 0 deletions src/SmartFormat.Tests/Localization/LocTest1.resx
Original file line number Diff line number Diff line change
Expand Up @@ -136,4 +136,10 @@
<data name="{} items" xml:space="preserve">
<value>{} items</value>
</data>
<data name="paper" xml:space="preserve">
<value>Paper</value>
</data>
<data name="pen" xml:space="preserve">
<value>Pen</value>
</data>
</root>
21 changes: 15 additions & 6 deletions src/SmartFormat/Extensions/LocalizationFormatter.cs
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
//
//
// Copyright SmartFormat Project maintainers and contributors.
// Licensed under the MIT license.
//

using System;
using System.Collections.Generic;
Expand All @@ -17,7 +18,7 @@ namespace SmartFormat.Extensions;
public class LocalizationFormatter : IFormatter, IInitializer
{
private SmartFormatter? _formatter;

/// <summary>
/// Storage for localized versions of <see cref="Format"/>s
/// to avoid repetitive parsing.
Expand All @@ -27,7 +28,7 @@ public class LocalizationFormatter : IFormatter, IInitializer
/// Obsolete. <see cref="IFormatter"/>s only have one unique name.
/// </summary>
[Obsolete("Use property \"Name\" instead", true)]
public string[] Names { get; set; } = {"localize", "L"};
public string[] Names { get; set; } = { "localize", "L" };

///<inheritdoc/>
public string Name { get; set; } = "L";
Expand Down Expand Up @@ -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,
Expand All @@ -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))
{
Expand Down Expand Up @@ -124,4 +133,4 @@ private static CultureInfo GetCultureInfo(IFormattingInfo formattingInfo)

return cultureInfo;
}
}
}

0 comments on commit 350f4cd

Please sign in to comment.