Skip to content

Commit edb3cb9

Browse files
authored
Make statistical significant figures formatting culture-sensitive (#8039)
1 parent 17e57fb commit edb3cb9

2 files changed

Lines changed: 34 additions & 4 deletions

File tree

src/NuGetGallery/ViewModels/StatisticsPackagesViewModel.cs

Lines changed: 10 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -5,6 +5,7 @@
55
using System.Collections.Generic;
66
using System.Globalization;
77
using System.Linq;
8+
using System.Threading;
89

910
namespace NuGetGallery
1011
{
@@ -160,14 +161,20 @@ internal static string DisplayShortNumber(double number, int sigFigures = 3)
160161
var roundedNum = Math.Round(number * roundingFactor) / roundingFactor;
161162

162163
// Pad from right with zeroes to sigFigures length, so for 3 sig figs, 1.6 becomes 1.60
163-
var formattedNum = roundedNum.ToString("F" + sigFigures);
164-
var desiredLength = formattedNum.Contains('.') ? sigFigures + 1 : sigFigures;
164+
var decimalPoint = Thread.CurrentThread.CurrentUICulture.NumberFormat.NumberDecimalSeparator;
165+
var formattedNum = roundedNum.ToString("F" + sigFigures, Thread.CurrentThread.CurrentUICulture.NumberFormat);
166+
var desiredLength = formattedNum.Contains(decimalPoint) ? sigFigures + decimalPoint.Length : sigFigures;
165167
if (formattedNum.Length > desiredLength)
166168
{
167169
formattedNum = formattedNum.Substring(0, desiredLength);
168170
}
169171

170-
formattedNum = formattedNum.TrimEnd('.');
172+
// If trailing char/s is/are decimal point separator, trim it
173+
if (formattedNum.Length > decimalPoint.Length &&
174+
formattedNum.Substring(formattedNum.Length - decimalPoint.Length, decimalPoint.Length) == decimalPoint)
175+
{
176+
formattedNum = formattedNum.Substring(0, formattedNum.Length - decimalPoint.Length);
177+
}
171178

172179
if (numDiv >= _magnitudeAbbreviations.Length)
173180
{

tests/NuGetGallery.Facts/ViewModels/StatisticsPackagesViewModelFacts.cs

Lines changed: 24 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,8 @@
11
// Copyright (c) .NET Foundation. All rights reserved.
22
// Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information.
33

4+
using System.Globalization;
5+
using System.Threading;
46
using Xunit;
57

68
namespace NuGetGallery.ViewModels
@@ -15,19 +17,40 @@ public class StatisticsPackagesViewModelFacts
1517
[InlineData(1775856283, 3, "1.78B")]
1618
[InlineData(1775856283, 5, "1.7759B")]
1719
[InlineData(775856283, 3, "776M")]
20+
[InlineData(775856283, 3, "776M", "en-US")] // culture-specific decimal separator test, right-clipping separator (776. -> 776)
21+
[InlineData(775856283, 3, "776M", "ar-SA")] // culture-specific decimal separator test, right-clipping separator (776. -> 776)
22+
[InlineData(775856283, 3, "776M", "fr-FR")] // culture-specific decimal separator test, right-clipping separator (776. -> 776)
1823
[InlineData(775856283, 5, "775.86M")]
1924
[InlineData(75856283, 3, "75.9M")]
2025
[InlineData(56283, 3, "56.3k")]
26+
[InlineData(56283, 3, "56.3k", "en-US")] // culture-specific decimal separator test, no right-clipping of separator
27+
[InlineData(56283, 3, "56.3k", "ar-SA")] // culture-specific decimal separator test, no right-clipping of separator
28+
[InlineData(56283, 3, "56.3k", "fr-FR")] // culture-specific decimal separator test, no right-clipping of separator
2129
[InlineData(56283283283283, 3, "56.3T")]
2230
[InlineData(56283283283283283, 3, "56.3q")]
2331
[InlineData(56283283283283283283283283283283d, 3, "56.3n")]
2432
[InlineData(56283283283283283283283283283283283d, 3, "56.3 10^33")]
2533
[InlineData(1, 3, "1.00")]
2634
[InlineData(10, 3, "10.0")]
2735
[InlineData(100, 3, "100")]
28-
public void CreatesShortNumberRespectingSignificantFigures(double number, int sigFigs, string expected)
36+
public void CreatesShortNumberRespectingSignificantFigures(double number, int sigFigs, string expected, string culture = "")
2937
{
38+
CultureInfo cacheCulture = null;
39+
if (culture != "")
40+
{
41+
cacheCulture = Thread.CurrentThread.CurrentUICulture;
42+
Thread.CurrentThread.CurrentUICulture = CultureInfo.GetCultureInfo(culture);
43+
}
44+
45+
expected = expected.Replace(".", Thread.CurrentThread.CurrentUICulture.NumberFormat.NumberDecimalSeparator);
46+
3047
var result = StatisticsPackagesViewModel.DisplayShortNumber(number, sigFigs);
48+
49+
if (cacheCulture != null)
50+
{
51+
Thread.CurrentThread.CurrentUICulture = cacheCulture;
52+
}
53+
3154
Assert.Equal(expected, result);
3255
}
3356
}

0 commit comments

Comments
 (0)