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

@@ -14,6 +14,8 @@ public sealed class SearXNGSearchBackend : IWebSearchBackend
{
private static string TB(string fallbackEN) => I18N.I.T(fallbackEN, typeof(SearXNGSearchBackend).Namespace, nameof(SearXNGSearchBackend));
private static string TA(string fallbackEN) => I18N.I.TA(fallbackEN, typeof(SearXNGSearchBackend).Namespace, nameof(SearXNGSearchBackend));
private const string SETTINGS_GROUP = "searxng";
private const string BASE_URL_SETTING = $"{SETTINGS_GROUP}.baseUrl";
@@ -59,7 +61,7 @@ public sealed class SearXNGSearchBackend : IWebSearchBackend
public string GetSettingsFieldDescription(string fieldName) => fieldName switch
{
BASE_URL_SETTING => TB("Base URL of the SearXNG instance. You can enter either the instance root URL or the /search endpoint. The instance must have the JSON format enabled, which means 'json' has to be listed under 'search.formats' in its settings.yml. Public instances usually serve only the web interface and additionally block automated requests, so a self-hosted instance is the reliable option."),
BASE_URL_SETTING => TA("Base URL of the SearXNG instance. You can enter either the instance root URL or the /search endpoint. The instance must have the JSON format enabled, which means 'json' has to be listed under 'search.formats' in its settings.yml. Public instances usually serve only the web interface and additionally block automated requests, so a self-hosted instance is the reliable option."),
_ => string.Empty,
};
@@ -18,6 +18,8 @@ public sealed class StaanSearchBackend : IWebSearchBackend
{
private static string TB(string fallbackEN) => I18N.I.T(fallbackEN, typeof(StaanSearchBackend).Namespace, nameof(StaanSearchBackend));
private static string TA(string fallbackEN) => I18N.I.TA(fallbackEN, typeof(StaanSearchBackend).Namespace, nameof(StaanSearchBackend));
private const string SETTINGS_GROUP = "staan";
private const string API_KEY_SETTING = $"{SETTINGS_GROUP}.apiKey";
@@ -85,7 +87,7 @@ public sealed class StaanSearchBackend : IWebSearchBackend
public string GetSettingsFieldDescription(string fieldName) => fieldName switch
{
API_KEY_SETTING => TB("Your Staan API key. It is kept in your operating system's keyring, not in a settings file. Staan is a European search index; the first requests are free of charge, after which searching is billed per thousand requests."),
API_KEY_SETTING => TA("Your Staan API key. It is kept in your operating system's keyring, not in a settings file. Staan is a European search index; the first requests are free of charge, after which searching is billed per thousand requests."),
MARKET_SETTING => TB("The market Staan searches in. Staan searches one market at a time and offers only these three. When the AI model asks for German, English, or French, the matching market is used no matter what is chosen here; this setting decides what happens for every other language and when no language is requested at all."),
_ => string.Empty,
@@ -113,7 +115,7 @@ public sealed class StaanSearchBackend : IWebSearchBackend
if (string.IsNullOrWhiteSpace(market) || IsSupportedMarket(market))
return true;
error = string.Format(TB("The configured Staan market '{0}' is not one of the markets Staan offers. Please choose one of these: {1}."), market, string.Join(", ", SUPPORTED_MARKETS));
error = string.Format(TA("The configured Staan market '{0}' is not one of the markets Staan offers. Please choose one of these: {1}."), market, string.Join(", ", SUPPORTED_MARKETS));
return false;
}
@@ -15,6 +15,8 @@ public sealed class TavilySearchBackend : IWebSearchBackend
{
private static string TB(string fallbackEN) => I18N.I.T(fallbackEN, typeof(TavilySearchBackend).Namespace, nameof(TavilySearchBackend));
private static string TA(string fallbackEN) => I18N.I.TA(fallbackEN, typeof(TavilySearchBackend).Namespace, nameof(TavilySearchBackend));
private const string SETTINGS_GROUP = "tavily";
private const string API_KEY_SETTING = $"{SETTINGS_GROUP}.apiKey";
@@ -78,8 +80,8 @@ public sealed class TavilySearchBackend : IWebSearchBackend
public string GetSettingsFieldDescription(string fieldName) => fieldName switch
{
API_KEY_SETTING => TB("Your Tavily API key. It is kept in your operating system's keyring, not in a settings file. Tavily grants 1,000 requests per month without a credit card, which is enough for everyday use."),
SEARCH_DEPTH_SETTING => TB("How thoroughly Tavily searches. A basic search costs one of your monthly requests, an advanced search costs two and looks at more of each page before deciding how well it matches. Basic is the sensible choice unless you notice that results are missing the point."),
API_KEY_SETTING => TA("Your Tavily API key. It is kept in your operating system's keyring, not in a settings file. Tavily grants 1,000 requests per month without a credit card, which is enough for everyday use."),
SEARCH_DEPTH_SETTING => TA("How thoroughly Tavily searches. A basic search costs one of your monthly requests, an advanced search costs two and looks at more of each page before deciding how well it matches. Basic is the sensible choice unless you notice that results are missing the point."),
_ => string.Empty,
};
@@ -106,7 +108,7 @@ public sealed class TavilySearchBackend : IWebSearchBackend
if (string.IsNullOrWhiteSpace(searchDepth) || IsSupportedSearchDepth(searchDepth))
return true;
error = string.Format(TB("The configured Tavily search depth '{0}' is not one this app supports. Please choose one of these: {1}."), searchDepth, string.Join(", ", SUPPORTED_SEARCH_DEPTHS));
error = string.Format(TA("The configured Tavily search depth '{0}' is not one this app supports. Please choose one of these: {1}."), searchDepth, string.Join(", ", SUPPORTED_SEARCH_DEPTHS));
return false;
}
@@ -20,6 +20,8 @@ internal sealed class WebSearchDispatcher(IEnumerable<IWebSearchBackend> backend
{
private static string TB(string fallbackEN) => I18N.I.T(fallbackEN, typeof(WebSearchDispatcher).Namespace, nameof(WebSearchDispatcher));
private static string TA(string fallbackEN) => I18N.I.TA(fallbackEN, typeof(WebSearchDispatcher).Namespace, nameof(WebSearchDispatcher));
public IReadOnlyList<IWebSearchBackend> Backends { get; } = backends.OrderBy(backend => backend.Backend).ToList();
/// <summary>
@@ -115,7 +117,7 @@ internal sealed class WebSearchDispatcher(IEnumerable<IWebSearchBackend> backend
var remainingBackends = backendsToAsk.Where(backend => backend.Capabilities.SupportsSafeSearch).ToList();
if (remainingBackends.Count is 0)
throw new InvalidOperationException(TB("None of the search services this search would use can filter explicit results, which the configured safe search policy requires. Please configure a search service that can filter, or turn the policy off."));
throw new InvalidOperationException(TA("None of the search services this search would use can filter explicit results, which the configured safe search policy requires. Please configure a search service that can filter, or turn the policy off."));
foreach (var backend in backendsToAsk.Where(backend => !backend.Capabilities.SupportsSafeSearch))
notes.Add($"{backend.Backend.Name} was not asked, because it cannot filter explicit results and the configured safe search policy requires that.");
@@ -24,6 +24,8 @@ public sealed class WebSearchTool(IEnumerable<IWebSearchBackend> backends, WebPa
{
private static string TB(string fallbackEN) => I18N.I.T(fallbackEN, typeof(WebSearchTool).Namespace, nameof(WebSearchTool));
private static string TA(string fallbackEN) => I18N.I.TA(fallbackEN, typeof(WebSearchTool).Namespace, nameof(WebSearchTool));
//
// The dispatcher holds the backends: which of them answers a search, and in which order,
// is what it decides, so the order they are offered and tried in belongs to it rather than
@@ -185,7 +187,7 @@ public sealed class WebSearchTool(IEnumerable<IWebSearchBackend> backends, WebPa
public string GetDisplayName() => TB("Web Search");
public string GetDescription() => TB("Search the web with one of the configured search services and retrieve the readable content of the best matching pages.");
public string GetDescription() => TA("Search the web with one of the configured search services and retrieve the readable content of the best matching pages.");
public string GetSettingsGroupLabel(string groupKey) => this.FindBackend(groupKey)?.GetSettingsGroupLabel() ?? groupKey;
@@ -221,9 +223,9 @@ public sealed class WebSearchTool(IEnumerable<IWebSearchBackend> backends, WebPa
return fieldName switch
{
BACKEND_STRATEGY_SETTING => TB("What to do with the search services you configured. Asking them one after another moves on to the next one whenever the one before it found nothing, which is the sensible choice for almost everyone. Asking all of them at once combines their results and uses one request of every service for each search, which finds more but spends your free requests several times as fast. When this is not set, the services are asked one after another."),
PRIMARY_BACKEND_SETTING => TB("Which search service to ask first, and the only one asked when you chose to use just the preferred one. When this is not set, the services are asked in a fixed order."),
DEFAULT_LANGUAGE_SETTING => TB("The language to search in when the AI model does not ask for a specific one. This is required: without a language, many search engines return no results at all, and the search would come back empty without telling you why. Choose 'Any language' if you do not want to restrict the results."),
BACKEND_STRATEGY_SETTING => TA("What to do with the search services you configured. Asking them one after another moves on to the next one whenever the one before it found nothing, which is the sensible choice for almost everyone. Asking all of them at once combines their results and uses one request of every service for each search, which finds more but spends your free requests several times as fast. When this is not set, the services are asked one after another."),
PRIMARY_BACKEND_SETTING => TA("Which search service to ask first, and the only one asked when you chose to use just the preferred one. When this is not set, the services are asked in a fixed order."),
DEFAULT_LANGUAGE_SETTING => TA("The language to search in when the AI model does not ask for a specific one. This is required: without a language, many search engines return no results at all, and the search would come back empty without telling you why. Choose 'Any language' if you do not want to restrict the results."),
DEFAULT_SAFE_SEARCH_SETTING => TB("Optional safe search policy sent to the search service when configured."),
MAX_RESULTS_SETTING => TB("Optional default maximum number of results returned to the model when the model does not provide a limit."),
SEARCH_TIMEOUT_SECONDS_SETTING => TB("Optional HTTP timeout for the search request in seconds."),
@@ -302,7 +304,7 @@ public sealed class WebSearchTool(IEnumerable<IWebSearchBackend> backends, WebPa
{
var positiveIntegerErrorFormat = TB("The setting '{0}' must be a positive integer.");
var maximumErrorFormat = TB("The setting '{0}' must be less than or equal to {1}.");
var invalidOptionErrorFormat = TB("The setting '{0}' holds the value '{1}', which is not one of the available options. Please choose one of the offered values.");
var invalidOptionErrorFormat = TA("The setting '{0}' holds the value '{1}', which is not one of the available options. Please choose one of the offered values.");
//
// No backend field is required in the schema, because requiring one would mean every
@@ -315,7 +317,7 @@ public sealed class WebSearchTool(IEnumerable<IWebSearchBackend> backends, WebPa
return Task.FromResult<ToolConfigurationState?>(new ToolConfigurationState
{
IsConfigured = false,
Message = TB("Please configure at least one search service for the web search."),
Message = TA("Please configure at least one search service for the web search."),
});
}
@@ -362,7 +364,7 @@ public sealed class WebSearchTool(IEnumerable<IWebSearchBackend> backends, WebPa
return Task.FromResult<ToolConfigurationState?>(new ToolConfigurationState
{
IsConfigured = false,
Message = string.Format(TB("The preferred search service {0} is not configured. Please configure it, or choose one of the services you did configure."), primaryBackend.Value.Name),
Message = string.Format(TA("The preferred search service {0} is not configured. Please configure it, or choose one of the services you did configure."), primaryBackend.Value.Name),
});
}
@@ -371,7 +373,7 @@ public sealed class WebSearchTool(IEnumerable<IWebSearchBackend> backends, WebPa
return Task.FromResult<ToolConfigurationState?>(new ToolConfigurationState
{
IsConfigured = false,
Message = TB("Please choose the preferred search service, or let the services be used one after another."),
Message = TA("Please choose the preferred search service, or let the services be used one after another."),
});
}
}
@@ -412,7 +414,7 @@ public sealed class WebSearchTool(IEnumerable<IWebSearchBackend> backends, WebPa
return Task.FromResult<ToolConfigurationState?>(new ToolConfigurationState
{
IsConfigured = false,
Message = TB("None of the configured search services can filter explicit results, but a safe search policy is configured. Please configure a search service that can filter, or set the safe search policy to off."),
Message = TA("None of the configured search services can filter explicit results, but a safe search policy is configured. Please configure a search service that can filter, or set the safe search policy to off."),
});
}
@@ -429,7 +431,7 @@ public sealed class WebSearchTool(IEnumerable<IWebSearchBackend> backends, WebPa
return Task.FromResult<ToolConfigurationState?>(new ToolConfigurationState
{
IsConfigured = false,
Message = string.Format(TB("The preferred search service {0} cannot filter explicit results, but a safe search policy is configured and it is the only service that would be used. Please choose another service, let the services be used one after another, or set the safe search policy to off."), chosenBackend.Value.Name),
Message = string.Format(TA("The preferred search service {0} cannot filter explicit results, but a safe search policy is configured and it is the only service that would be used. Please choose another service, let the services be used one after another, or set the safe search policy to off."), chosenBackend.Value.Name),
});
}
}