In a country like Canada where there are two official languages it makes good business sense to design your applications with localization as a strategy. Windows Presentation Foundation provides the means to localizing applications. There are a few localization strategies available to developers. There are 3 that I’d like to touch base on in this article:
- Localizing WPF using resource in a .resx file format
- Localizing WPF using LocBaml
- Using a database to store localized information
Localizing WPF Using .resx Files
The .resx resource file format consists of XML entries, which specify objects and strings inside XML tags. One advantage of a .resx file is that when opened with a text editor (such as Notepad or Microsoft Word) it can be written to, parsed, and manipulated. Apart from any binary information stored in a .resx file it is completely readable and maintainable.
There are 7 key steps in creating a localized resource using this approach:
- Create a new or open an existing WPF project, add a resource file and call the new resource file Resource1.resx.
- Add an entry in the Resource1.resx file. Call the entry something you’ll remember. You will need to use this name to connect it with object that will use this text later on. Originally this method will have its scope set to internal, be sure to change the scope to public in the code behind.
- In the main form XAML file add namespace to window definition (e.g. xmlns:Resources="clr-namespace: WPFLocalizationRESX")
- In the controls content bind the resource to the control (e.g. <Label Content="{x:Static Resources:Resource1.Label1}" Margin="1,1,1,1"/>)
- Copy the resource file created in step 1 and rename it to Resource1_fr-CA.resx.
- Change the text of the resource entry in Resource1_fr-CA.resx
- In App.xaml.cs add a constructor to set the CurrentUICulture. Be sure to add the using directives using System.Globalization; and using System.Threading;
The sample project included with this blog entry is a demonstration of using .resx files to localize your applications. By changing the Thread.CurrentThread.CurrentUICulture = Thread.CurrentThread.CurrentCulture; line in the App.XAML.CS:App class you can simulate how your application will behave based in different cultures. For example changing the previous line to Thread.CurrentThread.CurrentUICulture = new System.Globalization.CultureInfo("fr-CA"); will simulate a French Canadian culture.
Using this approach has a couple of things going for it. First there is good support for editing .resx files within the Visual Studio environment. It also provides focus at the resource entry level.
There are however a couple of issues that may present obstacles to integrating this approach in your project. Binding the control for the text that needs changing requires that the XAML be changed to point to the resource file and binding using this method can only be applied to dependency properties in the XAML.
Localizing WPF using LocBaml
Microsoft has published a utility that will parse a resource DLL created by a WPF application. That utility is called LocBAML. The source code for LocBAML can be found here.
In order to develop an application that can be localized using LocBAML follow these steps:
- Specify a culture in the project file using the <UICulture> tag (e.g. <UICulture>en-CA</UICulture>)
- Add Uids to you XAML files. Uids are used to keep track of changes to your XAML files. To add Uids to your files run updateuid on your project file (e.g. msbuild /t:updateuid WPFApp.csproj).
- Build the application. This will create the main application assembly and a language resource assembly. If your current local settings are set to English Canadian the resource assembly will be created in the ..\Debug\en-CA\ directory.
- Copy the LocBAML.exe file to the resource assembly directory and run LocBAML.exe on the resource assembly.
- Running LocBAML.exe will create a CSV file listing all the components and their text values. Syntax for the switches used by LocBAML.exe are:
- parse or -p: Parses Baml, resources, or DLL files to generate a .csv or .txt file.
- generate or -g: Generates a localized binary file by using a translated file.
- out or -o [filedirectory]: Output file name.
- culture or -cul [culture]: Locale of output assemblies.
- translation or -trans [translation.csv]: Translated or localized file.
- asmpath or -asmpath: [filedirectory]: If your XAML code contains custom controls, you must supply the asmpath to the custom control assembly.
- nologo: Displays no logo or copyright information.
- verbose: Displays verbose mode information.
- Create a new resources assembly by running LocBAML.exe using the /generate switch (e.g. LocBAML.exe /generate en-CA/WPFApp.resources.dll /trans:WPFApp.csv /outc:\ /culture:fr-CA
- Now you’re able to create a new culture specific folder to store the resource. In step 5 we built a French Canadian resource so the correct folder would be fr-CA. Copy the assembly built in step 5 into the fr-CA directory.
Using LocBAML to create culture resources has a couple of advantages over the .resx method mentioned at the beginning of this article. Localization can be performed without the original source and localization does not need to be part of the development process. In addition binding to properties requires no change to the XAML and any change can be bound to any property.
LocBAML focused resource granularity is at the BAML resource level and will overwrite any existing CSV files. The tool will also fail to generate correct CSV files if a resource contains a comma.
Using a database to store localized information
If your application is connected to a database it is possible to store string translations in the database and query for the appropriate string translation at runtime. Binding data in XAML is inherent in the mark-up language.
Here are an excellent series of articles describing how to connect to different data sources using XAML. In short an application developer can bind at runtime to the results of a database query and display the resulting text to the user.
Best Practices for WPF UI Design
When you design a WPF based UI, these are a few best practices to keep in mind:
- Write your UI in XAML; avoid creating UI in code. When you create your UI using XAML, you expose it through built-in localization APIs.
- Avoid using absolute positions and fixed sizes to lay out content; instead, use relative or automatic sizing.
- Use SizeToContent and keep widths and heights set to Auto.
- Avoid using Canvas to lay out UIs.
- Use Grid and its size-sharing feature.
- Provide extra space in margins because localized text often requires more space. Extra space allows for possible overhanging characters.
- Enable TextWrapping on TextBlock to avoid clipping.
- Set the xml:lang attribute. This attribute describes the culture of a specific element and its child elements. The value of this property changes the behaviour of several features in WPF. For example, it changes the behaviour of hyphenation, spell checking, number substitution, complex script shaping, and font fall-back. See Globalization for the Windows Presentation Foundation for more information about setting the xml:lang Handling in XAML.
- Create a customized composite font to obtain better control of fonts that are used for different languages. By default, WPF uses the GlobalUserInterface.composite font in your Windows\Fonts directory.
- When you create navigation applications that may be localized in a culture that presents text in a right-to-left format, explicitly set the FlowDirection of every form.
References:
WPF Application Quality Guide
How to: Localize an Application
Globalization for the Windows Presentation Foundation
LocBaml Tool Sample
Thanks,
John Hinz
ISV Developer Advisor
Microsoft Canada