前言
在公司做的桌面软件在国内以及亚美洲地区都能正常使用,结果到了俄罗斯客户那边软件就根本打不开,不能正常使用。
经定位排查,最终发现是俄罗斯的浮点数不是用小数点,而是用逗号来分割的。在电脑的【控制面板——时钟和区域——其他设置】,可以看到小数点的种类,当然也能看到其他数据格式的分割符号。
既然是不同区域的小数点分隔符号不一致导致的,那么就从这里入手,目前有两个解决方案。
方案一: 兼容不同国家的小数点分隔符,在软件启动时设置一下,使用统一的文化。
大体思路:软件启动前读取电脑控制面板的默认设置,设置CultureInfo的小数点符号,字符串和数字的转换时使用CultureInfo。
举个例子:
1、使用一个工具类记录小数点分割符号,以及数值的转换格式。
class Utility
{
//记录小数点分隔符
public static string NumberDecimalSeparator = ".";
public const string NormalDot = ".";
//数值转换格式
public static NumberFormatInfo cusNumFormatInfo;
}
2、在Main函数中获取控制面板中的设置
//获得和设置当前系统语言区域
string tempLanguage = "";
tempLanguage = System.Globalization.CultureInfo.InstalledUICulture.Name;
//区域文化 参考链接
// https://docs.microsoft.com/zh-cn/dotnet/api/system.globalization.numberformatinfo?view=net-6.0
Utility.cusNumFormatInfo = CultureInfo.CreateSpecificCulture(tempLanguage).NumberFormat;
//获取小数点分隔符号
Utility.NumberDecimalSeparator = System.Globalization.CultureInfo.CurrentCulture.NumberFormat.NumberDecimalSeparator;
Utility.cusNumFormatInfo.NumberDecimalSeparator = Utility.NumberDecimalSeparator;
Utility.cusNumFormatInfo.CurrencyDecimalSeparator = Utility.NumberDecimalSeparator;
3、使用例子
① 数值转字符串
int tempValue = 10;
string tempValueStr = String.Format(Utility.cusNumFormatInfo,"{0:f2}", Convert.ToUInt16(tempValue));
// 假设使用的小数点分割符号是逗号,则
// tempValueStr = 10,00;
②字符串转数值
string tempValueStr = "34,58";
double tempValue = Convert.ToDouble(tempValueStr , Utility.cusNumFormatInfo);
// 假设使用的小数点分割符号是逗号,则
// tempValue = 34.58; //注:在软件调试的时候数值还是使用小数点做分割符号
但是也会有一个小缺点:在软件使用期间,控制面板的设置可能会被用户更改。
方案二: 忽略不同国家地区的小数点,统一使用点(.)作为小数点。
可以通过反射的方式设置CultureInfo,那么就可以这么写代码:
///
/// 多语言国际化问题
///
static void LoadSetting()
{
//欧洲国家的小数点为",",而中国的小数点是"."
//设置语言文化为统一不变的文化
SetDefaultCulture(CultureInfo.InvariantCulture);
}
static void SetDefaultCulture(CultureInfo culture)
{
Type type = typeof(CultureInfo);
try
{
type.InvokeMember("s_userDefaultCulture",
BindingFlags.SetField | BindingFlags.NonPublic | BindingFlags.Static,
null,
culture,
new object[] { culture });
type.InvokeMember("s_userDefaultUICulture",
BindingFlags.SetField | BindingFlags.NonPublic | BindingFlags.Static,
null,
culture,
new object[] { culture });
}
catch { }
try
{
type.InvokeMember("m_userDefaultCulture",
BindingFlags.SetField | BindingFlags.NonPublic | BindingFlags.Static,
null,
culture,
new object[] { culture });
type.InvokeMember("m_userDefaultUICulture",
BindingFlags.SetField | BindingFlags.NonPublic | BindingFlags.Static,
null,
culture,
new object[] { culture });
}
catch { }
}
在Main函数调用LoadSetting之后,无论切换成什么语言环境,奇怪的多语言问题都迎刃而解了。 来自 C# 多语言国际化问题中的 CULTUREINFO,感谢大神的思路。
方法一适用于客户提出需要按自己习惯方式输入和显示数值,缺点:在数值转换的地方都要用上数值格式化NumberFormatInfo ,比较麻烦。
方法二 比较简易方便。缺点:不能根据国家地区的习惯显示数值字符串。
如果无太大的需求推荐使用方法二。