Added the informal address to the BeyondFacts Lab (#1176)

This commit is contained in:
Thorsten Sommer authored and GitHub committed 2026-11-08 21:10:51 +01:00
1 parent b6c3fbb5db
commit e77645f44c
48 files changed
+1254 -160

No files matched your search

@@ -14,13 +14,13 @@
<InnerScrolling>
<MudText Typo="Typo.body1" Class="mb-3 mr-3">
@T("Prepare a challenging appearance as a researcher step by step, e.g., a panel discussion, an interview, or a hearing. Each preparation belongs to one event and has its own steps, chats, and work states.")
@TA("Prepare a challenging appearance as a researcher step by step, e.g., a panel discussion, an interview, or a hearing. Each preparation belongs to one event and has its own steps, chats, and work states.")
</MudText>
<MudText Typo="Typo.h5" Class="mb-1">@T("Your preparations")</MudText>
<MudText Typo="Typo.h5" Class="mb-1">@TA("Your preparations")</MudText>
@if (this.projects.Count == 0)
{
<MudText Typo="Typo.body2" Class="mb-3">@T("You have no preparations yet. Create one for the event you want to prepare for.")</MudText>
<MudText Typo="Typo.body2" Class="mb-3">@TA("You have no preparations yet. Create one for the event you want to prepare for.")</MudText>
}
else
{
@@ -100,7 +100,7 @@
<MudText Typo="Typo.h5" Class="mt-2">@step.Title</MudText>
<MudText Typo="Typo.body2" Class="mb-4">@step.Description</MudText>
<MudText Typo="Typo.h6" Class="mb-2">@T("Your details")</MudText>
<MudText Typo="Typo.h6" Class="mb-2">@TA("Your details")</MudText>
@if (this.forms.TryGetValue(step, out var form))
{
<BflStepForm Step="@step" Form="@form" FormChanged="@(() => this.SaveFormAsync(step))"/>
@@ -108,7 +108,7 @@
else
{
<MudAlert Severity="Severity.Error" Variant="Variant.Outlined">
@T("AI Studio cannot open your details for this step. Their file may be damaged, or a newer version of AI Studio stored it. AI Studio leaves the file unchanged.")
@TA("AI Studio cannot open your details for this step. Their file may be damaged, or a newer version of AI Studio stored it. AI Studio leaves the file unchanged.")
</MudAlert>
}
</MudStep>
@@ -119,7 +119,7 @@
else
{
<MudPaper Outlined="true" Class="pa-6 mr-3">
<MudText Typo="Typo.h5">@T("Create a preparation to begin.")</MudText>
<MudText Typo="Typo.h5">@TA("Create a preparation to begin.")</MudText>
</MudPaper>
}
</InnerScrolling>
@@ -77,7 +77,7 @@ public partial class BeyondFactsLabAssistant
/// </summary>
private async Task CreateProjectAsync()
{
var name = await this.AskForNameAsync(T("New preparation"), T("Name the event you want to prepare for, e.g., the title of a panel discussion."), string.Empty, T("Create"));
var name = await this.AskForNameAsync(T("New preparation"), TA("Name the event you want to prepare for, e.g., the title of a panel discussion."), string.Empty, T("Create"));
if (name is null)
return;
@@ -97,7 +97,7 @@ public partial class BeyondFactsLabAssistant
if (this.selectedProject?.Project is not { } project)
return;
var name = await this.AskForNameAsync(T("Rename preparation"), T("Enter a new name for this preparation."), project.Name, T("Rename"));
var name = await this.AskForNameAsync(T("Rename preparation"), TA("Enter a new name for this preparation."), project.Name, T("Rename"));
if (name is null)
return;
@@ -121,8 +121,8 @@ public partial class BeyondFactsLabAssistant
{
dialog => dialog.Message,
project.IsAvailable
? string.Format(T("Permanently delete the preparation '{0}' with all of its steps, chats, and work states?"), project.Name)
: T("This preparation cannot be opened. Permanently delete it with all of its files?")
? string.Format(TA("Permanently delete the preparation '{0}' with all of its steps, chats, and work states?"), project.Name)
: TA("This preparation cannot be opened. Permanently delete it with all of its files?")
},
};
@@ -173,7 +173,7 @@ public partial class BeyondFactsLabAssistant
{ dialog => dialog.ConfirmText, confirmText },
{ dialog => dialog.ConfirmColor, Color.Primary },
{ dialog => dialog.AllowEmptyInput, false },
{ dialog => dialog.EmptyInputErrorMessage, T("Please enter a name.") },
{ dialog => dialog.EmptyInputErrorMessage, TA("Please enter a name.") },
};
var reference = await this.DialogService.ShowAsync<SingleInputDialog>(title, parameters, DialogOptions.FULLSCREEN);
@@ -198,7 +198,7 @@ public partial class BeyondFactsLabAssistant
catch (Exception exception) when (exception is IOException or UnauthorizedAccessException or InvalidDataException or ArgumentException)
{
this.Logger.LogError(exception, "A change of the preparations of the BeyondFacts Lab failed.");
await this.MessageBus.SendError(new(Icons.Material.Filled.RecordVoiceOver, T("AI Studio could not save the change of your preparations. Please try again.")));
await this.MessageBus.SendError(new(Icons.Material.Filled.RecordVoiceOver, TA("AI Studio could not save the change of your preparations. Please try again.")));
await this.ReloadAfterFailureAsync();
}
finally
@@ -265,7 +265,7 @@ public partial class BeyondFactsLabAssistant
/// <param name="status">The status of the preparation.</param>
private string ProjectRecoveryMessage(BflProjectLoadStatus status) => status switch
{
BflProjectLoadStatus.NEWER_VERSION => T("A newer version of AI Studio stored this preparation. This version cannot open it. Please update AI Studio."),
BflProjectLoadStatus.NEWER_VERSION => TA("A newer version of AI Studio stored this preparation. This version cannot open it. Please update AI Studio."),
_ => T("AI Studio cannot read this preparation. Its files may be damaged."),
};
}
@@ -85,7 +85,7 @@ public partial class BeyondFactsLabAssistant
catch (Exception exception) when (exception is IOException or UnauthorizedAccessException or InvalidDataException)
{
this.Logger.LogError(exception, "Could not save the details of a step in the BeyondFacts Lab.");
await this.MessageBus.SendError(new(Icons.Material.Filled.RecordVoiceOver, T("AI Studio could not save your details. Please try again.")));
await this.MessageBus.SendError(new(Icons.Material.Filled.RecordVoiceOver, TA("AI Studio could not save your details. Please try again.")));
}
}
@@ -80,11 +80,17 @@ public partial class BeyondFactsLabAssistant : MSGComponentBase
/// <inheritdoc />
protected override async Task ProcessIncomingMessage<T>(ComponentBase? sendingComponent, Event triggeredEvent, T? data) where T : default
{
// An organization may hide the lab, or the person may switch its preview feature off, while the page is open:
if (triggeredEvent is Event.CONFIGURATION_CHANGED && !BflAccess.CanOpen(this.SettingsManager))
if (triggeredEvent is Event.CONFIGURATION_CHANGED)
{
this.NavigationManager.NavigateTo(Routes.ASSISTANTS);
return;
// An organization may hide the lab, or the person may switch its preview feature off, while the page is open:
if (!BflAccess.CanOpen(this.SettingsManager))
{
this.NavigationManager.NavigateTo(Routes.ASSISTANTS);
return;
}
// A changed option, such as the form of address in the options of the lab, shows right away:
this.StateHasChanged();
}
await base.ProcessIncomingMessage(sendingComponent, triggeredEvent, data);
@@ -1,17 +0,0 @@
namespace AIStudio.Assistants.BeyondFactsLab;
/// <summary>
/// How the BeyondFacts Lab addresses the person in languages which tell a formal address from an informal one, such as German.
/// </summary>
public enum BflAddressForm
{
/// <summary>
/// The formal address, such as "Sie" in German. The texts of AI Studio use it as well.
/// </summary>
FORMAL,
/// <summary>
/// The informal address, such as "du" in German.
/// </summary>
INFORMAL,
}
@@ -1,21 +0,0 @@
namespace AIStudio.Assistants.BeyondFactsLab;
public static class BflAddressFormExtensions
{
private static string TB(string fallbackEN) => Tools.PluginSystem.I18N.I.T(fallbackEN, typeof(BflAddressFormExtensions).Namespace, nameof(BflAddressFormExtensions));
/// <param name="addressForm">The form of address.</param>
extension(BflAddressForm addressForm)
{
/// <summary>
/// Gets the name of the form of address, as the settings show it.
/// </summary>
public string Name => addressForm switch
{
BflAddressForm.FORMAL => TB("Formal address (Sie in German)"),
BflAddressForm.INFORMAL => TB("Informal address (du in German)"),
_ => TB("Formal address (Sie in German)"),
};
}
}
@@ -7,6 +7,8 @@ public static class BflFieldTexts
{
private static string TB(string fallbackEN) => Tools.PluginSystem.I18N.I.T(fallbackEN, typeof(BflFieldTexts).Namespace, nameof(BflFieldTexts));
private static string TA(string fallbackEN) => Tools.PluginSystem.I18N.I.TA(fallbackEN, typeof(BflFieldTexts).Namespace, nameof(BflFieldTexts));
/// <param name="definition">The field.</param>
extension(BflFieldDefinition definition)
{
@@ -18,25 +20,25 @@ public static class BflFieldTexts
BflFieldCatalog.FORMAT => TB("Format of the event"),
BflFieldCatalog.EVENT_TOPIC => TB("Topic of the event"),
BflFieldCatalog.AUDIENCE => TB("Audience"),
BflFieldCatalog.CONTRIBUTION_TOPIC => TB("Topic of your contribution or your specific assignment"),
BflFieldCatalog.CONTRIBUTION_TOPIC => TA("Topic of your contribution or your specific assignment"),
BflFieldCatalog.EVENT_DATE => TB("Date and time"),
BflFieldCatalog.EVENT_LOCATION => TB("Place"),
BflFieldCatalog.EVENT_DURATION => TB("Total duration of the event"),
BflFieldCatalog.CONTRIBUTION_DURATION => TB("Duration of your contribution"),
BflFieldCatalog.CONTRIBUTION_DURATION => TA("Duration of your contribution"),
BflFieldCatalog.OTHER_PARTICIPANTS => TB("Other participants"),
BflFieldCatalog.EVENT_LINK => TB("Link to the event"),
BflFieldCatalog.CONTRIBUTION_SUMMARY => TB("Short description of your contribution"),
BflFieldCatalog.CONTRIBUTION_SUMMARY => TA("Short description of your contribution"),
BflFieldCatalog.CORE_THESES => TB("Core theses and arguments (if any)"),
BflFieldCatalog.UNCERTAINTIES => TB("Uncertainties and controversies in content and science (if known)"),
BflFieldCatalog.MATERIAL_NOTES => TB("Notes on how to use your materials"),
BflFieldCatalog.MATERIAL_NOTES => TA("Notes on how to use your materials"),
BflFieldCatalog.GOALS => TB("What do you want to achieve with your contribution?"),
BflFieldCatalog.GOALS => TA("What do you want to achieve with your contribution?"),
BflFieldCatalog.GOAL_DIRECTIONS => TB("Suggestions"),
BflFieldCatalog.VALUES_AND_CONCERNS => TB("Values and concerns: What matters most to you about this topic?"),
BflFieldCatalog.PERSONAL_CONCERN => TB("Personal involvement: Where does the topic touch you personally? Which question or criticism could trigger a strong reaction?"),
BflFieldCatalog.OTHER_PERSPECTIVES => TB("Other perspectives: Whose point of view would you like to understand better, or have you hardly considered so far?"),
BflFieldCatalog.VALUES_AND_CONCERNS => TA("Values and concerns: What matters most to you about this topic?"),
BflFieldCatalog.PERSONAL_CONCERN => TA("Personal involvement: Where does the topic touch you personally? Which question or criticism could trigger a strong reaction?"),
BflFieldCatalog.OTHER_PERSPECTIVES => TA("Other perspectives: Whose point of view would you like to understand better, or have you hardly considered so far?"),
BflFieldCatalog.COMMUNICATION_WORRIES => TB("Uncertainties and worries about communicating"),
@@ -44,7 +46,7 @@ public static class BflFieldTexts
BflFieldCatalog.DIFFICULTY => TB("Difficulty at the start"),
BflFieldCatalog.TEST_NOTES => TB("Special notes for the test"),
BflFieldCatalog.POSITION_CHANGES => TB("What have you changed, kept, or left open compared to your initial position, and why?"),
BflFieldCatalog.POSITION_CHANGES => TA("What have you changed, kept, or left open compared to your initial position, and why?"),
_ => string.Empty,
};
@@ -57,24 +59,24 @@ public static class BflFieldTexts
BflFieldCatalog.FORMAT => TB("E.g., panel, keynote, or interview; online, on site, or hybrid"),
BflFieldCatalog.EVENT_TOPIC => TB("The central question or the title"),
BflFieldCatalog.AUDIENCE => TB("E.g., students, experts, or the general public"),
BflFieldCatalog.CONTRIBUTION_TOPIC => TB("Stays in your preparation and never goes into the research on the web"),
BflFieldCatalog.CONTRIBUTION_TOPIC => TA("Stays in your preparation and never goes into the research on the web"),
BflFieldCatalog.EVENT_DATE => TB("E.g., December 10, 2 pm"),
BflFieldCatalog.EVENT_LOCATION => TB("E.g., the venue and the city, or online"),
BflFieldCatalog.EVENT_DURATION => TB("E.g., 90 minutes"),
BflFieldCatalog.CONTRIBUTION_DURATION => TB("E.g., 8 minutes"),
BflFieldCatalog.OTHER_PARTICIPANTS => TB("Names and roles, as far as you know them"),
BflFieldCatalog.OTHER_PARTICIPANTS => TA("Names and roles, as far as you know them"),
BflFieldCatalog.EVENT_LINK => TB("The address of the event page, beginning with https://"),
BflFieldCatalog.CONTRIBUTION_SUMMARY => TB("A few sentences are enough"),
BflFieldCatalog.MATERIAL_NOTES => TB("E.g., use only paper X as the basis for the content"),
BflFieldCatalog.GOALS => TB("In your own words, with the suggestions below, or still open: the chat sharpens your goal and role with you."),
BflFieldCatalog.GOALS => TA("In your own words, with the suggestions below, or still open: the chat sharpens your goal and role with you."),
BflFieldCatalog.PERSONAL_CONCERN => TB("Personal detail: it goes into exports and shared sessions only when you explicitly choose so."),
BflFieldCatalog.PERSONAL_CONCERN => TA("Personal detail: it goes into exports and shared sessions only when you explicitly choose so."),
BflFieldCatalog.COMMUNICATION_WORRIES => TB("E.g., aggressive moderation, time pressure, or a particular counterpart"),
BflFieldCatalog.DIFFICULTY => TB("You can raise the difficulty after each question."),
BflFieldCatalog.DIFFICULTY => TA("You can raise the difficulty after each question."),
BflFieldCatalog.TEST_NOTES => TB("E.g., take up a confirmed conflict of values or a perspective from the step about values and perspectives"),
_ => string.Empty,
@@ -9,16 +9,17 @@ namespace AIStudio.Assistants.BeyondFactsLab;
/// <remarks>
/// The notes are a text of the localization, so they come in every language of the app. The settings keep a hash of
/// the notes as the app showed them when the person confirmed them. A new wording, in English or in a translation,
/// therefore shows them again, and so does a switch to another language, whose notes the person has not read yet.
/// therefore shows them again, and so does a switch to another language or to another form of address, whose notes
/// the person has not read yet.
/// </remarks>
public static class BflNotice
{
private static string TB(string fallbackEN) => Tools.PluginSystem.I18N.I.T(fallbackEN, typeof(BflNotice).Namespace, nameof(BflNotice));
private static string TA(string fallbackEN) => Tools.PluginSystem.I18N.I.TA(fallbackEN, typeof(BflNotice).Namespace, nameof(BflNotice));
/// <summary>
/// Gets the notes in the language of the app, as Markdown.
/// Gets the notes in the language of the app and in the form of address the person chose, as Markdown.
/// </summary>
public static string Text => TB("""
public static string Text => TA("""
## Welcome!
The BeyondFacts Lab guides you through an AI-supported process of reflection, which helps you take a position in challenging communication situations and stay able to communicate.
@@ -4,6 +4,8 @@ public static class BflStepExtensions
{
private static string TB(string fallbackEN) => Tools.PluginSystem.I18N.I.T(fallbackEN, typeof(BflStepExtensions).Namespace, nameof(BflStepExtensions));
private static string TA(string fallbackEN) => Tools.PluginSystem.I18N.I.TA(fallbackEN, typeof(BflStepExtensions).Namespace, nameof(BflStepExtensions));
/// <param name="step">The step.</param>
extension(BflStep step)
{
@@ -28,13 +30,13 @@ public static class BflStepExtensions
/// </summary>
public string Description => step switch
{
BflStep.FRAMEWORK => TB("What the event is about, for whom, and what you were asked to contribute."),
BflStep.KNOWLEDGE => TB("What you know for sure, what is uncertain, and where your expertise ends."),
BflStep.GOALS_AND_ROLE => TB("What you want to achieve, and in which role you speak."),
BflStep.VALUES_AND_PERSPECTIVES => TB("What matters to you, what touches you, and what moves others."),
BflStep.STRATEGY => TB("How you convey evidence, trade-offs between values, and open questions."),
BflStep.TEST_SITUATION => TB("Play through critical questions and opposing positions."),
BflStep.RESULTS => TB("What you take away from your preparation."),
BflStep.FRAMEWORK => TA("What the event is about, for whom, and what you were asked to contribute."),
BflStep.KNOWLEDGE => TA("What you know for sure, what is uncertain, and where your expertise ends."),
BflStep.GOALS_AND_ROLE => TA("What you want to achieve, and in which role you speak."),
BflStep.VALUES_AND_PERSPECTIVES => TA("What matters to you, what touches you, and what moves others."),
BflStep.STRATEGY => TA("How you convey evidence, trade-offs between values, and open questions."),
BflStep.TEST_SITUATION => TA("Play through critical questions and opposing positions."),
BflStep.RESULTS => TA("What you take away from your preparation."),
_ => string.Empty,
};
@@ -44,7 +46,7 @@ public static class BflStepExtensions
/// </summary>
public string FormHint => step switch
{
BflStep.VALUES_AND_PERSPECTIVES => TB("You can fill in single fields or start right away in the chat."),
BflStep.VALUES_AND_PERSPECTIVES => TA("You can fill in single fields or start right away in the chat."),
_ => string.Empty,
};
@@ -3,7 +3,7 @@
@if (this.MissingFields.Count > 0)
{
<MudAlert Severity="Severity.Info" Variant="Variant.Outlined" Dense="true" Class="mb-3">
@T("Some details are still missing. The chat will ask for them, and you can continue anyway.")
@TA("Some details are still missing. The chat will ask for them, and you can continue anyway.")
<br/>
@string.Join(", ", this.MissingFields.Select(field => field.Label))
</MudAlert>
@@ -93,5 +93,5 @@
@if (this.HasKeyDetails)
{
<MudText Typo="Typo.caption" Class="mt-2">@T("* The chat works best when you fill in these details.")</MudText>
<MudText Typo="Typo.caption" Class="mt-2">@TA("* The chat works best when you fill in these details.")</MudText>
}
@@ -70,6 +70,6 @@ public partial class BflStepForm : MSGComponentBase
return Uri.TryCreate(value.Trim(), UriKind.Absolute, out var uri) && (uri.Scheme == Uri.UriSchemeHttps || uri.Scheme == Uri.UriSchemeHttp)
? null
: T("Please enter an address that begins with https:// or http://.");
: TA("Please enter an address that begins with https:// or http://.");
}
}