Document home

Visual C++

.NET Localization and Internationalization

.NET (Wikipedia) is a software framework developed by Microsoft. It is an extensive framework. It contains several technologies and programming methods. Soluling localization tool and service support every part of .NET.

The list describes different files that .NET uses.

The following list describes .NET localization step by step.

Platform specific information about .NET localization

Overview of .NET Implementations, APIs, Files and Resources

.NET is an extensive group of technologies. It contains several implementations, APIs, and programming methods. You can use .NET to create desktop applications, command-line applications, server applications, mobile applications, web pages, web services, single-page applications, console games, etc. .NET contains APIs such as ASP.NET, Blazor, Windows Forms, WPF and Universal Windows Platform. The common thing for all .NET projects is that the output file is an assembly file. An assembly file is a compiled file that contains compiled code and compiled resources. Sometimes some of the resources are in external files. However, in most cases, the assembly contains resource files embedded as resource data. The file extension of an assembly file is either .exe or .dll, and assembly files use Windows PE file format. When you deploy your .NET application, you deploy the assembly files and optional resources files that your .NET development tool created.

.NET implementations

The following table contains a list of .NET implementations:

Implemen​tation Description APIs
Notes
.NET Framework Classic .NET implementation for Windows desktop and server

WPF, Windows Forms, ASP.NET

 

.NET Core New cross-platform .NET implementation for Windows, Mac, and Linux WPF, Windows Forms, Blazor, ASP.NET Core
Universal Windows Platform .NET API for Windows 10. Universal Windows Platform This is called WinRT on Windows 8.x
Mono/Xamarin New cross platform .NET implementation for iOS, Android and browsers. Xamarin
,NET Compact Framework A subset of .NET Framework implemented for the Windows Embedded Compact platform Windows Forms Not compatible to .NET Standard.

Soluling supports all the above .NET implementations plus .NET Standard.

.NET APIs

.NET platform contains several APIs. The main APIs are:

API Description Resource types Files to localize
ASP.NET Core .NET API for web applications and services. Resx, templates, other Visual Studio project file
ASP.NET Classic .NET API for web applications and services. Resx, templates, other Visual Studio project file, or Assembly files, template files and script files
Blazor API for single-page web applications. Resx, other Visual Studio project file
WPF .NET API for desktop applications. XAML, Resx, other, unmanaged Visual Studio project file or Assembly files
Windows Forms Classic .NET API for desktop applications.
.NET Compact Framework uses its own version that is a subset of Windows Forms.
Resx, other, unmanaged Visual Studio project file or Assembly files
Universal Windows Platform .NET API for desktop and mobile applications for Windows 10.

XAML, Resx, other, unmanaged

Visual Studio project file or Appx files
Silverlight * A subset of WPF that works on web browsers. XAML, Resx, other XAP file
Windows Phone * A subset of WPF that works on cell phones. Based on Silverlight. XAML, Resx, other XAP file

Soluling supports all the above .NET APIs. *) However, Silverlight and Windows Phone have been deprecated, and so our support for them.

.NET resource types

.NET projects can contain several different resource types. The following table describes different resource types.

Resource type Description
Standard resources This is the basic .NET resource type. It contains one or more resource items. Each item represents a resource value. The original resource file is a .resx file. In most cases, these items contain strings data such as message strings or images. However, they can include other kinds of data too.
Windows Forms resources

Windows Forms stores form data into .resx files. However, unlike the standard resource, a form resource contains additional data such as property type and component where the property belongs to.

XAML resources Universal Windows Platform, WPF, Xamarin, Windows Phone, and Silverlight all use XAML files to store resources. In addition to XAML, they also use standard resource files (.resx).
Images and other files It is possible to store images and any other files as resource data.
Unmanaged resources

In addition to the managed resources above, .NET assemblies also contain unmanaged resources. These resources contain application icon and version information.

Soluling can localize all resource types of .NET.

Visual Studio Project File

Visual Studio project file is the project file that all .NET projects use. In most cases, you need to add this file to your Soluling project.

Visual Studio Solution File

Visual Studio solution file is a container for one or more Visual Studio project files. If you have several projects in a solution file, you can add the solution file instead of the Visual Studio project file.

Resx and Resw files

Resx is the basic resource format of .NET and UWP. It is based on XML, but files are converted to a binary format when added into assemblies. All .NET platforms use .resx file format. UWP uses the same file format, but .resw file extension is used instead of .resx.

Form files

Windows Forms uses .resx files to store the properties of the form. Such a .resx file is called the form file. Soluling uses a dedicated parser to scan form files because not all properties should be extracted. Scan rules are used to determine what properties are extracted.

XAML file

XAML (Wikipedia) is a declarative XML-based language created by Microsoft that is used for structured data and objects. UWP, WPF, and Xamarin use XAML.

Rules and Ids

Use scan rules to select what properties are parsed and localized. You can optionally also use id attributes to control what to localize. If you check Localize only components with an id attribute checkbox in the XAML options sheet, Soluling scans only those elements with an id.

Bindings

XAML files use the binding feature a lot. For example, the following XAML has bound a formatted text box value into the text block.

<TextBlock Name="textBlock1" Text="{Binding ElementName=textBox, Path=Text, StringFormat=Distance is {0} meters.}" />

The raw text value would be

{Binding ElementName=textBox, Path=Text, StringFormat=Distance is {0} meters.}

This would be too difficult (translator might not know what part to translate) and too dangerous (translator might break the format) to extract as a complete string value. Instead, Soluling parses the Binding value and extracts only the actual string part that in this case is

Distance is {0} meters

This will ensure that the translator gets strings as a simple plain string and cannot accidentally break the binding format.

Hard coding property values

Unfortunately, all localization tutorials and how-to-do papers from the web recommend that you do not store string values into the XAML file. Instead, they recommend to store the values into a .resx file and use those ResX items from XAML using markup extensions (e.g. {x:Static Resources.String1}). Do not apply. Those documents were written by people that do not know that modern localization tools can easily localize XAML. Tools and services they use can only localize .resx resources. When you use Soluling, you can always store all strings into your XAML file and let Soluling localize the XAML file. Use .resx to store only the strings that are used in your C#/VB code. If you already have used the method described above, you don't have to remove the ResX items from XAML files. You can mix and match the plain string and .resx strings.

Learn more about this here.

BAML

BAML is a binary XAML. It is Microsoft's proprietary format to store XAML data in a binary format. All XAML files for the WPF application are compiled into BAML before adding into the assembly resource. The BAML format cannot be converted back to the original XAML. Localization must be done using .NET localization API. This makes localization of BAML data more limited. However, if properly written (i.e., includes x:Uid attributes) BAML data can also be localized. XAML files in UWP, Windows Phone, Silverlight, and Xamarin assemblies are kept in standard XML based XAML files or in a binary format that can be converted back to text XAML.

Template files

Template files define the HTML markup. Page and view files are templates files. Read more about how to internationalize and/or localize them in ASP.NET and ASP.NET Core.

Script files

Page and view files can contain client-side script files. Scripts are generally localized in the same way as the templates. However, if you have standalone script files, you can localize the files.

Image, audio, and other files

Besides the templates and string resource files, Soluling can localize images, audio, and other file types.

Assembly File

Assembly file is a building block of .NET platform and applications. An assembly file contains both compiled code and compiled resource data.

No matter what .NET implementation or .NET language you use, your compiler creates an assembly file. Assembly files are the executable files in .NET. They contain both compiled code and resources. If your source code is properly internationalized, then all the items that need to be localized are localized in the resource blocks of your assembly files. If you have not internationalized your application, there might be some hard coded strings in the compiled code. In this case, you have two options. Either you replace hardcoded strings with resource string (i.e., internationalize code. This is recommended) or your turn on Soluling's hardcoded string localization.

One type of assembly is the satellite assembly. It contains only resource data but no code. .NET uses satellite assemblies for localization. If you use satellite assemblies instead of localized assemblies, you should make sure that .NET can load them correctly.

When using Windows Forms, WPF, or ASP.NET, you deploy assembly files.

Original assembly file

The original assembly file is the assembly file that the compiler creates. It contains the compiled code and original resources. Original resources do not have a language id. Even the resources do not have a language id the text in the resources is, of course, written in a human language. This so-called original language is the language that is used in the development tool when entering Text values. The original language is very often English, but it can be any language. The following picture contains an original assembly file that contains original resources written in English.

Original assembly

The file extension of an assembly file is either EXE or DLL. Applications use EXE, and library files use DLL. In Soluling, the original assembly file is the source file that you add to the Soluling project. Soluling creates either localized assembly files or satellite assembly files.

Localized assembly file

The localized assembly file is just like the original assembly file, but the resource data has been localized from the original language to the target language. The following picture contains the German assembly file.

German assembly

If you start the above assembly file, it always uses the German resources that are embedded in the assembly file. The French assembly file would look like this.

French assembly

Each resource in a localized assembly file uses an empty language id. Only the resource data itself has been localized.

Satellite assembly file

The satellite assembly file contains only resource data. It does not contain any code. The resource data has been localized, and each resource uses the language id. Finally, the satellite assembly file must locale a locale-specific relative subdirectory of the original assembly file.

German satellite assembly

French satellite assembly

The following picture shows a configuration where there are an original (English) assembly file and three satellite assembly files: German, French, and Japanese. If the original assembly file name is C:\Sample\Application.exe, then the German satellite assembly file must be C:\Sample\de\Application.resources.dll. The French satellite assembly file is C:\Sample\fr\Application.resources.dll. The Japanese satellite assembly file is C:\Sample\ja\Application.resources.dll.

Original assembly and satellite assemblies

When you start the above application, it has four language choices. Either it uses the original (English) resources found the original assembly file, or it uses resources found from one of the satellite assembly files. If you do not have any special code in your application .NET framework will choose a language that matches the user interface of your operating system. This means that if you run the application on English OS the original (English) resources are used. If you run the application on German OS, the resources from the German satellite assembly file are used. You can override this default feature by setting the user interface culture of the current thread. For example the following code makes .NET framework to use the resources matching the default locale of the operating system.

Thread.CurrentThread.CurrentUICulture = CultureInfo.CurrentCulture;

Note! You must set the culture before the application loads any resources. A good place to set the culture is the Main procedure before Application.Run is called. Learn more about satellite assembly loading.

Unmanaged resources of .NET assembly

The most common unmanaged resource in .NET assembly is the version resource. If you need to localize it, turn on the assembly info localization. Right-click you .NET project file in the project tree, right-click, and choose Options. Select Resources and check Assembly info.

Assembly info

Localization Process

Soluling reads the Visual Studio project file, Visual Studio solution file, or original assembly file to extract resource items into the Soluling project. Translators use Soluling to translate the items. Finally, when building Soluling creates satellite assembly files. There is one output file (.dll) for each language. If you use Visual Studio solution or project file, you need to have the full source code. If you use an assembly file, you don't need to have the source code files. The only file you need is the original assembly file.

If you use the original assembly as a source, Soluling can also create localized assembly files. The localized assembly file is an identical copy of the original assembly, except the strings in it have been replaced. The assembly contains exactly the same code segments as the original. You can replace the original assembly with localized assembly without breaking anything. You deploy the localized assembly file without the original assembly file. The satellite assembly files, on the other hand, contain only resources. They do not contain any code. They do not run alone but must always be deployed with the original assembly file. By default, Soluling creates satellite assemblies. You can change this by using the Output sheet of Source dialog.

If you project uses either Windows Forms form resources or XAML resources that have string it is recommended to use Visual Studio project file or Visual Studio solution file localization.

Resource file

Soluling reads the original resource files to extract resource items into the Soluling project. Translators use Soluling to translate the items. Finally, when building Soluling creates localized resource files. There is one output file (.resx) for each language. At the end of the process, you have the localized resource files, but you can not use them directly unless you put them inside an assembly file. If you use resource file localization, it is up to you to compile either the localized assembly file(s) or localized satellite assembly file(s).

Visual Studio project file

This is similar to add a single assembly file. Soluling reads the project file locating all the resource files (.resx, form, and XAML) it uses and extracts items from them.

Visual Studio solution file

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

The result you will get by using a Visual Studio solution file instead of individual project or assembly files is exactly the same. Your Soluling project will contain the same 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.

Internationalization

Hard coded strings

String.Format

{0} vs {SomeName}

UI

Dialog filters

Sharing files

Visual Studio lets you share code and resources in many different ways. It helps to reduce unnecessary code duplication but also make localization more challenging.

Shared assemblies

This is the most comment method. You create a shared library. It has its own project and output assembly. If the library contains any resources, you need to localize the library. As a result, you will have satellite assemblies for the library, and you need to deploy them as well.

Linked files

Sometimes if you have one file or two and you don't want to create a separate library, you can share the files by adding them as links. You only have one copy of the file. If you change it, the project using the file changes. If you share a resource this way, the resource will be included in all assemblies that linked it, and you have to localize the resource in all projects using it.

Shared projects

This is a very rare case. .NET lets you create a shared project that is linked to a project. It is a bit like linked files, but instead of linking a single file, you link a collection of files. Soluling detects shared projects in your project file and lets you localize them too.

Signing

Most .NET assemblies are signed. They are signed for two reasons. One is to prevent hacking of assemblies (digital signature), and another is to guarantee that every assembly has a unique name (strong name). There is a separate signing method for both purposes.

Strong name

To ensure a unique name, you use strong name signing. Signing is performed on the linking process by the AL.exe tool or after building by using the Sn.exe tool. Either way, you must have a key file. Keys files contain a public-private key pair. The signed assembly will contain the sign data and the public key. Only the private key can be used to create the sign data. The .NET framework uses the public key to make sure that the signed data is authentic.

Digital signature

To make sure that your customer can be sure that the assembly really comes from you, you can add a digital signature to the assembly. This is performed after building by using the Singtool.exe tool.

Localization

Unfortunately, strong name signing makes localization harder. If the main assembly is a strong name signed, the localized satellite assembly must be signed with the same key(s). If you are localizing your own assemblies, the signing is no problem because you have the key. However, 3rd party vendors hardly ever release their keys. This means that if you want to localize an assembly of a 3rd party vendor, you or Soluling can not completely sign the satellite assemblies Soluling creates. Instead, Soluling will delay-sign the assemblies. Such assemblies contain only public key and empty space for the sign data but no actual sign data. You must use Sn.exe to complete the signing. To do that, you need the key file. If you do not have the key file, you have few choices.

  1. The first option is to use the localized satellite assemblies provided by the vendor. Most vendors provide satellite assemblies in some languages. Unfortunately, no vendor we know provides satellite assemblies in all major languages and keeps localized assemblies always up to date.
  2. This leads you to the second option, where you must get the key. This might be difficult because vendors hardly ever release their private keys.
  3. The third option is to send the delay signed satellite assemblies to the vendor to be signed.
  4. The fourth and last option is to use some alternative localization methods provided by the vendor. Some vendors let to create your own resource and assign the resource manager of that resource into the vendor's library. This way, you can include the resources that need to be translated into your own assembly that you can localize.

If the vendor does not provide the alternative localization method, does not give you the key, or won't sign your assemblies, there is nothing you can do except to keep pressuring the vendor. More clients there are demanding a proper localization, more likely the vendor either provides localized satellite assemblies, signing services, or even give you the strong name key file.

Not having a digital signature in your localized satellite files may not be a show stopper. However, not having a strong name in your localized satellite assemblies is a show stopper because .NET runtime will not load a satellite assembly files if it is not a strong name signed in the same way as the original assembly.

Key files

Two types of key files exist. One is an SNK file that contains a public/private key pair, and you can make your key file yourself. Another is PFX that is a key file provided by certificate providers such as Verisign. Using the key files differs. If you use SNK, then you use the key file when signing the files. If you use PFX, then you install the key into the key container and give the key a name. When singing, you don't use the key file but the key name. Soluling can handle both key types. If you use SNK, then you enter the key file name in the sign dialog. If you use PFX, you enter either the key file or the key name.

Reference satellite assembly directory

The reference assembly directory is a directory that contains satellite assemblies in language-specific subdirectories. The directory is usually installed together with the library. In other words, it contains ready to be used localized satellite assembly files made by the original assembly vendor. The following directory is a reference assembly directory of Expression Blend. It contains German (de), English (en), Spanish (es), French (fr), Italian (it), Japanese (ja), Korean (ko), Simplified Chinese (zh-Hans) and Traditional Chinese (zh-Hant) satellite assemblies.

Reference assembly directory

Each satellite assembly must be in the right subdirectory where the name of the directory matches the .NET culture id of the language. If your satellite assemblies are in some other directories, you must rename the directories to use proper .NET naming.

Delay signing

If you don't have the key file and you don't have existing satellite assemblies in the reference directory, then your choice is to use delay signing. In this process, Soluling does not completely sign the assemblies but inserts the public key and reserves a space for sign data. You must complete the signing before deploying your files. However, you can test your localized assemblies without completing signing by registers assemblies for verification skipping. Use the Sn.exe tool for that. Sn.exe is a part of the .NET SDK. The following command registers the German satellite assembly, de\MyApplication.resources.dll, for verification skipping.

sn.exe -Vr de\MyApplication.resources.dll

You must run the command as an administrator. You can let Soluling handle registering by checking Register created assemblies for verification skipping checkbox of sign sheet, sign methods dialog, or sign method dialog.

Soluling NuGet package

You can get the Soluling API as a NuGet package.

PM> Install-Package Soluling

You can read the API documentation from <data-dir>\Library\NET\NET.chm file. The API source code is in GitHub.

Patterns such as Plurals, Genders and Selects

Standard .NET and UWP source code uses String.Format function. It is not plural-enabled, but fortunately, Soluling contains a plural enabled Format function for .NET and Windows Runtime. If you use standard String.Format function you might have something like this

str = String.Format("{0} files", count);

Replace "{0} files" with "{plural, one {{0} file} other {{0} files}}" and add that into the Resources.resx and give it MessagePlural name. Replace String.Format with Soluling's Format function. The modified .NET code is

str = Soluling.Plural.Format(Properties.Resources.MessagePlural, count, count);

The modified Windows Runtime code is

var rl = new ResourceLoader();
str = Soluling.Plural.Format(rl.GetString("MessagePlural"), count, count);

Soluling.Plural.Format function is found from <data-dir>\Library\Net\Plural.cs. The same code works with .NET, ASP.NET, and UWP. The code is also available at GitHub.

See the following samples:

Technology Sample directory
ASP.NET <data-dir>\Samples\ASP.NET\Framework\​MVC\Driving
ASP.NET Core <data-dir>\Samples\ASP.NET\Core\​RazorPages\Driving
UWP <data-dir>\Samples\UWP\Plural
Windows Forms <data-dir>\Samples\WindowsForms\​Plural
WPF <data-dir>\Samples\WPF\Plural

File dialog format filters

Both Windows Forms and WPF contain file dialogs that you can use to select a file to be opened and specify the file to be saved. The dialog contains Filter property that specifies file typed shown in the file type combo box.

OpenFileDialog dialog = new OpenFileDialog();
dialog.Title = "All supported files (*.xml;*.ini)|*.xml;*.ini|XML files (*.xml)|*.xml|Ini files (*.ini)|*.ini";

The format of the string is quite complicated. It contains the description text separator with file mask(s). There can be several of these pairs. If you place the above string into a string resource, the translator will see it as it is

All supported files (*.xml;*.ini)|*.xml;*.ini|XML files (*.xml)|*.xml|Ini files (*.ini)|*.ini

It may be that the translator will miss one | character or enter one extra. Either one is fatal, and your application will crash if the invalid localized file string is used. This is why it is better to use Soluling's file dialog filter format class.

OpenFileDialog dialog = new OpenFileDialog();

dialog.Filter = new Soluling.DialogFilter()
  .Supported("All supported files")
  .Add("XML files", "xml")
  .Add("Ini files", "ini")
  .ToString();

This will expose translator three plain strings: "All supported files," "XML files," and "Ini files." They are easy to translate, and a translator cannot enter invalid values. If you don't want to use or cannot use the file dialog filter format class, use the file dialog filter validation to check if any of the filter translations are invalid.

Soluling.DialogFilter class is found from <data-dir>\Library\Net\DialogFilter.cs. See following samples:

Technology Sample directory
Windows Forms <data-dir>\Samples\WinForms\FileDialog
WPF <data-dir>\Samples\WPF\FileDialog

Initial language of an application

.NET framework has a built-in support to load a satellite assembly file. When .NET assembly (application or library) is started the framework looks if there are any available satellite assembly files for the main assembly. Each satellite assembly file must be in a culture (.NET's term for locale) specific sub directory of the main assembly. If the main assembly is Application.exe then German satellite assembly is de\Application.resources.dl and German (Germany) satellite assembly file is de-DE\Application.resources.dll.

The method how a .NET application chooses this initial satellite assembly file file is shown in following.

  1. Default culture or custom culture
  2. Original resources

In addition it is possible to disable satellite assembly files.

Default culture

When a .NET application starts, the framework tries to look for the right satellite assembly file. This depends on the settings and operating system. If you have not specified the culture that should used framework uses the default culture.

Default culture is always the same culture the same as the user interface language of your operating system. If you have an English (US) operating system, the default culture is en-US. The secondary culture is en. This means that the application tries to first look for an en-US satellite assembly file. If found, the application loads it. If not found application tries to find an en satellite assembly file.

Custom culture

The file .NET runtime looks for depends on the user interface language of your operating system. If you have an English (US) OS, the runtime will look satellite assembly file from en-US or en. On German OS, the runtime looks for de-DE or de. This method to select is a bit limited because the user has no control over the initial language except for installing a multilingual OS or reinstall OS with a different language. This seems way too heavy to just select a different initial language for your application. Fortunately, there is an easier way. By adding just one line of code to your application, you can make the initial language selection smarter.

Thread.CurrentThread.CurrentUICulture = CultureInfo.CurrentCulture;

This line of C# code makes .NET runtime to look for a satellite assembly file that matched the default locale of the user. Not the user interface language of the operating system itself. Changing the default locale of the user is easy using the control panel.

You can change the default culture. This can be done by setting the CurrentUICulture property of the current thread. The following line sets the default culture to English.

Thread.CurrentThread.CurrentUICulture = new CultureInfo("en");

If you want that the application uses the default culture of the user, use the following code.

Thread.CurrentThread.CurrentUICulture = CultureInfo.CurrentCulture;

Note that this is not necessarily the same as the user interface culture of the operating system. The user might have an English operating system, but the default locale is German (Germany). The user can change the default locale from the Control Panel.

Regional and language options

You can read more about how to make the application to use the user default language.

Original resources

If the application can not found any of the above satellite assembly files, it will use the original resources of the main assembly. Our sample application will use the resources of application.

Disable satellite assembly files

If you want your application not to use the satellite assembly file, the easiest way is to remove the satellite assembly file(s). If you want to keep the files but not to use them, you can disable the satellite assembly file by setting a null default culture.

using System.Threading;
using System.Globalization; ... Thread.CurrentThread.CurrentUICulture = new CultureInfo("");

See <data-dir>\Samples\Windows Forms\IgnoreSatelliteAssembly sample.

Configuration

When you use Visual Studio project file localization Soluling reads your Visual Studio project file (.csproj or .vbproj). Most projects have two or more configurations and/or platforms. These let you specify a different set of properties for different purposes. For example, the debug configuration contains the debug information. One of the main properties of each configuration is the output directory. It specifies the directory where the output assembly is created. By default, Debug configuration uses bin\Debug sub folder and Release configuration uses bin\Release subfolder.

When Soluling compiles XAML, ResX, or satellite assembly files, it needs to know where the original assembly and the assemblies it depends on are localized. To find this, Soluling read the output path from the project file and uses that path. When you create a new Visual Studio project file source, you can specify the configuration and platform that are used. For example, the following same uses Debug configuration and AnyCPU platform.

Configuration

Before you add such a source, make sure that you compiled the project using that configuration. That will ensure that the output directory contains the assembly file, and it is up to date. Whenever you rescan the Soluling project, make sure that the Visual Studio project has been fully rebuilt so that the assembly is up to date.

Visual Studio 626

If you use a command line, use the following command:

"C:\Program Files (x86)\Microsoft Visual Studio\2019\Professional\MSBuild\15.0\Bin\MsBuild.exe" Simple471.csproj /property:Configuration=Debug

User Interface Culture

By default, .NET runtime uses a satellite assembly matching the language of the operating system itself. This means that on the English operating system, the runtime uses an English assembly file. In most cases, this is the right thing to do. However, a better choice is to use the satellite assembly matching the default culture of the operating system. Many users use the English operating system, but their default localize is not English but some other. To use the default culture instead of the language of the operating system itself, you have to add one line of code. Set Thread.CurrentThread.CurrentUiCulture property to change the user interface culture. The CultureInfo.CurrentCulture property contains the default culture of your system. This setting is specified in the Regional and Language Options of Control Panel.

Default locale

The above image contains a case where an English Windows 8.1 has Finnish as default format (e.g. locale or culture in .NET). Without modification, a .NET application will start up in English. If you want it to start up using the default culture (in this case, Finnish), follow the instructions below.

How to set the user interface culture

The following examples show how to set the user interface culture. Add lines written in bold typeface.

Note! Even Soluling can localize your application properly; it can not run (Project | Run Localized) in the desired language if you do not set the user interface culture to match the default culture.

Windows Forms (C#)

Set the culture in the Main function (Program.cs).

using System.Globalization;
using System.Threading; static void Main() { // Add this line of code Thread.CurrentThread.CurrentUICulture = CultureInfo.CurrentCulture; Application.EnableVisualStyles(); Application.SetCompatibleTextRenderingDefault(false); Application.Run(new Form1()); }

Windows Forms (Visual Basic)

Set the culture in the constructor of the main form.

Imports System.Globalization
Imports System.Threading

Public Class Form1
  ...
  Public Sub New()
    ' Add this line of code
    Thread.CurrentThread.CurrentUICulture = CultureInfo.CurrentCulture
   
    ' This call is required by the Windows Form Designer.
    InitializeComponent()
  End Sub
  ...
End Class

WPF (C#)

Add contructor in the App class (App.xaml.cs) and set the culture there.

using System.Globalization;
using System.Threading;

public partial class App : Application
{
  // Add these lines of code
  public App()
  {
    Thread.CurrentThread.CurrentUICulture = CultureInfo.CurrentCulture;
  }
}

WPF (Visual Basic)

Set the culture in the constructor of the main form.

Imports System.Globalization
Imports System.Threading

Class Application
// Add these line of codes Public Sub New() Thread.CurrentThread.CurrentUICulture = CultureInfo.CurrentCulture End Sub End Class

Why does my .NET satellite assembly not load?

If you use satellite assemblies instead of localized assemblies, it may be that your application does not load the satellite assembly you think it should load. There are a few reasons why the loading might fail. The first three ones, incorrect path, signing, and version, are fatal. They totally prevent .NET runtime to even load the assembly.

Incorrect path

Each satellite assembly must locate on a culture id specific subdirectory of the directory where the main assembly exists. If your main assembly is C:\Files\Application.exe, then German satellite assembly must be in C:\Files\Application\de\Application.resources.dll. If the path or file name is different, .NET runtime does not find the assembly. Soluling always creates satellite assemblies with the right file name and to the right subdirectory. Do not rename or move them to a different directory. You can move them if the relative path to the main assembly remains the same.

Signing

If your main assembly is a strong name signed, then all the satellite assemblies that are loaded must also be signed with the same key as the main assembly. Make sure that you specify your key in the Signing sheet of Source dialog.

Assembly version

The version number of the main assembly and its satellite assemblies must match. If they are not the same .NET runtime does not load the satellite assembly. When Soluling creates localized satellite assembly files, it, by default, gives them the same version numbers as the original assembly has. Every time you change the version of your main assembly, use Soluling or its SoluMake command-line tool to build new satellite assemblies that has matching version numbers.

No resources entry in the dependencies file

.NET Core uses a dependencies file with the main assembly. It is located on the same directory as the application assembly: <appname>.deps.json. This file must contain the satellite assembly files specified in the resources section. Either edit the dependencies file manually or let Soluling update it.

Set Initial language

The above issues are the main reason why .NET runtime can not load a satellite assembly at all. There is one more reason that makes .NET to load a different satellite assembly that you though. The initial language is the language that .NET runtime tries to load once the application starts. By default, .NET runtime tries to load a language matching the language of the operating system. This means that an English satellite assembly on English Windows, and a German satellite assembly on German Windows. If you want to load a satellite assembly matching the current language specified in the Region and Language sheet of Control Panel, you have to add some code. Here is the main function of a sample Windows Forms application.

static void Main()
{
  Application.EnableVisualStyles();
  Application.SetCompatibleTextRenderingDefault(false);
  Application.Run(new Form1());
}

Add the following lines of code in Program.cs:

using System.Threading;
using System.Globalization;
...
static void Main()
{
  Thread.CurrentThread.CurrentUICulture = CultureInfo.CurrentCulture;
  Application.EnableVisualStyles();
  Application.SetCompatibleTextRenderingDefault(false);
  Application.Run(new Form1());
}

Now your application tries to load a satellite assembly matching the regional settings instead of the operating system's language itself.

On WPF application you have to do the following modifications to App.xaml.cs.

public partial class App : Application
{
  public App()
  {
    Thread.CurrentThread.CurrentUICulture = CultureInfo.CurrentCulture;
  }
}

There is one more thing that might make .NET to load different satellite assembly file. It is the case where you have hardcoded a specific culture. For example, you might have the following code

static void Main()
{
  Thread.CurrentThread.CurrentUICulture = new Culture("en");
  Application.EnableVisualStyles();
  Application.SetCompatibleTextRenderingDefault(false);
  Application.Run(new Form1());
}

This will always make .NET to load English satellite assembly no matter the language of the operating system or settings in Control Panel.

Resource string comments

.NET has a very good resource string mechanism: .rexs files. Each resource strings item has an id and value. In addition, they can contain an optional comment that is a good place to give extra information for a translator to properly translate the string. When using .resx localization or project/solution file localization, then Soluling automatically reads also comments. However, the compiled assemblies no longer have comments. They only have the id and resource value. If you use the assembly file localization Soluling has to read them original resource source files (.resx). To do this, Soluling needs to know the Visual Studio project for the selected assembly file. In most cases, Soluling automatically detects the localization of the project file (if it exists). If detection fails, you can use the File sheet to select the files. You need to have resource file source files (.resx). A recommended way to localize a .NET project is to use the project or solution file localization.

See <data-dir>\Samples\WindowsForms\Comments sample to see how to use comments.

Resource string locations

In .NET, resource strings are stored in a specific resource file (.resx) that is compiled into a resource item (.resources). The user interface of the application uses those resource items. It is very useful for a translator to know where a specific resource string is used. This is why the context of the string should be available. This relation is not stored anywhere in the resource file or compiled assembly. However the location where a resource string is used can be found by analyzing the source code. Soluling can do that if you turn the option on by using Options sheet. In order to do this Soluling must know where the source code files are located. Soluling needs to know the Visual Studio project file to find the source code. Use File sheet to specify the project file. You need to have full sources files (.cs or .vb).

If Soluling finds resource strings that are used in a form, Soluling links them into the form node. If you select the node, the rows are shown along with node's own rows. Each row that is a linked row shows a chain icon in the info column.

Linked rows

The above image shows Form1 form of ResourceStringLocation application. The form has only one row of its own, $this.Text, but in addition it uses three resource strings: MyName, String2 and String3.

If you select the resource string node you can see only the resource strings.

Resource string rows

See <data-dir>\Samples\WindowsForms\ResourceStringLocation sample to see how to use resource strings locations.

How to localize hard coded strings of .NET application

A hardcoded string is a string inside your source code that contains a string value that should be localized. For example, you might have the following code

private void Form1_Load(object sender, EventArgs e)
{
  label2.Text = "Hello World";
}

Here "Hello World" is a hardcoded string. The right way to deal with these is to remove the hardcoded strings and replace them with resource strings. This process is called resourcing. You first add the above string into a string resource files (.resx) and replace the string literal with the resource string variable.

private void Form1_Load(object sender, EventArgs e)
{
  label2.Text = Properties.Resources.HelloWorld;
} 

Now the string value is in a resource file, and it can be easily localized without any change into the source code. This is the right way to deal with hardcoded strings. Removing them is the most important part of internationalization.

Note! Use the following feature only as of the last option if you absolutely have no possibility to modify the original source code by removing the hardcoded strings.

If you do not have any possibility to modify your application, then your option is to let Soluling localize hard coded strings. To do that, you have to turn that option on.

  1. Right-click your source in the project tree and choose Options.
  2. Select the Resources sheet and check the Hardcoded strings checkbox.
    Hard coded strings
  3. Soluling shows confirmation.
    Hard coded strings warning
  4. Click Yes to accept localization of hardcoded strings.
  5. Click OK and accept rescanning when the application prompts it.

Normally Soluling changes only the resource data of .NET assemblies. It does not modify the actual code. A localized assembly file has a 100% identical code compared to the original assembly. If you use satellite assembly files, then the localized file does not contain any code because satellite assembly is always used together with the original assembly. By localizing the hardcoded strings, Soluling starts "localizing" code too. This causes satellite assembly output to be disabled. Soluling can only create localized assemblies that contain localized resources and localized code. Most often, code contains many strings that must not be localized. For example, most SQL statements should remain intact. When you use hardcoded string localization, you have to exclude those strings that must not be localized carefully. If you localize (e.g., change) such as a string, it may be that your code does not work anymore.

Assembly info

If you need to localize the version info resources of your assembly, check Assembly info. This makes Soluling scan your assembly info files. Those files contain copyright text, application name, and various application version numbers. By default Soluling only scans the string data from assembly info. If you need to get version data (e.g., you need to change the version number), select the assembly info file in the project tree, right-click, and choose Options. Then check Scan string numbers.

.NET tools that are needed

The default localization method of Windows Forms and WPF applications is to create localized satellite assembly files. If you use that, Soluling can localize all .NET files as long as your computer has a matching .NET framework installed. If you can run the application, then Soluling can localize it. If you can not run the application, the reason is most likely a missing framework or a missing assembly. If you don't have the .NET framework that the application uses, download it from Microsoft's site and install it. If you don't have an assembly that the application uses, run the application setup again or get the missing assemblies.

In addition to satellite assembly files, Soluling can also create localized assembly files. If you choose that method, you must also have a matching .NET SDK installed. The framework alone is not enough. If you don't have the SDK, download it from Microsoft's site and install it. If you have Visual Studio installed, you also have .NET SDK.

Localization method
Framework needed
SDK needed
Project files
Yes
Yes
Assembly files, creating satellite assembly files
Yes
-*
Assembly files, creating localized assembly files
Yes
Yes

*) When creating satellite assembly files, SDK is needed on the cases the original assembly is signed with a container key, assembly uses delay signing, or you want to delay-sign the localized satellite assembly files.

The following table shows what .NET frameworks each operating system contains by default.

Operating system .NET 2.0 .NET 3.0 .NET 3.5 .NET 4.0 .NET 4.5 .NET 4.6 .NET 4.6.1 .NET 4.6.2 .NET 4.7 .NET 4.7.1 .NET 4.7.2 .NET 4.8
Windows 7
Yes
Yes
Yes
-
-
-
-
-
-
-
-
-
Windows 7 + Visual Studio 2010
Yes
Yes
Yes
Yes
-
-
-
-
-
-
-
-
Windows 7 + Visual Studio 2012
Yes
Yes
Yes
Yes
Yes
-
-
-
-
-
-
-
Windows 8
Yes
Yes
Yes
Yes
Yes
-
-
-
-
-
-
-
Windows 10, Windows 8 + VS 2015
Yes
Yes
Yes
Yes
Yes
Yes
-
-
-
-
-
-
Windows 10 Novermber Update
Yes
Yes
Yes
Yes
Yes
Yes
Yes
-
-
-
-
-
Windows 10 Anniversary Update
Yes
Yes
Yes
Yes
Yes
Yes
Yes
Yes
-
-
-
-
Windows 10 Creators Update
Yes
Yes
Yes
Yes
Yes
Yes
Yes
Yes
Yes
-
-
-
Windows 10 Fall Creators Update
Yes
Yes
Yes
Yes
Yes
Yes
Yes
Yes
Yes
Yes
-
-
Windows 10 April 2018 Update
Yes
Yes
Yes
Yes
Yes
Yes
Yes
Yes
Yes
Yes
Yes
-
Windows 10 May 2019 Update and later
Yes
Yes
Yes
Yes
Yes
Yes
Yes
Yes
Yes
Yes
Yes
Yes

For example, if you want to localize an application that uses .NET 4.0 and you use Windows 7, you have to install .NET 4.0 framework if you have not already done it or you do not have Visual Studio 2010 or later installed. The following list contains links where you can download .NET frameworks.

There are two versions of the .NET 4.0 framework: full and client profile. You don't need a full framework, but a client profile framework is enough.

.NET Samples

The following list contains samples for each .NET technologies: