currentculturemaui-blazor

Can't keep CultureInfo across pages on .Net Maui Blazor


Next sample page features a language selector, a label to display current language and a button to reload the page.

The language selector is binded to a variable with a setter where I update all culture settings I can think of.

The label successfully reflects any change on the selector. But when we click on the button to reload the page, it does not remember the changes.

@page "/test"
@inject NavigationManager NavigationManager
@using System.Globalization

<div class="Wrapper">
    <select @bind="@Culture">
        @foreach (var culture in cultures)
        {
            <option value="@culture">@culture.DisplayName</option>
        }
    </select>

    <div>
        Current culture: @CultureInfo.CurrentCulture.Name
    </div>

    <button @onclick="Reload">Reload the page</button>
</div>

<style>
    .Wrapper {
        display:flex;
        flex-direction:column;
        gap:15px;
        max-width:200px;
        margin:50px auto;
    }
</style>

@code {
    CultureInfo[] cultures = new[] {
        new CultureInfo("es-ES"),
        new CultureInfo("ca"),
        new CultureInfo("en-US"),
        new CultureInfo("pt-PT")
    };

    CultureInfo Culture
    {
        get => CultureInfo.CurrentCulture;
        set
        {
            if (CultureInfo.CurrentCulture != value)
            {
                Thread.CurrentThread.CurrentCulture = value;
                Thread.CurrentThread.CurrentUICulture = value;
                CultureInfo.DefaultThreadCurrentCulture = value;
                CultureInfo.DefaultThreadCurrentUICulture = value;

            }
        }
    }

    void Reload() {
        NavigationManager.NavigateTo(NavigationManager.Uri, true);
    }

}

Solution

  • After some help from @Liyun Zhang and many trial and errors I succeeded replacing cookies storage by Preferences storage to persist selected culture:

    1. Create a new .Net Maui Blazor app project and name it "Test"
    2. Open Nuget console and type:

    Install-Package Microsoft.Extensions.Localization

    1. In MauiProgram.cs inside CreateMauiApp() procedure and before "return builder.Build()" line, insert next line to register localization service:
    builder.Services.AddLocalization();
    
    1. Following this line, insert next lines to set the initial culture to either the persisted value or a default value (Spanish in this case):
    string? cc = Preferences.Get("blazorCulture", null);  
    if (string.IsNullOrEmpty(cc)) {
        cc = "es-ES";
        Preferences.Default.Set("blazorCulture", cc);
        }
    CultureInfo.DefaultThreadCurrentUICulture = new CultureInfo(cc);
    
    1. Append next lines to _Imports.razor so you don't have to add them on each file:
    @using System.Globalization  
    @using Microsoft.Extensions.Localization  
    @using Test.Resources.Languages  
    
    1. Under Resources folder, add a Languages folder.
      Under Languages folder, add a resources file and call it "MyStrings.resx".
      Open MyStrings.resx and enter "HelloWorld" as key and "Hello, World!" as its default value.
      Add a new resources file called "MyStrings.es-ES.resx" for European Spanish values.
      Open MyStrings.es-ES.resx and enter "HelloWorld" as key and "Hola, Mundo!" as its Spanish value.
      Add a new resources file called "MyStrings.ca.resx"
      Open MyStrings.es-ES.resx and enter "HelloWorld" as key and "Hola, Mon!" as its Catalan value.
      Add a new resources file called "MyStrings.pt-PT.resx" for portuguese european language.
      Open MyStrings.pt-PT.resx and enter "HelloWorld" as key and "Olá Mundo!" as its Portuguese value.

    2. Under Shared folder, add next Lang.razor component, which lets you select among a list of available languages and sends a callback notification to the component host when selection changes.

    <select @bind="@Culture">
        @foreach (var culture in cultures)
        {
            <option value="@culture">@culture.DisplayName</option>
        }
    </select>
    
    @code {
        [Parameter] public EventCallback<CultureInfo> AfterUpdate { get; set; }
        [Parameter]
        public CultureInfo? Culture
        {
            get => _culture;
            set
            {
                if (_culture != value)
                {
                    _culture = value;
                    if (AfterUpdate.HasDelegate) AfterUpdate.InvokeAsync(value);
                }
            }
        }
    
        private CultureInfo? _culture;
    
        CultureInfo[] cultures = new[] {
            new CultureInfo("es-ES"),
            new CultureInfo("ca"),
            new CultureInfo("en-US"),
            new CultureInfo("pt-PT")
        };
    }
    
    1. In order to make use of the component, replace Pages/Index.razor code by the following code. AfterLangUpdate callback delegate is responsible for a) persist the selected language setting the new value on Preferences, b) setting CurrentUICulture so Localizer can pick the right resource file to display the translation and c) reloading the page to make sure the new language is active everywhere:
    @page "/"
    
    @inject IStringLocalizer<MyStrings> Localizer
    @inject NavigationManager NavigationManager
    
    <h1>@Localizer["HelloWorld"]</h1>
    
    <Lang Culture="CultureInfo.DefaultThreadCurrentUICulture" AfterUpdate="AfterLangUpdate"></Lang>
    
    @code {
    
        private void AfterLangUpdate(CultureInfo culture) {
            Preferences.Set("blazorCulture", culture.Name);
            CultureInfo.DefaultThreadCurrentUICulture = culture;
            NavigationManager.NavigateTo(NavigationManager.Uri, true);
        }
    }