Click here to Skip to main content
15,885,537 members
Articles / Desktop Programming / WPF
Tip/Trick

How to Localize WPF pages

Rate me:
Please Sign up or sign in to vote.
5.00/5 (1 vote)
17 Apr 2015CPOL2 min read 20.4K   4   2

Introduction

Today there are many ways WPF localization projects mainly based on bindings.
This approach has its advandages and disadvandages. I do not like this approach because a huge number of bindings in xaml markup, additional delay when the page loads. Just more time to search for a string in the source code, that is when I see the text in the running program, first I need to find this line in the resx resources, and after only xaml containing this key.

Background

Recently, we have connected Elas for localization of our project. Elas extracts all the xaml markup element which attribute values marked x:Uid and puts them into xlf file for later translation. I'll show you a simple example how to do it.

Using the Elas

Windows 8, Visual Studio 2013

So create a new WPF project.

And add a few controls to the main window.

MainWindow.xaml

XML
<Window x:Class="WpfApplication1.MainWindow"
        xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
        xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
        Title="MainWindow"
        Width="525"
        Height="350">
    <Grid>

        <Menu Height="22" VerticalAlignment="Top">
            <MenuItem Header="File">
                <MenuItem Header="New" />
                <MenuItem Header="Open" />
                <Separator />
                <MenuItem Header="Exit" />
            </MenuItem>
            <MenuItem Header="Help">
                <MenuItem Header="About" />
            </MenuItem>
        </Menu>
        <TabControl Margin="10,40,10,10">
            <TabItem Header="File">
                <Grid>
                    <Button Width="97"
                            Height="21"
                            Margin="11,26,0,0"
                            HorizontalAlignment="Left"
                            VerticalAlignment="Top"
                            Content="Add" />
                    <Button Width="97"
                            Height="21"
                            Margin="11,53,0,0"
                            HorizontalAlignment="Left"
                            VerticalAlignment="Top"
                            Content="Remove" />
                    <ListBox Margin="122,28,13,38" />
                    <TextBlock Height="26"
                               Margin="6,0,6,6"
                               VerticalAlignment="Bottom">
                        <TextBlock>
                            Selected Item:<Run Text="{Binding SelectedItem}" />
                        </TextBlock>
                    </TextBlock>
                </Grid>
            </TabItem>
            <TabItem Header="Directory">
                <Grid>
                    <TextBox Height="21"
                             Margin="14,16,24,0"
                             VerticalAlignment="Top" />
                </Grid>
            </TabItem>
        </TabControl>
    </Grid>
</Window>

Add Elas Core Nuget package.

Pay attention in the solution added a new file ".elas \ Elas Configuration.props"

This configuration file of the Elas where you can add the language(s) in which you wish to receive a localization.

Run build.

After the build, now we have a xliff file for "MainWindow.xaml":

But it does not have any trans-unit because we have not set any x:Uid for elements.

Add x:Uid for each element.

MainWindow.xaml

XML
<Window x:Class="WpfApplication1.MainWindow"
        xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
        xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
        Title="MainWindow"
        Width="525"
        Height="350">
    <Grid>

        <Menu x:Uid="Menu"
              Height="22"
              VerticalAlignment="Top">
            <MenuItem x:Uid="Menu.File" Header="File">
                <MenuItem x:Uid="Menu.File.New" Header="New" />
                <MenuItem x:Uid="Menu.File.Open" Header="Open" />
                <Separator x:Uid="Menu.File.Separator" />
                <MenuItem x:Uid="Menu.File.Exit" Header="Exit" />
            </MenuItem>
            <MenuItem x:Uid="Menu.Help" Header="Help">
                <MenuItem x:Uid="Menu.Help.About" Header="About" />
            </MenuItem>
        </Menu>
        <TabControl x:Uid="TabControl" Margin="10,40,10,10">
            <TabItem x:Uid="TabControl.File" Header="File">
                <Grid x:Uid="TabControl.File.Grid">
                    <Button x:Uid="TabControl.File.Add"
                            Width="97"
                            Height="21"
                            Margin="11,26,0,0"
                            HorizontalAlignment="Left"
                            VerticalAlignment="Top"
                            Content="Add" />
                    <Button x:Uid="TabControl.File.Remove"
                            Width="97"
                            Height="21"
                            Margin="11,53,0,0"
                            HorizontalAlignment="Left"
                            VerticalAlignment="Top"
                            Content="Remove" />
                    <ListBox Margin="122,28,13,38" />
                    <TextBlock x:Uid="TabControl.File.Bottom"
                               Height="26"
                               Margin="6,0,6,6"
                               VerticalAlignment="Bottom">
                        <TextBlock x:Uid="TabControl.File.Bottom.SelectedItem">
                            Selected Item:<Run x:Uid="TabControl.File.Bottom.SelectedItem.Run" Text="{Binding SelectedItem}" />
                        </TextBlock>
                    </TextBlock>
                </Grid>
            </TabItem>
            <TabItem x:Uid="TabControl.Directory" Header="Directory">
                <Grid x:Uid="TabControl.Directory.Grid">
                    <TextBox x:Uid="TabControl.Directory.TextBox"
                             Height="21"
                             Margin="14,16,24,0"
                             VerticalAlignment="Top" />
                </Grid>
            </TabItem>
        </TabControl>
    </Grid>
</Window>

Build again. And now we can begin localization.

If you want to work with "MainWindow.xaml.xlf" file directly in Visual Studio, then it will be more convenient to add xml schema "xliff-core-1.2-transitional.xsd" into Visual Studio. This file can be found in "%SolutionDir%\packages\DevUtils.Elas.Core.XXX\schemas\xliff-core-1.2-transitional.xsd" and add it to Visual Studio.

Consider the "MainWindow.xaml.xls" file.

This file contains the keys (1) (x:Uid) and the initial value (2) to be translated. Translation added to the target element and the value of state is changed to "translated". Elements for which you do not want to do the translation set translate into "no" and state into the "final".

That's what I get.

MainWindow.xaml.xlf

XML
<xliff version="1.2" xmlns:elas="urn:devutils:names:tc:xliff:document:1.2" xmlns="urn:oasis:names:tc:xliff:document:1.2">
    <file original="MainWindow.xaml" source-language="en-US" target-language="ru-RU" datatype="xml">
        <header>
            <tool tool-version="0.0.8.0" tool-name="ELAS" tool-company="DevUtils.Net" tool-id="DevUtils.Elas.Tasks.Core, Version=0.0.8.0, Culture=neutral, PublicKeyToken=3cae0f4d0d366709" />
        </header>
        <body>
            <group id="Menu">
                <trans-unit id="Menu.$Content" translate="no">
                    <source xml:space="preserve">#Menu.File;#Menu.Help;</source>
                    <target xml:space="preserve" state="final"></target>
                </trans-unit>
                <group id="File">
                    <trans-unit id="Menu.File.$Content" translate="no">
                        <source xml:space="preserve">#Menu.File.New;#Menu.File.Open;#Menu.File.Separator;#Menu.File.Exit;</source>
                        <target xml:space="preserve" state="final"> </target>
                    </trans-unit>
                    <trans-unit id="Menu.File.Header" translate="yes">
                        <source xml:space="preserve">File</source>
                        <target xml:space="preserve" state="translated">Файл</target>
                    </trans-unit>
                    <group id="New">
                        <trans-unit id="Menu.File.New.Header" translate="yes">
                            <source xml:space="preserve">New</source>
                            <target xml:space="preserve" state="translated">Новый</target>
                        </trans-unit>
                    </group>
                    <group id="Open">
                        <trans-unit id="Menu.File.Open.Header" translate="yes">
                            <source xml:space="preserve">Open</source>
                            <target xml:space="preserve" state="translated">Открыть</target>
                        </trans-unit>
                    </group>
                    <group id="Exit">
                        <trans-unit id="Menu.File.Exit.Header" translate="yes">
                            <source xml:space="preserve">Exit</source>
                            <target xml:space="preserve" state="translated">Выход</target>
                        </trans-unit>
                    </group>
                </group>
                <group id="Help">
                    <trans-unit id="Menu.Help.$Content" translate="no">
                        <source xml:space="preserve">#Menu.Help.About;</source>
                        <target xml:space="preserve" state="final"></target>
                    </trans-unit>
                    <trans-unit id="Menu.Help.Header" translate="yes">
                        <source xml:space="preserve">Help</source>
                        <target xml:space="preserve" state="translated">Помощь</target>
                    </trans-unit>
                    <group id="About">
                        <trans-unit id="Menu.Help.About.Header" translate="yes">
                            <source xml:space="preserve">About</source>
                            <target xml:space="preserve" state="translated">О программе</target>
                        </trans-unit>
                    </group>
                </group>
            </group>
            <group id="TabControl">
                <group id="File">
                    <trans-unit id="TabControl.File.$Content" translate="no">
                        <source xml:space="preserve">#TabControl.File.Grid;</source>
                        <target xml:space="preserve" state="final"></target>
                    </trans-unit>
                    <trans-unit id="TabControl.File.Header" translate="yes">
                        <source xml:space="preserve">File</source>
                        <target xml:space="preserve" state="translated">Файл</target>
                    </trans-unit>
                    <group id="Add">
                        <trans-unit id="TabControl.File.Add.Content" translate="yes">
                            <source xml:space="preserve">Add</source>
                            <target xml:space="preserve" state="translated">Добавить</target>
                        </trans-unit>
                    </group>
                    <group id="Remove">
                        <trans-unit id="TabControl.File.Remove.Content" translate="yes">
                            <source xml:space="preserve">Remove</source>
                            <target xml:space="preserve" state="translated">Удалить</target>
                        </trans-unit>
                    </group>
                    <group id="Bottom">
                        <trans-unit id="TabControl.File.Bottom.$Content" translate="no">
                            <source xml:space="preserve">#TabControl.File.Bottom.SelectedItem;</source>
                            <target xml:space="preserve" state="final"></target>
                        </trans-unit>
                        <group id="SelectedItem">
                            <trans-unit id="TabControl.File.Bottom.SelectedItem.$Content" translate="yes">
                                <source xml:space="preserve">Selected Item:#TabControl.File.Bottom.SelectedItem.Run;</source>
                                <target xml:space="preserve" state="translated">Выбранный элемент:#TabControl.File.Bottom.SelectedItem.Run;</target>
                            </trans-unit>
                        </group>
                    </group>
                </group>
                <group id="Directory">
                    <trans-unit id="TabControl.Directory.$Content" translate="no">
                        <source xml:space="preserve">#TabControl.Directory.Grid;</source>
                        <target xml:space="preserve" state="final"></target>
                    </trans-unit>
                    <trans-unit id="TabControl.Directory.Header" translate="yes">
                        <source xml:space="preserve">Directory</source>
                        <target xml:space="preserve" state="translated">Директория</target>
                    </trans-unit>
                </group>
            </group>
        </body>
    </file>
</xliff>

Build again. Check whether no warnings or errors.

Next, switch on the Russian locale in Windows or in the program

(I added into the class constructor "App"

C#
CultureInfo.DefaultThreadCurrentUICulture = new CultureInfo("ru-RU");

)

And we get a localized application to Russian.

P.S. Next time I'll tell you how to use the Elas to localize C++ (Windows resources) applications.

History

Initial release

License

This article, along with any associated source code and files, is licensed under The Code Project Open License (CPOL)


Written By
Software Developer (Senior) Congree Language Technologies GmbH
Russian Federation Russian Federation
This member has not yet provided a Biography. Assume it's interesting and varied, and probably something to do with programming.

Comments and Discussions

 
QuestionCan this mechanism be used to implement multiple languages? Pin
Member 826240710-Nov-15 18:39
professionalMember 826240710-Nov-15 18:39 
AnswerRe: Can this mechanism be used to implement multiple languages? Pin
|\/|ax21-Dec-15 21:14
|\/|ax21-Dec-15 21:14 

General General    News News    Suggestion Suggestion    Question Question    Bug Bug    Answer Answer    Joke Joke    Praise Praise    Rant Rant    Admin Admin   

Use Ctrl+Left/Right to switch messages, Ctrl+Up/Down to switch threads, Ctrl+Shift+Left/Right to switch pages.