私は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が使用すると信じています。Unicode(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;
}
}