mirror of
https://github.com/MindWorkAI/AI-Studio.git
synced 2026-09-01 20:09:15 +00:00
Fixed and guarded the I18N key collection against missing keys (#936)
This commit is contained in:
parent
415ed35422
commit
99089f853e
@ -22,9 +22,13 @@ public sealed partial class CollectI18NKeysCommand
|
||||
T(@"
|
||||
""";
|
||||
|
||||
private const string END_TAG = """
|
||||
")
|
||||
""";
|
||||
private const string END_TAG1 = """
|
||||
")
|
||||
""";
|
||||
|
||||
private const string END_TAG2 = """
|
||||
",
|
||||
""";
|
||||
|
||||
private static readonly (string Tag, int Length)[] START_TAGS =
|
||||
[
|
||||
@ -32,6 +36,12 @@ public sealed partial class CollectI18NKeysCommand
|
||||
(START_TAG2, START_TAG2.Length),
|
||||
(START_TAG3, START_TAG3.Length)
|
||||
];
|
||||
|
||||
private static readonly string[] END_TAGS =
|
||||
[
|
||||
END_TAG1,
|
||||
END_TAG2
|
||||
];
|
||||
|
||||
[Command("collect-i18n", Description = "Collect I18N keys")]
|
||||
public async Task CollectI18NKeys()
|
||||
@ -49,6 +59,7 @@ public sealed partial class CollectI18NKeysCommand
|
||||
var allFiles = Directory.EnumerateFiles(cwd, "*", SearchOption.AllDirectories);
|
||||
var counter = 0;
|
||||
|
||||
var warnings = new List<string>();
|
||||
var allI18NContent = new Dictionary<string, string>();
|
||||
foreach (var filePath in allFiles)
|
||||
{
|
||||
@ -66,7 +77,7 @@ public sealed partial class CollectI18NKeysCommand
|
||||
continue;
|
||||
|
||||
var content = await File.ReadAllTextAsync(filePath, Encoding.UTF8);
|
||||
var matches = this.FindAllTextTags(content);
|
||||
var matches = this.FindAllTextTags(content, filePath, warnings);
|
||||
if (matches.Count == 0)
|
||||
continue;
|
||||
|
||||
@ -89,7 +100,9 @@ public sealed partial class CollectI18NKeysCommand
|
||||
}
|
||||
|
||||
Console.WriteLine($" {counter:###,###} files processed, {allI18NContent.Count:###,###} keys found.");
|
||||
|
||||
foreach (var warning in warnings)
|
||||
Console.WriteLine(warning);
|
||||
|
||||
Console.Write("- Creating Lua code ...");
|
||||
var luaCode = this.ExportToLuaAssignments(allI18NContent);
|
||||
|
||||
@ -163,7 +176,7 @@ public sealed partial class CollectI18NKeysCommand
|
||||
return sb.ToString();
|
||||
}
|
||||
|
||||
private List<string> FindAllTextTags(ReadOnlySpan<char> fileContent)
|
||||
private List<string> FindAllTextTags(ReadOnlySpan<char> fileContent, string filePath, List<string> warnings)
|
||||
{
|
||||
(int Index, int Len) FindNextStart(ReadOnlySpan<char> content)
|
||||
{
|
||||
@ -182,6 +195,19 @@ public sealed partial class CollectI18NKeysCommand
|
||||
|
||||
return (bestIndex, bestLength);
|
||||
}
|
||||
|
||||
int FindNextEnd(ReadOnlySpan<char> content)
|
||||
{
|
||||
var bestIndex = -1;
|
||||
foreach (var tag in END_TAGS)
|
||||
{
|
||||
var index = content.IndexOf(tag);
|
||||
if (index != -1 && (bestIndex == -1 || index < bestIndex))
|
||||
bestIndex = index;
|
||||
}
|
||||
|
||||
return bestIndex;
|
||||
}
|
||||
|
||||
var matches = new List<string>();
|
||||
var startIdx = FindNextStart(fileContent);
|
||||
@ -196,15 +222,26 @@ public sealed partial class CollectI18NKeysCommand
|
||||
while(content[0] == '"')
|
||||
content = content[1..];
|
||||
|
||||
var endIdx = content.IndexOf(END_TAG);
|
||||
var endIdx = FindNextEnd(content);
|
||||
if (endIdx == -1)
|
||||
break;
|
||||
|
||||
var match = content[..endIdx];
|
||||
while (match[^1] == '"')
|
||||
match = match[..^1];
|
||||
|
||||
matches.Add(match.ToString());
|
||||
|
||||
var text = match.ToString();
|
||||
|
||||
//
|
||||
// We read the raw source text, whereas the app hashes the unescaped string at
|
||||
// runtime. Thus, any escape sequence makes both hashes differ, so that the text
|
||||
// never finds its translation. Since we cannot detect this at runtime, we warn
|
||||
// about it here:
|
||||
//
|
||||
if(text.Contains('\\'))
|
||||
warnings.Add($"- Warning: The text '{text}' in the file '{filePath}' contains an escape sequence. Its key does not match the key the app looks up at runtime, so this text stays untranslated. Please use a raw string literal instead.");
|
||||
|
||||
matches.Add(text);
|
||||
startIdx = FindNextStart(content);
|
||||
}
|
||||
|
||||
|
||||
@ -6238,6 +6238,9 @@ UI_TEXT_CONTENT["AISTUDIO::DIALOGS::PROVIDERDIALOG::T2646845972"] = "Add"
|
||||
-- Additional API parameters
|
||||
UI_TEXT_CONTENT["AISTUDIO::DIALOGS::PROVIDERDIALOG::T2728244552"] = "Additional API parameters"
|
||||
|
||||
-- Invalid JSON: Add the parameters in proper JSON formatting, e.g., "temperature": 0.5. Remove trailing commas. The usual surrounding curly brackets {} must not be used, though.
|
||||
UI_TEXT_CONTENT["AISTUDIO::DIALOGS::PROVIDERDIALOG::T2765821959"] = "Invalid JSON: Add the parameters in proper JSON formatting, e.g., \"temperature\": 0.5. Remove trailing commas. The usual surrounding curly brackets {} must not be used, though."
|
||||
|
||||
-- No models loaded or available.
|
||||
UI_TEXT_CONTENT["AISTUDIO::DIALOGS::PROVIDERDIALOG::T2810182573"] = "No models loaded or available."
|
||||
|
||||
@ -6271,9 +6274,6 @@ UI_TEXT_CONTENT["AISTUDIO::DIALOGS::PROVIDERDIALOG::T3361153305"] = "Show Expert
|
||||
-- Audio input
|
||||
UI_TEXT_CONTENT["AISTUDIO::DIALOGS::PROVIDERDIALOG::T3404621481"] = "Audio input"
|
||||
|
||||
-- Invalid JSON: Add the parameters in proper JSON formatting, e.g., \"temperature\": 0.5. Remove trailing commas. The usual surrounding curly brackets {} must not be used, though.
|
||||
UI_TEXT_CONTENT["AISTUDIO::DIALOGS::PROVIDERDIALOG::T3502745319"] = "Invalid JSON: Add the parameters in proper JSON formatting, e.g., \\\"temperature\\\": 0.5. Remove trailing commas. The usual surrounding curly brackets {} must not be used, though."
|
||||
|
||||
-- Reasoning (thinking) behavior
|
||||
UI_TEXT_CONTENT["AISTUDIO::DIALOGS::PROVIDERDIALOG::T3546126752"] = "Reasoning (thinking) behavior"
|
||||
|
||||
@ -8851,6 +8851,9 @@ UI_TEXT_CONTENT["AISTUDIO::PAGES::PLUGINS::T2222816203"] = "Plugins"
|
||||
-- Edit Assistant Plugin
|
||||
UI_TEXT_CONTENT["AISTUDIO::PAGES::PLUGINS::T2477579768"] = "Edit Assistant Plugin"
|
||||
|
||||
-- The assistant plugin '{0}' was audited with the level '{1}', which is below the required minimum level '{2}'. Your current settings allow activation anyway, but this may be potentially dangerous. Do you really want to enable this plugin?
|
||||
UI_TEXT_CONTENT["AISTUDIO::PAGES::PLUGINS::T2608443050"] = "The assistant plugin '{0}' was audited with the level '{1}', which is below the required minimum level '{2}'. Your current settings allow activation anyway, but this may be potentially dangerous. Do you really want to enable this plugin?"
|
||||
|
||||
-- Enabled Plugins
|
||||
UI_TEXT_CONTENT["AISTUDIO::PAGES::PLUGINS::T2738444034"] = "Enabled Plugins"
|
||||
|
||||
@ -8905,9 +8908,6 @@ UI_TEXT_CONTENT["AISTUDIO::PAGES::PLUGINS::T4157246824"] = "The assistant plugin
|
||||
-- Open website
|
||||
UI_TEXT_CONTENT["AISTUDIO::PAGES::PLUGINS::T4239378936"] = "Open website"
|
||||
|
||||
-- The assistant plugin '{0}' was audited with the level '{1}', which is below the required minimum level \"{2}\". Your current settings allow activation anyway, but this may be potentially dangerous. Do you really want to enable this plugin?
|
||||
UI_TEXT_CONTENT["AISTUDIO::PAGES::PLUGINS::T448946658"] = "The assistant plugin '{0}' was audited with the level '{1}', which is below the required minimum level \\\"{2}\\\". Your current settings allow activation anyway, but this may be potentially dangerous. Do you really want to enable this plugin?"
|
||||
|
||||
-- The plugin archive was exported to '{0}'.
|
||||
UI_TEXT_CONTENT["AISTUDIO::PAGES::PLUGINS::T659549952"] = "The plugin archive was exported to '{0}'."
|
||||
|
||||
@ -10567,9 +10567,15 @@ UI_TEXT_CONTENT["AISTUDIO::TOOLS::SERVICES::GLOBALSHORTCUTSERVICE::T1204510649"]
|
||||
-- The global shortcut could not be registered. The previous shortcut remains active.
|
||||
UI_TEXT_CONTENT["AISTUDIO::TOOLS::SERVICES::GLOBALSHORTCUTSERVICE::T2266307101"] = "The global shortcut could not be registered. The previous shortcut remains active."
|
||||
|
||||
-- Global shortcut
|
||||
UI_TEXT_CONTENT["AISTUDIO::TOOLS::SERVICES::GLOBALSHORTCUTSERVICE::T2637055764"] = "Global shortcut"
|
||||
|
||||
-- The global shortcut change was cancelled. The previous shortcut remains active.
|
||||
UI_TEXT_CONTENT["AISTUDIO::TOOLS::SERVICES::GLOBALSHORTCUTSERVICE::T3299913860"] = "The global shortcut change was cancelled. The previous shortcut remains active."
|
||||
|
||||
-- Toggle voice recording
|
||||
UI_TEXT_CONTENT["AISTUDIO::TOOLS::SERVICES::GLOBALSHORTCUTSERVICE::T40517664"] = "Toggle voice recording"
|
||||
|
||||
-- The configured transcription provider could not be created.
|
||||
UI_TEXT_CONTENT["AISTUDIO::TOOLS::SERVICES::MEDIATRANSCRIPTIONSERVICE::T1235984176"] = "The configured transcription provider could not be created."
|
||||
|
||||
|
||||
@ -631,7 +631,7 @@ public partial class ProviderDialog : MSGComponentBase, ISecretId
|
||||
}
|
||||
catch (JsonException)
|
||||
{
|
||||
return T("Invalid JSON: Add the parameters in proper JSON formatting, e.g., \"temperature\": 0.5. Remove trailing commas. The usual surrounding curly brackets {} must not be used, though.");
|
||||
return T("""Invalid JSON: Add the parameters in proper JSON formatting, e.g., "temperature": 0.5. Remove trailing commas. The usual surrounding curly brackets {} must not be used, though.""");
|
||||
}
|
||||
}
|
||||
|
||||
@ -764,7 +764,7 @@ public partial class ProviderDialog : MSGComponentBase, ISecretId
|
||||
|
||||
if (objectStack.Count != 0)
|
||||
{
|
||||
errorMessage = T("Invalid JSON: Add the parameters in proper JSON formatting, e.g., \"temperature\": 0.5. Remove trailing commas. The usual surrounding curly brackets {} must not be used, though.");
|
||||
errorMessage = T("""Invalid JSON: Add the parameters in proper JSON formatting, e.g., "temperature": 0.5. Remove trailing commas. The usual surrounding curly brackets {} must not be used, though.""");
|
||||
return false;
|
||||
}
|
||||
|
||||
|
||||
@ -175,7 +175,7 @@ public partial class Plugins : MSGComponentBase
|
||||
{
|
||||
x => x.Message,
|
||||
string.Format(
|
||||
this.T("The assistant plugin '{0}' was audited with the level '{1}', which is below the required minimum level \"{2}\". Your current settings allow activation anyway, but this may be potentially dangerous. Do you really want to enable this plugin?"),
|
||||
this.T("The assistant plugin '{0}' was audited with the level '{1}', which is below the required minimum level '{2}'. Your current settings allow activation anyway, but this may be potentially dangerous. Do you really want to enable this plugin?"),
|
||||
pluginName,
|
||||
actualLevel.GetName(),
|
||||
this.AssistantPluginAuditSettings.MinimumLevel.GetName())
|
||||
|
||||
@ -6240,6 +6240,9 @@ UI_TEXT_CONTENT["AISTUDIO::DIALOGS::PROVIDERDIALOG::T2646845972"] = "Hinzufügen
|
||||
-- Additional API parameters
|
||||
UI_TEXT_CONTENT["AISTUDIO::DIALOGS::PROVIDERDIALOG::T2728244552"] = "Zusätzliche API-Parameter"
|
||||
|
||||
-- Invalid JSON: Add the parameters in proper JSON formatting, e.g., "temperature": 0.5. Remove trailing commas. The usual surrounding curly brackets {} must not be used, though.
|
||||
UI_TEXT_CONTENT["AISTUDIO::DIALOGS::PROVIDERDIALOG::T2765821959"] = "Ungültiges JSON: Fügen Sie die Parameter in korrektem JSON-Format hinzu, z. B. "temperature": 0.5. Entfernen Sie abschließende Kommas. Die üblichen umgebenden geschweiften Klammern {} dürfen jedoch nicht verwendet werden."
|
||||
|
||||
-- No models loaded or available.
|
||||
UI_TEXT_CONTENT["AISTUDIO::DIALOGS::PROVIDERDIALOG::T2810182573"] = "Keine Modelle geladen oder verfügbar."
|
||||
|
||||
@ -6273,9 +6276,6 @@ UI_TEXT_CONTENT["AISTUDIO::DIALOGS::PROVIDERDIALOG::T3361153305"] = "Experten-Ei
|
||||
-- Audio input
|
||||
UI_TEXT_CONTENT["AISTUDIO::DIALOGS::PROVIDERDIALOG::T3404621481"] = "Audioeingabe"
|
||||
|
||||
-- Invalid JSON: Add the parameters in proper JSON formatting, e.g., \"temperature\": 0.5. Remove trailing commas. The usual surrounding curly brackets {} must not be used, though.
|
||||
UI_TEXT_CONTENT["AISTUDIO::DIALOGS::PROVIDERDIALOG::T3502745319"] = "Ungültiges JSON: Fügen Sie die Parameter in korrektem JSON-Format hinzu, z. B. \"temperature\": 0.5. Entfernen Sie abschließende Kommas. Die üblichen umgebenden geschweiften Klammern {} dürfen jedoch nicht verwendet werden."
|
||||
|
||||
-- Reasoning (thinking) behavior
|
||||
UI_TEXT_CONTENT["AISTUDIO::DIALOGS::PROVIDERDIALOG::T3546126752"] = "Verhalten bezüglich Schlussfolgerungen (Denken)"
|
||||
|
||||
@ -8853,6 +8853,9 @@ UI_TEXT_CONTENT["AISTUDIO::PAGES::PLUGINS::T2222816203"] = "Plugins"
|
||||
-- Edit Assistant Plugin
|
||||
UI_TEXT_CONTENT["AISTUDIO::PAGES::PLUGINS::T2477579768"] = "Plugin für „Assistent bearbeiten“"
|
||||
|
||||
-- The assistant plugin '{0}' was audited with the level '{1}', which is below the required minimum level '{2}'. Your current settings allow activation anyway, but this may be potentially dangerous. Do you really want to enable this plugin?
|
||||
UI_TEXT_CONTENT["AISTUDIO::PAGES::PLUGINS::T2608443050"] = "Das Assistenten-Plugin „{0}“ wurde mit der Stufe „{1}“ geprüft, die unter der erforderlichen Mindeststufe „{2}“ liegt. Ihre aktuellen Einstellungen erlauben die Aktivierung dennoch, dies kann jedoch potenziell gefährlich sein. Möchten Sie dieses Plugin wirklich aktivieren?"
|
||||
|
||||
-- Enabled Plugins
|
||||
UI_TEXT_CONTENT["AISTUDIO::PAGES::PLUGINS::T2738444034"] = "Aktivierte Plugins"
|
||||
|
||||
@ -8907,9 +8910,6 @@ UI_TEXT_CONTENT["AISTUDIO::PAGES::PLUGINS::T4157246824"] = "Das Assistenten-Plug
|
||||
-- Open website
|
||||
UI_TEXT_CONTENT["AISTUDIO::PAGES::PLUGINS::T4239378936"] = "Website öffnen"
|
||||
|
||||
-- The assistant plugin '{0}' was audited with the level '{1}', which is below the required minimum level '{2}'. Your current settings allow activation anyway, but this may be potentially dangerous. Do you really want to enable this plugin?
|
||||
UI_TEXT_CONTENT["AISTUDIO::PAGES::PLUGINS::T448946658"] = "Das Assistenten-Plugin „{0}“ wurde mit der Stufe „{1}“ geprüft, die unter der erforderlichen Mindeststufe „{2}“ liegt. Ihre aktuellen Einstellungen erlauben die Aktivierung dennoch, dies kann jedoch potenziell gefährlich sein. Möchten Sie dieses Plugin wirklich aktivieren?"
|
||||
|
||||
-- The plugin archive was exported to '{0}'.
|
||||
UI_TEXT_CONTENT["AISTUDIO::PAGES::PLUGINS::T659549952"] = "Das Plugin-Archiv wurde nach „{0}“ exportiert."
|
||||
|
||||
@ -10569,9 +10569,15 @@ UI_TEXT_CONTENT["AISTUDIO::TOOLS::SERVICES::GLOBALSHORTCUTSERVICE::T1204510649"]
|
||||
-- The global shortcut could not be registered. The previous shortcut remains active.
|
||||
UI_TEXT_CONTENT["AISTUDIO::TOOLS::SERVICES::GLOBALSHORTCUTSERVICE::T2266307101"] = "Die globale Tastenkombination konnte nicht registriert werden. Die vorherige Tastenkombination bleibt aktiv."
|
||||
|
||||
-- Global shortcut
|
||||
UI_TEXT_CONTENT["AISTUDIO::TOOLS::SERVICES::GLOBALSHORTCUTSERVICE::T2637055764"] = "Globale Tastenkombination"
|
||||
|
||||
-- The global shortcut change was cancelled. The previous shortcut remains active.
|
||||
UI_TEXT_CONTENT["AISTUDIO::TOOLS::SERVICES::GLOBALSHORTCUTSERVICE::T3299913860"] = "Die Änderung der globalen Tastenkombination wurde abgebrochen. Die vorherige Tastenkombination bleibt aktiv."
|
||||
|
||||
-- Toggle voice recording
|
||||
UI_TEXT_CONTENT["AISTUDIO::TOOLS::SERVICES::GLOBALSHORTCUTSERVICE::T40517664"] = "Sprachaufnahme umschalten"
|
||||
|
||||
-- The configured transcription provider could not be created.
|
||||
UI_TEXT_CONTENT["AISTUDIO::TOOLS::SERVICES::MEDIATRANSCRIPTIONSERVICE::T1235984176"] = "Der konfigurierte Transkriptionsanbieter konnte nicht erstellt werden."
|
||||
|
||||
|
||||
@ -6240,6 +6240,9 @@ UI_TEXT_CONTENT["AISTUDIO::DIALOGS::PROVIDERDIALOG::T2646845972"] = "Add"
|
||||
-- Additional API parameters
|
||||
UI_TEXT_CONTENT["AISTUDIO::DIALOGS::PROVIDERDIALOG::T2728244552"] = "Additional API parameters"
|
||||
|
||||
-- Invalid JSON: Add the parameters in proper JSON formatting, e.g., "temperature": 0.5. Remove trailing commas. The usual surrounding curly brackets {} must not be used, though.
|
||||
UI_TEXT_CONTENT["AISTUDIO::DIALOGS::PROVIDERDIALOG::T2765821959"] = "Invalid JSON: Add the parameters in proper JSON formatting, e.g., \"temperature\": 0.5. Remove trailing commas. The usual surrounding curly brackets {} must not be used, though."
|
||||
|
||||
-- No models loaded or available.
|
||||
UI_TEXT_CONTENT["AISTUDIO::DIALOGS::PROVIDERDIALOG::T2810182573"] = "No models loaded or available."
|
||||
|
||||
@ -6273,9 +6276,6 @@ UI_TEXT_CONTENT["AISTUDIO::DIALOGS::PROVIDERDIALOG::T3361153305"] = "Show Expert
|
||||
-- Audio input
|
||||
UI_TEXT_CONTENT["AISTUDIO::DIALOGS::PROVIDERDIALOG::T3404621481"] = "Audio input"
|
||||
|
||||
-- Invalid JSON: Add the parameters in proper JSON formatting, e.g., \"temperature\": 0.5. Remove trailing commas. The usual surrounding curly brackets {} must not be used, though.
|
||||
UI_TEXT_CONTENT["AISTUDIO::DIALOGS::PROVIDERDIALOG::T3502745319"] = "Invalid JSON: Add the parameters in proper JSON formatting, e.g., \\\"temperature\\\": 0.5. Remove trailing commas. The usual surrounding curly brackets {} must not be used, though."
|
||||
|
||||
-- Reasoning (thinking) behavior
|
||||
UI_TEXT_CONTENT["AISTUDIO::DIALOGS::PROVIDERDIALOG::T3546126752"] = "Reasoning (thinking) behavior"
|
||||
|
||||
@ -8853,6 +8853,9 @@ UI_TEXT_CONTENT["AISTUDIO::PAGES::PLUGINS::T2222816203"] = "Plugins"
|
||||
-- Edit Assistant Plugin
|
||||
UI_TEXT_CONTENT["AISTUDIO::PAGES::PLUGINS::T2477579768"] = "Edit Assistant Plugin"
|
||||
|
||||
-- The assistant plugin '{0}' was audited with the level '{1}', which is below the required minimum level '{2}'. Your current settings allow activation anyway, but this may be potentially dangerous. Do you really want to enable this plugin?
|
||||
UI_TEXT_CONTENT["AISTUDIO::PAGES::PLUGINS::T2608443050"] = "The assistant plugin '{0}' was audited with the level '{1}', which is below the required minimum level '{2}'. Your current settings allow activation anyway, but this may be potentially dangerous. Do you really want to enable this plugin?"
|
||||
|
||||
-- Enabled Plugins
|
||||
UI_TEXT_CONTENT["AISTUDIO::PAGES::PLUGINS::T2738444034"] = "Enabled Plugins"
|
||||
|
||||
@ -8907,9 +8910,6 @@ UI_TEXT_CONTENT["AISTUDIO::PAGES::PLUGINS::T4157246824"] = "The assistant plugin
|
||||
-- Open website
|
||||
UI_TEXT_CONTENT["AISTUDIO::PAGES::PLUGINS::T4239378936"] = "Open website"
|
||||
|
||||
-- The assistant plugin '{0}' was audited with the level '{1}', which is below the required minimum level '{2}'. Your current settings allow activation anyway, but this may be potentially dangerous. Do you really want to enable this plugin?
|
||||
UI_TEXT_CONTENT["AISTUDIO::PAGES::PLUGINS::T448946658"] = "The assistant plugin '{0}' was audited with the level '{1}', which is below the required minimum level '{2}'. Your current settings allow activation anyway, but this may be potentially dangerous. Do you really want to enable this plugin?"
|
||||
|
||||
-- The plugin archive was exported to '{0}'.
|
||||
UI_TEXT_CONTENT["AISTUDIO::PAGES::PLUGINS::T659549952"] = "The plugin archive was exported to '{0}'."
|
||||
|
||||
@ -10569,9 +10569,15 @@ UI_TEXT_CONTENT["AISTUDIO::TOOLS::SERVICES::GLOBALSHORTCUTSERVICE::T1204510649"]
|
||||
-- The global shortcut could not be registered. The previous shortcut remains active.
|
||||
UI_TEXT_CONTENT["AISTUDIO::TOOLS::SERVICES::GLOBALSHORTCUTSERVICE::T2266307101"] = "The global shortcut could not be registered. The previous shortcut remains active."
|
||||
|
||||
-- Global shortcut
|
||||
UI_TEXT_CONTENT["AISTUDIO::TOOLS::SERVICES::GLOBALSHORTCUTSERVICE::T2637055764"] = "Global shortcut"
|
||||
|
||||
-- The global shortcut change was cancelled. The previous shortcut remains active.
|
||||
UI_TEXT_CONTENT["AISTUDIO::TOOLS::SERVICES::GLOBALSHORTCUTSERVICE::T3299913860"] = "The global shortcut change was cancelled. The previous shortcut remains active."
|
||||
|
||||
-- Toggle voice recording
|
||||
UI_TEXT_CONTENT["AISTUDIO::TOOLS::SERVICES::GLOBALSHORTCUTSERVICE::T40517664"] = "Toggle voice recording"
|
||||
|
||||
-- The configured transcription provider could not be created.
|
||||
UI_TEXT_CONTENT["AISTUDIO::TOOLS::SERVICES::MEDIATRANSCRIPTIONSERVICE::T1235984176"] = "The configured transcription provider could not be created."
|
||||
|
||||
|
||||
@ -269,11 +269,14 @@ public sealed class GlobalShortcutService : BackgroundService, IMessageBusReceiv
|
||||
|
||||
private async Task<string> GetShortcutDescription(Shortcut shortcutId)
|
||||
{
|
||||
// Message bus receivers run without being awaited, so I18N.Init in MainLayout may still be
|
||||
// pending during startup or a plugin reload. Resolve the active language directly to avoid
|
||||
// using no language or the previously active language for the shortcut description:
|
||||
var language = await this.settingsManager.GetActiveLanguagePlugin();
|
||||
return shortcutId switch
|
||||
{
|
||||
Shortcut.VOICE_RECORDING_TOGGLE => I18N.I.GetText(language, "Toggle voice recording", typeof(GlobalShortcutService).Namespace, nameof(GlobalShortcutService)),
|
||||
_ => I18N.I.GetText(language, "Global shortcut", typeof(GlobalShortcutService).Namespace, nameof(GlobalShortcutService)),
|
||||
Shortcut.VOICE_RECORDING_TOGGLE => TB("Toggle voice recording", language),
|
||||
_ => TB("Global shortcut", language),
|
||||
};
|
||||
}
|
||||
|
||||
@ -320,6 +323,8 @@ public sealed class GlobalShortcutService : BackgroundService, IMessageBusReceiv
|
||||
|
||||
private static string TB(string fallbackEN) => I18N.I.T(fallbackEN, typeof(GlobalShortcutService).Namespace, nameof(GlobalShortcutService));
|
||||
|
||||
private static string TB(string fallbackEN, ILanguagePlugin language) => I18N.I.GetText(language, fallbackEN, typeof(GlobalShortcutService).Namespace, nameof(GlobalShortcutService));
|
||||
|
||||
private async Task<ShortcutState> GetShortcutState(Shortcut shortcutId, ShortcutSyncSource source)
|
||||
{
|
||||
var shortcut = this.GetShortcutValue(shortcutId);
|
||||
|
||||
@ -7,4 +7,5 @@
|
||||
- Fixed AI Studio reading a document to the end even after you closed its preview. Closing the dialog now stops that work immediately.
|
||||
- Fixed AI Studio holding on to finished chats, presentation images, and plugin data. It releases them now, so memory no longer grows the longer you keep the app running.
|
||||
- Fixed assistants handing an outdated result to the chat. When you sent several results without opening the chat in between, you now receive the one you sent last.
|
||||
- Fixed rare issues when multiple configurations provided introduction texts or mandatory information under the same ID.
|
||||
- Fixed rare issues when multiple configurations provided introduction texts or mandatory information under the same ID.
|
||||
- Fixed the description of the global voice recording shortcut always appearing in English. On Linux, your desktop asks you to confirm such a shortcut and shows this description; it now appears in your language.
|
||||
@ -14,4 +14,5 @@
|
||||
MWAIS0008 | Naming | Error | LocalConstantsAnalyzer
|
||||
MWAIS0009 | Usage | Error | StaticServiceProviderCacheAnalyzer
|
||||
MWAIS0010 | Usage | Error | CanonicalJsonConfigurationAnalyzer
|
||||
MWAIS0011 | Usage | Error | CanonicalJsonShapeAnalyzer
|
||||
MWAIS0011 | Usage | Error | CanonicalJsonShapeAnalyzer
|
||||
MWAIS0012 | Usage | Error | DirectI18NGetTextAnalyzer
|
||||
|
||||
@ -13,4 +13,5 @@ public static class Identifier
|
||||
public const string STATIC_SERVICE_PROVIDER_CACHE_ANALYZER = $"{Tools.ID_PREFIX}0009";
|
||||
public const string CANONICAL_JSON_CONFIGURATION_ANALYZER = $"{Tools.ID_PREFIX}0010";
|
||||
public const string CANONICAL_JSON_SHAPE_ANALYZER = $"{Tools.ID_PREFIX}0011";
|
||||
public const string DIRECT_I18N_GET_TEXT_ANALYZER = $"{Tools.ID_PREFIX}0012";
|
||||
}
|
||||
@ -0,0 +1,67 @@
|
||||
using System.Collections.Immutable;
|
||||
using System.Linq;
|
||||
|
||||
using Microsoft.CodeAnalysis;
|
||||
using Microsoft.CodeAnalysis.CSharp;
|
||||
using Microsoft.CodeAnalysis.CSharp.Syntax;
|
||||
using Microsoft.CodeAnalysis.Diagnostics;
|
||||
using Microsoft.CodeAnalysis.Operations;
|
||||
|
||||
namespace SourceCodeRules.UsageAnalyzers;
|
||||
|
||||
#pragma warning disable RS1038
|
||||
[DiagnosticAnalyzer(LanguageNames.CSharp)]
|
||||
#pragma warning restore RS1038
|
||||
public sealed class DirectI18NGetTextAnalyzer : DiagnosticAnalyzer
|
||||
{
|
||||
private const string DIAGNOSTIC_ID = Identifier.DIRECT_I18N_GET_TEXT_ANALYZER;
|
||||
|
||||
private const string TITLE = "Direct translation lookup is not allowed";
|
||||
|
||||
private const string MESSAGE_FORMAT = "Call GetText only from a T or TB wrapper whose first string parameter is forwarded as the fallback text";
|
||||
|
||||
private const string DESCRIPTION = "Translation calls must use collector-compatible T or TB wrappers so that every fallback text is included in the generated I18N resources.";
|
||||
|
||||
private const string CATEGORY = "Usage";
|
||||
|
||||
private static readonly DiagnosticDescriptor RULE = new(DIAGNOSTIC_ID, TITLE, MESSAGE_FORMAT, CATEGORY, DiagnosticSeverity.Error, isEnabledByDefault: true, description: DESCRIPTION);
|
||||
|
||||
public override ImmutableArray<DiagnosticDescriptor> SupportedDiagnostics => [RULE];
|
||||
|
||||
public override void Initialize(AnalysisContext context)
|
||||
{
|
||||
context.ConfigureGeneratedCodeAnalysis(GeneratedCodeAnalysisFlags.None);
|
||||
context.EnableConcurrentExecution();
|
||||
context.RegisterSyntaxNodeAction(AnalyzeInvocation, SyntaxKind.InvocationExpression);
|
||||
}
|
||||
|
||||
private static void AnalyzeInvocation(SyntaxNodeAnalysisContext context)
|
||||
{
|
||||
var invocation = (InvocationExpressionSyntax)context.Node;
|
||||
if (context.SemanticModel.GetSymbolInfo(invocation).Symbol is not IMethodSymbol method)
|
||||
return;
|
||||
|
||||
var targetMethod = method.ReducedFrom ?? method;
|
||||
if (targetMethod.Name != "GetText" || targetMethod.ContainingType.Name != "ILangExtensions" || targetMethod.ContainingNamespace.ToDisplayString() != "AIStudio.Tools.PluginSystem")
|
||||
return;
|
||||
|
||||
if (context.SemanticModel.GetOperation(invocation) is IInvocationOperation operation
|
||||
&& IsCollectorCompatibleWrapper(context.ContainingSymbol as IMethodSymbol, operation))
|
||||
return;
|
||||
|
||||
context.ReportDiagnostic(Diagnostic.Create(RULE, invocation.GetLocation()));
|
||||
}
|
||||
|
||||
private static bool IsCollectorCompatibleWrapper(IMethodSymbol? containingMethod, IInvocationOperation invocation)
|
||||
{
|
||||
if (containingMethod?.Name is not ("T" or "TB")
|
||||
|| containingMethod.ReturnType.SpecialType != SpecialType.System_String
|
||||
|| containingMethod.Parameters.Length == 0
|
||||
|| containingMethod.Parameters[0].Type.SpecialType != SpecialType.System_String)
|
||||
return false;
|
||||
|
||||
var fallbackArgument = invocation.Arguments.FirstOrDefault(argument => argument.Parameter?.Name == "fallbackEN");
|
||||
return fallbackArgument?.Value is IParameterReferenceOperation parameterReference
|
||||
&& SymbolEqualityComparer.Default.Equals(parameterReference.Parameter, containingMethod.Parameters[0]);
|
||||
}
|
||||
}
|
||||
Loading…
Reference in New Issue
Block a user