📜 ⬆️ ⬇️

Localization of WPF pages

Today, there are many ways to localize WPF projects mainly based on banding.
This approach has its pros and cons. I am not satisfied with this approach, this is a huge amount of bindings in the xaml markup, an additional delay when the page loads. Also, the extra time to search for a string in the source code i. when I see a line in a running program, I must first find this line in the resx resources, and after only xaml containing this key.

We recently connected Elas to localize our project. Elas pulls out all the attribute values ​​of the element marked x: Uid from the xaml markup and puts them in the xlf file for later translation. I'll tell you on a simple example how this is done.

Windows 8, Visual Studio 2013

So, create a new WPF project.
')


And a few items on the main window.



MainWindow.xaml
<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 the Elas Core Nuget package.



Note in the solution there is a new file ".elas \ ElasConfiguration.props"



This is the Elas configuration file where you can specify the languages ​​you want to receive the translation.

Next, run the build.

And after the build, we now have an xliff file for "MainWindow.xaml":



But it has no trans-unit since we did not specify any x: Uid for the elements.

Add x: Uid for each item.
MainWindow.xaml
 <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> 



Again build. And now we can proceed to localization.

Before localization
If you are going to work with the “MainWindow.xaml.xlf” file yourself in Visual Studio, then it will be more convenient to add the xml scheme “xliff-core-1.2-transitional.xsd” in 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 file "MainWindow.xaml.xlf".



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

That's what happened with me.

MainWindow.xaml.xlf
 <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> 



Again build. Check for warnings or errors.

Next, we switch the locale to Russian in Windows or in the program (I added the “App” class constructor

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

And we get a localized application in Russian.



PS Next time I’ll tell you how to localize C ++ (Windows resources) applications using Elas.

Source: https://habr.com/ru/post/255809/


All Articles