사용자의 로케일을 기반으로 DotNet 프로그램에서 숫자 형식을 지정하는 데 어려움이 있음

사용자의 로케일을 기반으로 DotNet 프로그램에서 숫자 형식을 지정하는 데 어려움이 있음

내 DotNet 7 응용 프로그램을 호스팅할 서버를 얻었지만 사용자의 로케일에 따라 형식이 지정된 숫자를 표시하는 데 문제가 있습니다.

운영 체제는 다음과 같습니다.

$ cat os-release
NAME="Red Hat Enterprise Linux"
VERSION="8.7 (Ootpa)"
ID="rhel"
ID_LIKE="fedora"
VERSION_ID="8.7"
PLATFORM_ID="platform:el8"
PRETTY_NAME="Red Hat Enterprise Linux 8.7 (Ootpa)"
...

내 로케일은 다음과 같습니다.

$ locale
LANG=en_ZA.UTF-8
LC_CTYPE="en_ZA.UTF-8"
LC_NUMERIC="en_ZA.UTF-8"
LC_TIME="en_ZA.UTF-8"
LC_COLLATE="en_ZA.UTF-8"
LC_MONETARY="en_ZA.UTF-8"
LC_MESSAGES="en_ZA.UTF-8"
...

숫자는 다음과 같이 설정됩니다.

$ locale -k LC_NUMERIC
decimal_point="."
thousands_sep=","
grouping=3;3
numeric-decimal-point-wc=46
numeric-thousands-sep-wc=44
numeric-codeset="UTF-8"

123456789.9876그래서 로케일의 숫자 형식으로 형식화된 숫자 가 123,456,789.99.

가장 간단한 프로그램을 만든다면:

static void Main(string[] args) {
    const decimal d = 123456789.9876M;
    Console.WriteLine($"{d:n}");
}

그것 dotnet run, 그것 은 인쇄 됩니다 123 456 789,988.

나는 DotNet이 사용한다고 믿습니다.유니코드(ICU)의 내부 구성요소, 그러나 이는 모든 DotNet 애플리케이션을 실행하기 위한 요구 사항이며 설치된 것으로 보입니다.

$ dnf list installed \*libicu\*
libicu.x86_64    60.3-2.el8_1    @rhel-8-for-x86_64-baseos-rpms

내 애플리케이션에는 불변 문화권을 허용하지 않는 SQL Server가 필요하기 때문에 강제로 적용할 수 없습니다 DOTNET_SYSTEM_GLOBALIZATION_INVARIANT=true(예: 프로젝트 파일에서).

동일한 애플리케이션이 내 WSL/Ubuntu 인스턴스와 내가 시도한 모든 Windows 인스턴스에서 예상된 형식으로 숫자를 인쇄합니다.

나는 노력했다특정 버전의 libicu 포함응용 프로그램과 함께 사용할 수 있지만 형식에는 영향을 미치지 않습니다.

애플리케이션 개발자가 모든 배포에서 일관성을 보장할 수 있도록 .NET 5 이상에서는 Windows 및 Unix의 애플리케이션이 자체 ICU 복사본을 운반하고 사용할 수 있도록 허용합니다.

<PackageReference Include="Microsoft.ICU.ICU4C.Runtime" Version="68.2.0.9" />
<RuntimeHostConfigurationOption Include="System.Globalization.AppLocalIcu" Value="68.2.0.9" />

서버 소유자는 보안을 인식하고 있으며 사용자는 최소한의 필수 권한을 가지고 있습니다.

내 응용 프로그램이 구성된 로케일을 사용하도록 만드는 방법을 아는 사람이 있습니까?


간단한 테스트 프로그램에서 더 많은 출력을 보면 로케일이 정확하지만 위에 표시된 것과 다른 LC_NUMERIC/LC_MONETARY 설정을 사용하는 것 같습니다.

The current culture is en-ZA
The decimal separator is ","
The group separator is " "
The decimal digits is "3"
Number formatted: 123 456 789,988
The currency symbol is "R"
The currency decimal separator is ","
The currency group separator is " "
The currency decimal digits is "2"
Currency formatted: R123 456 789,99

내 상황에 대한 해결 방법으로 프로그래밍 방식으로 문화별 설정을 강제할 수 있었습니다.

public static void SetCustomZAThreadCulture(bool linuxOnly = true) {
    if (!linuxOnly || CrossPlatform.IsLinux()) {
        CultureInfo customCultureInfo = (CultureInfo)Thread.CurrentThread.CurrentCulture.Clone();
        customCultureInfo.NumberFormat = new NumberFormatInfo {
            NumberDecimalSeparator = ".",
            NumberGroupSeparator = ",",
            NumberDecimalDigits = 2,
            CurrencySymbol = "R",
            CurrencyDecimalSeparator = ".",
            CurrencyGroupSeparator = ",",
            CurrencyDecimalDigits = 2,
        };
        Thread.CurrentThread.CurrentCulture = customCultureInfo;
        CultureInfo.DefaultThreadCurrentCulture = customCultureInfo;
    }
}

관련 정보