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
| Pros | Cons |
---|
XAML | | 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:
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.
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.