Soluling home   Document home

Windows App SDK and WinUI 3 Localization and Internationalization

Windows App SDK and WinUI 3 Localization and Internationalization

Windows App SDK, (Wikipedia) is a Windows platform application platform created by Microsoft. Platform is new, it uses only Unicode, and localized resources a included in a locale depend sub directory. This make Windows App SDK one of the best environment for localization. Soluling localization tool and service support Windows App SDK and WinUI. The following pages describe Windows App SDK localization step by step.

Localization Process

The UI layer of Windows App SDK, WinUI 3, uses uses XAML and Resw files with either C#, or C++ programming languages. We can also use various other resource files such as images, sound and video. Following table contains all resource types that Windows App SDK applications use.

Resource Description
Resw String resources
XAML User interface resources
Images Image resources
Other Audio, video, XML data, JSON data, text data, etc

No matter what the resource file is the localized resource files are placed on a language specific sub directory of the original files. If the original string resource file is

Resources.resw

then the German file is

de\Resources.resw

and the French file is

fr\Resources.resw

You can also use a country specific sub directory. The following file is for German (Switzerland)

de-CH\Resources.resw

You can localize Windows App SDK applications using the following methods.

Visual Studio project file method

Visual Studio project file (.csproj) contains all the information about your application. Add the project file into Soluling project. When scanning it Soluling automatically scans also all the resource files it contains. You can turn on/off certain resource types. The advantage of using project files is that if you add or remove any resource file from the project you don't have to modify the sources in your Soluling project file. When building the project, Soluling add the localized resources into language specific sub directories. Finally, you add those files into your Visual Studio project and rebuild it to get a multilingual application.

Read Windows App SDK tutorial to get familiar to this method.

Visual Studio solution file method

When you localize your Windows App SDK project, you have to select what files you add into a Soluling project. In most cases this is easy and you just add your Visual Studio project file or files. However, sometimes you might have several project files, or you might have some other files types that are hard to locate. This is why Soluling has made it easy for you to localize your complete Visual Studio solution. Instead of manually adding all necessary project files you just add one file: your Visual Studio solution file (.sln). Soluling reads the solution file and locates all the project files that need to be localized. If you add new projects into your solution you don't have to add anything into your Soluling project because Soluling will automatically find the new items from the solution file and adds them into the project.

The result you will get by using Visual Studio solution file instead of individual project files is exactly the same. You Soluling project will contain the same project sources, you can configure them in the same way, and the output files will be the same. Support for Visual Studio solution file is just to make things easier for you.

Resource file localization method

The last localization method is to individually localize each XAML file (.xaml), and/or resource file (.resw). Soluling reads the original resource file and when building creates localized resource files. There is one output file for each language. You have to add all the resource files into your Soluling project. Even using wildcards it may be complicated. Also every time you add a new resource file you may have to add it to the project. It is recommended that you use either Visual Studio project file localization or Visual Studio solution file localization method.

Windows App SDK localization tutorial

This tutorial shows you how to localize a C# Universal Windows Platform application. The process is the same if you use C++. <data-dir>\Samples\WinUI\Tutorial\Original\Original.csproj is your sample tutorial application. Open it into Visual Studio. The project contains one window, MainWindow.xaml, that has some text controls. The first text control has Content property defined in XAML on design time.

<TextBlock>Hello World</TextBlock>

The control does not have any name or id property set. It is something that is not absolutely required for localization but if a control does not have a name Soluling can not assign a permanent context for it. Instead it uses a context value that depends on the index of the control. If you add or remove controls before the control the context value may change. This is why it is recommended to give a name property for every control. So lets add it.

<TextBlock x:Name="text1">Hello World</TextBlock>

The button controls is updated on run time by assigning a Content value to control.

<Button x:Name="myButton" Click="myButton_Click">Click Me</Button>

Because controls are accessed on run time they already have name properties set. The actual Text properties will be set on run time in Page_Loaded event. For example:

myButton.Content = "Clicked";

The above code sets the Text property. Unfortunately the text it uses is hard coded into program code. It can not be localized. In order to localize such text we need to replace hard coded strings with resource strings.

Resource hard coded strings

The first step is to add a string resource file. Right click the project file in Solution Explorer and choose Add | New Item. Select Resource File (.resw), accept the default name "Resources.resw" and click Add. Visual Studio adds an empty resource file.

Resources

Copy "Click the button below" text from source code and paste it to the value field. Change the value in the name field to Sample. The comment field can contain any text. It is meant to give some extra information for translator. Enter "Any comment". The resource file should look like this now:

Resources value

Now we have successfully added a hard coded string into a resource file. The next step is to remove the hard coded string and to use the resource string instead. First we have to create a ResourceLoaded object that is used to access resource strings. Add the following code

public sealed partial class ManiWindow : Window
{
  private ResourceLoader rl = new ResourceLoader();

This creates the object and makes it available to all method of MainPage. Next replace the hard coded string with call to rl.GetString.

text2.Text = rl.GetString("Sample");

The parameter specified the name of the resource string. It is the value in the name field of the resource file.

Use dynamic messages

The next hard code string is little bit more complicated.

text3.Text = "My name is " + name;

The value of Text property is a combination of a constant string and a string variable. Depending on the value of the variable the actual string gets different values. If name is "John" then the string gets to "My name is John". If name is "Mary" then the strings becomes to "My name is Mary". We could use the same approach as with text2 control

text3.Text = rl.GetString("Name") + name;

However this assumes that the name in the sentence is always the last word. This works on many languages such English, German and Finnish. However in Japanese you would say "マリーです" where マリー is the name and です is "My name is". This means that to create correct Japanese the above code should be

text3.Text = name + rl.GetString("Name");

Because our code has to work both on English and Japanese we need to find a more general solution. Such as solution is to use message patterns. Instead of using "..." + name we using String.Format function that combines a message pattern with the value(s). The message pattern is a string that contains placeholder(s) for the variables. Placeholders are marked with {x} where x specifies the index of the placeholder. 0 is the first, 1 is the second, etc. The line using message pattern and Format function is

text3.Text = String.Format("My name is {0}", name);

Add "My name is {0}" into the resource file with "Name" in the name field. The final line would be:

text3.Text = String.Format(rl.GetString("Name"), name);

Now the translator can freely move the placeholder where ever the grammar of the target language requires. The following table contains translated patterns in few languages:

Language Pattern
English My name is {0}
Finnish Nimeni on {0}
Japanese {0}です

Plural enabled messages

Most languages use plural forms. It means that the noun in the sentence is either in singular or plural form depending on the amount of object. For example, we way "Clicked 1 time" but "Clicked 2 times". In the last sentence is in plural form. How can we make out code to generate grammatically correct dynamic message? One approach it to use if clause. For example.

if (count == 1)
  myButton.Content = $"Clicked {count} time";
else
  myButton.Content = $"Clicked {count} times";

The above sample has two issues. The first one is that is uses string interpolation. You cannot use string interpolation if you want to localize the message. Instead, you have to use the old-fashioned String.Format approach with a pattern with placeholders. The second issue is that the above sample would only work on such languages where one uses singular and zero, two or more uses plurals. Such languages are English, German and Finnish. However French uses singular with 0 and 1, and plural in other cases. Japanese does not have plural at all. Polish has three forms: singular (1), paucal (2-4) and plural (0, 5 or more). So in order to handle all languages our code would be very complex. Standard Universal Windows Platform does not offer any solution for this. Fortunately Soluling does. Soluling.Plural.Format function is a plural enabled format function similar to String.Format. To use Soluling.Plural.Format add <data-dir>\Library\NET\Standard library project into your Visual Studio project file. Now we can use the following line.

text5.Text = Soluling.MultiPattern.Format("{plural, one {Clicked {0} time} other {Clicked {0} times}}", count);

Our original language is English and because it uses two forms the message pattern contains two parts. The first part is the singular pattern and the second part is the plural pattern. The second parameter in MultiPattern.Format function specifies the count that determines what plural form (singular, plural, ...) is used. The rest of the parameters work just like in String.Format. They are the variables to be inserted into the placeholders. Now the translator can enter patterns for each plural forms the language uses. The following table contains the translated multi-pattern strings is few languages:

Language Pattern
English
{plural, one {Clicked {0} time} other {Clicked {0} times}}
Finnish
{plural, one {Klikkasin {0} kerran} other {Klikkasin {0} kertaa}}
Japanese
{plural, other {{0}クリック}}

Soluling contains a sophisticated plural editor that lets you to easily and safely edit each patterns. The plural engine must know what is the current language. There is not 100% accurate method to acquire the current language. This is why the best way is to set the language yourself.

Plural.Language.Id = rl.GetString("Language");

Language resource string contains initially en that is a ISO code for English. Each translated resource contains the language code of that language. For example German resource file would contain de. After initializing the engine we can use it. Our last line would be.

myButton.Content = Soluling.MultiPattern.Format(rl.GetString("ClickedTimesPlural"), count);

Dates and times

We have one more thing to do. Look at the following line:

text4.Text = "Today is " + today.Month + "/" + today.Day + "/" + today.Year % 100;

It converts date into a string. In US this would be for example "Today is 1/14/2016". We could use message patterns like this

text4.Text = String.Format("Today is {0}/{1}/{2}", today.Month,  today.Day,  today.Year % 100); 

but it would only work in US and other countries that use month/day/two-digit-year. For example, in Finland a correct format would be 14.1.2016. The order is day, month and year. Separator is . and a full four digits year is used. Universal Windows Platform contains API that help to create correct date strings. Use Windows.Globalization.DateTimeFormatting.DateTimeFormatter class. First you create a date formatter using short date and current language of the user.

var formatter = new DateTimeFormatter("shortdate", GlobalizationPreferences.Languages);

Once you have the formatter you use used Format method to return a date as string.

text4.Text = String.Format(rl.GetString("Today"), formatter.Format(today));

The Today resource string is "Today is {0}". formatter.Format(today) returns date formatted into short string using the date format of the current language. Now the internationalization part is finished. We can start localizing our project.

Create a Soluling project

Start Soluling and click New from File button. Project Wizard appears. Browse into <data-dir>\Samples\WinUI\Tutorial\Localized directory and select Localized.csproj.

Select

Click Next. Soluling shows a dialog to choose the project type.

Select type

Accept the detected one (Windows App SDK/Win32 project file) and click OK. Resources sheet appears. It shows the available resource type. We don't need to localize images so uncheck Image resources.

Resources

Click Next. Select Languages sheet appears. This lets you to choose the target languages. Drag the language you want from right to left. In our sample we use Finnish.

Languages

Click Finish to complete the wizard. Soluling creates a new project, reads Complete.csproj, scans the resource files it contains, and finally shows the created project in the editor.

Project

On the right side you see the project tree. The top level items are called sources. Our sample contains one source, Localized.csproj. Each source contains rows and sub node. Each sub node represents one resource file. For example Resources.resw contains the string resources. If you select a specific node in the project tree the right side grid shows only rows belonging into the that node or one of the sub node of the selected node. Our project contains some resource file that we do not want to localize. Select App.xaml, right click and choose Exclude.

Exclude

Now App.xaml is excluded from the project. MainWindow.xaml contains a row that has dummy text. That text belongs to dummy value of Text property. it is never used but replaced with a resource string on run time. We do not localize them so we can exclude them. Easiest way is to exclude string "dummy". Select a "dummy" row, in the grid right click on the left side of the row and choose Exclude | All Rows with "dummy" original.

Exclude row

Soluling prompts to rescan. Accept that. Once scanned out project is ready for translation.

Project

Translate the project

The rightmost column of the grid contains Finnish strings. Currently, there are no translations so all values are empty. Start typing translations. You can also use machine translations by right click Finnish column header and choose Machine Translate. The fourth row contains a string that has plural forms. You can see a double bubble in the info column for all rows that have plural forms. To enter translations Soluling shows a plural editor.

You can also show a dialog to edit plurals. Right click the translation cell and choose Edit.

Translation

The editor shows the original forms. In our case the original language is English so the original forms are singular and plural. Out target language also contains two forms: singular and plural. Enter translations and click OK. Once you have translated all rows the project looks like this.

Project

Build localized files

Now we can create the localized resource files. Click Build button on ribbon. Soluling creates the localized resource files: fi\Resources.resw and fi\MainWindow.xaml.

Output

Now localized resource files are correctly included into the project and we can build a multilingual application.

Soluling creates the localized resource files but you have to set the Build Action in your Visual Studio project. There is no need to set the build action of XAML or RESW file. However, for any other resource type you need to set the Build Action to Content.

Build multilingual application

When you build your application Visual Studio will warn that you have "fi" resources but no "en" resource that is the default language. "en" resources are not needed because the project contains original neutral resources. When running a multilingual application Universal Windows Platform uses resource cascading. If a specific language resource is not found then default resource is looked. If that is not found either then a neutral resource is used.

Log

Unfortunately there is no way to turn off this warning. You just have to ignore it.

Run application on different languages

Now we have a multilingual application that supports English and Finnish. Lets run it. If we run it on English Windows or any Windows that has not Finnish language added into preferred languages the application will start in English.

Sample

Start Settings. Select Language settings and you will see your language of preferences. Add Finnish as the topmost language.

Languages

Run the application again and now it will appear in Finnish.

Localized sample

<data-dir>\Samples\WinUI\Tutorial\Localized\Localized.csproj is the same tutorial project that has been fully internationalized and localized into Finnish.

Other resource types

In our sample we localized XAML and RESW files. Soluling can localize all kind of resource files. If you have image or sound files in your project Soluling lets you easily specify a language depend version of the file. <data-dir>\Samples\WinUI\Resources sample to see how images, audio, XML, structural text, and segmented text data is localized.

Resources

In addition to the above resource data, Soluling can localize plain text, JSON data, image lists, video or any binary data. After building the localized files, remember to set the Build Action of the media resources (text, XML, image, etc) to Content in your Visual Studio project. Do not change the Build action of XAML and RESW files.

Samples

GitHub and <data-dir>\Samples\WinUI contains following Windows App SDK samples:

Directory Description Notes
Resources A C# sample that shows how to localize various kinds of resources such as images, sound and XML.  
Tutorial A tutorial project that shows you how to internationalize a Windows App SDK application. Contains following projects:
Original Original uninternationalized project.
Localized Internationalized and localized project.
Try this first!

WinUI.sln is a Visual Studio 2022 solution file that contains all the above samples.

Configuring Visual Studio project localization

You can configure how to localize your Windows App SDK project file (.csproj) by selecting the item in the project tree, right-clicking, and choosing the Options menu. A source dialog appears that lets you edit the options. This source uses the following option sheets.

Configuring Resource file localization

You can configure how to localize your Windows App SDK resource file (.resw) by selecting the item in the project tree, right-clicking, and choosing the Options menu. A source dialog appears that lets you edit the options. This source uses the following option sheets.