Files
radzen-blazor/Radzen.Blazor.Tests/LocalizerTests.cs
Vladimir Enchev e5bd0343fa Add built-in German, French, Spanish, Italian and Japanese translations
Ship satellite resource files (RadzenStrings.{de,fr,es,it,ja}.resx) with all
535 strings translated, so components localize out of the box via the standard
.NET ResourceManager.

Make culture handling reactive everywhere:
- RadzenDatePicker rebuilds its month/year lists when Culture or the
  DefaultCulture cascade changes (previously cached at init).
- Scheduler views, HtmlEditor tools and the spreadsheet ChartOverlay localize
  through their parent component's UICulture instead of CurrentUICulture;
  spreadsheet dialogs honor a DefaultUICulture cascade. UICulture is added to
  IScheduler/ISpreadsheet as default interface members, so this is non-breaking.

Update the Localization demo with an interactive language switcher (cascading
DefaultUICulture + DefaultCulture) backed by an ILocalizer so it works in-place
on Blazor WebAssembly.
2026-06-15 18:45:19 +03:00

175 lines
6.1 KiB
C#

using System.Collections.Generic;
using System.Globalization;
using Bunit;
using Microsoft.AspNetCore.Components;
using Microsoft.Extensions.DependencyInjection;
using Radzen;
using Radzen.Blazor;
using Xunit;
#nullable enable
namespace Radzen.Blazor.Tests;
public class LocalizerTests
{
[Fact]
public void Localizer_Returns_Resx_Default()
{
var result = Localizer.Default.Get(nameof(RadzenStrings.Spreadsheet_OK), CultureInfo.InvariantCulture);
Assert.Equal("OK", result);
}
[Fact]
public void Localizer_Returns_Key_When_Not_Found()
{
var result = Localizer.Default.Get("NonExistent_Key", CultureInfo.InvariantCulture);
Assert.Equal("NonExistent_Key", result);
}
[Fact]
public void Localizer_Custom_Override_Takes_Precedence()
{
var custom = new TestLocalizer("Spreadsheet_OK", "Aceptar");
var localizer = new Localizer(custom);
var result = localizer.Get(nameof(RadzenStrings.Spreadsheet_OK), CultureInfo.InvariantCulture);
Assert.Equal("Aceptar", result);
}
[Fact]
public void Localizer_Custom_Returns_Null_Falls_Back_To_Resx()
{
var custom = new TestLocalizer("other_key", "other_value");
var localizer = new Localizer(custom);
var result = localizer.Get(nameof(RadzenStrings.Spreadsheet_OK), CultureInfo.InvariantCulture);
Assert.Equal("OK", result);
}
[Fact]
public void Localizer_Returns_Resx_Default_For_Various_Keys()
{
var localizer = Localizer.Default;
Assert.Equal("Sort ascending", localizer.Get(nameof(RadzenStrings.Spreadsheet_SortAscending), CultureInfo.InvariantCulture));
Assert.Equal("Cancel", localizer.Get(nameof(RadzenStrings.Spreadsheet_Cancel), CultureInfo.InvariantCulture));
Assert.Equal("contains", localizer.Get(nameof(RadzenStrings.Spreadsheet_FilterContains), CultureInfo.InvariantCulture));
Assert.Equal("Format Cells...", localizer.Get(nameof(RadzenStrings.Spreadsheet_FormatCells), CultureInfo.InvariantCulture));
}
[Fact]
public void AddRadzenComponents_Registers_Localizer()
{
var services = new ServiceCollection();
services.AddRadzenComponents();
var provider = services.BuildServiceProvider();
var localizer = provider.GetService<Localizer>();
Assert.NotNull(localizer);
}
[Fact]
public void Localizer_Works_Without_ILocalizer_Registered()
{
var services = new ServiceCollection();
services.AddRadzenComponents();
var provider = services.BuildServiceProvider();
var localizer = provider.GetRequiredService<Localizer>();
var result = localizer.Get(nameof(RadzenStrings.Spreadsheet_OK), CultureInfo.InvariantCulture);
Assert.Equal("OK", result);
}
[Fact]
public void Localizer_Uses_Custom_ILocalizer_When_Registered()
{
var services = new ServiceCollection();
services.AddRadzenComponents();
services.AddSingleton<ILocalizer>(new TestLocalizer("Spreadsheet_OK", "Aceptar"));
var provider = services.BuildServiceProvider();
var localizer = provider.GetRequiredService<Localizer>();
var result = localizer.Get(nameof(RadzenStrings.Spreadsheet_OK), CultureInfo.InvariantCulture);
Assert.Equal("Aceptar", result);
}
[Fact]
public void Localizer_Format_String_Key_Contains_Placeholder()
{
var localizer = Localizer.Default;
var template = localizer.Get(nameof(RadzenStrings.Spreadsheet_SheetNameAlreadyExists), CultureInfo.InvariantCulture);
var result = string.Format(template, "Sheet2");
Assert.Equal("A sheet named 'Sheet2' already exists.", result);
}
[Theory]
[InlineData("de")]
[InlineData("fr")]
[InlineData("es")]
[InlineData("it")]
[InlineData("ja")]
public void Localizer_Resolves_Builtin_Translations_For_Culture(string lang)
{
var culture = new CultureInfo(lang);
var cancel = Localizer.Default.Get(nameof(RadzenStrings.Spreadsheet_Cancel), culture);
// The built-in satellite resource must resolve and translate Cancel away from English.
Assert.NotEqual("Cancel", cancel);
Assert.False(string.IsNullOrWhiteSpace(cancel));
}
[Fact]
public void Localizer_Translates_Known_Strings()
{
Assert.Equal("Abbrechen", Localizer.Default.Get(nameof(RadzenStrings.Spreadsheet_Cancel), new CultureInfo("de")));
Assert.Equal("Aujourd'hui", Localizer.Default.Get(nameof(RadzenStrings.Scheduler_TodayText), new CultureInfo("fr")));
Assert.Equal("キャンセル", Localizer.Default.Get(nameof(RadzenStrings.Spreadsheet_Cancel), new CultureInfo("ja")));
}
[Fact]
public void DataGrid_Uses_DefaultUICulture_Cascade_For_Localized_Strings()
{
using var ctx = new TestContext();
ctx.JSInterop.Mode = JSRuntimeMode.Loose;
ctx.JSInterop.SetupModule("_content/Radzen.Blazor/Radzen.Blazor.js");
ctx.Services.AddRadzenComponents();
var component = ctx.RenderComponent<CascadingValue<CultureInfo>>(parameters => parameters
.Add(p => p.Name, nameof(RadzenComponent.DefaultUICulture))
.Add(p => p.Value, new CultureInfo("de"))
.AddChildContent<RadzenDataGrid<dynamic>>(grid => grid
.Add(g => g.Data, (IEnumerable<dynamic>)new[] { new { Id = 1 } })
.Add(g => g.AllowGrouping, true)));
// German translation of DataGrid_GroupPanelText must appear via the cascade + satellite resource.
Assert.Contains("Ziehen Sie eine Spaltenüberschrift", component.Markup);
Assert.DoesNotContain("Drag a column header here", component.Markup);
}
private class TestLocalizer : ILocalizer
{
private readonly string key;
private readonly string value;
public TestLocalizer(string key, string value)
{
this.key = key;
this.value = value;
}
public string? Get(string key, CultureInfo culture)
{
return key == this.key ? value : null;
}
}
}