mirror of
https://github.com/MindWorkAI/AI-Studio.git
synced 2026-11-11 03:47: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
@@ -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