Localization in WPF

I just got a question at work about how to do Localization in WPF, and fortunately we have done a pretty nice solution to that I must say. So why not post that here as well.

First of all, there are several ways to achieve localization in WPF, you can read Microsoft’s way of doing it here http://msdn.microsoft.com/en-us/library/ms788718.aspx . But I would like to do it in a somewhat different way. In my WPF application I use the MVVM design pattern, so wouldn’t it be nice if all resources are accessable through the View’s datacontext? So that you can data bind to the resource strings in the same way as you data bind to all other data in the ViewModel.

I’ll try to explain it for you here and provide you with some code snippets.

End result
First of all let’s look at the end result. This is how it will look like in xaml, pretty nice I think.

<Button x:Name="OkButton" Content="{Binding Resources.Application_OK_Button, FallbackValue=OK}" Margin="4" … />

ViewModelBase
Our WPF application is following the MVVM design pattern, and all ViewModels in our application inherits a base class, ViewModelBase. This means that all Views in our application will be able to data bind to any property we specify in the base class.

In ViewModelBase class we have a property called Resources that provides each View with access to the language resources.

The Resources property in ViewModelBase:

public Infrastructure.Properties.Resources Resources
{
        get { return GlobalResources.Resources; }
}

The Resources property in the View Model base class accesses the application resources through a static class called GlobalResources that resides in a separate assembly. The GlobalResources class has among other things a property called Resources, but also some events that we can listen to when the language is changed. In my solution you can actually change language at runtime! Sweet.

Resources
Below is the implementation of the GlobalResources static class in the assembly that holds all the different language resource files.

    public static class GlobalResources
    {
        public delegate void LanguageChangedEventHandler(object sender, LanguageChangedEventArgs e);

        public static event LanguageChangedEventHandler LanguageChanged;

        static Resources res;

        public static Properties.Resources Resources
        {
            get
            {
                if (res== null)
                    res= new Properties.Resources();

                return res;
            }
        }

        public static void ChangeLanguage(string language)
        {
            CultureInfo culture = new CultureInfo(language);
            Properties.Resources.Culture = culture;
            Thread.CurrentThread.CurrentCulture = culture;
            OnLanguageChanged(null, new LanguageChangedEventArgs { NewCulture = Properties.Resources.Culture });
        }

        public static void OnLanguageChanged(object sender, LanguageChangedEventArgs args)
        {
            LanguageChangedEventHandler handler = LanguageChanged;

            if (handler != null)
            {
                handler(sender, args);
            }
        }

. . .

All resource files are regular .resx files, we have used English as default and then translated to several languages.

We then have an event handler in the ViewModelBase class that basically notifies the View through PropertyChanged event that the Resources has changed so that all UI elements can properly update themselves to reflect the new string resources.

        void OnLanguageChanged(object sender, EventArgs args)
        {
            OnPropertyChanged("Resources");
        }

Problem with decimal separator etc.
But there is an issue with changing language in WPF, and that is that all FrameworkElements in WPF uses the default Language property during data binding and value conversion, and the default for that is English. We really don’t want to write code in each element in the Views that sets the Language property, instead we want some automatic way of setting the Language property’s default value when the language is changed. What we did is to override the default value for Language property on FrameworkElement and that makes sure that all elements in the View will use the current selected language during data binding and value conversions. BUT, you can only override that once. The second time you try to set the default value you will get an exception.

In App.xaml.cs we have an event handler for the Language change event

GlobalResources.LanguageChanged += GlobalResources_LanguageChanged;

And the following code to handle the Language property override

        void GlobalResources_LanguageChanged(object sender, LanguageChangedEventArgs e)
        {
            UpdateFrameworkElementLanguage(e.NewCulture);
        }

        private static void UpdateFrameworkElementLanguage(CultureInfo culture)
        {
            // Workaround to have all dates, times, numbers bound to UI elements to be presented in the local culture
            // because by default all UI elements during binding and value converting use the en-US locale
            // TODO: need to specify DependencyPropertyKey since this code causes an error if we change it more than once
            try
            {
                FrameworkElement.LanguageProperty.OverrideMetadata(
                    typeof(FrameworkElement),
                    new FrameworkPropertyMetadata(XmlLanguage.GetLanguage(culture.IetfLanguageTag)));
            }
            catch (Exception )
            {

            }
        }

That’s it, you then have an easy way of handling localization and even the possibility to change language at runtime.
We solved the issue above with not being able to override the Language property more than once by displaying a message box to the user that he/she needs to save his work and restart the application. We did not put any effort in fixing it so that you can change language more than once during runtime. Perhaps some of you out there has a nice solution you want to share :)

Finally at application start after a successful login we call ChangeLanguage in the static GlobalResources class with the selected language we have stored in the user settings for the application.

Happy coding!

Advertisements
  1. Hi is there any working example that implements the same code .

  2. Hi, just checked if I had the source code left but did not find it. So, now I don’t have any working example. But if you add the Resources property as I described above to your ViewModel (I placed it in a ViewModelBase class that all my VMs inherit from so I get the functionality in all VMs) and after that you can write the xaml as I did above.

    • Alex
    • March 13th, 2012

    Thanx! Just what i need right now.

  1. May 11th, 2011

Leave a Reply

Fill in your details below or click an icon to log in:

WordPress.com Logo

You are commenting using your WordPress.com account. Log Out / Change )

Twitter picture

You are commenting using your Twitter account. Log Out / Change )

Facebook photo

You are commenting using your Facebook account. Log Out / Change )

Google+ photo

You are commenting using your Google+ account. Log Out / Change )

Connecting to %s

%d bloggers like this: