Added the choice between formal and informal address to the whole app (#1200)

This commit is contained in:
Thorsten Sommer authored and GitHub committed 2026-11-13 10:16:56 +01:00
1 parent 382db4b8d0
commit c9a376f742
342 files changed
+14378 -1893

No files matched your search

@@ -6,11 +6,11 @@ using Microsoft.CodeAnalysis.CSharp.Syntax;
namespace AIStudio.Tests.Tools.PluginSystem;
/// <summary>
/// Checks that every TB wrapper of the app looks its texts up under the class it belongs to.
/// Checks that every TB and TA wrapper of the app looks its texts up under the class it belongs to.
/// </summary>
/// <remarks>
/// The I18N collector files the texts of a TB wrapper under the namespace and the class of its source file, and
/// the language plugins translate them under that key. A wrapper which names another class in its typeof and
/// The I18N collector files the texts of a TB or TA wrapper under the namespace and the class of its source file,
/// and the language plugins translate them under that key. A wrapper which names another class in its typeof and
/// nameof looks every text up under a key no plugin knows, so its texts stay English in every language, and
/// nothing reports it. The wrapper of the Assistant Builder's parse errors named the enum instead of its own
/// class, which left twelve messages untranslated.
@@ -21,28 +21,7 @@ public sealed class TranslationWrapperTests
[Test]
public void EveryTBWrapperNamesItsOwnClass()
{
var appDirectory = AppSourceDirectory();
var wrappers = 0;
var mismatches = new List<string>();
var files = Directory.EnumerateFiles(appDirectory, "*.cs", SearchOption.AllDirectories)
.Where(path => !IsBuildOutput(Path.GetRelativePath(appDirectory, path)));
foreach (var file in files)
{
var source = File.ReadAllText(file);
if (!source.Contains("TB(", StringComparison.Ordinal))
continue;
var root = CSharpSyntaxTree.ParseText(source).GetRoot();
foreach (var wrapper in root.DescendantNodes().OfType<MethodDeclarationSyntax>().Where(method => method.Identifier.Text == "TB"))
{
wrappers++;
var owner = wrapper.Ancestors().OfType<BaseTypeDeclarationSyntax>().Last().Identifier.Text;
var named = NamedTypes(wrapper).ToList();
if (named.Count == 0 || named.Any(name => name != owner))
mismatches.Add($"{Path.GetRelativePath(appDirectory, file)}: the TB of {owner} names {(named.Count == 0 ? "no class" : string.Join(", ", named))}");
}
}
var mismatches = FindMismatches("TB", out var wrappers);
using (Assert.EnterMultipleScope())
{
@@ -51,6 +30,54 @@ public sealed class TranslationWrapperTests
}
}
/// <remarks>
/// The TA of a component, such as that of MSGComponentBase, may name no class at all: it looks its texts up
/// under the class of the component. A static TA has nothing but the class it names.
/// </remarks>
[Test]
public void EveryTAWrapperNamesItsOwnClass()
{
var mismatches = FindMismatches("TA", out var wrappers);
using (Assert.EnterMultipleScope())
{
Assert.That(wrappers, Is.GreaterThan(3), "The test found too few TA wrappers to be looking at the source of the app.");
Assert.That(mismatches, Is.Empty);
}
}
/// <summary>
/// Finds the wrappers of the given name which name another class than their own, or a static one which names none.
/// </summary>
private static List<string> FindMismatches(string wrapperName, out int wrappers)
{
var appDirectory = AppSourceDirectory();
var mismatches = new List<string>();
var files = Directory.EnumerateFiles(appDirectory, "*.cs", SearchOption.AllDirectories)
.Where(path => !IsBuildOutput(Path.GetRelativePath(appDirectory, path)));
wrappers = 0;
foreach (var file in files)
{
var source = File.ReadAllText(file);
if (!source.Contains($"{wrapperName}(", StringComparison.Ordinal))
continue;
var root = CSharpSyntaxTree.ParseText(source).GetRoot();
foreach (var wrapper in root.DescendantNodes().OfType<MethodDeclarationSyntax>().Where(method => method.Identifier.Text == wrapperName))
{
wrappers++;
var owner = wrapper.Ancestors().OfType<BaseTypeDeclarationSyntax>().Last().Identifier.Text;
var named = NamedTypes(wrapper).ToList();
var mayNameNone = wrapperName == "TA" && wrapper.Modifiers.All(modifier => modifier.Text != "static");
if ((named.Count == 0 && !mayNameNone) || named.Any(name => name != owner))
mismatches.Add($"{Path.GetRelativePath(appDirectory, file)}: the {wrapperName} of {owner} names {(named.Count == 0 ? "no class" : string.Join(", ", named))}");
}
}
return mismatches;
}
/// <summary>
/// The types a wrapper names to build its key, through typeof and nameof.
/// </summary>