0

How do I display number respecting culture-specific decimal and thousands separators in Blazor? It seems that in .ToString() I have to provide format, for example "N0" for the provider (CultureInfo) to be respected, but what if I don't know/want number format?

@using System.Globalization;

<p>@value</p> @* 30000.55 *@
<p>@valueAsString</p> @* 30000.55 *@
<p>@valueAsString2</p> @* 30,001 *@
<p>@valueAsString3</p> @* 30,000.550 *@

@code {
    CultureInfo japan = new CultureInfo("jp-JP");
    decimal value = 30_000.55m;
    string valueAsString => value.ToString(japan);
    string valueAsString2 => value.ToString("N0", japan);
    string valueAsString3 => value.ToString("N", japan);
}

example: https://try.mudblazor.com/snippet/GucdYfxOxUDiCPsv

How do I display 30,000.55 providing I do not know the precision and I do not want following zeroes?

phuzi
  • 12,078
  • 3
  • 26
  • 50
Pawel
  • 891
  • 1
  • 9
  • 31
  • There's always the option of using the current UI culture instead of having to know it beforehand - `CultureInfo.CurrentUICulture` – phuzi May 30 '23 at 09:40
  • I'm receiving CultureInfo from the client using js interop. – Pawel May 30 '23 at 09:48
  • Edited example to it better illustrates the problem. – Pawel May 30 '23 at 10:17
  • Your question is not very clear. Are you asking how to format a number in such a way that the number is formatted according to the culture with trailing decimal digits but remove trailing decimal zeroes no matter what the "precision" is? – phuzi May 30 '23 at 10:39
  • I'm asking how to format a number in such a way that the number is formatted according to the culture with regards to decimal numbers separator character and thousands separator character. Given the decimal number 30_000.55m in `de-DE` culture result I want would be "30.000,55", in `en-GB` culture the result would be "30,000.55". For the number 1_000.4m the results would be "1.000,4" and "1,000.4" accordingly, and for the number 100m the results would be "100" in both cases. – Pawel May 30 '23 at 11:31
  • I'll take that as a yes then. I don't think you can do this using [Standard Numeric Format Strings](https://learn.microsoft.com/en-us/dotnet/standard/base-types/standard-numeric-format-strings) and you will likely have to manually remove any trailing decimal zeroes manually. – phuzi May 30 '23 at 11:43
  • Do you mean for example `30_000.55m.ToString("N99", de).TrimEnd('0')`? Ugly but works as intended. – Pawel May 30 '23 at 11:49
  • That would be one way. – phuzi May 30 '23 at 12:07
  • Have you tried `value.ToString("#,##0.###########", japan )` you can add as many `#` as you think is reasonable to accomodate your numbers – Mister Magoo May 30 '23 at 22:56

1 Answers1

0

For time being, the best solution to this problem I found is the following FormatDecimal extension method:

/// <summary>
/// Formats a decimal value to a string representation with a specified number of decimal places and culture.
/// </summary>
/// <param name="value">The decimal number to be formatted.</param>
/// <param name="culture">Optional. The culture to format the number with. If not provided, the InvariantCulture will be used.</param>
/// <param name="decimalPlaces">Optional. The number of decimal places to format to. If not provided, the current number of decimal places in the value will be used.</param>
/// <returns>A string representation of the decimal value, formatted according to the specified decimal places and culture.</returns>
public static string FormatDecimal(this decimal value, CultureInfo? culture = null, int? decimalPlaces = null)
{
    culture ??= CultureInfo.InvariantCulture;
    decimalPlaces ??= GetDecimalPlaces(value);

    return value.ToString($"N{decimalPlaces}", culture);
}

/// <summary>
/// Gets the number of decimal places in a decimal number.
/// </summary>
/// <param name="value">The decimal number.</param>
/// <returns>The number of decimal places in the number.</returns>
/// <remarks>This method does not count trailing zeros as decimal places.
/// For example, the number 1.2300 has 2 decimal places. The method also works correctly 
/// with negative numbers.</remarks>
public static int GetDecimalPlaces(this decimal value)
{
    value = Math.Abs(value); //make sure it is positive.
    value -= (int)value;     //remove the integer part of the number.
    var decimalPlaces = 0;
    while (value > 0)
    {
        decimalPlaces++;
        value *= 10;
        value -= (int)value;
    }
    return decimalPlaces;
}

GetDecimalPlaces implementation found here: https://stackoverflow.com/a/30205131/3934322

Pawel
  • 891
  • 1
  • 9
  • 31