CultureInfo changes in UWP

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!

So there you go, this is a nice hack to retrieve a CultureInfo instance for the Regional Settings, which you can then use to parse and format values in your UWP (and WinRT) app! πŸ™‚

  • Pingback: Szumma #015 – 2015 45. hΓ©t | d/fuel()

  • Roman T

    There is also the namespace Windows.System.UserProfile giving some useful capabilities e.g.:

    using System.Globalization;
    using Windows.System.UserProfile;

    string LanguageTag = GlobalizationPreferences.Languages[0];
    CultureInfo oCultureInfo = new CultureInfo(LanguageTag);
    f (LanguageTag != CultureInfo.CurrentCulture.Name)
    {
    CultureInfo.CurrentCulture = oCultureInfo;
    }

    • Unfortunately, that also does not work correctly! If you have Display Language = “English (United Kingdom)”, Location = “Spain”, Regional Settings = “Portuguese (Portugal)”, you won’t get the correct “pt-PT” for the user selected regional settings!

      • Roman T

        And what is about CurrentInputMethodLanguageTag?

        using Windows.Globalization;

        string LanguageTag = Language.CurrentInputMethodLanguageTag;

        • Same issue… as far as I know, there isn’t any managed object/property that will return the user selected regional settings, just the “trick” presented in this article!

          • Roman T

            After changing some system settings I get in my new UWP app (Windows 10) following values. The thread shows region defined as application default language. This is, what I do not want and why I came to this discus blog. However, I can accept programmatically change to culture of display/input as intended for globe users instead of region/format setting. The location of the user seems not to have relevance, although I would maybe like to know how to get it. For my opinion, Windows should equalize β€œFormat” setting to first chosen language from the list meaning as culture of the user.

            Example:

            MS Visual Studio 2015 parameter Package.appxmanifest – Application – Default language: nl
            Windows – Settings – Time & Language – Region & Language – Country or region: Spain
            Windows – Settings – Time & Language – Region & Language – Languages: Deutsch (Γ–), English (US)
            Windows – Settings – Time & Language – Region & Language – Related settings – Region – Format – Portugese (Angola)
            Windows – Settings – Time & Language – Region & Language – Related settings – Region – Location – Home location: Spain (= Country or region)

            using System.Globalization;
            using Windows.Globalization;
            using Windows.Globalization.DateTimeFormatting;
            using Windows.System.UserProfile;
            …
            ? GlobalizationPreferences.Languages[0];
            “de-AT”
            ? GlobalizationPreferences.Languages[1];
            “en-US”
            ? Language.CurrentInputMethodLanguageTag;
            “de-AT”
            ? CultureInfo.CurrentCulture.Name;
            “nl”
            ? RegionInfo.CurrentRegion.Name;
            “NL”
            ? new DateTimeFormatter(“longdate”, new[] { “US” }).ResolvedLanguage;
            “pt-AO”

            If I clean Package.appxmanifest – Application – Default language (as empty), the compiler shows warning and the execution differences taking system culture of display/input.
            ? CultureInfo.CurrentCulture.Name;
            “de-AT”
            ? RegionInfo.CurrentRegion.Name;
            “AT”
            In fact, I would not have to look for any issue if there were no warning or default language to set in Package.appxmanifest!