Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Dynamic localized WPF application with resource files

Trying to make my wpf appliaction localized, I followed this CodeProject tutorial.

I created my localized resource files (e.g., Resource.resx, Resource.en-US.resx) and bind these on a label element in the xaml

<Label Foreground="{StaticResource ApplicationForgroundColor}" FontSize="21"
           Content="{x:Static strings:Resources.title}"/> 

In a LocalizedService I set the CultureInfo on some change events

class LocalizationService
{
    public static void SetLanguage(string locale)
    {
        if (string.IsNullOrEmpty(locale)) locale = "en-US";
        System.Threading.Thread.CurrentThread.CurrentUICulture = new System.Globalization.CultureInfo(locale);
    }
}

This solution compiles and shows the correct resource value, but because of the static binding, I could not change the locale on runtime. When I change the content binding to a DynamicResource as follow shown there is no resource value shown.

Content="{DynamicResource strings:Resources.title}"

How could I bind text values to a localized resource file and change it dynamically on runtime?

like image 868
CapriSo Avatar asked May 11 '18 12:05

CapriSo


1 Answers

There is an other approach of Code Infinity here which also used a wrapper for dynamically binding on resource files. Here the INotifyPropertyChanged event informs your ui elements of a new binded resource file when the locale was changed.

You start to implement a BindingExtenstion:

public class LocalizationExtension : Binding
{
    public LocalizationExtension(string name) : base("[" + name + "]")
    {
        this.Mode = BindingMode.OneWay;
        this.Source = TranslationSource.Instance;
    }
}

Then you need to implement the connection between a ResourceManager and the CultureInfo which is implemented as a singleton to enable synchronized access. It defines the Source for the binded element and also fires the INotifyPropertyChanged` event on localization changes:

public class TranslationSource : INotifyPropertyChanged
{
    private static readonly TranslationSource instance = new TranslationSource();

    public static TranslationSource Instance
    {
        get { return instance; }
    }

    private readonly ResourceManager resManager = Resources.Strings.Resources.ResourceManager;
    private CultureInfo currentCulture = null;

    public string this[string key]
    {
        get { return this.resManager.GetString(key, this.currentCulture); }
    }

    public CultureInfo CurrentCulture
    {
        get { return this.currentCulture; }
        set
        {
            if (this.currentCulture != value)
            {
                this.currentCulture = value;
                var @event = this.PropertyChanged;
                if (@event != null)
                {
                    @event.Invoke(this, new PropertyChangedEventArgs(string.Empty));
                }
            }
        }
    }

    public event PropertyChangedEventHandler PropertyChanged;
}

Note that your localized resource files (e.g., Resource.resx, Resource.en-US.resx) are in the folder <Project>/Resources/Strings/Resources/ otherwise you need to update this part of the code.

Now you can use this new binding:

<Label Foreground="{StaticResource ApplicationForgroundColor}" FontSize="21"
       Content="{util:Localization title}"/>

To change the locale in runtime you need to set:

public static void SetLanguage(string locale)
{
    if (string.IsNullOrEmpty(locale)) locale = "en-US";
    TranslationSource.Instance.CurrentCulture = new System.Globalization.CultureInfo(locale);
}
like image 96
DTeuchert Avatar answered Oct 14 '22 06:10

DTeuchert