WPF Set Application-Wide Culture, NumberFormat, Decimal Separator

Rustam Safin Dec 25, 2014

WPF by default uses built-in culture settings that come with .Net Framework libraries.

For example, for ru-RU culture double must look like 123456,789, for en-US like 123456.789, so if you don’t want your users to be angry, you must set your application culture at startup. However, our users want to see doubles like in en-US culture, e.g. 123456.789

There are two ways to do this:

1. Modify current culture settings. And that is awful    a. Not all controls support such behaviour    b. This code breaks all your hopes:

XmlLanguage xmlLanguage = XmlLanguage.GetLanguage("ru-RU");
FrameworkElement.LanguageProperty.OverrideMetadata(typeof (FrameworkElement),
                                                   new FrameworkPropertyMetadata(xmlLanguage));

XmlLanguage ignore all modifications to Thread.CurrentThread.CurrentCulture

2. Register your own culture (works if your users can get administator rights).

private const string CultureName = "ru-MIT";
private const string cultureEnglishName = "ru-MIT";
private const string cultureNativeName = "Русский (Мит)";

private static void Main(string[] args)
{
    CreateAndRegisterOwnCulture();
}

private static void CreateAndRegisterOwnCulture()
{
    var ownCulture = new CultureAndRegionInfoBuilder(CultureName, CultureAndRegionModifiers.None);

    var parentCulture = new CultureInfo("ru-RU");
    var region = new RegionInfo("RU");
    ownCulture.LoadDataFromCultureInfo(parentCulture);
    ownCulture.LoadDataFromRegionInfo(region);

    ownCulture.CultureEnglishName = cultureEnglishName;
    ownCulture.CultureNativeName = cultureNativeName;

    var nfi = (NumberFormatInfo) parentCulture.NumberFormat.Clone();
    nfi.NumberDecimalSeparator = ".";
    nfi.NumberGroupSeparator = " ";
    nfi.CurrencyDecimalSeparator = ".";
    nfi.CurrencyGroupSeparator = " ";

    ownCulture.NumberFormat = nfi;
    ownCulture.Parent = parentCulture;


    if (SystemHasMitCulture())
    {
        Console.WriteLine(">>> System already has own culture :)");
        return;
    }

    // Admin rights are needed here
    // CultureAndRegionInfoBuilder.Unregister(CultureName);

    try
    {
        // Admin rights are needed here
        Console.WriteLine(">>> Trying to set own culture");
        ownCulture.Register();
        Console.WriteLine(">>> Own culture set successfully");
    }
    catch (UnauthorizedAccessException)
    {
        Console.WriteLine(">>> Set own culture failed :(");
    }
    catch (InvalidOperationException)
    {
        Console.WriteLine(">>> Culture is already registered :)");
    }
}

private static bool SystemHasMitCulture()
{
    return CultureInfo.GetCultures(CultureTypes.UserCustomCulture).Any(ci => (ci.Name == CultureName));
}

The same code on Github Gist: https://gist.github.com/Snegovikufa/f051959dd105b7e56405

Rustam Safin

C# and Python developer