MULTIMEDIA

Application Patterns and Tips : Localize a WPF Application

8/21/2012 4:10:40 PM
There are two methods of localizing a WPF application: using XAML and using resources and data binding. Unfortunately, either way, compared to Windows Forms applications, doing localization in WPF is currently a real chore. Table 1 highlights some of the pros and cons of the two approaches.
Table 1. Pros and Cons of WPF Localization techniques
 ProsCons
XAML
  • Localization completely separate from development process

  • More efficient than data binding

  • Easy to modify CSV files

  • No easy way to repeat process with UI updates, unless you are extremely good at version control

  • The tool is unsupported

  • Hard to integrate with resource files

  • No Visual Studio support

Resources and data binding
  • Data-binding is easy and well-understood by WPF developers

  • Bindings are strongly typed and checked by the compiler

  • Resources are relatively easy to manage, and are similar to the other .Net platforms

  • No type conversion

  • You must manually map each UI element to a resource

  • Only works on dependency properties

  • Some tools, such as Blend, do not load resources from satellite assemblies (yet)


XAML Localization

To localize your WPF application using the XAML method, follow these steps:

1.
Manually edit the project file and add <UICulture>en-US</UICulture> under the <PropertyGroup> section.

2.
Add this line to your AssemblyInfo.cs file:

[assembly: NeutralResourcesLanguageAttribute("en-US", UltimateResourceFallbackLocation.Satellite)]

					  

3.
Open a command prompt and navigate to your project’s directory. Run the command:

msbuild /t:updateuid

This will generate a UID for every WPF element, modifying your XAML files in the process. You should never manually edit these UIDs.

Note

msbuild is located with the .Net framework files, and the easiest way to run it is to start the command prompt with the shortcut that Visual Studio installs; this will initialize the correct environment settings to access the .NET Framework binaries.

4.
Rebuild the project. A directory called en-US will appear in the output directory. This contains the resource DLL.

5.
Obtain the LocBaml tool from the Windows SDK. On my computer, it was packaged in C:\Program Files\Microsoft SDKs\windows\v7.0\Samples\WPFSamples.zip. To get it to work in .Net 4, I had to recreate the project from scratch and change the target framework to .Net 4.0. By the time you read this, the tool may work out of the box. However, the tool is not officially supported by Microsoft. (Are you starting to get nervous about this method yet?)

6.
Copy LocBaml.exe, the generated resource DLL, and your application executable to the same folder and run this command from a prompt:

locbaml.exe /parse myapp.resources.dll /out:translate_en-US.csv

7.
Copy the file translate_en-US.csv to files with different names, depending on your target cultures, e.g., translate_it-IT.csv, translate_fr-CA.csv.

8.
Open the csv files in a program that can edit them (such as any text editor or Excel) and translate the text into the target language. You can also modify things like file paths (in the case that you have different images for cultures, for example).

Note

It’s important to realize that other fields besides UI text will be present. When giving the files to translator, you may want to specify which fields need translating.

9.
Create a new directory for the localized DLL, e.g. “it-IT.”

10.
Create a localized resource DLL by running:

locbaml.exe /generate myapp.resources.dll /trans: translate_it-IT.csv /out :.\it-IT /cul:it-IT

					  

Copy the resource directory to the output directory, next to the existing en-US directory.

If you want to easily see the differences, you can add some code to the application startup that will set the UI culture to be to the region specified in Control Panel.

public App()
{
    //set UI to have whatever be same as non-UI,
    //which is what is in Control Panel
    Thread.CurrentThread.CurrentUICulture =
                     Thread.CurrentThread.CurrentCulture;
}

As you can see, this method is a little complex and tedious, especially if you need to make changes after localization has begun (make sure you have excellent version control practices). It’s recommended that you build your own set of tools to manage this process, even if it’s just a set of batch files.

Figures 1 and 2 show a localized WPF app running in English and Italian, with translated text and different resources.

Figure 1. The localized app running in the default culture.


Figure 2. Changing the system’s region to Italy causes the app to pick the localized DLL. If Windows were using the Italian language pack, then the Yes and No on the message box would also be in Italian.

See the LocWPFXAML project in the sample code for a full example.

Resource File Localization

Rather than go through all of that, you can use resource files just like with Windows Forms.

1.
Create a global resource file and add strings, images, etc. to it.

2.
Copy and rename it with the desired culture, e.g., Resources.it-IT.resx. (Make sure that this file is in the same directory as the original Resources.resx) Building the project should result in culture-specific directory being created under the output directory.

3.
Create an XML namespace Properties in the Window where you want to use the localized resource:

xmlns:props="clr-namespace:LocWPFResources.Properties"

4.
Use data binding to attach the resources to XAML controls:

<Label x:Name="labelName" Grid.Row="0" Grid.Column="0"
Content="{x:Static props:Resources.labelName}" />

This is much simpler, but it does require more thought as you develop the UI of your application. Also, you can’t directly bind very much other than strings.

For example, to use an image from resources in a XAML Image control, you can do something like this:

public MainWindow()
{
    InitializeComponent();

    //set the image
    imageFlag.BeginInit();
    imageFlag.Source = CreateImageSource(Properties.Resources.flag);
    imageFlag.EndInit();
}

private ImageSource CreateImageSource(System.Drawing.Bitmap bitmap)
{
    using (MemoryStream stream = new MemoryStream())
    {
        bitmap.Save(stream, System.Drawing.Imaging.ImageFormat.Jpeg);
        stream.Position = 0;
        //the OnLoad option uses the stream immediately
        //so that we can dispose it
        return BitmapFrame.Create(stream,BitmapCreateOptions.None,
                 BitmapCacheOption.OnLoad);
    }
}

Note

Given the complexities of localization, you should definitely give the topic a lot of thought before deciding on a strategy. I encourage you to read the whitepaper and look at the samples located at http://wpflocalization.codeplex.com/.


See the LocWPFResources project in the sample code for a full example.

Other  
  •  20 Top Tips Sunrise & Sunset (Part 2)
  •  20 Top Tips Sunrise & Sunset (Part 1)
  •  70 Ways To Take Better Photos (Part 7) - Process your shots
  •  70 Ways To Take Better Photos (Part 6) - Wildlife, How to achieve excellent wildlife images
  •  70 Ways To Take Better Photos (Part 5) - Check you’re covered
  •  70 Ways To Take Better Photos (Part 4) - Monochrome, Adjust colour channels
  •  70 Ways To Take Better Photos (Part 3) - Portraits, Adjust light intensity
  •  70 Ways To Take Better Photos (Part 2) - Improve your vista shots
  •  70 Ways To Take Better Photos (Part 1)
  •  Go Outside And Play
  •  MEElectronics Air-Fi AF32
  •  Lenco iPT-223
  •  Adobe Photoshop CS5 : Working with Automate Commands - Creating a PDF Document
  •  Adobe Photoshop CS5 : Working with Automate Commands - Converting a Multi-Page PDF to PSD
  •  Corel Painter X : Working with Layers - More Furniture
  •  Corel Painter X : Working with Layers - The Chair
  •  Aperture 3.3 : Nipping at Lightroom’s heels
  •  Orbitsound T9 : Music of the spheres
  •  Jawbone Big Jambox
  •  Sony Shows Off Their New Product Range
  •  
    Top 10
    Nikon 1 J2 With Stylish Design And Dependable Image And Video Quality
    Canon Powershot D20 - Super-Durable Waterproof Camera
    Fujifilm Finepix F800EXR – Another Excellent EXR
    Sony NEX-6 – The Best Compact Camera
    Teufel Cubycon 2 – An Excellent All-In-One For Films
    Dell S2740L - A Beautifully Crafted 27-inch IPS Monitor
    Philips 55PFL6007T With Fantastic Picture Quality
    Philips Gioco 278G4 – An Excellent 27-inch Screen
    Sony VPL-HW50ES – Sony’s Best Home Cinema Projector
    Windows Vista : Installing and Running Applications - Launching Applications
    Most View
    Bamboo Splash - Powerful Specs And Friendly Interface
    Powered By Windows (Part 2) - Toshiba Satellite U840 Series, Philips E248C3 MODA Lightframe Monitor & HP Envy Spectre 14
    MSI X79A-GD65 8D - Power without the Cost
    Canon EOS M With Wonderful Touchscreen Interface (Part 1)
    Windows Server 2003 : Building an Active Directory Structure (part 1) - The First Domain
    Personalize Your iPhone Case
    Speed ​​up browsing with a faster DNS
    Using and Configuring Public Folder Sharing
    Extending the Real-Time Communications Functionality of Exchange Server 2007 : Installing OCS 2007 (part 1)
    Google, privacy & you (Part 1)
    iPhone Application Development : Making Multivalue Choices with Pickers - Understanding Pickers
    Microsoft Surface With Windows RT - Truly A Unique Tablet
    Network Configuration & Troubleshooting (Part 1)
    Panasonic Lumix GH3 – The Fastest Touchscreen-Camera (Part 2)
    Programming Microsoft SQL Server 2005 : FOR XML Commands (part 3) - OPENXML Enhancements in SQL Server 2005
    Exchange Server 2010 : Track Exchange Performance (part 2) - Test the Performance Limitations in a Lab
    Extra Network Hardware Round-Up (Part 2) - NAS Drives, Media Center Extenders & Games Consoles
    Windows Server 2003 : Planning a Host Name Resolution Strategy - Understanding Name Resolution Requirements
    Google’s Data Liberation Front (Part 2)
    Datacolor SpyderLensCal (Part 1)