[ACCEPTED]-How to set and change the culture in WPF-localization

Accepted answer
Score: 11

I'm going to chime in here.

I successfully 16 did this using the OverrideMetadata() method that the OP mentioned:

var lang = System.Windows.Markup.XmlLanguage.GetLanguage(MyCultureInfo.IetfLanguageTag);
FrameworkElement.LanguageProperty.OverrideMetadata(
  typeof(FrameworkElement), 
  new FrameworkPropertyMetadata(lang)
);

But, I 15 still found instances in my WPF in which 14 the system culture was being applied for 13 dates and number values. It turned out these 12 were values in <Run> elements. It was happening 11 because the System.Windows.Documents.Run class does not inherit from 10 System.Windows.FrameworkElement, and so the overriding of metadata on FrameworkElement obviously 9 had no effect.

System.Windows.Documents.Run inherits its Language property from 8 System.Windows.FrameworkContentElement instead.

And so the obvious solution was 7 to override the metadata on FrameworkContentElement in the same 6 way. Alas, doing do threw an exception (PropertyMetadata is already registered for type System.Windows.FrameworkContentElement), and 5 so I had to do it on the next descendant 4 ancestor of Run instead, System.Windows.Documents.TextElement:

FrameworkContentElement.LanguageProperty.OverrideMetadata(
  typeof(System.Windows.Documents.TextElement), 
  new FrameworkPropertyMetadata(lang)
);

And that sorted out 3 all my issues.

There are a few more sub-classes 2 of FrameworkContentElement (listed here) which for completeness should 1 have their metadata overridden as well.

Score: 6

I'm not sure how to get around the "can't 7 call OverrideMetadata multiple times" exception.

As 6 a workaround, when the user changes UI cultures 5 in your app, you could restart your app 4 with that culture, passing in the new culture 3 as a command line argument. Unless your 2 users will be changing cultures often, this 1 sounds like a reasonable solution.

Score: 6

I never found a way to do exactly what I 10 asked for in the question. In my case I 9 ended up solving it by having all my usercontrols 8 inherit from a superclass that contained 7 this:

/// <summary>
///   Contains shared logic for all XAML-based Views in the application. 
///   Views that extend this type will have localization built-in.
/// </summary>
public abstract class ViewUserControl : UserControl
{
    /// <summary>
    ///   Initializes a new instance of the ViewUserControl class.
    /// </summary>
    protected ViewUserControl()
    {
        // This is very important! We make sure that all views that inherit 
        // from this type will have localization built-in. 
        // Notice that the following line must run before InitializeComponent() on 
        // the view. Since the supertype's constructor is executed before the type's 
        // own constructor (which call InitializeComponent()) this is as it 
        // should be for classes extending this
        this.Language = XmlLanguage.GetLanguage(CultureInfo.CurrentCulture.IetfLanguageTag);
    }
}

When the user changes the language 6 I then create new instances of any usercontrols 5 that are currently running.

This solved my 4 problem. However, I would still like a way 3 to do this "automatically" (i.e. without 2 having to keep track of any instantiated 1 objects).

Score: 5

Just my two cents: After almost going crazy 12 when trying to implement ComponentOne WPF 11 controls (DataGrid and C1DatePicker) with 10 my German language assembly I stumbled upon 9 this page.

This seems to be directing in 8 the right way: I just entered the above 7 code into my App.xaml.cs / Application_startup 6 routine and now German date/time formatting 5 for C1DatePicker finally works.

Got to test 4 DataGrid right after that.

    private void Application_Startup(object sender, StartupEventArgs e)
    {
        FrameworkElement.LanguageProperty.OverrideMetadata(
            typeof(FrameworkElement),
            new FrameworkPropertyMetadata(
            System.Windows.Markup.XmlLanguage.GetLanguage(CultureInfo.CurrentUICulture.IetfLanguageTag)));
    }

Thanks!

Update: Tested 3 C1DataGrid for WPF - works! This solved 2 all the problems I had with international 1 Date / Time settings in my Applications. Great!

Score: 4

Adaptive OverrideMetadata

Some form of reloading is inevitable, because 28 changing a control's Language property doesn't make 27 it update its text.

However, there's a way 26 of overriding the metadata which allows 25 you to set it once and have new controls automatically 24 use the current culture:

FrameworkElement.LanguageProperty.OverrideMetadata(
    typeof(FrameworkElement),
    new FrameworkPropertyMetadata(
        System.Windows.Markup.XmlLanguage.Empty,
        default(PropertyChangedCallback),
        _CoerceCurrentXmlLang));

where the CoerceValueCallback is

private static object _CoerceCurrentXmlLang(DependencyObject d, object baseValue)
{
    var lang = baseValue as System.Windows.Markup.XmlLanguage;
    var culture = System.Globalization.CultureInfo.CurrentUICulture;
    return lang != null && lang.IetfLanguageTag.Equals(culture.Name, StringComparison.InvariantCultureIgnoreCase)
        ? lang
        : System.Windows.Markup.XmlLanguage.GetLanguage(culture.Name);
}

By 23 itself this isn't quite enough, because 22 newly created controls will get the default 21 value System.Windows.Markup.XmlLanguage.Empty without it being coerced. However, if 20 you then set xml:lang="" in your windows' XAML, that 19 will be coerced, and then each new control 18 will see that it inherits a value from its 17 parent and will coerce it. The result is 16 that new controls added to that window will 15 use the current language.

PS As with many 14 things in WPF, it would be quite a bit simpler 13 if they hadn't been so keen to keep things 12 internal. DefaultValueFactory would be a far more elegant way of doing 11 this.

Reloading

The most extreme, but therefore reliable, way 10 of reloading is just to create a new main 9 window and discard the old one.

Almost as 8 extreme but not quite is to arrange for 7 the language setting to be changed only 6 in a very simple pane of the main window 5 with very little loaded, and that very little 4 to be entirely databound to a viewmodel 3 which supports forcing a property changed 2 notification for everything.

Existing answers 1 to this question have other suggestions.

Score: 3

I pretty much had the same issue.

I found 8 this: http://www.codeproject.com/Articles/35159/WPF-Localization-Using-RESX-Files (might not be the original source).

It 7 discusses a markup extension named "UICultureExtension" which 6 is attached to the Language property of 5 all framework elements that need localization 4 (in XAML).

If you raise a UI language changed 3 event, static extension managers in the 2 background will update all registered framework 1 elements.

Score: 1

It's not completely your answer, but I used 2 this to reload the resources. But you still 1 need to reload the windows...

 List<Uri> dictionaryList = new List<Uri>();
        foreach (ResourceDictionary dictionary in Application.Current.Resources.MergedDictionaries)
        {
            dictionaryList.Add(dictionary.Source);
        }
        Application.Current.Resources.MergedDictionaries.Clear();
        foreach (Uri uri in dictionaryList)
        {
            ResourceDictionary resourceDictionary1 = new ResourceDictionary();
            resourceDictionary1.Source = uri;
            Application.Current.Resources.MergedDictionaries.Add(resourceDictionary1);
        }
Score: 1

I use the merged resource dictionary/dynamic 5 resource appproach to change my strings. But 4 for correct automatic date/time/other regional 3 formatting I am setting the language on 2 Application.Current.MainWindow.Language, it gets inherited by the children and updates 1 automatically. At least on Net 5.0...

var l = System.Globalization.CultureInfo.CreateSpecificCulture(localeName);
                
Thread.CurrentThread.CurrentUICulture = l;
Thread.CurrentThread.CurrentCulture = l;
System.Globalization.CultureInfo.DefaultThreadCurrentCulture = l;
System.Globalization.CultureInfo.DefaultThreadCurrentUICulture = l;
// Order is important!!! Set Threads before MainWindow.Language, 
// otherwise regional settings are inconsistent

Application.Current.MainWindow.Language = XmlLanguage.GetLanguage(l.Name);

More Related questions