Localization

It is often necessary to adapt an application to a specific subset of users within a market. Localization includes the type of actions developers take to modify both user interface elements and content to adhere to more languages or cultures. Specifically, text translation is done by applying alternate strings of text at runtime which accommodate a user's language preference.

Many apps store these pieces of text in dedicated resource files that the app parses and assigns as text throughout the application. Uno.Extensions.Localization provides a consistent way to resolve the text of a specific culture or locale across platforms. This feature allows for modifying them to be applied upon app restart.

It uses Microsoft.Extensions.Localization for any localization-related work. For documentation on the broader process of localization, read the references listed at the bottom.

Set up localization

protected override void OnLaunched(LaunchActivatedEventArgs e)
{
    var appBuilder = this.CreateBuilder(args)
        .Configure(host => 
        {
            host.UseLocalization()
        });
...

An implementation of IStringLocalizer (ResourceLoaderStringLocalizer) will be registered as a service. This service offers a consistent way to resolve localized strings. Behind the scenes, it will automatically use ResourceManager on Windows and ResourceLoader on other platforms.

Adding language-specific resources

The ResourceLoaderStringLocalizer will look for .resw files in folders corresponding to the well-known language tag (eg en-US). For example, if the current culture is en-US, the ResourceLoaderStringLocalizer will look for .resw files in the en-US folder. If the current culture is fr-FR, the ResourceLoaderStringLocalizer will look for .resw files in the fr-FR folder.

Planning to support different locales

The cultures which the app will support are enumerated in a specific section of the appsettings.json configuration file. The LocalizationConfiguration section of the file should look like the code example below:

{
  "LocalizationConfiguration": {
    "Cultures": [ "fr", "en" ]
  },
  ...
}

Add resource files

To add a new resource file, right-click on the project and select Add > New Item.... Select Resource File (.resw) and name it Resources.resw. Resource files have a key-value pair structure. The key is used to identify the resource, and the value can represent any valid property value such as translated text, the width of an item, or a color.

Resolving localized strings

Once local-specific resources are included, the localization feature can be used to resolve those localized values.

Using resources in XAML

The key contains a name that corresponds to the x:Uid and the intended property of the XAML element. The value contains the localized text.

For example, if the x:Uid property of a TextBlock is MyTextBlock, the key in the resource file should be MyTextBlock.Text. In XAML, assigning a localized value to an element with an x:Uid property looks like this:

<TextBlock x:Uid="MyTextBlock" />

Using resources in code-behind

Setting the x:Uid property in markup is not required to resolve localized resources like text. The IStringLocalizer service can be resolved by the service provider. This service can be used to resolve localized strings in code behind.

var stringLocalizer = serviceProvider.GetService<IStringLocalizer>();

Strings can be resolved using the indexer on the IStringLocalizer as a dictionary. This indexer takes a key and returns the localized string value.

string myString = stringLocalizer["MyKey"];

LocalizedString objects are the primary type resolved from IStringLocalizer. While these objects can be implicitly converted to strings, they also contain additional information which may be desirable. For instance, LocalizedString includes a boolean indicating whether the resource was not found. This can be used to determine whether a fallback value should be used.

LocalizedString myString = stringLocalizer["MyKey"];
var isResourceNotFound = myString.ResourceNotFound;

UI Culture

Current culture or locale can be changed using ILocalizationService. This action requires an app restart.

public class MainViewModel
{
    private readonly ILocalizationService localizationService;

    public MainViewModel(ILocalizationService localizationService)
    {
        this.localizationService = localizationService;
    } 
    
    public Task ToggleLocalizationAsync()
    {
        var currentCulture = localizationService.CurrentCulture;
        var culture = localizationService.SupportedCultures.First(culture => culture.Name != currentCulture.Name);

        return localizationService.SetCurrentCultureAsync(culture);
    }
}

See also