我将其发布为对 OP 问题帖子中几乎提出的两个问题的回答:
在 Windows 10 进行重大更改以支持 BCP-47...
- 如何判断给定的
CultureInfo 对象是“真实”文化,还是从头开始在代码中创建的虚假/人为/私有 CultureInfo?
- 我如何判断用户提供的
String cultureName 值是否对 new CultureInfo(String) 有效并且运行时环境(.NET 和/或 OS)具有该名称的有意义的文化数据(不仅仅是DisplayName)?
问题 1:验证给定的 CultureInfo 实例:
As per the documentation for CultureTypes, prior to Windows 10,如果CultureInfo.CultureTypes 属性具有UserCustomCulture 标志,那么它是一种自定义文化。从 Windows 10 开始,UserCustomCulture 标志表示自定义文化,但也表示“没有完整的文化数据集支持的系统文化并且没有唯一的本地标识符”。
因此,如果您想在 Windows 10 上验证CultureInfo,完全相同,就像在 Windows 8.1 或更早版本上一样,只需检查:
-
CultureInfo.CultureTypes 没有设置 CultureTypes.UserCustomCulture 标志。
- 如果它确实有
UserCustomCulture,请确保CultureInfo.ThreeLetterWindowsLanguageName != "ZZZ"
所以这对我有用:
public static Boolean ValidateCultureInfoWithPreWindows10Logic( CultureInfo ci )
{
Boolean hasUserCustom = ( ci.CultureTypes & CultureTypes.UserCustomCulture ) == CultureTypes.UserCustomCulture;
if( hasUserCustom )
{
if( ci.ThreeLetterWindowsLanguageName == "ZZZ" )
{
// Windows doesn't have a name for this language - this CultureInfo is invalid under Windows 8.1 or earlier.
return false;
}
else
{
// The `UserCustomCulture` flag means *some* CultureData is missing, but not enough to make them useless.
// On both Win8 and Win10, the same 8 Neutral Cultures match here: [ jv, jv-Latn, mg, nqo, sn, sn-Latn, zgh, zgh-Tfng ]
return true;
}
}
else
{
// The `UserCustomCulture` flag is not set, which means 100% of the CultureInfo's CultureData exists in the system.
return true;
}
}
问题 2:验证给定的String cultureName:
下表显示了 new CultureInfo 与 CultureInfo.CreateSpecificCulture 在 Windows 10 与 Server 2012 R2 以及 .NET 4.8 与 .NET 6 上的结果:
| Expression |
Windows 10 + .NET 6 |
Windows 10 + .NET 4.8 |
Windows 2012 R2 + .NET 4.8 |
| CultureInfo ci1 = new CultureInfo("en-FR") |
|
|
|
| ci1.DisplayName |
"English (France)" |
"Unknown Locale (en-FR)" |
CultureNotFoundException |
| ci1.ThreeLetterWindowsLanguageName |
"ZZZ" |
"ENU" |
CultureNotFoundException |
| ci1.CultureTypes |
SpecificCultures | UserCustomCulture | InstalledWin32Cultures |
SpecificCultures | UserCustomCulture |
CultureNotFoundException |
|
|
|
|
| CultureInfo spec = CultureInfo.CreateSpecificCulture("en-FR") |
|
|
|
| spec.DisplayName |
"English (France)" |
"Unknown Locale (en-FR)" |
"English (United States)" |
| spec.ThreeLetterWindowsLanguageName |
"ZZZ" |
"ENU" |
"ENU" |
| spec.CultureTypes |
SpecificCultures | UserCustomCulture | InstalledWin32Cultures |
SpecificCultures | UserCustomCulture |
SpecificCultures | InstalledWin32Cultures | FrameworkCultures |
到目前为止,非常不一致。
如果您想允许任意语言名称,即使操作系统不了解该语言(更不用说该地区) - 无论是中性还是特定 CultureInfo...呃...我必须回答稍后再问。
其他提示:当您希望 cultureName 仅限于操作系统支持的文化(中性和/或特定)时,如何可靠地验证它:
快速解决方法是:
public static class KnownCultureInfoNameValidator
{
private static readonly HashSet<String> _preWindows10BuiltInCustomNames = new String[]
{
"jv", "jv-Latn", "mg", "nqo", "sn", "sn-Latn", "zgh", "zgh-Tfng"
}
.ToHashSet();
private static readonly HashSet<String> _knownLanguages = BuildHashSet( CultureInfo.GetCultures( CultureTypes.NeutralCultures ) );
private static readonly HashSet<String> _knownSpecific = BuildHashSet( CultureInfo.GetCultures( CultureTypes.SpecificCultures ) );
private static HashSet<String> BuildHashSet( IEnumerable<CultureInfo> cultures )
{
return cultures
.Where( ci => ci.ThreeLetterWindowsLanguageName != "ZZZ" )
.Where( ci => ci.LCID != 127 ) // Exclude InvariantCulture
#if LIKE_PRE_WINDOWS_10
.Where( ci =>
_preWindows10BuiltInCustomNames.Contains( ci.Name )
||
( ci.CultureTypes & CultureTypes.UserCustomCulture ) == 0
)
#endif
.Select( ci => ci.Name )
.ToHashSet();
}
// Only returns true if `cultureName` is an OS-known culture with sufficient OS-provided culture data. This method will return false for partially-known cultuires.
public static Boolean ValidateCultureName( String cultureName, Boolean allowNeutral, Boolean allowSpecific )
{
if( allowNeutral && _knownLanguages.Contains( cultureName ) ) return true;
if( allowSpecific && _knownSpecific.Contains( cultureName ) ) return true;
return false;
}
}
研究: