This article is currently in the process of being translated into Chinese (~95% done).
The CultureInfo class
前几章讨论了需要在程序中完全控制数字和日期的显示时CultureInfo类的巨大用途。还讨论了如何检查和修改程序所使用的默认文化设置。下面就进一步深入到CultureInfo类本身,看看如何充分利用其功能。
开始前先快速提醒下:CultureInfo类属于System.Globalization名空间,因此尝试下述例子前请确保先引入该名空间:
using System.Globalization;中性和特定文化
本章前面的例子都只使用了特定文化设置,那是一个同时指定了特定语言和国家/地区的文化设置。例如en-US文化,其明确指明所用语言为英语,地区为美国。如果换成en-GB文化,则语言不变(还是英语),但国家变成了英国,而非美国。
有些情况下这种差别很重要,因此应该使用此类指定地区版本的CultureInfo类设置。而另一方面,也有些情况下,只是要用英语,但不想把此语言绑定到特定的国家或地区上。针对此种情况,.NET framework定义了所谓的中性文化,只指定语言。实际上en-US和en-GB都继承自这样一个中性文化设置(这样做是很有道理的,因为它们使用的是同一种语言),可通过其Parent属性访问该父文化设置。如下例所示:
CultureInfo enGb = new CultureInfo("en-GB");
CultureInfo enUs = new CultureInfo("en-US");
Console.WriteLine(enGb.DisplayName);
Console.WriteLine(enUs.DisplayName);
Console.WriteLine(enGb.Parent.DisplayName);
Console.WriteLine(enUs.Parent.DisplayName);这不是一个很有用的例子,但应该能展示出一点CultureInfo类的内部细节。其输出应该象这样:
English (United Kingdom)
English (United States)
English
English建立正确的CultureInfo对象
前面的例子显示,可以通过把语言-国家/地区标识传递给构造器来建立所需的CultureInfo对象。不过因为也可能需要的是一个中性文化设置,如上面所述,也可以只传递语言标识:
CultureInfo en = new CultureInfo("en");.NET framework会因此返回一个英语语言,但地区中性的CultureInfo实例。对于全部可能的语言和/或语言-国家/地区标识列表,建议参考MSDN文档。
另一种标识特定文化的方法是使用所谓的LCID(LoCale ID)。可通过属性从在现有CultureInfo实例读取,但如果知道此ID,也可以用其实例化CultureInfo对象。如,en-US的LCID值是1033:
CultureInfo enUs = new CultureInfo(1033);不过,多数情况下,还是使用语言-国家/地区标识容易些,如前面展示的那样。
获取可用的文化配置列表
有了特定的文化设置就可用其实现不同的功能了,不过有时会需要一个可用的文化设置列表,比如,让用户可以选择语言和/或国家/地区。幸好.NET framework也提供了便利 - 看下面例子:
CultureInfo[] specificCultures = CultureInfo.GetCultures(CultureTypes.SpecificCultures);
foreach (CultureInfo ci in specificCultures)
Console.WriteLine(ci.DisplayName);
Console.WriteLine("Total: " + specificCultures.Length);第一行代码使用CultureInfo类的GetCultures静态方法获取了一个文化设置列表。此方法需要CultureTypes参数,用于指定要查找的文化设置类型。上例中是请求查找所有的特定文化设置,如上文所述,也就是所有绑定到特定语言和特定国家/地区的文化设置。输出可能会是很长的列表,顺便提一句 - 笔者电脑上就有563种可用的文化设置!
不过可能需要是中性文化设置?比如只是需要一份可用语言的列表,而对其对应的国家或地区并不关心。只需简单修改一下CultureTypes参数就搞定了:
CultureInfo[] neutralCultures = CultureInfo.GetCultures(CultureTypes.NeutralCultures);
foreach (CultureInfo ci in neutralCultures)
Console.WriteLine(ci.DisplayName);
Console.WriteLine("Total: " + neutralCultures.Length);通过上例也能看出,中性文化设置的数量就没有特定文化设置的数量那么多了 - 笔者电脑/.NET framework版本上,中性文化设置的数量是280。
CultureInfo类的重要属性和方法
获得CultureInfo类实例后,就可以访问很多有用的属性和方法了。这些成员有助于实现很多与文化相关的功能 - 下面介绍其中几个!
DateTimeFormat
使用DateTimeFormat属性可以获得日期和时间格式化的信息,以及指定文化下与日历相关的很多有用信息。例如FirstDayOfWeek和CalendarWeekRule属性 - 它们定义了一周的开始日(通常为星期天或星期一),及怎样确定一年的第一个日历周(如,是只需有一天便算,还是需要一个完整周):
CultureInfo enUs = new CultureInfo("en-US");
Console.WriteLine("First day of the: " + enUs.DateTimeFormat.FirstDayOfWeek.ToString());
Console.WriteLine("First calendar week starts with: " + enUs.DateTimeFormat.CalendarWeekRule.ToString());可以试着把上例中的CultureInfo实例换成自己的文化或知道的其它文化,看看这些属性的差异!
下一项是可通过MonthNames等属性和GetMonthName()等方法得到特定文化的月份和星期内天的名称。如下例所示:
CultureInfo enUs = new CultureInfo("en-US");
foreach (string monthName in enUs.DateTimeFormat.MonthNames)
Console.WriteLine(monthName);
Console.WriteLine("Current month: " + enUs.DateTimeFormat.GetMonthName(DateTime.Now.Month));可用几乎同样的方法来实现取得星期内天的名称,使用DayNames属性和GetDayName()方法:
CultureInfo enUs = new CultureInfo("en-US");
foreach (string dayName in enUs.DateTimeFormat.DayNames)
Console.WriteLine(dayName);
Console.WriteLine("Today is: " + enUs.DateTimeFormat.GetDayName(DateTime.Now.DayOfWeek));DateTimeFormat属性有太多的有用属性和方法,比如,DateSeparator,YearMonthPattern等等。可自行探索 - 也许有些与日期/时间相关的问题的解决方案就藏在其中:DateTimeFormatInfo文档。
NumberFormat
象DateTimeFormat含有日期的信息一样,可通过访问NumberFormat属性获得特定文化怎样处理数字的信息。此信息在每次需要对数字进行显示时都会被自动使用到,比如,需要把数字转化为字符串并输出到控制台上时,不过也可以通过NumberFormat的属性和方法直接访问此信息 - 如下例所示:
CultureInfo enUs = new CultureInfo("en-US");
Console.WriteLine(enUs.DisplayName + ":");
Console.WriteLine("NumberGroupSeparator: " + enUs.NumberFormat.NumberGroupSeparator);
Console.WriteLine("NumberDecimalSeparator: " + enUs.NumberFormat.NumberDecimalSeparator);
CultureInfo deDe = new CultureInfo("de-DE");
Console.WriteLine(deDe.DisplayName + ":");
Console.WriteLine("NumberGroupSeparator: " + deDe.NumberFormat.NumberGroupSeparator);
Console.WriteLine("NumberDecimalSeparator: " + deDe.NumberFormat.NumberDecimalSeparator);上例使用NumberGroupSeparator和NumberDecimalSeparator属性读取在英语和德语文化下数字如何显示(如,1,000.00或1.000,00)的信息。如果自行探索就会发现与货币相关的对应属性(CurrencyGroupSeparator和CurrencyDecimalSeparator)及与百分比相关的对应属性(PercentGroupSeparator和PercentDecimalSeparator)。
提到货币,NumberFormat属性还提供特定文化下的货币值显示符号 - 使用CurrencySymbol属性:
CultureInfo enUs = new CultureInfo("en-US");
Console.WriteLine(enUs.DisplayName + " - currency symbol: " + enUs.NumberFormat.CurrencySymbol);
CultureInfo deDe = new CultureInfo("de-DE");
Console.WriteLine(deDe.DisplayName + " - currency symbol: " + deDe.NumberFormat.CurrencySymbol);
CultureInfo ruRu = new CultureInfo("ru-RU");
Console.WriteLine(ruRu.DisplayName + " - currency symbol: " + ruRu.NumberFormat.CurrencySymbol);了解一下这些属性没有坏处,但是多数情况下不用与它们打交道,因为C#会自动使用这些信息来格式化数字,百分比及货币,只要在把数字转化为字符串时提供了正确的格式化字符串。
名称和标识
最后,看一下用于表示CultureInfo实例的一些属性。前面已经接触过一些,如,Name和DisplayName,不过它们是原理是什么呢?首先,下面列出了可用于标识一个CultureInfo实例的属性列表:
- Name以语言代码-国家/地区的格式来标识CultureInfo对象,如,“en-US”为美国英语,en-GB为英国英语等等。如果没有指定国家/地区,就只会返回第一部分,如,“en”为英语。
- TwoLetterISOLanguageName基本上与Name是一样的,但其只返回语言代码,不管有没有指定国家/地区。如,"en-US"和"en-GB"都会返回“en”。返回的字母组合在ISO 639-1标准中规定。
- ThreeLetterISOLanguageName与TwoLetterISOLanguageName很象,但其返回三位字母,而非两位,由ISO 639-2标准规定。
- EnglishName返回语言的名称(英语名称)。如果指定了国家/地区,也会包含在结果中,被括号括起来。
- NativeName会返回语言的名称(用相应文化实例的语言表示的名称)。如果指定了国家/地区,也会包含在结果中,被括号括起来。
总结
由本节的长度可知,通用文化处理并非易事。幸好.NET framework通过CultureInfo类大幅地整体简化了此工作。当需要格式化数字和日期时,此类在整个程序的后台默默地运行,但了解一下其工作原理不无益处,以便在必要时对其默认行为进行更改。希望本节充分展示了有关CultureInfo类所需掌握的大部分内容。