@page "/localization"
@inject IStringLocalizer<Localization> Localizer

<h3>@Localizer["Title"]</h3>

<p>
    @Localizer["P1"] <code>BootstrapBlazor</code> @Localizer["P2"] <code>UI</code> @Localizer["P3"]：
</p>

<Tips>
    <div>@Localizer["T1"] <a href="https://docs.microsoft.com/zh-cn/aspnet/core/blazor/globalization-localization" target="_blank">@Localizer["T2"]</a></div>
    <div>@Localizer["T3"] <code>wasm</code> @Localizer["T4"] <code>en</code></div>
    <div>@((MarkupString)Localizer["LocalizationFileDesc"].Value)</div>
</Tips>

<p><b>@Localizer["N1"]</b></p>

<p>
    <div>
        <code>BootstrapBlazor</code> @Localizer["N2"] <code>Json</code> @Localizer["N3"] <code>UI</code> @Localizer["N4"]。<a href="https://www.nuget.org/packages/BootstrapBlazor/" target="_blank">BootstrapBlazor</a> @Localizer["N5"]。
    </div>
    <ul class="ul-demo mt-2">
        <li>@Localizer["N6"]</li>
        <li>@Localizer["N7"]</li>
    </ul>
    <div class="mt-2">@((MarkupString)Localizer["AdditionalJsonFile"].Value)</div>
    <ul class="ul-demo mt-2">
        <li>@Localizer["N8"]</li>
        <li>@Localizer["N9"]</li>
        <li>@Localizer["ES"]</li>
        <li>@Localizer["TW"]</li>
    </ul>
    <div class="mt-2">
        @Localizer["N10"] <code>zh-CN</code> @Localizer["N11"] <code>zh-CN</code> @Localizer["N12"]：<code>zh-CN</code> @Localizer["N13"] <code>zh</code>
    </div>
    <div class="mt-2">
        @Localizer["N14"] <code>FallbackCulture</code> @Localizer["N15"] <code>en</code>
    </div>

    <div class=mt-2><b>@Localizer["N16"]：</b></div>

    <div class="mt-2">@Localizer["N17"] <code>Centos</code> <code>Ubuntu</code> <code>mac</code> @Localizer["N18"]：</div>
</p>

<Pre class="mb-3">{
  "BootstrapBlazorOptions": {
    "DefaultCultureInfo": "en"
  }
}</Pre>

<p><b>@Localizer["N19"]</b></p>

<p><b>Server-Side App</b></p>

<p><b>1. @Localizer["N20"]</b></p>

<p>@Localizer["N21"] <code>FallbackCultureName</code> @Localizer["N22"] <code>SupportedCultures</code> @Localizer["N23"]</p>

<Pre class="mb-3">{
  "BootstrapBlazorOptions": {
    "FallbackCultureName": "en",
    "SupportedCultures": [
      "zh-CN",
      "en-US"
    ]
  }
}</Pre>

<p><b>2. @Localizer["N24"]</b></p>

<Tab>
    <TabItem Text="NET6.0" Icon="fa-solid fa-code" Closable="false">
<Pre>builder.Services.AddRazorPages();
builder.Services.AddServerSideBlazor();

// @Localizer["N25"]
builder.Services.AddBootstrapBlazor();

// @Localizer["N26"]
builder.Services.AddRequestLocalization&lt;IOptions&lt;BootstrapBlazorOptions&gt;&gt;((localizerOption, blazorOption)=>
{
    var supportedCultures = blazorOption.Value.GetSupportedCultures();
    localizerOption.SupportedCultures = supportedCultures;
    localizerOption.SupportedUICultures = supportedCultures;
});

var app = builder.Build();

// @Localizer["N27"]
var option = app.Services.GetService&lt;IOptions&lt;RequestLocalizationOptions&gt;&gt;();
if (option != null)
{
    app.UseRequestLocalization(option.Value);
}
</Pre>
    </TabItem>
    <TabItem Text="NET5.0" Icon="fa-solid fa-code" Closable="false">
<Pre class="mb-3">public class Startup
{
    public void ConfigureServices(IServiceCollection services)
    {
        // @Localizer["N28"]
        services.AddBootstrapBlazor();

        // @Localizer["N29"]
        services.AddRequestLocalization&lt;IOptions&lt;BootstrapBlazorOptions&gt;&gt;((localizerOption, blazorOption) =>
        {
            var supportedCultures = blazorOption.Value.GetSupportedCultures();

            localizerOption.SupportedCultures = supportedCultures;
            localizerOption.SupportedUICultures = supportedCultures;
        });
    }

    public void Configure(IApplicationBuilder app, IWebHostEnvironment env)
    {
        // @Localizer["N30"]
        app.UseRequestLocalization(app.ApplicationServices.GetService&lt;IOptions&lt;RequestLocalizationOptions&gt;&gt;()!.Value);
    }
}</Pre>
    </TabItem>
</Tab>

<p><b>3. @Localizer["N31"]</b></p>
<Pre class="mb-3">[Route("[controller]/[action]")]
public class CultureController : Controller
{
    public IActionResult SetCulture(string culture, string redirectUri)
    {
        if (!string.IsNullOrEmpty(culture))
        {
            HttpContext.Response.Cookies.Append(
                CookieRequestCultureProvider.DefaultCookieName,
                CookieRequestCultureProvider.MakeCookieValue(new RequestCulture(culture, culture)));
        }

        return LocalRedirect(redirectUri);
    }

    public IActionResult ResetCulture(string redirectUri)
    {
        HttpContext.Response.Cookies.Delete(CookieRequestCultureProvider.DefaultCookieName);

        return LocalRedirect(redirectUri);
    }
}</Pre>

<p><b>3. @Localizer["N32"]</b></p>
<Pre class="mb-3">@@inherits BootstrapComponentBase
@@inject IOptions&lt;BootstrapBlazorOptions&gt; BootstrapOptions
@@inject NavigationManager NavigationManager
@@inject ICultureStorage CultureStorage

&lt;div @@attributes="@@AdditionalAttributes" class="@@ClassString"&gt;
    &lt;label&gt;@Localizer["N33"]：&lt;/label&gt;
    &lt;Select Value="@@SelectedCulture" OnSelectedItemChanged="@@SetCulture"&gt;
        &lt;Options&gt;
            @@foreach (var kv in Configuration.GetSupportCultures())
            {
                &lt;SelectOption Text="@@kv.Key" Value="@@kv.Value" /&gt;
            }
        &lt;/Options&gt;
    &lt;/Select&gt;
&lt;/div&gt;

@@code {
    private string? ClassString =&gt; CssBuilder.Default("culture-selector")
        .AddClassFromAttributes(AdditionalAttributes)
        .Build();

    private string SelectedCulture { get; set; } = CultureInfo.CurrentUICulture.Name;

    private async Task SetCulture(SelectedItem item)
    {
        if (CultureStorage.Mode == CultureStorageMode.Webapi)
        {
            // @Localizer["N34"]
            if (SelectedCulture != item.Value)
            {
                var culture = item.Value;
                var uri = new Uri(NavigationManager.Uri).GetComponents(UriComponents.PathAndQuery, UriFormat.SafeUnescaped);
                var query = $"?culture={Uri.EscapeDataString(culture)}&redirectUri={Uri.EscapeDataString(uri)}";

                // use a path that matches your culture redirect controller from the previous steps
                NavigationManager.NavigateTo("/Culture/SetCulture" + query, forceLoad: true);
            }
        }
        else
        {
            var cultureName = item.Value;
            if (cultureName != CultureInfo.CurrentCulture.Name)
            {
                await JSRuntime.SetCulture(cultureName);
                var culture = new CultureInfo(cultureName);
                CultureInfo.CurrentCulture = culture;
                CultureInfo.CurrentUICulture = culture;

                NavigationManager.NavigateTo(NavigationManager.Uri, forceLoad: true);
            }
        }
    }
}</Pre>

<p><b>4. @Localizer["N35"] <code>Json</code> @Localizer["N36"]</b></p>

<p>
    <code>BootstrapBlazor</code> @Localizer["N37"] <code>resx</code> @Localizer["N38"] <code>json</code> @Localizer["N39"] <code>json</code> @Localizer["N40"]
</p>

<p>
    <div>@Localizer["N41"]</div>

    <ul class="ul-demo mt-3">
        <li>@Localizer["N42"]</li>
        <li>@Localizer["N43"]</li>
        <li>@Localizer["N44"]</li>
        <li>@Localizer["N45"]</li>
    </ul>
</p>

<Pre class="mb-3">public void ConfigureServices(IServiceCollection services)
{
    services.AddBootstrapBlazor(null, options =>
    {
        // @Localizer["N46"]
        options.IgnoreLocalizerMissing = true;

        // @Localizer["N47"]
        options.ResourceManagerStringLocalizerType = typeof(Program);

        // @Localizer["N48"]
        options.AdditionalJsonAssemblies = new[] { typeof(BootstrapBlazor.Server.App).Assembly };

        // @Localizer["N49"]
        options.AdditionalJsonFiles = new string[]
        {
            @@"D:\Argo\src\BootstrapBlazor\src\BootstrapBlazor.Server\Locales\zh-TW.json",
            @@"D:\Argo\src\BootstrapBlazor\src\BootstrapBlazor.Server\Locales\zh-CN.json"
        };
    });
}
</Pre>

<p>@Localizer["N50"] <code>ConfigureJsonLocalizationOptions</code></p>

<Pre class="mb-3">public void ConfigureServices(IServiceCollection services)
{
    services.AddBootstrapBlazor();
    services.ConfigureJsonLocalizationOptions(options =>
    {
        // @Localizer["N51"]
        options.IgnoreLocalizerMissing = true;

        // @Localizer["N52"]
        options.AdditionalJsonAssemblies = new Assembly[]
        {
            typeof(BootstrapBlazor.Server.App).Assembly,
        };

        // @Localizer["N53"]
        options.AdditionalJsonFiles = new string[]
        {
            @@"D:\Argo\src\BootstrapBlazor\src\BootstrapBlazor.Server\Locales\zh-TW.json",
            @@"D:\Argo\src\BootstrapBlazor\src\BootstrapBlazor.Server\Locales\zh-CN.json"
        };
    });
}</Pre>

<p><b>Web Assembly</b></p>

<p><b>1. @Localizer["N54"]</b></p>
<Pre class="mb-3">public static async Task Main(string[] args)
{
    var builder = WebAssemblyHostBuilder.CreateDefault(args);

    builder.RootComponents.Add&lt;App&gt;("app");

    builder.Services.AddTransient(sp =&gt; new HttpClient { BaseAddress = new Uri(builder.HostEnvironment.BaseAddress) });

    // @Localizer["N55"]
    builder.Services.AddBootstrapBlazor();

    builder.Services.AddSingleton&lt;ICultureStorage, DefaultCultureStorage&gt;();

    // @Localizer["N56"]
    builder.Services.Configure&lt;BootstrapBlazorOptions&gt;(op =>
    {
        op.ToastDelay = 4000;
        op.SupportedCultures = new List&lt;string&gt; { "zh-CN", "en-US" };
    });

    var host = builder.Build();

    await GetCultureAsync(host);

    await host.RunAsync();
}

private static async Task GetCultureAsync(WebAssemblyHost host)
{
    var jsRuntime = host.Services.GetRequiredService&lt;IJSRuntime&gt;();
    var cultureName = await jsRuntime.GetCulture() ?? "zh-CN";
    var culture = new CultureInfo(cultureName);
    CultureInfo.DefaultThreadCurrentCulture = culture;
    CultureInfo.DefaultThreadCurrentUICulture = culture;
}

internal class DefaultCultureStorage : ICultureStorage
{
    public CultureStorageMode Mode { get; set; } = CultureStorageMode.LocalStorage;
}
</Pre>

<p><b>2. @Localizer["N57"]</b></p>

<p>@Localizer["N58"]</p>

<p id="lang"><b>@Localizer["N59"]</b></p>

<Pre class="mb-3">public static async Task Main(string[] args)
{
    // @Localizer["N60"]
    CultureInfo.CurrentCulture = new CultureInfo("zh-CN");
    CultureInfo.CurrentUICulture = new CultureInfo("zh-CN");

    // ...

    var host = builder.Build();

    await GetCultureAsync(host);

    await host.RunAsync();
}
</Pre>

<p><b>@Localizer["N61"]</b></p>

<Tab>
    <TabItem Text="appsettings.json" Icon="fa-solid fa-code" Closable="false">
<Pre class="mb-3">"BootstrapBlazorOptions": {
    "IgnoreLocalizerMissing": true
}</Pre>
    </TabItem>
    <TabItem Text="C#" Icon="fa-solid fa-code" Closable="false">
<Pre>var builder = WebApplication.CreateBuilder(args);

// @Localizer["N62"]
builder.Services.AddBootstrapBlazor(null, options =>
{
    // @Localizer["N63"]
    options.IgnoreLocalizerMissing = true;
});</Pre>
    </TabItem>
</Tab>

<Video Name="localizer" />
