mirror of
https://github.com/MindWorkAI/AI-Studio.git
synced 2026-11-11 12:27:21 +00:00
Added the informal address to the BeyondFacts Lab (#1176)
This commit is contained in:
1 parent
b6c3fbb5db
commit
e77645f44c
48 files changed
+1254
-160
No files matched your search
@@ -7,11 +7,11 @@ using SourceCodeRules.UsageAnalyzers;
|
||||
namespace AIStudio.Tests.Analyzers;
|
||||
|
||||
/// <summary>
|
||||
/// Checks that the texts of the app are looked up only through a T or TB wrapper, whose fallback text the I18N
|
||||
/// Checks that the texts of the app are looked up only through a T, TB, or TA wrapper, whose fallback text the I18N
|
||||
/// collector finds.
|
||||
/// </summary>
|
||||
/// <remarks>
|
||||
/// The collector reads the texts from calls of T and TB. A text handed to GetText anywhere else never reaches
|
||||
/// The collector reads the texts from calls of T, TB, and TA. A text handed to GetText anywhere else never reaches
|
||||
/// the language plugins, so it is never translated, and nothing at runtime shows it. MWAIS0012 refuses such a
|
||||
/// call while compiling. GetText is an extension method, so these tests ask in both of the forms C# knows for
|
||||
/// one: the classic method with a this parameter and the member of an extension block.
|
||||
@@ -42,6 +42,7 @@ public sealed class DirectI18NGetTextAnalyzerTests
|
||||
[TestCase(CLASSIC_FORM, "TB", TestName = "A TB wrapper around a classic extension method")]
|
||||
[TestCase(EXTENSION_BLOCK_FORM, "T", TestName = "A T wrapper around the member of an extension block")]
|
||||
[TestCase(EXTENSION_BLOCK_FORM, "TB", TestName = "A TB wrapper around the member of an extension block")]
|
||||
[TestCase(EXTENSION_BLOCK_FORM, "TA", TestName = "A TA wrapper around the member of an extension block")]
|
||||
public async Task AWrapperWhichForwardsItsTextIsAllowed(string form, string wrapper)
|
||||
{
|
||||
var reported = await AnalyzeAsync(form, $"public string {wrapper}(string fallbackEN) => this.GetText(fallbackEN);");
|
||||
@@ -54,6 +55,7 @@ public sealed class DirectI18NGetTextAnalyzerTests
|
||||
[TestCase(CLASSIC_FORM, """public string Describe() => ILangExtensions.GetText(this, "Hello");""", TestName = "A classic extension method called as a static method")]
|
||||
[TestCase(EXTENSION_BLOCK_FORM, """public string Describe() => this.GetText("Hello");""", TestName = "The member of an extension block called from another method")]
|
||||
[TestCase(EXTENSION_BLOCK_FORM, """public string T(string fallbackEN) => this.GetText("Hello");""", TestName = "The member of an extension block called by a wrapper with a text of its own")]
|
||||
[TestCase(EXTENSION_BLOCK_FORM, """public string TA(string fallbackEN) => this.GetText("Hello");""", TestName = "The member of an extension block called by a TA wrapper with a text of its own")]
|
||||
[TestCase(EXTENSION_BLOCK_FORM, """public string Describe() => ILangExtensions.GetText(this, "Hello");""", TestName = "The member of an extension block called as a static method")]
|
||||
public async Task ADirectLookupIsRefused(string form, string member)
|
||||
{
|
||||
|
||||
@@ -28,6 +28,8 @@ public sealed class ThisUsageAnalyzerTests
|
||||
[TestCase("CITY", TestName = "A static field")]
|
||||
[TestCase("ROOM", TestName = "A constant")]
|
||||
[TestCase("Shorten(this.location)", TestName = "A static method")]
|
||||
[TestCase("""T("Kickoff")""", TestName = "A text of T")]
|
||||
[TestCase("""TA("Your meeting")""", TestName = "A text of TA")]
|
||||
public async Task AMemberWhichNeedsNoThisIsLeftAlone(string expression)
|
||||
{
|
||||
var reported = await AnalyzeClassAsync(expression);
|
||||
@@ -160,6 +162,10 @@ public sealed class ThisUsageAnalyzerTests
|
||||
private string Describe() => this.Name;
|
||||
|
||||
private static string Shorten(string text) => text[..1];
|
||||
|
||||
private string T(string fallbackEN) => fallbackEN;
|
||||
|
||||
private string TA(string fallbackEN) => fallbackEN;
|
||||
}
|
||||
""";
|
||||
|
||||
|
||||
@@ -0,0 +1,103 @@
|
||||
using AIStudio.Assistants.I18N;
|
||||
|
||||
using SharedTools;
|
||||
|
||||
namespace AIStudio.Tests.Assistants.I18N;
|
||||
|
||||
/// <summary>
|
||||
/// Checks how the localization assistant translates the two variants of a text of TA(), which addresses the reader.
|
||||
/// </summary>
|
||||
/// <remarks>
|
||||
/// The informal variant starts from the formal translation, so that both read alike and a reviewed formal translation
|
||||
/// keeps its wording. The formal translations of a run therefore come first.
|
||||
/// </remarks>
|
||||
[TestFixture]
|
||||
public sealed class I18NAddressPromptTests
|
||||
{
|
||||
private const string KEY = "root::AISTUDIO::TESTS::TEXTS::T123";
|
||||
private static readonly string INFORMAL_KEY = I18NAddressVariant.InformalKeyOf(KEY);
|
||||
|
||||
[Test]
|
||||
public void TheInformalVariantsComeAfterAllOtherTexts()
|
||||
{
|
||||
var content = new Dictionary<string, string>
|
||||
{
|
||||
[INFORMAL_KEY] = "Enter your name.",
|
||||
["root::A::T1"] = "Save",
|
||||
[KEY] = "Enter your name.",
|
||||
["root::A::T2::INFORMAL"] = "Check your input.",
|
||||
["root::A::T2"] = "Check your input.",
|
||||
};
|
||||
|
||||
var order = I18NAddressPrompt.FormalFirst(content).Select(entry => entry.Key);
|
||||
|
||||
Assert.That(order, Is.EqualTo(new[] { "root::A::T1", KEY, "root::A::T2", INFORMAL_KEY, "root::A::T2::INFORMAL" }));
|
||||
}
|
||||
|
||||
[Test]
|
||||
public void TheFormalTranslationOfThisRunComesFirst()
|
||||
{
|
||||
var translatedNow = new Dictionary<string, string> { [KEY] = "Geben Sie Ihren Namen ein." };
|
||||
var translatedBefore = new Dictionary<string, string> { [KEY] = "Ihr Name, bitte." };
|
||||
|
||||
Assert.That(I18NAddressPrompt.FindFormalTranslation(INFORMAL_KEY, translatedNow, translatedBefore), Is.EqualTo("Geben Sie Ihren Namen ein."));
|
||||
}
|
||||
|
||||
[Test]
|
||||
public void TheFormalTranslationOfTheLanguagePluginCountsAsWell()
|
||||
{
|
||||
var translatedBefore = new Dictionary<string, string> { [KEY] = "Geben Sie Ihren Namen ein." };
|
||||
|
||||
Assert.That(I18NAddressPrompt.FindFormalTranslation(INFORMAL_KEY, new Dictionary<string, string>(), translatedBefore), Is.EqualTo("Geben Sie Ihren Namen ein."));
|
||||
}
|
||||
|
||||
[Test]
|
||||
public void WithoutAFormalTranslationThereIsNone()
|
||||
{
|
||||
using (Assert.EnterMultipleScope())
|
||||
{
|
||||
Assert.That(I18NAddressPrompt.FindFormalTranslation(INFORMAL_KEY, new Dictionary<string, string>(), new Dictionary<string, string> { [KEY] = " " }), Is.Null);
|
||||
Assert.That(I18NAddressPrompt.FindFormalTranslation(KEY, new Dictionary<string, string> { [KEY] = "Geben Sie Ihren Namen ein." }, new Dictionary<string, string>()), Is.Null, "A usual key is no informal variant.");
|
||||
}
|
||||
}
|
||||
|
||||
[Test]
|
||||
public void AUsualTextAddressesTheReaderFormally()
|
||||
{
|
||||
var section = I18NAddressPrompt.Section("German (Germany)", false, null);
|
||||
|
||||
using (Assert.EnterMultipleScope())
|
||||
{
|
||||
Assert.That(section, Does.Contain("formal address of German (Germany)"));
|
||||
Assert.That(section, Does.Not.Contain("informal"));
|
||||
}
|
||||
}
|
||||
|
||||
[Test]
|
||||
public void AnInformalVariantChangesOnlyTheAddressOfTheFormalTranslation()
|
||||
{
|
||||
const string FORMAL = "## Willkommen!\n\nGeben Sie Ihren Namen ein.";
|
||||
|
||||
// The line endings of the prompt are those of the checkout:
|
||||
var section = I18NAddressPrompt.Section("German (Germany)", true, FORMAL).ReplaceLineEndings("\n");
|
||||
|
||||
using (Assert.EnterMultipleScope())
|
||||
{
|
||||
Assert.That(section, Does.Contain("informal address of German (Germany)"));
|
||||
Assert.That(section, Does.Contain($"<formal_translation>\n{FORMAL}\n</formal_translation>"));
|
||||
Assert.That(section, Does.Contain("change only what the informal address"));
|
||||
}
|
||||
}
|
||||
|
||||
[Test]
|
||||
public void AnInformalVariantWithoutAFormalTranslationIsTranslatedInformally()
|
||||
{
|
||||
var section = I18NAddressPrompt.Section("French (France)", true, null);
|
||||
|
||||
using (Assert.EnterMultipleScope())
|
||||
{
|
||||
Assert.That(section, Does.Contain("informal address of French (France)"));
|
||||
Assert.That(section, Does.Not.Contain("formal_translation"));
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -66,7 +66,7 @@ public sealed class BflAccessTests
|
||||
{
|
||||
var forms = ConfigurationSelectDataFactory.GetBeyondFactsLabAddressFormData().Select(data => data.Value);
|
||||
|
||||
Assert.That(forms, Is.EquivalentTo(Enum.GetValues<BflAddressForm>()));
|
||||
Assert.That(forms, Is.EquivalentTo(Enum.GetValues<AddressForm>()));
|
||||
}
|
||||
|
||||
private static SettingsManager CreateSettingsManager() => new(NullLogger<SettingsManager>.Instance, null!);
|
||||
|
||||
@@ -0,0 +1,49 @@
|
||||
using System.Runtime.CompilerServices;
|
||||
using System.Text.RegularExpressions;
|
||||
|
||||
using SharedTools;
|
||||
|
||||
namespace AIStudio.Tests.BeyondFactsLab;
|
||||
|
||||
/// <summary>
|
||||
/// Checks that the texts of the BeyondFacts Lab follow the form of address the person chose.
|
||||
/// </summary>
|
||||
/// <remarks>
|
||||
/// A text which says "you" in English addresses the reader in other languages as well, so it needs TA(). With T() or
|
||||
/// TB(), it would stay formal in German, although the person chose the informal address.
|
||||
/// </remarks>
|
||||
[TestFixture]
|
||||
public sealed partial class BflAddressTests
|
||||
{
|
||||
[Test]
|
||||
public void EveryTextOfTheLabWhichSaysYouFollowsTheFormOfAddress()
|
||||
{
|
||||
var texts = 0;
|
||||
var formalOnly = new List<string>();
|
||||
foreach (var file in LabSourceFiles())
|
||||
{
|
||||
foreach (var text in I18NSourceScanner.FindTexts(File.ReadAllText(file), file, []))
|
||||
{
|
||||
texts++;
|
||||
if (!text.HasAddressVariants && YouRegex().IsMatch(text.Text))
|
||||
formalOnly.Add($"{Path.GetFileName(file)}: {text.Text}");
|
||||
}
|
||||
}
|
||||
|
||||
using (Assert.EnterMultipleScope())
|
||||
{
|
||||
Assert.That(texts, Is.GreaterThan(80), "The test found too few texts to be looking at the lab.");
|
||||
Assert.That(formalOnly, Is.Empty);
|
||||
}
|
||||
}
|
||||
|
||||
[GeneratedRegex(@"\byou(r|rs|rself)?\b", RegexOptions.IgnoreCase)]
|
||||
private static partial Regex YouRegex();
|
||||
|
||||
private static IEnumerable<string> LabSourceFiles([CallerFilePath] string sourceFilePath = "")
|
||||
{
|
||||
var appDirectory = Path.GetFullPath(Path.Combine(Path.GetDirectoryName(sourceFilePath)!, "..", "..", "MindWork AI Studio"));
|
||||
return Directory.EnumerateFiles(Path.Combine(appDirectory, "Assistants", "BeyondFactsLab"))
|
||||
.Append(Path.Combine(appDirectory, "Dialogs", "Settings", "SettingsDialogBeyondFactsLab.razor"));
|
||||
}
|
||||
}
|
||||
@@ -1,4 +1,3 @@
|
||||
using AIStudio.Assistants.BeyondFactsLab;
|
||||
using AIStudio.Provider;
|
||||
using AIStudio.Settings;
|
||||
using AIStudio.Settings.DataModel;
|
||||
@@ -142,7 +141,7 @@ public sealed class BflComponentTests
|
||||
[Test]
|
||||
public void NewSettingsAddressFormally()
|
||||
{
|
||||
Assert.That(new DataBeyondFactsLab().AddressForm, Is.EqualTo(BflAddressForm.FORMAL), "The texts of AI Studio address the person formally as well.");
|
||||
Assert.That(new DataBeyondFactsLab().AddressForm, Is.EqualTo(AddressForm.FORMAL), "The texts of AI Studio address the person formally as well.");
|
||||
}
|
||||
|
||||
private static SettingsManager CreateSettingsManager() => new(NullLogger<SettingsManager>.Instance, null!);
|
||||
|
||||
@@ -50,6 +50,18 @@ public sealed class LuaTableTests
|
||||
}
|
||||
}
|
||||
|
||||
[Test]
|
||||
public async Task TheKeyOfAnInformalVariantKeepsItsEnding()
|
||||
{
|
||||
var code = Create(new Dictionary<string, string>
|
||||
{
|
||||
[KEY] = "Enter your name.",
|
||||
[SharedTools.I18NAddressVariant.InformalKeyOf(KEY)] = "Enter your name.",
|
||||
});
|
||||
|
||||
Assert.That(await ReadAsync(code, $"{LUA_KEY}::INFORMAL"), Is.EqualTo("Enter your name."), code);
|
||||
}
|
||||
|
||||
[Test]
|
||||
public void TextsOnOneLineAreWrittenAsBefore()
|
||||
{
|
||||
|
||||
@@ -0,0 +1,33 @@
|
||||
using AIStudio.Tools.PluginSystem;
|
||||
|
||||
namespace AIStudio.Tests.Tools.PluginSystem;
|
||||
|
||||
/// <summary>
|
||||
/// A language plugin with texts of its own and a base language behind it, as PluginLanguage has.
|
||||
/// </summary>
|
||||
/// <param name="content">The texts of the language itself.</param>
|
||||
/// <param name="baseContent">The texts of the base language, which answer for the keys the language lacks.</param>
|
||||
public sealed class FakeLanguagePlugin(IReadOnlyDictionary<string, string> content, IReadOnlyDictionary<string, string>? baseContent = null) : ILanguagePlugin
|
||||
{
|
||||
/// <inheritdoc />
|
||||
public bool TryGetText(string key, out string value, bool logWarning = false)
|
||||
{
|
||||
if (content.TryGetValue(key, out var text) || baseContent is not null && baseContent.TryGetValue(key, out text))
|
||||
{
|
||||
value = text;
|
||||
return true;
|
||||
}
|
||||
|
||||
value = string.Empty;
|
||||
return false;
|
||||
}
|
||||
|
||||
/// <inheritdoc />
|
||||
public string IETFTag => "de-DE";
|
||||
|
||||
/// <inheritdoc />
|
||||
public string LangName => "Deutsch (Deutschland)";
|
||||
|
||||
/// <inheritdoc />
|
||||
public IReadOnlyDictionary<string, string> Content => content;
|
||||
}
|
||||
@@ -0,0 +1,132 @@
|
||||
using AIStudio.Settings.DataModel;
|
||||
using AIStudio.Tools.PluginSystem;
|
||||
|
||||
using SharedTools;
|
||||
|
||||
namespace AIStudio.Tests.Tools.PluginSystem;
|
||||
|
||||
/// <summary>
|
||||
/// Checks the two variants of a text of TA(), which addresses the reader: their keys, and which of them the app shows.
|
||||
/// </summary>
|
||||
/// <remarks>
|
||||
/// The informal variant has a key of its own. When the language in use lacks it, the person reads the formal variant
|
||||
/// of that language, never the English text which the base language holds under the informal key.
|
||||
/// </remarks>
|
||||
[TestFixture]
|
||||
public sealed class I18NAddressVariantTests
|
||||
{
|
||||
private const string NAMESPACE = "AIStudio.Tests";
|
||||
private const string TYPE = "Texts";
|
||||
private const string TEXT = "Enter your name.";
|
||||
private const string FORMAL = "Geben Sie Ihren Namen ein.";
|
||||
private const string INFORMAL = "Gib deinen Namen ein.";
|
||||
|
||||
private static readonly string KEY = $"root::AISTUDIO::TESTS::TEXTS::T{I18NKeyHash.Of(TEXT)}";
|
||||
private static readonly string INFORMAL_KEY = I18NAddressVariant.InformalKeyOf(KEY);
|
||||
|
||||
[Test]
|
||||
public void TheKeyOfTheInformalVariantLeadsBackToTheUsualKey()
|
||||
{
|
||||
using (Assert.EnterMultipleScope())
|
||||
{
|
||||
Assert.That(INFORMAL_KEY, Is.EqualTo($"{KEY}::INFORMAL"));
|
||||
Assert.That(I18NAddressVariant.TryGetFormalKey(INFORMAL_KEY, out var formalKey), Is.True);
|
||||
Assert.That(formalKey, Is.EqualTo(KEY));
|
||||
}
|
||||
}
|
||||
|
||||
[Test]
|
||||
public void AUsualKeyBelongsToNoInformalVariant()
|
||||
{
|
||||
using (Assert.EnterMultipleScope())
|
||||
{
|
||||
Assert.That(I18NAddressVariant.TryGetFormalKey(KEY, out var formalKey), Is.False);
|
||||
Assert.That(formalKey, Is.EqualTo(KEY));
|
||||
}
|
||||
}
|
||||
|
||||
[Test]
|
||||
public void TheInformalVariantShowsWhenThePersonWantsIt()
|
||||
{
|
||||
var plugin = new FakeLanguagePlugin(new Dictionary<string, string> { [KEY] = FORMAL, [INFORMAL_KEY] = INFORMAL });
|
||||
|
||||
using (Assert.EnterMultipleScope())
|
||||
{
|
||||
Assert.That(Lookup(plugin, AddressForm.INFORMAL), Is.EqualTo(INFORMAL));
|
||||
Assert.That(Lookup(plugin, AddressForm.FORMAL), Is.EqualTo(FORMAL));
|
||||
Assert.That(I18N.I.GetText(plugin, TEXT, NAMESPACE, TYPE), Is.EqualTo(FORMAL), "Texts of T() address the reader formally.");
|
||||
}
|
||||
}
|
||||
|
||||
[Test]
|
||||
public void WithoutAnInformalVariantTheFormalTextOfTheLanguageShows()
|
||||
{
|
||||
// The English language plugin, the base of every other one, holds the informal variant in English:
|
||||
var plugin = new FakeLanguagePlugin(
|
||||
new Dictionary<string, string> { [KEY] = FORMAL },
|
||||
new Dictionary<string, string> { [KEY] = TEXT, [INFORMAL_KEY] = TEXT });
|
||||
|
||||
Assert.That(Lookup(plugin, AddressForm.INFORMAL), Is.EqualTo(FORMAL));
|
||||
}
|
||||
|
||||
[Test]
|
||||
public void AnEmptyInformalVariantDoesNotCount()
|
||||
{
|
||||
var plugin = new FakeLanguagePlugin(new Dictionary<string, string> { [KEY] = FORMAL, [INFORMAL_KEY] = " " });
|
||||
|
||||
Assert.That(Lookup(plugin, AddressForm.INFORMAL), Is.EqualTo(FORMAL));
|
||||
}
|
||||
|
||||
[Test]
|
||||
public void WithoutAnyTranslationTheEnglishTextShows()
|
||||
{
|
||||
var plugin = new FakeLanguagePlugin(new Dictionary<string, string>());
|
||||
|
||||
using (Assert.EnterMultipleScope())
|
||||
{
|
||||
Assert.That(Lookup(plugin, AddressForm.INFORMAL), Is.EqualTo(TEXT));
|
||||
Assert.That(Lookup(plugin, AddressForm.FORMAL), Is.EqualTo(TEXT));
|
||||
Assert.That(I18N.I.GetText(NoPluginLanguage.INSTANCE, TEXT, NAMESPACE, TYPE, AddressForm.INFORMAL), Is.EqualTo(TEXT));
|
||||
}
|
||||
}
|
||||
|
||||
[Test]
|
||||
public void ALanguageWithAnInformalVariantOfItsOwnOffersTheChoice()
|
||||
{
|
||||
var german = new FakeLanguagePlugin(new Dictionary<string, string> { ["root::A::T1"] = "Speichern", [KEY] = FORMAL, [INFORMAL_KEY] = INFORMAL });
|
||||
|
||||
Assert.That(german.HasInformalAddress(), Is.True);
|
||||
}
|
||||
|
||||
[Test]
|
||||
public void ALanguageWithOneFormOfAddressOffersNoChoice()
|
||||
{
|
||||
// The localization assistant writes the informal variants of English in the same words:
|
||||
var english = new FakeLanguagePlugin(new Dictionary<string, string> { [KEY] = TEXT, [INFORMAL_KEY] = TEXT });
|
||||
|
||||
Assert.That(english.HasInformalAddress(), Is.False);
|
||||
}
|
||||
|
||||
[Test]
|
||||
public void ALanguageWithoutInformalVariantsOffersNoChoice()
|
||||
{
|
||||
// The informal variant of the base language does not count for the language in use:
|
||||
var german = new FakeLanguagePlugin(
|
||||
new Dictionary<string, string> { [KEY] = FORMAL },
|
||||
new Dictionary<string, string> { [KEY] = TEXT, [INFORMAL_KEY] = "Enter your name, please." });
|
||||
|
||||
using (Assert.EnterMultipleScope())
|
||||
{
|
||||
Assert.That(german.HasInformalAddress(), Is.False);
|
||||
Assert.That(NoPluginLanguage.INSTANCE.HasInformalAddress(), Is.False);
|
||||
}
|
||||
}
|
||||
|
||||
[Test]
|
||||
public void TheTextsAddressThePersonFormallyUntilTheAppSaysOtherwise()
|
||||
{
|
||||
Assert.That(I18N.I.AddressForm, Is.EqualTo(AddressForm.FORMAL), "Nothing in the tests sets where the form of address comes from.");
|
||||
}
|
||||
|
||||
private static string Lookup(ILanguagePlugin plugin, AddressForm addressForm) => I18N.I.GetText(plugin, TEXT, NAMESPACE, TYPE, addressForm);
|
||||
}
|
||||
@@ -8,7 +8,7 @@ using SharedTools;
|
||||
namespace AIStudio.Tests.Tools.PluginSystem;
|
||||
|
||||
/// <summary>
|
||||
/// Checks how the I18N collector finds the texts of T() and TB(), and which key it files them under.
|
||||
/// Checks how the I18N collector finds the texts of T(), TB(), and TA(), and which key it files them under.
|
||||
/// </summary>
|
||||
/// <remarks>
|
||||
/// The app looks up a translation by the hash of the string the compiler made of a text. The collector has to file
|
||||
@@ -58,7 +58,7 @@ public sealed class I18NSourceScannerTests
|
||||
var root = CSharpSyntaxTree.ParseText(content).GetRoot();
|
||||
foreach (var invocation in root.DescendantNodes().OfType<InvocationExpressionSyntax>())
|
||||
{
|
||||
if (CalledName(invocation) is not ("T" or "TB") || invocation.ArgumentList.Arguments.FirstOrDefault()?.Expression is not LiteralExpressionSyntax literal)
|
||||
if (CalledName(invocation) is not ("T" or "TB" or "TA") ||invocation.ArgumentList.Arguments.FirstOrDefault()?.Expression is not LiteralExpressionSyntax literal)
|
||||
continue;
|
||||
|
||||
// The collector takes only a text which follows the parenthesis right away:
|
||||
@@ -108,18 +108,28 @@ public sealed class I18NSourceScannerTests
|
||||
public void AllKindsOfCallsAreFound()
|
||||
{
|
||||
const string SOURCE = """
|
||||
T("First"); TB("Second"); this.T("Third", typeof(X).Namespace, nameof(X)); @T(@"Fourth"); T( "Not found");
|
||||
T("First"); TB("Second"); this.T("Third", typeof(X).Namespace, nameof(X)); @T(@"Fourth"); TA("Fifth"); @TA("Sixth"); T( "Not found");
|
||||
""";
|
||||
|
||||
var texts = I18NSourceScanner.FindTexts(SOURCE, "Calls.cs", []);
|
||||
|
||||
Assert.That(texts.Select(text => text.Text), Is.EqualTo(new[] { "First", "Second", "Third", "Fourth" }));
|
||||
Assert.That(texts.Select(text => text.Text), Is.EqualTo(new[] { "First", "Second", "Third", "Fourth", "Fifth", "Sixth" }));
|
||||
}
|
||||
|
||||
[Test]
|
||||
public void OnlyATextOfTAGetsAVariantWithTheInformalAddress()
|
||||
{
|
||||
const string SOURCE = """T("Save"); TB("Your details"); TA("Enter your name."); TA(@"Please check ""this"".");""";
|
||||
|
||||
var texts = I18NSourceScanner.FindTexts(SOURCE, "Address.cs", []);
|
||||
|
||||
Assert.That(texts.Where(text => text.HasAddressVariants).Select(text => text.Text), Is.EqualTo(new[] { "Enter your name.", "Please check \"this\"." }));
|
||||
}
|
||||
|
||||
[Test]
|
||||
public void ACallOfAnotherMethodIsIgnored()
|
||||
{
|
||||
const string SOURCE = """GetT("No text"); MyTB("No text either"); T("Text");""";
|
||||
const string SOURCE = """GetT("No text"); MyTB("No text either"); DATA("No text at all"); T("Text");""";
|
||||
|
||||
var texts = I18NSourceScanner.FindTexts(SOURCE, "Other.cs", []);
|
||||
|
||||
|
||||
Reference in new issue
Block a user