WPF Localization
In WPF the localization process
is also based on resources but with different steps. Also, there are
some alternative techniques for accomplishing localization but we cover
the most common.
Code examples shown in this
section assume that your system’s regional settings are based on the
en-US (English-United States) culture. If your system is based on
different regional settings, replace en-US with the culture information
that suits your system.
|
When you compile a WPF project,
the XAML code is parsed into a more efficient file format known as BAML
(Binary Application Markup Language). Generally each Baml file
represents a resource that is then linked into the executable storing
all resources. To localize a WPF application you need to localize Baml
objects and put the result into a satellite assembly. This is
accomplished using a command-line tool named LocBaml.exe, which is
available for free from the MSDN. It is distributed as C# source code so
you need to open it inside Visual Studio and compile it.
Preparing the LocBaml tool
Until a new version of LocBaml is
available for .NET 4.0, you can download the previous version and
upgrade it manually. To accomplish this follow these steps:
1. | If not installed, install Visual C# on your machine (the Express Edition is also supported).
|
2. | |
3. | Uncompress the downloaded archive into any folder you like.
|
4. | Start Visual Studio 2010 and create a new Console Application with Visual C#, naming the project as LocBaml.
|
5. | Save the new project into a different folder than the downloaded source code.
|
6. | Remove
the Program.cs and AssemblyInfo.cs code file from the project. Notice
that the second file is just a duplicate of the one generated by the IDE
and so can be safely removed.
|
7. | Using the Project, Add Existing Item command, add all the code files (with .cs extension) from the downloaded source code folder to the current project folder.
|
8. | Add a reference to the following assemblies: WindowsBase.dll, PresentationCore.dll, PresentationFramework.dll
|
9. | In
the new project, add a folder named Resources and add to this new
folder the StringTable.resText file which you can pick from the
same-named folder of the original LocBaml code.
|
10. | After you’ve added the file, open the Properties window and set the Build Action property as Embedded Resource.
|
11. | Open the LocBaml.csproj project file with the Windows Notepad and add the following lines (if not already available) within an ItemGroup node:
<EmbeddedResource Include="Resources\StringTable.resText">
<LogicalName>Resources.StringTable.resources</LogicalName>
</EmbeddedResource>
|
12. | In
Solution Explorer click Properties and ensure that the
BamlLocalizaion.LocBaml is set as the startup object in the Application
tab.
|
Now build the project. At this point you have a new version of LocBaml.exe which targets the .NET Framework 4.0.
Localizing a WPF Application
When you have completed
the steps required to prepare LocBaml, imagine you want to create a
localized version for the Italian culture of a WPF application based on
English as the primary culture. Create a new WPF project with Visual
Basic and name it as WpfLocalization, and simply add the code shown in Listing 1 on the XAML side. The goal is to provide a WPF counterpart of the Windows Forms example shown in the previous section.
Listing 1. Preparing the User Interface Before Localization
<Window x:Class="MainWindow"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
Title="MainWindow" Height="350" Width="525">
<StackPanel>
<Button Name="Button1" Width="100" Margin="5"
Height="40" Content="Localized button"/>
<TextBlock Text="Localized text"
Margin="5"
Name="TextBlock1"/>
</StackPanel>
</Window>
|
The
first step required to localize a WPF application is to specify the
neutral-language specification at assembly level. Click the Show All Files button in Solution Explorer, expand My Project, and double-click AssemblyInfo.vb; finally uncomment the following line of code:
<Assembly: NeutralResourcesLanguage("en-US",
UltimateResourceFallbackLocation.Satellite)>
This is required
because the application looks for localization resources inside external
satellite assemblies, and at least one culture must be provided as
neutral. This is simply the culture you are writing code with. The next
step is to open the project file, thus click the File, Open, File command and browse the project folder; then open the WpfLocalization.vbproj file. At this point you need to add the following line of Xml markup inside one of the PropertyGroup items:
<UICulture>en-US</UICulture>
This works with the
neutral language specification and ensures that a satellite assembly for
current culture resources will be generated. The successive step is
marking UI elements in XAML as localizable. This is accomplished by
adding an x:Uid attribute to
each localizable member, assigning an identifier equal or similar to the
element name. This task can be accomplished manually but can be
difficult if you have a lot of elements to mark as localizable, so the
most common option is running the MSBuild
compiler that automates this for you. Save the project, and then open a
command prompt pointing to the project folder. At this point write the
following command lines following the exact sequence shown:
msbuild /t:updateuid WpfLocalization.vbproj
msbuild /t:checkuid WpfLocalization.vbproj
The first command line adds an x:Uid
attribute to each UI element possible (updateuid), whereas the second
one performs a check to verify that all localizable members have an x:Uid. When MSBuild completes, you notice how visual elements have been marked as localizable, as shown in Listing 2.
Listing 2. The XAML Code Marked as Localizable by MsBuild
<Window x:Uid="Window_1" x:Class="MainWindow"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
Title="MainWindow" Height="350" Width="525">
<StackPanel x:Uid="StackPanel_1">
<Button x:Uid="LocalizedButton" Name="LocalizedButton" Margin="5"
Width="140" Height="40"
Content="Localized button"/>
<TextBlock x:Uid="LocalizedTextBlock" Name="LocalizedTextBlock" Margin="5"
Text="Localized text"/>
</StackPanel>
</Window>
|
Now build the project
again in Visual Studio. You now notice that in the project output folder
(Bin\Debug or Bin\Release) there is a new subfolder named en-US, which
contains a WpfLocalization.Resources.dll satellite assembly containing
localized resources for the en-US culture. So the goal now is to create a
similar folder/assembly structure per culture. In this case you see how
to create a localized satellite assembly for the Italian culture, but
you can replace it with a different one. A subsequent step requires
invoking LocBaml. The need is to extract resources information and edit
the information with localized ones. The following command line parses
the neutral language resources and creates an editable .CSV file where
you can place custom information:
LocBaml.exe /parse en-US\WpfLocalization.resources.dll
/out:WpfLocalization.csv
When ready, open the generated WpfLocalization.csv file with an appropriate editor, such as Microsoft Excel or Visual Studio. Figure 1 shows how the content of the file appears in Microsoft Excel.
If you inspect the content
of the file, among other things you notice the content of UI elements.
For example, row 2 contains the Window title, row 9 contains the Button text as the last word, whereas row 12 contains the TextBlock
text. At this point you simply need to replace original values with new
ones. Continuing the example of the Italian localization, perform the
following replacements:
In row 2 replace MainWindow with Finestra principale.
In row 9 replace Localized button with Pulsante localizzato.
In row 12 replace Localized text with Testo localizzato.
Figure 2 represents how the file will look like after edits.
Now save the file with a different name, for example WpfLocalization_it-IT.csv.
When done, you need to manually create a new directory where the new
localized resources will be published; create a folder named it-IT
inside the same folder of en-US. At this point you still need to invoke
LocBaml to build the localized satellite assembly; write the following
command line:
LocBaml.exe /generate en-US\WpfLocalization.resources.dll /trans: WpfLocalization
_it-IT.csv /out:c:\ /cul:it-IT
The /generate option tells LocBaml to generate a new satellite assembly, translating (/trans) the specified .csv file into the desired culture (/cul). The /out
option allows specifying the target directory that in this example is
the hard drive root folder. When ready, move the newly generated
WpfLocalization.resources.dll assembly from C:\ into the it-IT subfolder
you created before. The last step is to initialize the desired culture
information at the application startup. In Application.xaml.vb provide a
constructor as follows:
Imports System.Globalization
Imports System.Threading
Class Application
Public Sub New()
Thread.CurrentThread.CurrentUICulture = _
New CultureInfo("it-IT")
Thread.CurrentThread.CurrentCulture = _
New CultureInfo("it-IT")
End Sub
End Class
This is different from Windows
Forms, because in WPF the Application class is the actual application
entry point. If you now run the application, you get the result shown in
Figure 3 where you can see how UI elements have been localized.