mirror of
https://github.com/AtomUI/AtomUI.git
synced 2026-10-18 22:46:38 +08:00
228 lines
8.4 KiB
C#
228 lines
8.4 KiB
C#
using System.Globalization;
|
|
using Shouldly;
|
|
using Xunit;
|
|
|
|
namespace AtomUI.Localization.Tests;
|
|
|
|
public class LocalizationBuilderTests
|
|
{
|
|
[Fact]
|
|
public void Build_Defaults_To_English_As_The_Only_Supported_Language()
|
|
{
|
|
var builder = CreateBuilderWithEnglishCatalog();
|
|
|
|
using var runtime = builder.Build(static () => true);
|
|
|
|
runtime.LanguageManager.Current.CurrentLanguage.ShouldBe(LanguageTags.EnUS);
|
|
runtime.LanguageManager.Current.Revision.ShouldBe(0);
|
|
runtime.LanguageManager.SupportedLanguages.Select(static definition => definition.Tag)
|
|
.ShouldBe([LanguageTags.EnUS]);
|
|
runtime.Snapshots.Keys.ShouldBe([LanguageTags.EnUS]);
|
|
}
|
|
|
|
[Fact]
|
|
public void Build_Defensively_Copies_And_DeDuplicates_Supported_Languages()
|
|
{
|
|
var languages = new[]
|
|
{
|
|
LanguageTags.ZhCN,
|
|
LanguageTags.EnUS,
|
|
LanguageTags.ZhCN
|
|
};
|
|
var builder = CreateBuilderWithEnglishCatalog();
|
|
builder.AddTranslationBundle(CreateBundle(LanguageTags.ZhCN, "中文"));
|
|
builder.ConfigureLanguages(LanguageTags.ZhCN, languages);
|
|
|
|
languages[0] = LanguageTags.FrFR;
|
|
using var runtime = builder.Build(static () => true);
|
|
|
|
runtime.LanguageManager.Current.CurrentLanguage.ShouldBe(LanguageTags.ZhCN);
|
|
runtime.LanguageManager.SupportedLanguages.Select(static definition => definition.Tag)
|
|
.ShouldBe([LanguageTags.ZhCN, LanguageTags.EnUS]);
|
|
runtime.Snapshots.Keys.ShouldBe([LanguageTags.ZhCN, LanguageTags.EnUS], ignoreOrder: true);
|
|
}
|
|
|
|
[Fact]
|
|
public void Build_Requires_Default_Language_To_Be_Supported()
|
|
{
|
|
var builder = CreateBuilderWithEnglishCatalog();
|
|
builder.ConfigureLanguages(LanguageTags.ZhCN, [LanguageTags.EnUS]);
|
|
|
|
var exception = Should.Throw<LanguageConfigurationException>(() =>
|
|
builder.Build(static () => true));
|
|
|
|
exception.Message.ShouldContain("zh-CN");
|
|
exception.Message.ShouldContain("supported");
|
|
}
|
|
|
|
[Fact]
|
|
public void Build_Rejects_An_Empty_Supported_Language_Set()
|
|
{
|
|
var builder = CreateBuilderWithEnglishCatalog();
|
|
builder.ConfigureLanguages(LanguageTags.EnUS, []);
|
|
|
|
Should.Throw<LanguageConfigurationException>(() => builder.Build(static () => true))
|
|
.Message.ShouldContain("At least one");
|
|
}
|
|
|
|
[Fact]
|
|
public void Build_Rejects_Default_Language_Tag_In_Supported_Set()
|
|
{
|
|
var builder = CreateBuilderWithEnglishCatalog();
|
|
builder.ConfigureLanguages(LanguageTags.EnUS, [LanguageTags.EnUS, default]);
|
|
|
|
Should.Throw<LanguageConfigurationException>(() => builder.Build(static () => true))
|
|
.Message.ShouldContain("valid language tag");
|
|
}
|
|
|
|
[Fact]
|
|
public void Build_Uses_Generated_Standard_Language_Definitions()
|
|
{
|
|
var builder = CreateBuilderWithEnglishCatalog();
|
|
builder.AddTranslationBundle(CreateBundle(LanguageTags.ArSA, "العربية"));
|
|
builder.ConfigureLanguages(LanguageTags.ArSA, [LanguageTags.ArSA]);
|
|
|
|
using var runtime = builder.Build(static () => true);
|
|
var definition = runtime.LanguageManager.SupportedLanguages.ShouldHaveSingleItem();
|
|
|
|
definition.Tag.ShouldBe(LanguageTags.ArSA);
|
|
definition.FormattingCulture.Name.ShouldBe("ar-SA");
|
|
definition.NativeName.ShouldBe("العربية (المملكة العربية السعودية)");
|
|
definition.TextDirection.ShouldBe(LanguageTextDirection.RightToLeft);
|
|
}
|
|
|
|
[Fact]
|
|
public void Build_Requires_An_Explicit_Definition_For_Unknown_Private_Tag()
|
|
{
|
|
var privateTag = LanguageTag.Parse("en-x-acme");
|
|
var builder = CreateBuilderWithEnglishCatalog();
|
|
builder.ConfigureLanguages(privateTag, [privateTag]);
|
|
|
|
var exception = Should.Throw<LanguageConfigurationException>(() =>
|
|
builder.Build(static () => true));
|
|
|
|
exception.Message.ShouldContain("en-x-acme");
|
|
exception.Message.ShouldContain(nameof(LanguageDefinition));
|
|
}
|
|
|
|
[Fact]
|
|
public void Build_Uses_An_Explicit_Definition_For_A_Private_Tag()
|
|
{
|
|
var privateTag = LanguageTag.Parse("en-x-acme");
|
|
var builder = CreateBuilderWithEnglishCatalog();
|
|
builder.AddLanguageDefinition(new LanguageDefinition(
|
|
privateTag,
|
|
CultureInfo.GetCultureInfo("en-US"),
|
|
"Acme English",
|
|
LanguageTextDirection.LeftToRight));
|
|
builder.ConfigureLanguages(privateTag, [privateTag]);
|
|
|
|
using var runtime = builder.Build(static () => true);
|
|
var definition = runtime.LanguageManager.SupportedLanguages.ShouldHaveSingleItem();
|
|
|
|
definition.Tag.ShouldBe(privateTag);
|
|
definition.NativeName.ShouldBe("Acme English");
|
|
runtime.Localizer.Get(BuilderResourceKind.Value).ShouldBe("English");
|
|
}
|
|
|
|
[Fact]
|
|
public void Build_Rejects_Duplicate_Explicit_Language_Definitions()
|
|
{
|
|
var builder = CreateBuilderWithEnglishCatalog();
|
|
builder.AddLanguageDefinition(new LanguageDefinition(
|
|
LanguageTags.EnUS,
|
|
CultureInfo.GetCultureInfo("en-US"),
|
|
"First",
|
|
LanguageTextDirection.LeftToRight));
|
|
builder.AddLanguageDefinition(new LanguageDefinition(
|
|
LanguageTags.EnUS,
|
|
CultureInfo.GetCultureInfo("en-GB"),
|
|
"Second",
|
|
LanguageTextDirection.RightToLeft));
|
|
|
|
var exception = Should.Throw<LanguageConfigurationException>(() =>
|
|
builder.Build(static () => true));
|
|
|
|
exception.Message.ShouldContain("en-US");
|
|
exception.Message.ShouldContain("more than once");
|
|
}
|
|
|
|
[Fact]
|
|
public void Build_Prebuilds_Every_Supported_Language_Snapshot()
|
|
{
|
|
var builder = CreateBuilderWithEnglishCatalog();
|
|
builder.ConfigureLanguages(
|
|
LanguageTags.EnUS,
|
|
[LanguageTags.EnUS, LanguageTags.ZhCN]);
|
|
|
|
var exception = Should.Throw<LanguageCoverageException>(() =>
|
|
builder.Build(static () => true));
|
|
|
|
exception.Message.ShouldContain("zh-CN");
|
|
exception.Message.ShouldContain("Acme:Acme.BuilderResourceKind");
|
|
}
|
|
|
|
[Fact]
|
|
public void Build_Composes_One_Shared_Runtime_And_Is_Idempotent()
|
|
{
|
|
var builder = CreateBuilderWithEnglishCatalog();
|
|
|
|
using var runtime = builder.Build(static () => true);
|
|
var second = builder.Build(static () => false);
|
|
|
|
second.ShouldBeSameAs(runtime);
|
|
runtime.ResourceProvider.TryGetResource(BuilderResourceKind.Value, null, out var resource).ShouldBeTrue();
|
|
resource.ShouldBe(runtime.Localizer.Get(BuilderResourceKind.Value));
|
|
runtime.LanguageManager.ShouldBeAssignableTo<ILanguageManager>();
|
|
runtime.Localizer.ShouldBeAssignableTo<ILocalizer>();
|
|
}
|
|
|
|
[Fact]
|
|
public void Build_Freezes_All_Further_Registrations()
|
|
{
|
|
var builder = CreateBuilderWithEnglishCatalog();
|
|
using var runtime = builder.Build(static () => true);
|
|
|
|
Should.Throw<InvalidOperationException>(() =>
|
|
builder.AddTranslationBundle(CreateBundle(LanguageTags.ZhCN, "中文")));
|
|
Should.Throw<InvalidOperationException>(() =>
|
|
builder.AddLanguageDefinition(new LanguageDefinition(
|
|
LanguageTags.ZhCN,
|
|
CultureInfo.GetCultureInfo("zh-CN"),
|
|
"简体中文",
|
|
LanguageTextDirection.LeftToRight)));
|
|
Should.Throw<InvalidOperationException>(() =>
|
|
builder.ConfigureLanguages(LanguageTags.EnUS, [LanguageTags.EnUS]));
|
|
}
|
|
|
|
private static LocalizationBuilder CreateBuilderWithEnglishCatalog()
|
|
{
|
|
var builder = new LocalizationBuilder();
|
|
builder.AddCatalog(new LanguageCatalogDescriptor<BuilderResourceKind>(
|
|
"Acme:Acme.BuilderResourceKind",
|
|
1,
|
|
[new LanguageCatalogUnitDescriptor("Value")],
|
|
static key => key == BuilderResourceKind.Value ? 0 : -1));
|
|
builder.AddTranslationBundle(CreateBundle(LanguageTags.EnUS, "English"));
|
|
return builder;
|
|
}
|
|
|
|
private static TranslationBundleDescriptor CreateBundle(
|
|
LanguageTag language,
|
|
string value)
|
|
{
|
|
return new TranslationBundleDescriptor(
|
|
"Acme:Acme.BuilderResourceKind",
|
|
1,
|
|
language,
|
|
TranslationSourceKind.ModuleBuiltIn,
|
|
"Acme",
|
|
[value]);
|
|
}
|
|
|
|
private enum BuilderResourceKind
|
|
{
|
|
Value
|
|
}
|
|
}
|