From 3a5ab9f0cc410b9da87273dec1ff12a08cc652f0 Mon Sep 17 00:00:00 2001 From: axunonb Date: Thu, 17 Nov 2022 14:19:00 +0200 Subject: [PATCH] PluralLocalizationFormatter: Fix processing for Singular languages (#322) * Fix: Throws FormattingException for Singular languages * Add unit test for Singular language (Japanese) * Auto detection only works with more than 1 format argument. * Is recommended to set CanAutoDetect to false. This will be the default in a future version. Added xmdoc with this hint. * Fix: AppVeyor dotnet test command: remove --no-build --- appveyor.yml | 2 +- src/Performance_v27/Performance_v27.csproj | 2 +- .../PluralLocalizationFormatterTests.cs | 12 +++++++ .../SmartFormat.Tests.csproj | 8 ++--- .../Extensions/PluralLocalizationFormatter.cs | 32 ++++++++++++------- src/SmartFormat/SmartFormat.csproj | 2 +- 6 files changed, 40 insertions(+), 18 deletions(-) diff --git a/appveyor.yml b/appveyor.yml index f56504da..f692b5ab 100644 --- a/appveyor.yml +++ b/appveyor.yml @@ -38,7 +38,7 @@ for: } test_script: - cmd: nuget install Appveyor.TestLogger - - cmd: dotnet test --no-build --framework net6.0 --test-adapter-path:. --logger:Appveyor SmartFormat.sln /p:configuration=release /p:AltCover=true /p:AltCoverXmlReport="coverage.xml" /p:AltCover=true /p:AltCoverStrongNameKey="..\SmartFormat\SmartFormat.snk" /p:AltCoverAssemblyExcludeFilter="SmartFormat.Tests|SmartFormat.ZString|NUnit3.TestAdapter" /p:AltCoverLineCover="true" + - cmd: dotnet test --framework net6.0 --test-adapter-path:. --logger:Appveyor SmartFormat.sln /p:configuration=release /p:AltCover=true /p:AltCoverXmlReport="coverage.xml" /p:AltCover=true /p:AltCoverStrongNameKey="..\SmartFormat\SmartFormat.snk" /p:AltCoverAssemblyExcludeFilter="SmartFormat.Tests|SmartFormat.ZString|NUnit3.TestAdapter" /p:AltCoverLineCover="true" - cmd: nuget install codecov -excludeversion - cmd: .\Codecov\Tools\win7-x86\codecov.exe -f ".\SmartFormat.Tests\coverage.net6.0.xml" -n net6.0win artifacts: diff --git a/src/Performance_v27/Performance_v27.csproj b/src/Performance_v27/Performance_v27.csproj index 96126448..3e5ad778 100644 --- a/src/Performance_v27/Performance_v27.csproj +++ b/src/Performance_v27/Performance_v27.csproj @@ -2,7 +2,7 @@ Exe - net5.0 + net6.0 9.0 ../SmartFormat/SmartFormat.snk false diff --git a/src/SmartFormat.Tests/Extensions/PluralLocalizationFormatterTests.cs b/src/SmartFormat.Tests/Extensions/PluralLocalizationFormatterTests.cs index 9ac8a85b..efde4134 100644 --- a/src/SmartFormat.Tests/Extensions/PluralLocalizationFormatterTests.cs +++ b/src/SmartFormat.Tests/Extensions/PluralLocalizationFormatterTests.cs @@ -49,6 +49,18 @@ public void Explicit_Formatter_Without_IEnumerable_Arg_Should_Throw() Assert.That(() => smart.Format("{0:plural:One|Two}", new object()), Throws.Exception.TypeOf()); } + [TestCase(0)] + [TestCase(1)] + [TestCase(100)] + public void Explicit_Should_Process_Singular_PluralRule(int count) + { + var smart = Smart.CreateDefaultSmartFormat(); + // Japanese does not have plural definitions (is a Singular language) + // "リンゴを2個持っています。" => "I have 2 apple(s)" + var result = smart.Format("リンゴを{0:plural(ja):{}個持っています。}", count); + Assert.That(result, Is.EqualTo($"リンゴを{count}個持っています。")); + } + [Test] public void Test_Default() { diff --git a/src/SmartFormat.Tests/SmartFormat.Tests.csproj b/src/SmartFormat.Tests/SmartFormat.Tests.csproj index 808a888c..c69edd1f 100644 --- a/src/SmartFormat.Tests/SmartFormat.Tests.csproj +++ b/src/SmartFormat.Tests/SmartFormat.Tests.csproj @@ -18,10 +18,10 @@ - - - - + + + + diff --git a/src/SmartFormat/Extensions/PluralLocalizationFormatter.cs b/src/SmartFormat/Extensions/PluralLocalizationFormatter.cs index 22ea9eda..8816e999 100644 --- a/src/SmartFormat/Extensions/PluralLocalizationFormatter.cs +++ b/src/SmartFormat/Extensions/PluralLocalizationFormatter.cs @@ -70,7 +70,21 @@ public PluralLocalizationFormatter(string defaultTwoLetterIsoLanguageName) /// public string Name { get; set; } = "plural"; - /// + /// + /// Any extensions marked as will be called implicitly + /// (when no formatter name is specified in the input format string). + /// For example, "{0:N2}" will implicitly call extensions marked as . + /// Implicit formatter invocations should not throw exceptions. + /// With == , the formatter can only be + /// called by its name in the input format string. + /// + /// Auto detection only works with more than 1 format argument. + /// Is recommended to set to . This will be the default in a future version. + /// + /// + /// + /// If more than one registered can auto-detect, the first one in the formatter list will win. + /// public bool CanAutoDetect { get; set; } = true; /// @@ -93,17 +107,13 @@ public bool TryEvaluateFormat(IFormattingInfo formattingInfo) // Extract the plural words from the format string: var pluralWords = format.Split(SplitChar); - // This extension requires at least two plural words: - if (pluralWords.Count == 1) + + // This extension requires at least two plural words for auto detection + // For locales + if (pluralWords.Count <= 1 && string.IsNullOrEmpty(formattingInfo.Placeholder?.FormatterName)) { // Auto detection calls just return a failure to evaluate - if (string.IsNullOrEmpty(formattingInfo.Placeholder?.FormatterName)) - return false; - - // throw, if the formatter has been called explicitly - throw new FormatException( - $"Formatter named '{formattingInfo.Placeholder?.FormatterName}' requires at least 2 plural words."); - + return false; } decimal value; @@ -228,4 +238,4 @@ public PluralRules.PluralRuleDelegate GetPluralRule() { return _pluralRule; } -} \ No newline at end of file +} diff --git a/src/SmartFormat/SmartFormat.csproj b/src/SmartFormat/SmartFormat.csproj index 179162cb..0915b60d 100644 --- a/src/SmartFormat/SmartFormat.csproj +++ b/src/SmartFormat/SmartFormat.csproj @@ -53,7 +53,7 @@ /~https://github.com/axuno/SmartFormat/blob/main/CHANGES.md - +