YACVCP (Yet another CurrentCulture vs. CurrentUICulture post)
The CultureInfo class and particularly its properties CurrentCulture and CurrentUICulture are often a source of confusion when people are confronted with them for the first time. Many articles and blog posts about this topic have been published in the past unfortunately including some which don't tell the whole story (and not to mention some which are simply incorrect). Personally I think this is reason enough to post "yet another one". But I'm also adding a little twist to my post. While most existing posts simply state "these are the properties, this is how you use them" I want to start from the end user's point of view and then move on to how all this relates to the CultureInfo class.
So, let's say you're in the US. You just installed Windows Vista and kept all the US-related default settings like the keyboard layout, formats or the location. You log in and everything you see like your Windows Explorer, Internet Explorer, Media Player and so forth is in English as expected. And of course it should be. After all you installed the English version of Vista. Well, that's close enough for a "real" end user but for a developer it's interesting to know that actually there are no separate language versions of Vista. Instead there is one version of the binaries and a language pack for each supported language. In other words when you install the "English version" of Vista you really install Vista (which is language-agnostic) and the English language pack (see also Windows Vista Ultimate language pack release information). Side note: This is not the case with earlier versions of Windows which require the English version in order to install a language pack (see also What are the system requirements of Windows MUI).
At this point I'd like to introduce a little sample application which is both correctly globalized and localized into German with English being the neutral language (i.e. the one that will be used if there are no resources available for the current display language). That means that - based on the OS settings - the date and time is formatted correctly and the right UI resources are used. On our English Vista with default settings it looks like this:
The question is what happens when we install the German language pack for Vista (see the link above if you’re running Vista Ultimate and want to give this a try). Just installing it won't have any effect. However, once it's installed there is a new option on the Keyboards and Languages tab of the Regional and Language Options dialog called Choose a display language.
This option is only available if there is more than one language pack installed. Let's change the display language to Deutsch (German) and log off and on again in order for the change to take effect. Now the Windows UI is in German but if you for example open a folder in Windows Explorer and look at any date or file size you'll notice that these strings are still formatted using the culture en-US. This is the correct behavior since we have only changed the display language but not the current format. Thus my little sample application will look like this now:
Like Windows it's using localized resources but still uses the American way of date and time formatting. So, how do we change the format of dates (or numbers)? From an end user's perspective this is done through the Formats tab which is also located on the Regional and Language Options dialog. This setting is absolutely independent from the selected display language and is always available even if there is only one Windows language pack (the one that came on the Vista DVD) installed. Changing it from English (United States) to German (Germany) (or Deutsch (Deutschland) respectively in case you have changed the display language to German) will result in applications displaying dates, numbers, etc. in the formats for the culture de-DE (assuming that the application in question is globalized correctly).
Back to CultureInfo. The screenshots of my sample application have already given away what CurrentCulture and CurrentUICulture are about:
CurrentUICulture is what Windows refers to as the "display language" (some people also call it "UI language"). It is used by applications (and the OS) to determine which UI resources to load - i.e. (slightly simplified) either the resources for the current UI culture or neutral resources in case there are no resources for the UI culture. Or as the MSDN .NET class reference puts it: The CurrentUICulture is "the CultureInfo that represents the current culture used by the Resource Manager to look up culture-specific resources at run time". A reason (other than testing purposes) to set the UI culture would be to allow the end user to change the display language of a particular application independently regardless of the OS settings. An example for this is the language settings tool that is part of Office 2007.
CurrentCulture is for formatting strings and is primarily used in ToString() methods and other methods that convert values like numbers or dates into strings. I honestly cannot think of a good reason (other than testing purposes) to set this culture in code (not saying that there are none but they are exceptions).
Finally, I want to share a couple of lines of code I used in the sample application. The method CultureTestForm_Load() sets the labels that display the current (UI) culture and sets another label to DateTime.Now formatted using CultureInfo.CurrentCulture as expected.
private void CultureTestForm_Load(object sender, EventArgs e)
{
cultureValueLabel.Text = CultureInfo.CurrentCulture.Name;
uiCultureValueLabel.Text = CultureInfo.CurrentUICulture.Name;
dateTimeSampleLabel.Text = DateTime.Now.ToString(CultureInfo.CurrentCulture);
}
The next method is a bit more interesting. InitializeComponent() which in this case has been generated by the Visual Studio WinForms designer for me creates a new ComponentResourceManager in the first line. This object loads and applies resources based on the display language. However, this line (and obviously any call to that object) is only generated it the Localizable property is set to true (note that this is not actually a property of the Form class but a feature of the WinForms designer).
/// <summary>
/// Required method for Designer support - do not modify
/// the contents of this method with the code editor.
/// </summary>
private void InitializeComponent()
{
System.ComponentModel.ComponentResourceManager resources = new System.ComponentModel.ComponentResourceManager(typeof(CultureTestForm));
this.currentCultureLabel = new System.Windows.Forms.Label();
this.currentUICultureLabel = new System.Windows.Forms.Label();
this.dateTimeLabel = new System.Windows.Forms.Label();
this.uiCultureValueLabel = new System.Windows.Forms.Label();
this.cultureValueLabel = new System.Windows.Forms.Label();
this.dateTimeSampleLabel = new System.Windows.Forms.Label();
this.SuspendLayout();
//
// currentCultureLabel
//
resources.ApplyResources(this.currentCultureLabel, "currentCultureLabel");
this.currentCultureLabel.Name = "currentCultureLabel";
//
// currentUICultureLabel
//
resources.ApplyResources(this.currentUICultureLabel, "currentUICultureLabel");
this.currentUICultureLabel.Name = "currentUICultureLabel";
//
// dateTimeLabel
//
resources.ApplyResources(this.dateTimeLabel, "dateTimeLabel");
this.dateTimeLabel.Name = "dateTimeLabel";
//
// uiCultureValueLabel
//
resources.ApplyResources(this.uiCultureValueLabel, "uiCultureValueLabel");
this.uiCultureValueLabel.Name = "uiCultureValueLabel";
//
// cultureValueLabel
//
resources.ApplyResources(this.cultureValueLabel, "cultureValueLabel");
this.cultureValueLabel.Name = "cultureValueLabel";
//
// dateTimeSampleLabel
//
resources.ApplyResources(this.dateTimeSampleLabel, "dateTimeSampleLabel");
this.dateTimeSampleLabel.Name = "dateTimeSampleLabel";
//
// CultureTestForm
//
resources.ApplyResources(this, "$this");
this.AutoScaleMode = System.Windows.Forms.AutoScaleMode.Font;
this.Controls.Add(this.dateTimeSampleLabel);
this.Controls.Add(this.cultureValueLabel);
this.Controls.Add(this.uiCultureValueLabel);
this.Controls.Add(this.dateTimeLabel);
this.Controls.Add(this.currentUICultureLabel);
this.Controls.Add(this.currentCultureLabel);
this.Name = "CultureTestForm";
this.Load += new System.EventHandler(this.CultureTestForm_Load);
this.ResumeLayout(false);
this.PerformLayout();
}
This posting is provided "AS IS" with no warranties, and confers no rights.
Comments
Anonymous
March 11, 2008
There are a lot of blogs out that that tries to explain which is what, and why it is the way it is. ToAnonymous
April 26, 2008
Preguntaron en los grupos de noticias de asp.net, como obtener la cultura del browser del cliente. (y