mirror of
https://github.com/AtomUI/AtomUI.git
synced 2026-10-18 14:37:19 +08:00
640 lines
23 KiB
C#
640 lines
23 KiB
C#
using System.Collections.Immutable;
|
|
using AtomUI.Generator.Localization.Catalog;
|
|
using AtomUI.Generator.Localization.Xliff;
|
|
using AtomUI.Build.Tasks.LocalizationBuild;
|
|
using Microsoft.CodeAnalysis;
|
|
using Microsoft.CodeAnalysis.Text;
|
|
using Shouldly;
|
|
using Xunit;
|
|
using static AtomUI.Generator.Tests.Localization.LocalizationGeneratorTestHost;
|
|
|
|
namespace AtomUI.Generator.Tests.Localization;
|
|
|
|
public class LanguageCatalogCompilerGeneratorTests
|
|
{
|
|
[Fact]
|
|
public void Compiled_Bundle_Slots_Follow_Ordinal_Keys_Instead_Of_File_Order()
|
|
{
|
|
var catalog = new LanguageCatalogInfo(
|
|
"Test.Package",
|
|
CatalogMetadataName,
|
|
"TestApp.Localization",
|
|
"global::TestApp.Localization.LoginLangResourceKind",
|
|
[
|
|
new LanguageCatalogUnitInfo("Title", Location.None),
|
|
new LanguageCatalogUnitInfo("ItemCount", Location.None)
|
|
],
|
|
Location.None);
|
|
var file = new LanguageFileInput(
|
|
new AdditionalLanguageFile(
|
|
"Localization/en-US.xlf",
|
|
SourceText.From(SourceXliff),
|
|
Xliff21Parser.Parse(SourceXliff).Document!),
|
|
"Test.Package",
|
|
LanguageFileSourceKind.ModuleBuiltIn,
|
|
"Test.Package",
|
|
LanguageFileContractValidation.Verified,
|
|
null);
|
|
|
|
var result = LanguageCatalogCompiler.Compile(
|
|
[new LanguageCatalogParseResult(catalog, ImmutableArray<Diagnostic>.Empty)],
|
|
[new LanguageFileInputResult(file, ImmutableArray<Diagnostic>.Empty)]);
|
|
|
|
result.Diagnostics.ShouldBeEmpty();
|
|
var compiled = result.Catalogs.ShouldHaveSingleItem();
|
|
compiled.FormattedUnits.ShouldBe([false, true]);
|
|
compiled.Bundles.ShouldHaveSingleItem().Values.ShouldBe(["Title", "Items {0}"]);
|
|
}
|
|
|
|
[Fact]
|
|
public void Joins_Complete_BuiltIn_Languages_To_The_Catalog()
|
|
{
|
|
var result = Run(
|
|
CatalogSource,
|
|
SourceFile(),
|
|
TargetFile("zh-CN", "标题", "项目 {0}"),
|
|
TargetFile("zh-TW", "標題", "項目 {0}"));
|
|
|
|
result.Diagnostics.ShouldBeEmpty();
|
|
}
|
|
|
|
[Fact]
|
|
public void Allows_An_Explicit_Empty_Translation_When_The_English_Source_Is_Empty()
|
|
{
|
|
var source = SourceXliff.Replace(
|
|
"<source>Title</source>",
|
|
"<source></source>");
|
|
var target = TargetXliff("zh-CN", "", "项目 {0}").Replace(
|
|
"<source>Title</source>",
|
|
"<source></source>");
|
|
var result = Run(
|
|
CatalogSource,
|
|
SourceFile().WithText(source),
|
|
LanguageFile("Localization/zh-CN.xlf", target));
|
|
|
|
result.Diagnostics.ShouldBeEmpty();
|
|
var tree = result.GeneratedSources.Single(static sourceResult =>
|
|
sourceResult.HintName == "GeneratedLanguageModuleRegistration.g.cs").SyntaxTree;
|
|
var value = tree.GetRoot(TestContext.Current.CancellationToken).DescendantNodes().OfType<Microsoft.CodeAnalysis.CSharp.Syntax.VariableDeclaratorSyntax>()
|
|
.Single(static variable => variable.Identifier.ValueText == "Data").Initializer!.Value;
|
|
var data = AtomUI.Localization.Data.LanguageModuleDataCodec.Read("Test.Package",
|
|
((Microsoft.CodeAnalysis.CSharp.Syntax.LiteralExpressionSyntax)value).Token.ValueText);
|
|
data.Bundles.Single(static bundle => bundle.Language == "zh-CN").Values[1].ShouldBe(string.Empty);
|
|
data.Bundles.Single(static bundle => bundle.Language == "en-US").Values[1].ShouldBe(string.Empty);
|
|
}
|
|
|
|
[Fact]
|
|
public void Reports_A_Missing_English_Source_Bundle()
|
|
{
|
|
var result = Run(
|
|
CatalogSource,
|
|
TargetFile("zh-CN", "标题", "项目 {0}"));
|
|
|
|
AssertHasDiagnostic(result, "ATOMUILOC006", "complete en-US");
|
|
}
|
|
|
|
[Fact]
|
|
public void Reports_Duplicate_English_Source_Bundles()
|
|
{
|
|
var result = Run(
|
|
CatalogSource,
|
|
SourceFile(),
|
|
LanguageFile("Localization/duplicate.en-US.xlf", SourceXliff));
|
|
|
|
AssertHasDiagnostic(result, "ATOMUILOC006", "exactly one en-US");
|
|
}
|
|
|
|
[Fact]
|
|
public void Reports_A_File_Id_That_Does_Not_Match_The_Catalog()
|
|
{
|
|
var result = Run(
|
|
CatalogSource,
|
|
SourceFile().WithText(SourceXliff.Replace(CatalogMetadataName, "TestApp.Localization.OtherKind")));
|
|
|
|
AssertHasDiagnostic(result, "ATOMUILOC006", "does not match");
|
|
}
|
|
|
|
[Theory]
|
|
[InlineData("id=\"Title\"", "id=\"Heading\"", "unit Key")]
|
|
public void Reports_A_Unit_Contract_Mismatch(
|
|
string oldValue,
|
|
string newValue,
|
|
string messageFragment)
|
|
{
|
|
var result = Run(
|
|
CatalogSource,
|
|
SourceFile().WithText(SourceXliff.Replace(oldValue, newValue)));
|
|
|
|
AssertHasDiagnostic(result, "ATOMUILOC006", messageFragment);
|
|
}
|
|
|
|
[Fact]
|
|
public void Reports_Target_Source_Text_That_Differs_From_English()
|
|
{
|
|
var result = Run(
|
|
CatalogSource,
|
|
SourceFile(),
|
|
TargetFile("zh-CN", "标题", "项目 {0}")
|
|
.WithText(TargetXliff("zh-CN", "标题", "项目 {0}")
|
|
.Replace("Items {0}", "Changed {0}")));
|
|
|
|
AssertHasDiagnostic(result, "ATOMUILOC006", "source text");
|
|
}
|
|
|
|
[Fact]
|
|
public void Ignores_Obsolete_Historical_Units_In_A_Translation_File()
|
|
{
|
|
var target = TargetXliff("zh-CN", "标题", "项目 {0}")
|
|
.Replace(
|
|
" </file>",
|
|
" <unit id=\"Removed\" translate=\"no\"><segment>" +
|
|
"<source>Removed</source><target state=\"reviewed\">已移除</target>" +
|
|
"</segment></unit>\n </file>");
|
|
var result = Run(
|
|
CatalogSource,
|
|
SourceFile(),
|
|
LanguageFile("Localization/zh-CN.xlf", target));
|
|
|
|
result.Diagnostics.ShouldBeEmpty();
|
|
}
|
|
|
|
[Fact]
|
|
public void Reports_A_Target_That_Is_Not_Publishable()
|
|
{
|
|
var result = Run(
|
|
CatalogSource,
|
|
SourceFile(),
|
|
TargetFile("zh-CN", "标题", "项目 {0}")
|
|
.WithText(TargetXliff("zh-CN", "标题", "项目 {0}")
|
|
.Replace("state=\"translated\"", "state=\"initial\"")));
|
|
|
|
AssertHasDiagnostic(result, "ATOMUILOC007", "publishable");
|
|
}
|
|
|
|
[Theory]
|
|
[InlineData("<target state=\"translated\">标题</target>", "<target state=\"translated\"> </target>")]
|
|
[InlineData("<target state=\"translated\">标题</target>", "<target state=\"translated\" subState=\"needs-review\">标题</target>")]
|
|
public void Reports_A_Target_With_Unpublishable_Content_Or_SubState(
|
|
string currentTarget,
|
|
string invalidTarget)
|
|
{
|
|
var result = Run(
|
|
CatalogSource,
|
|
SourceFile(),
|
|
TargetFile("zh-CN", "标题", "项目 {0}")
|
|
.WithText(TargetXliff("zh-CN", "标题", "项目 {0}")
|
|
.Replace(currentTarget, invalidTarget)));
|
|
|
|
AssertHasDiagnostic(result, "ATOMUILOC007", "publishable");
|
|
}
|
|
|
|
[Fact]
|
|
public void Reports_Duplicate_Same_Priority_Translation_Sources()
|
|
{
|
|
var result = Run(
|
|
CatalogSource,
|
|
SourceFile(),
|
|
TargetFile("zh-CN", "标题", "项目 {0}"),
|
|
TargetFile("zh-CN", "另一标题", "另一个 {0}", "Localization/duplicate.zh-CN.xlf"));
|
|
|
|
AssertHasDiagnostic(result, "ATOMUILOC006", "same priority");
|
|
}
|
|
|
|
[Fact]
|
|
public void Resolves_A_Static_Language_Pack_Catalog_From_Metadata()
|
|
{
|
|
var reference = CreateExternalCatalogReference();
|
|
var result = Run(
|
|
"namespace TestApp { public sealed class Marker { } }",
|
|
[reference],
|
|
ReferencedSourceFile(),
|
|
StaticPackFile());
|
|
|
|
result.Diagnostics.ShouldBeEmpty();
|
|
}
|
|
|
|
[Fact]
|
|
public void Resolves_An_Active_Deferred_Static_Language_Pack_Against_The_Referenced_Catalog()
|
|
{
|
|
var reference = CreateExternalCatalogReference();
|
|
var result = Run(
|
|
"""
|
|
namespace Avalonia { public class Application { } }
|
|
namespace TestApp { public partial class App : Avalonia.Application { } }
|
|
""",
|
|
[reference],
|
|
ReferencedSourceFile(),
|
|
StaticPackFile(contractValidation: "Deferred"));
|
|
|
|
result.Diagnostics.ShouldBeEmpty();
|
|
var bootstrap = result.GeneratedSources
|
|
.Single(source =>
|
|
source.HintName == "GeneratedApplicationLanguageBootstrap.g.cs")
|
|
.SourceText
|
|
.ToString();
|
|
bootstrap.ShouldContain("GeneratedApplicationLanguageData.Register(builder)");
|
|
}
|
|
|
|
[Fact]
|
|
public void Reports_A_Deferred_Static_Pack_With_An_Unknown_Unit_Key()
|
|
{
|
|
var reference = CreateExternalCatalogReference();
|
|
var result = Run(
|
|
"namespace TestApp { public sealed class Marker { } }",
|
|
[reference],
|
|
ReferencedSourceFile(),
|
|
StaticPackFile(
|
|
unitKey: "Heading",
|
|
contractValidation: "Deferred"));
|
|
|
|
AssertHasDiagnostic(result, "ATOMUILOC006", "unit Key");
|
|
}
|
|
|
|
[Fact]
|
|
public void Reports_A_Deferred_Static_Pack_With_Changed_Source_Text()
|
|
{
|
|
var reference = CreateExternalCatalogReference();
|
|
var result = Run(
|
|
"namespace TestApp { public sealed class Marker { } }",
|
|
[reference],
|
|
ReferencedSourceFile(),
|
|
StaticPackFile(
|
|
contractValidation: "Deferred",
|
|
titleSource: "Changed title"));
|
|
|
|
AssertHasDiagnostic(result, "ATOMUILOC006", "source text");
|
|
AssertHasDiagnostic(result, "ATOMUILOC006", "source fingerprint");
|
|
}
|
|
|
|
[Fact]
|
|
public void Reports_A_Static_Language_Pack_Without_An_Authoritative_English_Source()
|
|
{
|
|
var reference = CreateExternalCatalogReference();
|
|
var result = Run(
|
|
"namespace TestApp { public sealed class Marker { } }",
|
|
[reference],
|
|
StaticPackFile());
|
|
|
|
AssertHasDiagnostic(result, "ATOMUILOC006", "complete en-US");
|
|
}
|
|
|
|
[Fact]
|
|
public void Ignores_A_Static_Pack_When_The_Target_Module_Is_Not_Referenced()
|
|
{
|
|
var result = Run(
|
|
"namespace TestApp { public sealed class Marker { } }",
|
|
[],
|
|
StaticPackFile());
|
|
|
|
result.Diagnostics.ShouldBeEmpty();
|
|
result.GeneratedSources.ShouldBeEmpty();
|
|
}
|
|
|
|
[Fact]
|
|
public void Keeps_A_Deferred_Static_Pack_Dormant_When_The_Target_Module_Is_Not_Referenced()
|
|
{
|
|
var result = Run(
|
|
"namespace TestApp { public sealed class Marker { } }",
|
|
[],
|
|
StaticPackFile(contractValidation: "Deferred"));
|
|
|
|
result.Diagnostics.ShouldBeEmpty();
|
|
result.GeneratedSources.ShouldBeEmpty();
|
|
}
|
|
|
|
[Fact]
|
|
public void Reports_A_Static_Pack_For_An_Unknown_Catalog_In_A_Referenced_Module()
|
|
{
|
|
var reference = CreateExternalModuleReference();
|
|
var result = Run(
|
|
"namespace TestApp { public sealed class Marker { } }",
|
|
[reference],
|
|
StaticPackFile());
|
|
|
|
AssertHasDiagnostic(result, "ATOMUILOC006", "referenced Catalog");
|
|
}
|
|
|
|
[Fact]
|
|
public void Reports_A_Deferred_Static_Pack_For_An_Unknown_Catalog_In_An_Active_Module()
|
|
{
|
|
var reference = CreateExternalModuleReference();
|
|
var result = Run(
|
|
"namespace TestApp { public sealed class Marker { } }",
|
|
[reference],
|
|
StaticPackFile(contractValidation: "Deferred"));
|
|
|
|
AssertHasDiagnostic(result, "ATOMUILOC006", "referenced Catalog");
|
|
}
|
|
|
|
[Fact]
|
|
public void Accepts_A_Partial_Application_Override()
|
|
{
|
|
var result = Run(
|
|
CatalogSource,
|
|
SourceFile(),
|
|
ApplicationOverrideFile(includeItemCount: false));
|
|
|
|
result.Diagnostics.ShouldBeEmpty();
|
|
}
|
|
|
|
[Fact]
|
|
public void Accepts_Disjoint_Application_Override_Fragments()
|
|
{
|
|
var result = Run(
|
|
CatalogSource,
|
|
SourceFile(),
|
|
ApplicationOverrideFile(
|
|
includeItemCount: false,
|
|
path: "Localization/Overrides/title.zh-CN.xlf",
|
|
sourceIdentity: "TestApp.Title"),
|
|
ApplicationOverrideFile(
|
|
includeTitle: false,
|
|
path: "Localization/Overrides/item-count.zh-CN.xlf",
|
|
sourceIdentity: "TestApp.ItemCount"));
|
|
|
|
result.Diagnostics.ShouldBeEmpty();
|
|
}
|
|
|
|
[Fact]
|
|
public void Reports_Overlapping_Application_Override_Units()
|
|
{
|
|
var result = Run(
|
|
CatalogSource,
|
|
SourceFile(),
|
|
ApplicationOverrideFile(
|
|
includeItemCount: false,
|
|
path: "Localization/Overrides/first.zh-CN.xlf",
|
|
sourceIdentity: "TestApp.One"),
|
|
ApplicationOverrideFile(
|
|
includeItemCount: false,
|
|
path: "Localization/Overrides/second.zh-CN.xlf",
|
|
sourceIdentity: "TestApp.Two"));
|
|
|
|
AssertHasDiagnostic(result, "ATOMUILOC006", "unit Key 'Title'");
|
|
}
|
|
|
|
[Fact]
|
|
public void Reports_A_Static_Pack_Module_Id_Mismatch()
|
|
{
|
|
var reference = CreateExternalCatalogReference();
|
|
var result = Run(
|
|
"namespace TestApp { public sealed class Marker { } }",
|
|
[reference],
|
|
ReferencedSourceFile(),
|
|
StaticPackFile(moduleId: "Other.Package"));
|
|
|
|
AssertHasDiagnostic(result, "ATOMUILOC006", "language module");
|
|
}
|
|
|
|
[Fact]
|
|
public void Resolves_Module_Id_From_Referenced_Assembly_Metadata()
|
|
{
|
|
var reference = CreateExternalCatalogReference(
|
|
assemblyName: "External.Package.Runtime",
|
|
moduleId: "External.Package");
|
|
var result = Run(
|
|
"namespace TestApp { public sealed class Marker { } }",
|
|
[reference],
|
|
ReferencedSourceFile(moduleId: "External.Package"),
|
|
StaticPackFile());
|
|
|
|
result.Diagnostics.ShouldBeEmpty();
|
|
}
|
|
|
|
[Fact]
|
|
public void Reports_A_Renamed_Referenced_Unit_As_A_Key_Change()
|
|
{
|
|
var reference = CreateExternalCatalogReference();
|
|
var result = Run(
|
|
"namespace TestApp { public sealed class Marker { } }",
|
|
[reference],
|
|
ReferencedSourceFile(unitKey: "Heading"),
|
|
StaticPackFile());
|
|
|
|
AssertHasDiagnostic(result, "ATOMUILOC006", "unit Key");
|
|
}
|
|
|
|
private static void AssertHasDiagnostic(
|
|
GeneratorRunResult result,
|
|
string id,
|
|
string messageFragment)
|
|
{
|
|
var diagnostic = result.Diagnostics.FirstOrDefault(diagnostic =>
|
|
diagnostic.Id == id &&
|
|
diagnostic.GetMessage().Contains(messageFragment, StringComparison.Ordinal));
|
|
diagnostic.ShouldNotBeNull();
|
|
diagnostic.Severity.ShouldBe(DiagnosticSeverity.Error);
|
|
}
|
|
|
|
private static TestAdditionalText SourceFile()
|
|
{
|
|
return LanguageFile("Localization/en-US.xlf", SourceXliff);
|
|
}
|
|
|
|
private static TestAdditionalText ReferencedSourceFile(
|
|
string moduleId = "External.Package",
|
|
string unitKey = "Title")
|
|
{
|
|
var content = SourceXliff.Replace("id=\"Title\"", $"id=\"{unitKey}\"");
|
|
return new TestAdditionalText(
|
|
$"packages/{moduleId}/Localization/en-US.xlf",
|
|
content,
|
|
new Dictionary<string, string>(StringComparer.Ordinal)
|
|
{
|
|
["build_metadata.AdditionalFiles.AtomUILanguage"] = "true",
|
|
["build_metadata.AdditionalFiles.AtomUILanguageModuleId"] = moduleId,
|
|
["build_metadata.AdditionalFiles.AtomUILanguageSourceKind"] = "ModuleBuiltIn",
|
|
["build_metadata.AdditionalFiles.AtomUILanguageSourceIdentity"] = moduleId
|
|
});
|
|
}
|
|
|
|
private static TestAdditionalText TargetFile(
|
|
string language,
|
|
string title,
|
|
string itemCount,
|
|
string? path = null)
|
|
{
|
|
return LanguageFile(
|
|
path ?? $"Localization/{language}.xlf",
|
|
TargetXliff(language, title, itemCount));
|
|
}
|
|
|
|
private static TestAdditionalText LanguageFile(
|
|
string path,
|
|
string text)
|
|
{
|
|
var metadata = new Dictionary<string, string>(StringComparer.Ordinal)
|
|
{
|
|
["build_metadata.AdditionalFiles.AtomUILanguage"] = "true",
|
|
["build_metadata.AdditionalFiles.AtomUILanguageSourceKind"] = "ModuleBuiltIn",
|
|
["build_metadata.AdditionalFiles.AtomUILanguageSourceIdentity"] = "Test.Package"
|
|
};
|
|
return new TestAdditionalText(
|
|
path,
|
|
text,
|
|
metadata);
|
|
}
|
|
|
|
private static TestAdditionalText StaticPackFile(
|
|
string moduleId = "External.Package",
|
|
string unitKey = "Title",
|
|
string contractValidation = "Verified",
|
|
string titleSource = "Title")
|
|
{
|
|
var content = TargetXliff("zh-CN", "标题", "项目 {0}")
|
|
.Replace("id=\"Title\"", $"id=\"{unitKey}\"")
|
|
.Replace("<source>Title</source>", $"<source>{titleSource}</source>");
|
|
var sourceFingerprint = LanguageSourceFingerprint.Compute(
|
|
Xliff21Parser.Parse(content).Document!);
|
|
var metadata = new Dictionary<string, string>(StringComparer.Ordinal)
|
|
{
|
|
["build_metadata.AdditionalFiles.AtomUILanguage"] = "true",
|
|
["build_metadata.AdditionalFiles.AtomUILanguageSourceKind"] = "StaticLanguagePack",
|
|
["build_metadata.AdditionalFiles.AtomUILanguageSourceIdentity"] = "External.Package.I18n.ZhCN",
|
|
["build_metadata.AdditionalFiles.AtomUILanguageModuleId"] = moduleId,
|
|
["build_metadata.AdditionalFiles.AtomUILanguageContractValidation"] = contractValidation,
|
|
["build_metadata.AdditionalFiles.AtomUILanguageSourceFingerprint"] = sourceFingerprint
|
|
};
|
|
|
|
return new TestAdditionalText(
|
|
"packages/External.Package.I18n.ZhCN/zh-CN.xlf",
|
|
content,
|
|
metadata);
|
|
}
|
|
|
|
private static TestAdditionalText ApplicationOverrideFile(
|
|
bool includeItemCount = true,
|
|
bool includeTitle = true,
|
|
string path = "Localization/Overrides/zh-CN.xlf",
|
|
string sourceIdentity = "TestApp")
|
|
{
|
|
var content = TargetXliff("zh-CN", "覆盖标题", "覆盖项目 {0}");
|
|
if (!includeItemCount)
|
|
{
|
|
const string itemCountUnit =
|
|
"<unit id=\"ItemCount\"><segment><source>Items {0}</source>" +
|
|
"<target state=\"translated\">覆盖项目 {0}</target></segment></unit>\n";
|
|
content = content.Replace(itemCountUnit, string.Empty);
|
|
}
|
|
if (!includeTitle)
|
|
{
|
|
const string titleUnit =
|
|
"<unit id=\"Title\"><segment><source>Title</source>" +
|
|
"<target state=\"translated\">覆盖标题</target></segment></unit>\n";
|
|
content = content.Replace(titleUnit, string.Empty);
|
|
}
|
|
|
|
return new TestAdditionalText(
|
|
path,
|
|
content,
|
|
new Dictionary<string, string>(StringComparer.Ordinal)
|
|
{
|
|
["build_metadata.AdditionalFiles.AtomUILanguage"] = "true",
|
|
["build_metadata.AdditionalFiles.AtomUILanguageSourceKind"] = "ApplicationOverride",
|
|
["build_metadata.AdditionalFiles.AtomUILanguageSourceIdentity"] = sourceIdentity,
|
|
["build_metadata.AdditionalFiles.AtomUILanguageModuleId"] = "Test.Package"
|
|
});
|
|
}
|
|
|
|
private static MetadataReference CreateExternalCatalogReference(
|
|
string assemblyName = "External.Package",
|
|
string? moduleId = null,
|
|
string unitKey = "Title")
|
|
{
|
|
var assemblyMetadata = moduleId is null
|
|
? string.Empty
|
|
: $"[assembly: System.Reflection.AssemblyMetadata(\"AtomUILanguageModuleId\", \"{moduleId}\")]";
|
|
return LocalizationGeneratorTestHost.CreateMetadataReference(
|
|
assemblyName,
|
|
$$"""
|
|
{{assemblyMetadata}}
|
|
|
|
namespace AtomUI.Localization
|
|
{
|
|
[System.AttributeUsage(System.AttributeTargets.Enum, AllowMultiple = false)]
|
|
public sealed class LanguageCatalogAttribute : System.Attribute;
|
|
}
|
|
|
|
namespace TestApp.Localization
|
|
{
|
|
[AtomUI.Localization.LanguageCatalog]
|
|
public enum LoginLangResourceKind
|
|
{
|
|
ItemCount,
|
|
{{unitKey}}
|
|
}
|
|
}
|
|
""");
|
|
}
|
|
|
|
private static MetadataReference CreateExternalModuleReference()
|
|
{
|
|
return LocalizationGeneratorTestHost.CreateMetadataReference(
|
|
"External.Package.Runtime",
|
|
"""
|
|
[assembly: System.Reflection.AssemblyMetadata("AtomUILanguageModuleId", "External.Package")]
|
|
|
|
namespace External.Package
|
|
{
|
|
public sealed class Marker;
|
|
}
|
|
""");
|
|
}
|
|
|
|
private static string TargetXliff(string language, string title, string itemCount)
|
|
{
|
|
return $$"""
|
|
<xliff xmlns="urn:oasis:names:tc:xliff:document:2.0" version="2.1" srcLang="en-US" trgLang="{{language}}">
|
|
<file id="{{CatalogMetadataName}}">
|
|
<unit id="ItemCount"><segment><source>Items {0}</source><target state="translated">{{itemCount}}</target></segment></unit>
|
|
<unit id="Title"><segment><source>Title</source><target state="translated">{{title}}</target></segment></unit>
|
|
</file>
|
|
</xliff>
|
|
""";
|
|
}
|
|
|
|
private const string CatalogMetadataName = "TestApp.Localization.LoginLangResourceKind";
|
|
|
|
private const string CatalogSource = """
|
|
namespace AtomUI.Localization
|
|
{
|
|
[System.AttributeUsage(System.AttributeTargets.Enum, AllowMultiple = false)]
|
|
public sealed class LanguageCatalogAttribute : System.Attribute;
|
|
}
|
|
|
|
namespace TestApp.Localization
|
|
{
|
|
using AtomUI.Localization;
|
|
|
|
[LanguageCatalog]
|
|
public enum LoginLangResourceKind
|
|
{
|
|
ItemCount,
|
|
Title
|
|
}
|
|
}
|
|
""";
|
|
|
|
private const string SourceXliff = """
|
|
<xliff xmlns="urn:oasis:names:tc:xliff:document:2.0" version="2.1" srcLang="en-US">
|
|
<file id="TestApp.Localization.LoginLangResourceKind">
|
|
<unit id="ItemCount"><segment><source>Items {0}</source></segment></unit>
|
|
<unit id="Title"><segment><source>Title</source></segment></unit>
|
|
</file>
|
|
</xliff>
|
|
""";
|
|
}
|
|
|
|
internal static class TestAdditionalTextExtensions
|
|
{
|
|
internal static LocalizationGeneratorTestHost.TestAdditionalText WithText(
|
|
this LocalizationGeneratorTestHost.TestAdditionalText source,
|
|
string text)
|
|
{
|
|
return new LocalizationGeneratorTestHost.TestAdditionalText(
|
|
source.Path,
|
|
text,
|
|
source.Metadata);
|
|
}
|
|
}
|