Best Practices: Localize a WPF application

Coordinator
Apr 10, 2009 at 3:31 PM
Edited Aug 3 at 3:11 PM
.
An updated version of this article can be found here: Localization: Localize a WPF Application
.


Microsoft encourages you to use their tool “LocBaml” for localizing WPF applications (see MSDN). Unfortunately, this tool is still not production-ready and it has some serious disadvantages when you have to sign the assemblies of your application.

I prefer the usage of the “old” ResX files for localizing my WPF applications. They are very well supported by Visual Studio and I like the fallback strategy of the resources system when a resource item isn’t found.


How to use a ResX file in a WPF application:
  1. Create a Resource (ResX) file in your project or you can reuse the Properties/Resources.resx file.
  2. In the Visual Studio Resource designer you have to change the Access Modifier from Internal to Public. This can be found in the top toolbar of the designer.
  3. Add the namespace to your XAML View:
xmlns:p="clr-namespace:Jbe.TestSuite.Infrastructure.Shell.Properties"
  1. The Resources can be accessed via the x:Static markup extension of XAML:
<MenuItem Header="{x:Static p:Resources.FileMenu}">
What about Images?

If you have the need to localize images then it definitely gets trickier. The ResX files support only the native bitmap representation of images whereas WPF uses a managed version called BitmapSource. Therefore, you have to convert a GDI “Bitmap” object into a “BitmapSource” object. The CompositeExtensions library contains the method CreateBitmapSource in the class ResourceService that does the trick.
public static BitmapSource CreateBitmapSource(System.Drawing.Bitmap bitmap)
{
    return Imaging.CreateBitmapSourceFromHBitmap(bitmap.GetHbitmap(), IntPtr.Zero,
        new Int32Rect(0, 0, bitmap.Width, bitmap.Height), BitmapSizeOptions.FromEmptyOptions());
}
How to configure the application language?

By default the .NET Framework uses the language of the operating system. I believe this behavior should be fine for most customers. However, some customers or software testers like to define the language for the application independent of the operating system settings.

I use the Settings designer that Visual Studio offers to implement the language configuration. In the Settings designer I just define a Culture and UICulture string property. One of the first lines when the application start calls this method:
private void InitializeCultures()
{
    if (!string.IsNullOrEmpty(Settings.Default.Culture))
    {
        Thread.CurrentThread.CurrentCulture = new CultureInfo(Settings.Default.Culture);
    }
    if (!string.IsNullOrEmpty(Settings.Default.UICulture))
    {
        Thread.CurrentThread.CurrentUICulture = new CultureInfo(Settings.Default.UICulture);
    }
}
The code snippet above reads the culture settings from the configuration file and sets it for the whole application. Now you can modify the “App.config” file when you need to start the application with another language.

Don’t get confused with CurrentCulture and CurrentUICulture. These two properties represent the “Regional and Language Options” which can be found in the Windows Control Panel.
  • CurrentCulture represents the “Format” tab of the “Regional and Language Options”. This setting is responsible for formatting and parsing of values.
  • CurrentUICulture represents the second part of the “Keyboards and Languages” tab, the “Display Language”. This property controls which language of the resources are loaded and shown to the user.
Note: This discussion is only about CurrentUICulture.


Part 2 discusses the usage of CurrentCulture in WPF applications.

Code Download: http://compositeextensions.codeplex.com/Release/ProjectReleases.aspx?ReleaseId=27102
Oct 20, 2010 at 5:58 PM
Edited Oct 20, 2010 at 7:11 PM

Above for step 3 you have: xmlns:p="clr-namespace:Jbe.TestSuite.Infrastructure.Shell.Properties"

In the actual code you have: xmlns:p="clr-namespace:WpfLocalizationDemo.Properties"

Obviously, I see that it is not wrong, just your project namespace was Jbe.TestSuite.Infrastructure.Shell.  It just through me off for a second.

May 30, 2013 at 9:05 AM
hi

Thank you for sharing yours experience

AFAIU this will work only if you have resources files in the same assembly where xaml is located. But we have a separate resource project in winforms app that is linked only from client project. And localization is made using ResourceManager

to reuse this project in the xaml I've added new MarkupExtension class
public class Localize : MarkupExtension
{
    static Regex _reg = new Regex(@"[\w\d_]*", RegexOptions.Compiled);
    string _res;
    public Localize(string res)
    {
        _res = res;
    }
    public override object ProvideValue(IServiceProvider serviceProvider)
    {
        var m = _reg.Match(_res);
        return m.Success 
            ? string.Format("{0}{1}", m.Value.Localize(), _reg.Replace(_res, ""))
            : _res.Localize();
    }
}
where Localize is string extension method that executes legacy code.
Also I've modified AssemblyInfo file in the assembly where Localize class is and have added new line

[assembly: XmlnsDefinition("http://schemas.microsoft.com/winfx/2006/xaml/presentation", "YourNameSpaceHereWereLocalizeClassExists")]

this allows to localize WPF labels and buttons like this:
<Setter Property="Content" Value="{Localize ResIDHere}"/>
<TextBlock Text="{Localize ResIDHere:}"/>
please make a note that colon in last sample will apper in the TextBlock text after localized string due to regex _reg in the code.