The CultureInfo Class


The CultureInfo class, introduced in Chapter 3, is the single most important class in .NET's internationalization story. It encapsulates a language; optionally, a country or region; and, in some cases, a script. In this section, we look beyond the introduction given in Chapter 3.

The CultureInfo class has four constructors:

 public CultureInfo(int culture); public CultureInfo(int culture, bool useUserOverride); public CultureInfo(string name); public CultureInfo(string name, bool useUserOverride); 


Two of the constructors accept an LCID (locale identifier) and two accept a culture string. The LCID constructors are useful for constructing new CultureInfo objects when the culture string is not immediately available (for example, when using Win32 APIs). In addition, they are useful for constructing CultureInfo objects that cannot be distinguished by their culture strings (e.g., "es-ES" (Traditional Sort) and "en-ES" (Modern Sort)). See the section entitled "Alternate Sort Orders" for more details. An alternative to using the CultureInfo constructors in the .NET Framework 2.0 is to use the CultureInfo.GetCultureInfo method, which has the following overrides:

 public static CultureInfo GetCultureInfo(int culture); public static CultureInfo GetCultureInfo(string name); public static CultureInfo GetCultureInfo(     string name, string altName); 


Two differences exist between the CultureInfo constructor and the Culture-Info.GetCultureInfo method:

  • CultureInfo objects returned by the GetCultureInfo method are cached, and, therefore, subsequent hits on the same culture are returned faster.

  • CultureInfo objects are read-only.

CultureInfo has a similar method called GetCultureInfoByIetfLanguageTag that performs the same operation but accepts an IETF language tag instead of a culture name.

The culture string used in the CultureInfo constructor and GetCultureInfo method accepts a string in the RFC 1766 format:

 languagecode2[-country/regioncode2[-script]] 


languagecode2 is an ISO 639-1 or 639-2 code, and country/regioncode2 is an ISO 3166 code. The ISO 639-1 standard specifies the two-letter code used to identify a language. Sometimes there is no two-letter code for a language, so the three-letter ISO 639-2 code is used instead. In the .NET Framework 1.1. and 2.0, this applies to just three cultures:

 div (Divehi) kok (Konkani) syr (Syriac) 


Correspondingly, the CultureInfo.TwoLetterISOLanguage property returns three letters instead of two letters for these cultures.

Some cultures support more than one writing system (script). Table 6.1 shows the cultures that have a script tag suffix of "Cyrl" (for Cyrillic scripts) or "Latn" (for Latin scripts).

Table 6.1. Cultures with Scripts

Culture Name

DisplayName

.NET 1.1

.NET 2.0

az-AZ-Cyrl

Azeri (Cyrillic, Azerbaijan)

Yes

Yes

az-AZ-Latn

Azeri (Latin, Azerbaijan)

Yes

Yes

bs-BA-Latn

Bosnian (Bosnia and Herzegovina)

No

Yes

sr-BA-Cyrl

Serbian (Cyrillic, Bosnia and Herzegovina)

No

Yes

sr-BA-Latn

Serbian (Latin, Bosnia and Herzegovina)

No

Yes

sr-SP-Cyrl

Serbian (Cyrillic, Serbia and Montenegro)

Yes

Yes

sr-SP-Latn

Serbian (Latin, Serbia and Montenegro)

Yes

Yes

uz-UZ-Latn

Uzbek (Latin, Uzbekistan)

Yes

Yes

uz-UZ-Cyrl

Uzbek (Cyrillic, Uzbekistan)

Yes

Yes


Two cultures use nonstandard culture string formats: zh-CHS (Chinese (Simplified)) and zh-CHT (Chinese (Traditional)). Looking at these strings, you would expect them to represent specific cultures ("zh" being a language and "CHS"/"CHT" being a country), but they do not. Instead, they are both neutral cultures and are parents to zh-CN (Chinese (People's Republic of China)) and zh-TW (Chinese (Taiwan)), respectively. For this reason, you should take care to use the CultureInfo.IsNeutralCulture property to determine whether a culture is neutral instead of making an inference by parsing the culture's name. This property is similarly important when considering custom cultures because there is no requirement that the name of a custom culture follow a strict <language>-<region> format. Note that there is no CultureInfo.IsSpecificCulture property, so the implication is that if IsNeutralCulture is false, the culture is specific. This is true for all cultures except CultureInfo.InvariantCulture, which is neither neutral nor specific (although it can behave like a specific culture). You can test a culture to see if it is the invariant culture by making a comparison with CultureInfo.InvariantCulture.

Two CultureInfo constructors accept a second Boolean parameter, useUserOverride. This parameter specifies whether the user should be able to override the culture's number, currency, time, and date default settings (used in the DateTimeFormatInfo and NumberFormatInfo classes) in the Customize Regional Options dialog (in the Regional and Language Options dialog, click on the Customize... button) (see Figure 6.1). (Prior to Windows XP Professional, these same tabs are included in the Regional and Language Options dialog, so there is no need for a Customize button.) When the useUserOverride parameter is TRue, the user's settings override the culture's default settings.

Figure 6.1. The Customize Regional Options Dialog Currency tab


If this parameter isn't specified, the default is TRue, so the user's own settings override the default settings. In an ASP.NET 2.0 application where Culture and/or UICulture is "auto", the useUserOverride parameter is not specified; if you don't want to accept the user's settings, you need to override the InitializeCulture method to change this behavior (see Chapter 5, "ASP.NET Specifics"). In addition, the CultureInfo.GetCultureInfo method does not have a useUserOverride parameter, so this method always returns CultureInfo objects where useUserOverride is false.

The recommended practice is to accept the user's overrides. There are many reasons why the user's settings would be considered essential. For example, when a country changes its currency, the currency symbol needs to be updated. This happens frequently: in the past with France changing from francs to euros, more recently with Turkey changing from TL (Türk Lirasi) to YTL (Yeni Türk Lirasi), and possibly in the future with the English pound changing to euros. Whereas the most recent versions of the operating system are updated with such changes, they cannot predict future events, and older operating systems (e.g., Windows 98 and Windows NT, in the case of the French franc) remain out-of-date. (Windows XP SP2 was released before the introduction of the new Turkish Lira on January 1, 2005, so it became out-of-date when the old Turkish Lira was removed from circulation at the end of 2005.) A simple solution to this problem is to ensure that your users run Windows Update on a regular basis, as Windows Update keeps culture information up-to-date. The problem itself, however, is lessened by using the .NET Framework 2.0 as opposed to 1.1. The culture information provided by the .NET Framework 2.0 has been updated with known changes, so whereas the .NET Framework 1.1's tr-TR (Turkish (Turkey)) culture reports that the currency symbol is "TL", the .NET Framework 2.0's same culture reports that the currency symbol is "YTL".

In addition, typically you should trust the user's good intentions and accept their overrides. The alternative is to reject the user's overrides and either create new custom cultures with the updated information (see Chapter 11, "Custom Cultures") or create a CultureInfoProvider:

 public class CultureInfoProvider {     public static CultureInfo GetCultureInfo(string name)     {         CultureInfo cultureInfo = new CultureInfo(name);         ApplyKnownUpdates(cultureInfo);         return cultureInfo;     }     public static CultureInfo GetCultureInfo(int LCID)     {         CultureInfo cultureInfo = new CultureInfo(LCID);         ApplyKnownUpdates(cultureInfo);         return cultureInfo;     }     public static void ApplyKnownUpdates(CultureInfo cultureInfo)     {         if (cultureInfo.Name == "fr-FR")             cultureInfo.NumberFormat.CurrencySymbol = "€";         else if (cultureInfo.Name == "tr-TR")             cultureInfo.NumberFormat.CurrencySymbol = "YTL";         else if (cultureInfo.Name == "en-GB")             cultureInfo.NumberFormat.CurrencySymbol = "€";     } } 


The problem with this solution is that you have to catch every situation that creates a CultureInfo and furthermore be able to change the code to create the CultureInfo using the new CultureInfoProvider class. FxCop can help with this. See the "CultureInfo not provided by Provider" rule in Chapter 13, "Testing Internationalization Using FxCop." A more sophisticated version of this CultureInfoProvider (which creates the CultureInfoEx objects shown in the section entitled "Extending the CultureInfo Class," later in this chapter) is included in the source code for this book.

CultureInfo.GetCultures and CultureTypes Enumeration

The static CultureInfo.GetCultures method gets a list of cultures that match a CultureTypes enumeration (see Table 6.2). So CultureInfo.GetCultures(Culture Types.NeutralCultures) returns an array of culture-neutral CultureInfo objects:

 foreach (CultureInfo cultureInfo in     CultureInfo.GetCultures(CultureTypes.NeutralCultures)) {     listBox1.Items.Add(cultureInfo.DisplayName); } 


Table 6.2. CultureTypes Enumeration

Name

Value

Description

.NET 1.1

.NET 2.0

AllCultures

7

All cultures known to the .NET Framework (and, in .NET 2.0, the operating system and custom cultures)

Yes

Yes

FrameworkCultures

64

All cultures known to the .NET Framework

No

Yes

InstalledWin32Cultures

4

All cultures known to the current operating system

Yes

Yes

NeuTRalCultures

1

Neutral cultures (language part only)

Yes

Yes

ReplacementCultures

16

Custom cultures that replace existing cultures

No

Yes

SpecificCultures

2

Specific cultures (language and country/region)

Yes

Yes

UserCustomCulture

8

Custom cultures installed on this machine

No

Yes

WindowsOnlyCultures

32

Cultures known to the operating system but not to the .NET Framework

No

Yes


The invariant culture is included in the list of neutral cultures even though CultureInfo.InvariantCulture.IsNeutralCulture is false. This inclusion in the list of neutral cultures represents a bug that was present in the .NET Framework 1.0. It persists in later versions of the .NET Framework for backward compatibility.

You can see from the enumeration value in Table 6.2 that CultureTypes can be added together, so CultureInfo.GetCultures(CultureTypes.NeutralCultures | CultureTypes.InstalledWin32Cultures) returns an array of cultures that are either neutral or known to the operating system.

The UserCustomCulture element is singular (i.e., it does not have an s at the end), whereas all the other elements are plural (i.e., they do have an s at the end). The naming of this element is inconsistent with its siblings. Unfortunately, the issue was not caught until it was too late in the testing cycle, and compatibility won over consistency. The singular name stays.


The InstalledWin32Cultures value deserves a special mention. This represents all of the cultures that are known to the current version of the operating system. For each version of the operating system, this is a different number, with Windows XP Service Pack 2 including the highest number of cultures at the time of writing. What is especially useful about this is that when new cultures are subsequently added in later versions of the operating system, they will be included in the list returned by GetCultures and they will be recognized without requiring a new version of the framework. In fact, some cultures either exist or not, depending upon how the operating system has been configured. The Bengali (India), Hindi and Malayam (India) cultures are added to the list of cultures when complex script support is installed (see the "Supplemental Language Support" section in Chapter 7, "Middle East and East Asian Cultures"). This adaptable behavior is new in the .NET Framework 2.0, and, as the .NET Framework 1.1 doesn't support this option, it is unaware of new cultures and uses its own hard-coded culture list.

The order in which the cultures are returned is unsorted. As the culture list in .NET Framework 1.1 is fixed, the order is a constant and most similar cultures are loosely grouped together, but they are not alphabetically sorted by any criteria. The culture list in the .NET Framework 2.0 is variable, and cultures are returned in a different order than that of the .NET Framework 1.1; however, the order is still, nonetheless, unsorted.

A few of the Windows-only cultures (e.g., cy-GB) have an incorrect DisplayName in Windows XP Professional Service Pack 2. The DisplayName is missing the region (e.g., "Welsh" should be "Welsh (United Kingdom)"). This is a fault in the ELK resources for these cultures and should be fixed in a later Service Pack or release of the operating system. The workaround is to use the EnglishName or NativeName.


The Relationship Between CultureInfo and Other Globalization Classes

The CultureInfo class frequently represents the focal point of the System.Globalization namespace. It is supported by, and references, many other System. Globalization classes. The relationship between its properties and those classes can be seen in Figure 6.2.

Figure 6.2. The Relationship between CultureInfo and Other System.Globalization Classes


(The properties listed in the diagram are only those properties that relate to other classes; this is not a complete list.) We explore these classes throughout this chapter.




.NET Internationalization(c) The Developer's Guide to Building Global Windows and Web Applications
.NET Internationalization: The Developers Guide to Building Global Windows and Web Applications
ISBN: 0321341384
EAN: 2147483647
Year: 2006
Pages: 213

flylib.com © 2008-2017.
If you may any questions please contact us: flylib@qtcs.net