Update: There’s now a part 2 for this article!

Since the very first versions of the .NET Framework, developers had the System.Globalization namespace “containing classes that define culture-related information, including language, country/region, calendars in use, format patterns for dates, currency, and numbers, and sort order for strings.”

One of the most useful classes in this namespace is the CultureInfo class!

To demonstrate the usage of this class, take a look at this really simple console app code:

using System ; using System . Globalization ; class Program { static void Main ( string [ ] args ) { Console . WriteLine ( "CurrentCulture: {0}" , CultureInfo . CurrentCulture ) ; Console . WriteLine ( "CurrentUICulture: {0}" , CultureInfo . CurrentUICulture ) ; } }

If you run the above code with different system configurations, this is what it would output:

// Display Language = "English (US)", Location = "United States", Regional Settings = "English (US)" CurrentCulture: en-US CurrentUICulture: en-US // Display Language = "English (US)", Location = "United States", Regional Settings = "Portuguese (Portugal)" CurrentCulture: pt-PT CurrentUICulture: en-US // Display Language = "English (United Kingdom)", Location = "Spain", Regional Settings = "Portuguese (Angola)" CurrentCulture: pt-AO CurrentUICulture: en-GB

As you can see from the above results, the CurrentCulture and CurrentUICulture property values are inferred respectively from Regional Settings and Display Language; the Location however, doesn’t seem to have any effect over these two properties.

This feature allowed any app to show data using the proper currency, date, and number formats, even if the app itself wasn’t localized for those cultures!

But then came WinRT with the Windows.Globalization namespace as a replacement, and that apparently affected the way the CultureInfo class behaved…

To show the differences, I’ve created a blank Windows 8 app, and set the following code in the MainView.xaml.cs file:

using System ; using System . Globalization ; using Windows . UI . Popups ; using Windows . UI . Xaml . Controls ; public sealed partial class MainPage : Page { public MainPage ( ) { this . InitializeComponent ( ) ; this . Loaded += MainPage_Loaded ; } private void MainPage_Loaded ( object sender , Windows . UI . Xaml . RoutedEventArgs e ) { var messageDialog = new MessageDialog ( string . Format ( "CurrentCulture: {0}" + Environment . NewLine + "CurrentUICulture: {1}" , CultureInfo . CurrentUICulture , CultureInfo . CurrentCulture ) ) ; messageDialog . ShowAsync ( ) ; } }

These are the results of running the above code:

// Display Language = "English (US)", Location = "United States", Regional Settings = "English (US)" CurrentCulture: en-US CurrentUICulture: en-US // Display Language = "English (US)", Location = "United States", Regional Settings = "Portuguese (Portugal)" CurrentCulture: en-US CurrentUICulture: en-US // Display Language = "English (United Kingdom)", Location = "Spain", Regional Settings = "Portuguese (Angola)" CurrentCulture: en-GB CurrentUICulture: en-GB

As you can see here, both the CurrentCulture and CurrentUICulture property values are now based on the selected Display Language!

In my personal opinion, this change of behavior is wrong for various reasons, but mostly because it breaks the expected known behavior of the CultureInfo class properties.

Right now you might be thinking that the impact of this change is really small, but it might actually be bigger than expect due to a specific feature: Cortana!

As of today, Cortana is still only available in a few locations, and as such, most users have “faked” their location in order to get Cortana active on their devices, but maintained the Regional Settings matching their real location!

Retrieving the “proper” CurrentCulture

One could use the Windows API GetUserDefaultLocaleName to retrieve the Regional Settings, but this only works on full Windows 10, so it’s not a “universal” way of doing it!

However, I’ve found that if you create a DateTimeFormatter instance with “US” as language, you can retrieve the culture name from the DateTimeFormatter.ResolvedLanguage property!

And here is a simple code example demonstrating how to do it:

using Windows . Globalization . DateTimeFormatting ; public class CultureInfoHelper { public static CultureInfo GetCurrentCulture ( ) { var cultureName = new DateTimeFormatter ( "longdate" , new [ ] { "US" } ) . ResolvedLanguage ; return new CultureInfo ( cultureName ) ; } }

I honestly still don’t know how or why does this work with that Magic String™ (others might also do the trick though), but it does, and at this stage all I care are positive results!