From 47b6a896851527e280e553c9a06b587b3d1cdd46 Mon Sep 17 00:00:00 2001 From: Thorsten Sommer Date: Sun, 27 Apr 2025 16:13:15 +0200 Subject: [PATCH] Add German localization (#430) --- README.md | 2 +- app/Build/Commands/CollectI18NKeysCommand.cs | 34 +- app/MindWork AI Studio.sln.DotSettings | 1 + .../Assistants/AssistantBase.razor | 10 +- .../Assistants/AssistantBase.razor.cs | 5 +- .../Assistants/I18N/AssistantI18N.razor.cs | 22 +- .../Assistants/I18N/allTexts.lua | 261 ++ .../Components/ChatComponent.razor | 8 +- .../Components/DataSourceSelection.razor | 55 +- .../Components/DataSourceSelection.razor.cs | 38 +- .../Components/MSGComponentBase.cs | 31 +- .../Components/MudTextList.razor | 4 +- .../Components/Vision.razor.cs | 27 +- .../Components/Workspaces.razor.cs | 18 +- .../Dialogs/ConfirmDialog.razor | 13 +- .../Dialogs/ConfirmDialog.razor.cs | 4 +- .../Dialogs/ProfileDialog.razor | 32 +- .../Dialogs/ProfileDialog.razor.cs | 20 +- .../Dialogs/ProviderDialog.razor | 40 +- .../Dialogs/ProviderDialog.razor.cs | 17 +- .../Dialogs/Settings/SettingsDialogBase.cs | 4 +- .../SettingsDialogDataSources.razor.cs | 4 +- .../Settings/SettingsDialogTranslation.razor | 2 +- .../Dialogs/SingleInputDialog.razor | 15 +- .../Dialogs/SingleInputDialog.razor.cs | 7 +- .../Dialogs/UpdateDialog.razor | 11 +- .../Dialogs/UpdateDialog.razor.cs | 7 +- .../Dialogs/WorkspaceSelectionDialog.razor | 13 +- .../Dialogs/WorkspaceSelectionDialog.razor.cs | 3 +- .../Layout/MainLayout.razor.cs | 4 + app/MindWork AI Studio/Pages/Assistants.razor | 18 +- app/MindWork AI Studio/Pages/Chat.razor | 2 +- app/MindWork AI Studio/Pages/Home.razor | 2 +- app/MindWork AI Studio/Pages/Home.razor.cs | 40 +- app/MindWork AI Studio/Pages/Supporters.razor | 2 +- .../contentHome.lua | 3 - .../plugin.lua | 2485 ++++++++++++++++- .../plugin.lua | 261 ++ .../Settings/SettingsManager.cs | 6 - .../Tools/PluginSystem/ILang.cs | 20 + .../Tools/PluginSystem/ILangExtensions.cs | 11 +- .../PluginSystem/PluginFactory.HotReload.cs | 18 +- .../PluginSystem/PluginFactory.Loading.cs | 75 +- .../wwwroot/changelog/v0.9.41.md | 1 + 44 files changed, 3394 insertions(+), 262 deletions(-) delete mode 100644 app/MindWork AI Studio/Plugins/languages/de-de-43065dbc-78d0-45b7-92be-f14c2926e2dc/contentHome.lua diff --git a/README.md b/README.md index d1955382..bcec5001 100644 --- a/README.md +++ b/README.md @@ -33,7 +33,7 @@ Things we are currently working on: - [x] ~~Added hot-reload support for plugins ([PR #377](https://github.com/MindWorkAI/AI-Studio/pull/377), [PR #391](https://github.com/MindWorkAI/AI-Studio/pull/391))~~ - [ ] Add support for other languages (I18N) to AI Studio (~~[PR #381](https://github.com/MindWorkAI/AI-Studio/pull/381), [PR #400](https://github.com/MindWorkAI/AI-Studio/pull/400), [PR #404](https://github.com/MindWorkAI/AI-Studio/pull/404), [PR #429](https://github.com/MindWorkAI/AI-Studio/pull/429))~~ - [x] ~~Add an I18N assistant to translate all AI Studio texts to a certain language & culture ([PR #422](https://github.com/MindWorkAI/AI-Studio/pull/422))~~ - - [ ] Provide MindWork AI Studio in German ([#31](https://github.com/MindWorkAI/Planning/issues/31)) + - [ ] Provide MindWork AI Studio in German ([PR #430](https://github.com/MindWorkAI/AI-Studio/pull/430)) - [ ] Add configuration plugins, which allow pre-defining some LLM providers in organizations - [ ] Add an app store for plugins, showcasing community-contributed plugins from public GitHub and GitLab repositories. This will enable AI Studio users to discover, install, and update plugins directly within the platform. - [ ] Add assistant plugins diff --git a/app/Build/Commands/CollectI18NKeysCommand.cs b/app/Build/Commands/CollectI18NKeysCommand.cs index f7a533f9..3108a488 100644 --- a/app/Build/Commands/CollectI18NKeysCommand.cs +++ b/app/Build/Commands/CollectI18NKeysCommand.cs @@ -133,24 +133,48 @@ public sealed partial class CollectI18NKeysCommand private List FindAllTextTags(ReadOnlySpan fileContent) { - const string START_TAG = """ + const string START_TAG1 = """ T(" """; + const string START_TAG2 = """ + TB(" + """; + const string END_TAG = """ ") """; + (int Index, int Len) FindNextStart(ReadOnlySpan content) + { + var startIdx1 = content.IndexOf(START_TAG1); + var startIdx2 = content.IndexOf(START_TAG2); + + if (startIdx1 == -1 && startIdx2 == -1) + return (-1, 0); + + if (startIdx1 == -1) + return (startIdx2, START_TAG2.Length); + + if (startIdx2 == -1) + return (startIdx1, START_TAG1.Length); + + if (startIdx1 < startIdx2) + return (startIdx1, START_TAG1.Length); + + return (startIdx2, START_TAG2.Length); + } + var matches = new List(); - var startIdx = fileContent.IndexOf(START_TAG); + var startIdx = FindNextStart(fileContent); var content = fileContent; - while (startIdx > -1) + while (startIdx.Index > -1) { // // In some cases, after the initial " there follow more " characters. // We need to skip them: // - content = content[(startIdx + START_TAG.Length)..]; + content = content[(startIdx.Index + startIdx.Len)..]; while(content[0] == '"') content = content[1..]; @@ -163,7 +187,7 @@ public sealed partial class CollectI18NKeysCommand match = match[..^1]; matches.Add(match.ToString()); - startIdx = content.IndexOf(START_TAG); + startIdx = FindNextStart(content); } return matches; diff --git a/app/MindWork AI Studio.sln.DotSettings b/app/MindWork AI Studio.sln.DotSettings index f8edfd31..3eb9acc5 100644 --- a/app/MindWork AI Studio.sln.DotSettings +++ b/app/MindWork AI Studio.sln.DotSettings @@ -11,6 +11,7 @@ OS RAG RID + TB UI URL I18N diff --git a/app/MindWork AI Studio/Assistants/AssistantBase.razor b/app/MindWork AI Studio/Assistants/AssistantBase.razor index c27704c4..47714c22 100644 --- a/app/MindWork AI Studio/Assistants/AssistantBase.razor +++ b/app/MindWork AI Studio/Assistants/AssistantBase.razor @@ -34,7 +34,7 @@ @if (this.isProcessing && this.cancellationTokenSource is not null) { - + } @@ -80,7 +80,7 @@ { @if (this.ShowSendTo) { - + @foreach (var assistant in Enum.GetValues().Where(n => n.AllowSendTo()).OrderBy(n => n.Name().Length)) { @@ -110,7 +110,7 @@ break; case SendToButton sendToButton: - + @foreach (var assistant in Enum.GetValues().Where(n => n.AllowSendTo()).OrderBy(n => n.Name().Length)) { @@ -125,14 +125,14 @@ @if (this.ShowCopyResult) { - Copy result + @TB("Copy result") } @if (this.ShowReset) { - Reset + @TB("Reset") } diff --git a/app/MindWork AI Studio/Assistants/AssistantBase.razor.cs b/app/MindWork AI Studio/Assistants/AssistantBase.razor.cs index 877374ad..7abc5824 100644 --- a/app/MindWork AI Studio/Assistants/AssistantBase.razor.cs +++ b/app/MindWork AI Studio/Assistants/AssistantBase.razor.cs @@ -103,6 +103,8 @@ public abstract partial class AssistantBase : AssistantLowerBase wher protected override async Task OnInitializedAsync() { + await base.OnInitializedAsync(); + this.formChangeTimer.AutoReset = false; this.formChangeTimer.Elapsed += async (_, _) => { @@ -113,7 +115,6 @@ public abstract partial class AssistantBase : AssistantLowerBase wher this.MightPreselectValues(); this.providerSettings = this.SettingsManager.GetPreselectedProvider(this.Component); this.currentProfile = this.SettingsManager.GetPreselectedProfile(this.Component); - await base.OnInitializedAsync(); } protected override async Task OnParametersSetAsync() @@ -136,6 +137,8 @@ public abstract partial class AssistantBase : AssistantLowerBase wher #endregion + private string TB(string fallbackEN) => this.T(fallbackEN, typeof(AssistantBase).Namespace, nameof(AssistantBase)); + private string SubmitButtonStyle => this.SettingsManager.ConfigurationData.LLMProviders.ShowProviderConfidence ? this.providerSettings.UsedLLMProvider.GetConfidence(this.SettingsManager).StyleBorder(this.SettingsManager) : string.Empty; protected string? ValidatingProvider(AIStudio.Settings.Provider provider) diff --git a/app/MindWork AI Studio/Assistants/I18N/AssistantI18N.razor.cs b/app/MindWork AI Studio/Assistants/I18N/AssistantI18N.razor.cs index ee3a94cf..93284c3f 100644 --- a/app/MindWork AI Studio/Assistants/I18N/AssistantI18N.razor.cs +++ b/app/MindWork AI Studio/Assistants/I18N/AssistantI18N.razor.cs @@ -306,8 +306,23 @@ public partial class AssistantI18N : AssistantBaseCore if(this.cancellationTokenSource!.IsCancellationRequested) return; - // Phase 2: Create the Lua code - this.Phase2CreateLuaCode(); + // + // Phase 2: Create the Lua code. We want to use the base language + // for the comments, though: + // + var commentContent = new Dictionary(this.addedContent); + foreach (var keyValuePair in PluginFactory.BaseLanguage.Content) + { + if (this.cancellationTokenSource!.IsCancellationRequested) + break; + + if (this.removedContent.ContainsKey(keyValuePair.Key)) + continue; + + commentContent.TryAdd(keyValuePair.Key, keyValuePair.Value); + } + + this.Phase2CreateLuaCode(commentContent); } private async Task Phase1TranslateAddedContent() @@ -346,10 +361,9 @@ public partial class AssistantI18N : AssistantBaseCore } } - private void Phase2CreateLuaCode() + private void Phase2CreateLuaCode(IReadOnlyDictionary commentContent) { this.finalLuaCode.Clear(); - var commentContent = this.addedContent.Concat(PluginFactory.BaseLanguage.Content).ToDictionary(); LuaTable.Create(ref this.finalLuaCode, "UI_TEXT_CONTENT", this.localizedContent, commentContent, this.cancellationTokenSource!.Token); // Next, we must remove the `root::` prefix from the keys: diff --git a/app/MindWork AI Studio/Assistants/I18N/allTexts.lua b/app/MindWork AI Studio/Assistants/I18N/allTexts.lua index 4791d157..f23e9219 100644 --- a/app/MindWork AI Studio/Assistants/I18N/allTexts.lua +++ b/app/MindWork AI Studio/Assistants/I18N/allTexts.lua @@ -46,9 +46,21 @@ LANG_NAME = "English (United States)" UI_TEXT_CONTENT = {} +-- Stop generation +UI_TEXT_CONTENT["AISTUDIO::ASSISTANTS::ASSISTANTBASE::T1317408357"] = "Stop generation" + +-- Reset +UI_TEXT_CONTENT["AISTUDIO::ASSISTANTS::ASSISTANTBASE::T180921696"] = "Reset" + -- Assistant - {0} UI_TEXT_CONTENT["AISTUDIO::ASSISTANTS::ASSISTANTBASE::T3043922"] = "Assistant - {0}" +-- Send to ... +UI_TEXT_CONTENT["AISTUDIO::ASSISTANTS::ASSISTANTBASE::T4242312602"] = "Send to ..." + +-- Copy result +UI_TEXT_CONTENT["AISTUDIO::ASSISTANTS::ASSISTANTBASE::T83711157"] = "Copy result" + -- Provide a list of bullet points and some basic information for an e-mail. The assistant will generate an e-mail based on that input. UI_TEXT_CONTENT["AISTUDIO::ASSISTANTS::EMAIL::ASSISTANTEMAIL::T1143222914"] = "Provide a list of bullet points and some basic information for an e-mail. The assistant will generate an e-mail based on that input." @@ -397,6 +409,12 @@ UI_TEXT_CONTENT["AISTUDIO::COMPONENTS::CHATCOMPONENT::T1133040906"] = "Move chat -- Are you sure you want to move this chat? All unsaved changes will be lost. UI_TEXT_CONTENT["AISTUDIO::COMPONENTS::CHATCOMPONENT::T1142475422"] = "Are you sure you want to move this chat? All unsaved changes will be lost." +-- Stop generation +UI_TEXT_CONTENT["AISTUDIO::COMPONENTS::CHATCOMPONENT::T1317408357"] = "Stop generation" + +-- Save chat +UI_TEXT_CONTENT["AISTUDIO::COMPONENTS::CHATCOMPONENT::T1516264254"] = "Save chat" + -- Type your input here... UI_TEXT_CONTENT["AISTUDIO::COMPONENTS::CHATCOMPONENT::T1849313532"] = "Type your input here..." @@ -415,12 +433,18 @@ UI_TEXT_CONTENT["AISTUDIO::COMPONENTS::CHATCOMPONENT::T3403290862"] = "The selec -- Select a provider first UI_TEXT_CONTENT["AISTUDIO::COMPONENTS::CHATCOMPONENT::T3654197869"] = "Select a provider first" +-- Start temporary chat +UI_TEXT_CONTENT["AISTUDIO::COMPONENTS::CHATCOMPONENT::T4113970938"] = "Start temporary chat" + -- Please select the workspace where you want to move the chat to. UI_TEXT_CONTENT["AISTUDIO::COMPONENTS::CHATCOMPONENT::T474393241"] = "Please select the workspace where you want to move the chat to." -- Move the chat to a workspace, or to another if it is already in one. UI_TEXT_CONTENT["AISTUDIO::COMPONENTS::CHATCOMPONENT::T636393754"] = "Move the chat to a workspace, or to another if it is already in one." +-- Show your workspaces +UI_TEXT_CONTENT["AISTUDIO::COMPONENTS::CHATCOMPONENT::T733672375"] = "Show your workspaces" + -- Region UI_TEXT_CONTENT["AISTUDIO::COMPONENTS::CONFIDENCEINFO::T1227782301"] = "Region" @@ -463,6 +487,69 @@ UI_TEXT_CONTENT["AISTUDIO::COMPONENTS::CONFIGURATIONPROVIDERSELECTION::T14699849 -- Use app default UI_TEXT_CONTENT["AISTUDIO::COMPONENTS::CONFIGURATIONPROVIDERSELECTION::T3672477670"] = "Use app default" +-- Yes, let the AI decide which data sources are needed. +UI_TEXT_CONTENT["AISTUDIO::COMPONENTS::DATASOURCESELECTION::T1031370894"] = "Yes, let the AI decide which data sources are needed." + +-- Yes, let the AI validate & filter the retrieved data. +UI_TEXT_CONTENT["AISTUDIO::COMPONENTS::DATASOURCESELECTION::T1309929755"] = "Yes, let the AI validate & filter the retrieved data." + +-- Data Source Selection +UI_TEXT_CONTENT["AISTUDIO::COMPONENTS::DATASOURCESELECTION::T15302104"] = "Data Source Selection" + +-- AI-Selected Data Sources +UI_TEXT_CONTENT["AISTUDIO::COMPONENTS::DATASOURCESELECTION::T168406579"] = "AI-Selected Data Sources" + +-- AI-based data validation +UI_TEXT_CONTENT["AISTUDIO::COMPONENTS::DATASOURCESELECTION::T1744745490"] = "AI-based data validation" + +-- Yes, I want to use data sources. +UI_TEXT_CONTENT["AISTUDIO::COMPONENTS::DATASOURCESELECTION::T1975014927"] = "Yes, I want to use data sources." + +-- You haven't configured any data sources. To grant the AI access to your data, you need to add such a source. However, if you wish to use data from your device, you first have to set up a so-called embedding. This embedding is necessary so the AI can effectively search your data, find and retrieve the correct information required for each task. In addition to local data, you can also incorporate your company's data. To do so, your company must provide the data through an ERI (External Retrieval Interface). +UI_TEXT_CONTENT["AISTUDIO::COMPONENTS::DATASOURCESELECTION::T2113594442"] = "You haven't configured any data sources. To grant the AI access to your data, you need to add such a source. However, if you wish to use data from your device, you first have to set up a so-called embedding. This embedding is necessary so the AI can effectively search your data, find and retrieve the correct information required for each task. In addition to local data, you can also incorporate your company's data. To do so, your company must provide the data through an ERI (External Retrieval Interface)." + +-- Select the data you want to use here. +UI_TEXT_CONTENT["AISTUDIO::COMPONENTS::DATASOURCESELECTION::T21181525"] = "Select the data you want to use here." + +-- Manage your data sources +UI_TEXT_CONTENT["AISTUDIO::COMPONENTS::DATASOURCESELECTION::T2149927097"] = "Manage your data sources" + +-- Select data +UI_TEXT_CONTENT["AISTUDIO::COMPONENTS::DATASOURCESELECTION::T274155039"] = "Select data" + +-- Read more about ERI +UI_TEXT_CONTENT["AISTUDIO::COMPONENTS::DATASOURCESELECTION::T3095532189"] = "Read more about ERI" + +-- AI-based data source selection +UI_TEXT_CONTENT["AISTUDIO::COMPONENTS::DATASOURCESELECTION::T3100256862"] = "AI-based data source selection" + +-- No, I don't want to use data sources. +UI_TEXT_CONTENT["AISTUDIO::COMPONENTS::DATASOURCESELECTION::T3135725655"] = "No, I don't want to use data sources." + +-- Your data sources cannot be used with the LLM provider you selected due to data privacy, or they are currently unavailable. +UI_TEXT_CONTENT["AISTUDIO::COMPONENTS::DATASOURCESELECTION::T3215374102"] = "Your data sources cannot be used with the LLM provider you selected due to data privacy, or they are currently unavailable." + +-- No, I manually decide which data source to use. +UI_TEXT_CONTENT["AISTUDIO::COMPONENTS::DATASOURCESELECTION::T3440789294"] = "No, I manually decide which data source to use." + +-- Close +UI_TEXT_CONTENT["AISTUDIO::COMPONENTS::DATASOURCESELECTION::T3448155331"] = "Close" + +-- The AI evaluates each of your inputs to determine whether and which data sources are necessary. Currently, the AI has not selected any source. +UI_TEXT_CONTENT["AISTUDIO::COMPONENTS::DATASOURCESELECTION::T3574254516"] = "The AI evaluates each of your inputs to determine whether and which data sources are necessary. Currently, the AI has not selected any source." + +-- No, use all data retrieved from the data sources. +UI_TEXT_CONTENT["AISTUDIO::COMPONENTS::DATASOURCESELECTION::T3751463241"] = "No, use all data retrieved from the data sources." + +-- Are data sources enabled? +UI_TEXT_CONTENT["AISTUDIO::COMPONENTS::DATASOURCESELECTION::T396683085"] = "Are data sources enabled?" + +-- Manage Data Sources +UI_TEXT_CONTENT["AISTUDIO::COMPONENTS::DATASOURCESELECTION::T700666808"] = "Manage Data Sources" + +-- Available Data Sources +UI_TEXT_CONTENT["AISTUDIO::COMPONENTS::DATASOURCESELECTION::T86053874"] = "Available Data Sources" + -- Issues UI_TEXT_CONTENT["AISTUDIO::COMPONENTS::ISSUES::T3229841001"] = "Issues" @@ -1042,6 +1129,117 @@ UI_TEXT_CONTENT["AISTUDIO::COMPONENTS::WORKSPACES::T474393241"] = "Please select -- Delete Workspace UI_TEXT_CONTENT["AISTUDIO::COMPONENTS::WORKSPACES::T701874671"] = "Delete Workspace" +-- No +UI_TEXT_CONTENT["AISTUDIO::DIALOGS::CONFIRMDIALOG::T1642511898"] = "No" + +-- Yes +UI_TEXT_CONTENT["AISTUDIO::DIALOGS::CONFIRMDIALOG::T3013883440"] = "Yes" + +-- Tell the AI what you want it to do for you. What are your goals or are you trying to achieve? Like having the AI address you informally. +UI_TEXT_CONTENT["AISTUDIO::DIALOGS::PROFILEDIALOG::T1458195391"] = "Tell the AI what you want it to do for you. What are your goals or are you trying to achieve? Like having the AI address you informally." + +-- Update +UI_TEXT_CONTENT["AISTUDIO::DIALOGS::PROFILEDIALOG::T1847791252"] = "Update" + +-- Tell the AI something about yourself. What is your profession? How experienced are you in this profession? Which technologies do you like? +UI_TEXT_CONTENT["AISTUDIO::DIALOGS::PROFILEDIALOG::T2119274961"] = "Tell the AI something about yourself. What is your profession? How experienced are you in this profession? Which technologies do you like?" + +-- What should the AI do for you? +UI_TEXT_CONTENT["AISTUDIO::DIALOGS::PROFILEDIALOG::T2261456575"] = "What should the AI do for you?" + +-- Please enter a profile name. +UI_TEXT_CONTENT["AISTUDIO::DIALOGS::PROFILEDIALOG::T2386844536"] = "Please enter a profile name." + +-- The text must not exceed 256 characters. +UI_TEXT_CONTENT["AISTUDIO::DIALOGS::PROFILEDIALOG::T2560188276"] = "The text must not exceed 256 characters." + +-- Add +UI_TEXT_CONTENT["AISTUDIO::DIALOGS::PROFILEDIALOG::T2646845972"] = "Add" + +-- The profile name must not exceed 40 characters. +UI_TEXT_CONTENT["AISTUDIO::DIALOGS::PROFILEDIALOG::T3243902394"] = "The profile name must not exceed 40 characters." + +-- The text must not exceed 444 characters. +UI_TEXT_CONTENT["AISTUDIO::DIALOGS::PROFILEDIALOG::T3253349421"] = "The text must not exceed 444 characters." + +-- Profile Name +UI_TEXT_CONTENT["AISTUDIO::DIALOGS::PROFILEDIALOG::T3392578705"] = "Profile Name" + +-- Please enter what the LLM should know about you and/or what actions it should take. +UI_TEXT_CONTENT["AISTUDIO::DIALOGS::PROFILEDIALOG::T3708405102"] = "Please enter what the LLM should know about you and/or what actions it should take." + +-- The name of the profile is mandatory. Each profile must have a unique name. Whether you provide information about yourself or only fill out the actions is up to you. Only one of these pieces is required. +UI_TEXT_CONTENT["AISTUDIO::DIALOGS::PROFILEDIALOG::T4061896123"] = "The name of the profile is mandatory. Each profile must have a unique name. Whether you provide information about yourself or only fill out the actions is up to you. Only one of these pieces is required." + +-- Store personal data about yourself in various profiles so that the AIs know your personal context. This saves you from having to explain your context each time, for example, in every chat. When you have different roles, you can create a profile for each role. +UI_TEXT_CONTENT["AISTUDIO::DIALOGS::PROFILEDIALOG::T4125557797"] = "Store personal data about yourself in various profiles so that the AIs know your personal context. This saves you from having to explain your context each time, for example, in every chat. When you have different roles, you can create a profile for each role." + +-- What should the AI know about you? +UI_TEXT_CONTENT["AISTUDIO::DIALOGS::PROFILEDIALOG::T4227846635"] = "What should the AI know about you?" + +-- Are you a project manager in a research facility? You might want to create a profile for your project management activities, one for your scientific work, and a profile for when you need to write program code. In these profiles, you can record how much experience you have or which methods you like or dislike using. Later, you can choose when and where you want to use each profile. +UI_TEXT_CONTENT["AISTUDIO::DIALOGS::PROFILEDIALOG::T56359901"] = "Are you a project manager in a research facility? You might want to create a profile for your project management activities, one for your scientific work, and a profile for when you need to write program code. In these profiles, you can record how much experience you have or which methods you like or dislike using. Later, you can choose when and where you want to use each profile." + +-- Cancel +UI_TEXT_CONTENT["AISTUDIO::DIALOGS::PROFILEDIALOG::T900713019"] = "Cancel" + +-- The profile name must be unique; the chosen name is already in use. +UI_TEXT_CONTENT["AISTUDIO::DIALOGS::PROFILEDIALOG::T911748898"] = "The profile name must be unique; the chosen name is already in use." + +-- Hugging Face Inference Provider +UI_TEXT_CONTENT["AISTUDIO::DIALOGS::PROVIDERDIALOG::T1085481431"] = "Hugging Face Inference Provider" + +-- Failed to store the API key in the operating system. The message was: {0}. Please try again. +UI_TEXT_CONTENT["AISTUDIO::DIALOGS::PROVIDERDIALOG::T1122745046"] = "Failed to store the API key in the operating system. The message was: {0}. Please try again." + +-- API Key +UI_TEXT_CONTENT["AISTUDIO::DIALOGS::PROVIDERDIALOG::T1324664716"] = "API Key" + +-- Create account +UI_TEXT_CONTENT["AISTUDIO::DIALOGS::PROVIDERDIALOG::T1356621346"] = "Create account" + +-- Load models +UI_TEXT_CONTENT["AISTUDIO::DIALOGS::PROVIDERDIALOG::T15352225"] = "Load models" + +-- Hostname +UI_TEXT_CONTENT["AISTUDIO::DIALOGS::PROVIDERDIALOG::T1727440780"] = "Hostname" + +-- Update +UI_TEXT_CONTENT["AISTUDIO::DIALOGS::PROVIDERDIALOG::T1847791252"] = "Update" + +-- Failed to load the API key from the operating system. The message was: {0}. You might ignore this message and provide the API key again. +UI_TEXT_CONTENT["AISTUDIO::DIALOGS::PROVIDERDIALOG::T1870831108"] = "Failed to load the API key from the operating system. The message was: {0}. You might ignore this message and provide the API key again." + +-- Please enter a model name. +UI_TEXT_CONTENT["AISTUDIO::DIALOGS::PROVIDERDIALOG::T1936099896"] = "Please enter a model name." + +-- Model +UI_TEXT_CONTENT["AISTUDIO::DIALOGS::PROVIDERDIALOG::T2189814010"] = "Model" + +-- (Optional) API Key +UI_TEXT_CONTENT["AISTUDIO::DIALOGS::PROVIDERDIALOG::T2331453405"] = "(Optional) API Key" + +-- Add +UI_TEXT_CONTENT["AISTUDIO::DIALOGS::PROVIDERDIALOG::T2646845972"] = "Add" + +-- No models loaded or available. +UI_TEXT_CONTENT["AISTUDIO::DIALOGS::PROVIDERDIALOG::T2810182573"] = "No models loaded or available." + +-- Instance Name +UI_TEXT_CONTENT["AISTUDIO::DIALOGS::PROVIDERDIALOG::T2842060373"] = "Instance Name" + +-- Show available models +UI_TEXT_CONTENT["AISTUDIO::DIALOGS::PROVIDERDIALOG::T3763891899"] = "Show available models" + +-- Host +UI_TEXT_CONTENT["AISTUDIO::DIALOGS::PROVIDERDIALOG::T808120719"] = "Host" + +-- Provider +UI_TEXT_CONTENT["AISTUDIO::DIALOGS::PROVIDERDIALOG::T900237532"] = "Provider" + +-- Cancel +UI_TEXT_CONTENT["AISTUDIO::DIALOGS::PROVIDERDIALOG::T900713019"] = "Cancel" + -- There is no social event UI_TEXT_CONTENT["AISTUDIO::DIALOGS::SETTINGS::SETTINGSDIALOGAGENDA::T1222800281"] = "There is no social event" @@ -1270,6 +1468,9 @@ UI_TEXT_CONTENT["AISTUDIO::DIALOGS::SETTINGS::SETTINGSDIALOGDATASOURCES::T145419 -- Delete UI_TEXT_CONTENT["AISTUDIO::DIALOGS::SETTINGS::SETTINGSDIALOGDATASOURCES::T1469573738"] = "Delete" +-- External (ERI) +UI_TEXT_CONTENT["AISTUDIO::DIALOGS::SETTINGS::SETTINGSDIALOGDATASOURCES::T1652430727"] = "External (ERI)" + -- Local File UI_TEXT_CONTENT["AISTUDIO::DIALOGS::SETTINGS::SETTINGSDIALOGDATASOURCES::T1687345358"] = "Local File" @@ -1291,6 +1492,9 @@ UI_TEXT_CONTENT["AISTUDIO::DIALOGS::SETTINGS::SETTINGSDIALOGDATASOURCES::T262437 -- Name UI_TEXT_CONTENT["AISTUDIO::DIALOGS::SETTINGS::SETTINGSDIALOGDATASOURCES::T266367750"] = "Name" +-- No valid embedding +UI_TEXT_CONTENT["AISTUDIO::DIALOGS::SETTINGS::SETTINGSDIALOGDATASOURCES::T2698203405"] = "No valid embedding" + -- Embedding UI_TEXT_CONTENT["AISTUDIO::DIALOGS::SETTINGS::SETTINGSDIALOGDATASOURCES::T2838542994"] = "Embedding" @@ -1684,6 +1888,9 @@ UI_TEXT_CONTENT["AISTUDIO::DIALOGS::SETTINGS::SETTINGSDIALOGTRANSLATION::T103037 -- When enabled, you can preselect the translator options. This is might be useful when you prefer a specific target language or LLM model. UI_TEXT_CONTENT["AISTUDIO::DIALOGS::SETTINGS::SETTINGSDIALOGTRANSLATION::T1111006275"] = "When enabled, you can preselect the translator options. This is might be useful when you prefer a specific target language or LLM model." +-- milliseconds +UI_TEXT_CONTENT["AISTUDIO::DIALOGS::SETTINGS::SETTINGSDIALOGTRANSLATION::T1275514075"] = "milliseconds" + -- Preselect the target language UI_TEXT_CONTENT["AISTUDIO::DIALOGS::SETTINGS::SETTINGSDIALOGTRANSLATION::T1417990312"] = "Preselect the target language" @@ -1792,6 +1999,24 @@ UI_TEXT_CONTENT["AISTUDIO::DIALOGS::SETTINGS::SETTINGSDIALOGWRITINGEMAILS::T3832 -- Preselect one of your profiles? UI_TEXT_CONTENT["AISTUDIO::DIALOGS::SETTINGS::SETTINGSDIALOGWRITINGEMAILS::T4004501229"] = "Preselect one of your profiles?" +-- Chat name +UI_TEXT_CONTENT["AISTUDIO::DIALOGS::SINGLEINPUTDIALOG::T1746586282"] = "Chat name" + +-- Cancel +UI_TEXT_CONTENT["AISTUDIO::DIALOGS::SINGLEINPUTDIALOG::T900713019"] = "Cancel" + +-- Install now +UI_TEXT_CONTENT["AISTUDIO::DIALOGS::UPDATEDIALOG::T2366359512"] = "Install now" + +-- Update from v{0} to v{1} +UI_TEXT_CONTENT["AISTUDIO::DIALOGS::UPDATEDIALOG::T25417398"] = "Update from v{0} to v{1}" + +-- Install later +UI_TEXT_CONTENT["AISTUDIO::DIALOGS::UPDATEDIALOG::T2936430090"] = "Install later" + +-- Cancel +UI_TEXT_CONTENT["AISTUDIO::DIALOGS::WORKSPACESELECTIONDIALOG::T900713019"] = "Cancel" + -- Settings UI_TEXT_CONTENT["AISTUDIO::LAYOUT::MAINLAYOUT::T1258653480"] = "Settings" @@ -1993,9 +2218,21 @@ UI_TEXT_CONTENT["AISTUDIO::PAGES::ABOUT::T870640199"] = "For some data transfers -- Get coding and debugging support from an LLM. UI_TEXT_CONTENT["AISTUDIO::PAGES::ASSISTANTS::T1243850917"] = "Get coding and debugging support from an LLM." +-- Business +UI_TEXT_CONTENT["AISTUDIO::PAGES::ASSISTANTS::T131837803"] = "Business" + -- Legal Check UI_TEXT_CONTENT["AISTUDIO::PAGES::ASSISTANTS::T1348190638"] = "Legal Check" +-- General +UI_TEXT_CONTENT["AISTUDIO::PAGES::ASSISTANTS::T1432485131"] = "General" + +-- Grammar & Spelling +UI_TEXT_CONTENT["AISTUDIO::PAGES::ASSISTANTS::T1514925962"] = "Grammar & Spelling" + +-- Assistants +UI_TEXT_CONTENT["AISTUDIO::PAGES::ASSISTANTS::T1614176092"] = "Assistants" + -- Coding UI_TEXT_CONTENT["AISTUDIO::PAGES::ASSISTANTS::T1617786407"] = "Coding" @@ -2026,15 +2263,27 @@ UI_TEXT_CONTENT["AISTUDIO::PAGES::ASSISTANTS::T2547582747"] = "Synonyms" -- Find synonyms for a given word or phrase. UI_TEXT_CONTENT["AISTUDIO::PAGES::ASSISTANTS::T2712131461"] = "Find synonyms for a given word or phrase." +-- AI Studio Development +UI_TEXT_CONTENT["AISTUDIO::PAGES::ASSISTANTS::T2830810750"] = "AI Studio Development" + -- Generate a job posting for a given job description. UI_TEXT_CONTENT["AISTUDIO::PAGES::ASSISTANTS::T2831103254"] = "Generate a job posting for a given job description." -- My Tasks UI_TEXT_CONTENT["AISTUDIO::PAGES::ASSISTANTS::T3011450657"] = "My Tasks" +-- E-Mail +UI_TEXT_CONTENT["AISTUDIO::PAGES::ASSISTANTS::T3026443472"] = "E-Mail" + -- Translate AI Studio text content into other languages UI_TEXT_CONTENT["AISTUDIO::PAGES::ASSISTANTS::T3181803840"] = "Translate AI Studio text content into other languages" +-- Software Engineering +UI_TEXT_CONTENT["AISTUDIO::PAGES::ASSISTANTS::T3260960011"] = "Software Engineering" + +-- Rewrite & Improve +UI_TEXT_CONTENT["AISTUDIO::PAGES::ASSISTANTS::T3309133329"] = "Rewrite & Improve" + -- Icon Finder UI_TEXT_CONTENT["AISTUDIO::PAGES::ASSISTANTS::T3693102312"] = "Icon Finder" @@ -2062,6 +2311,9 @@ UI_TEXT_CONTENT["AISTUDIO::PAGES::ASSISTANTS::T613888204"] = "Translation" -- Rewrite and improve a given text for a chosen style. UI_TEXT_CONTENT["AISTUDIO::PAGES::ASSISTANTS::T722167136"] = "Rewrite and improve a given text for a chosen style." +-- Learning +UI_TEXT_CONTENT["AISTUDIO::PAGES::ASSISTANTS::T755590027"] = "Learning" + -- Bias of the Day UI_TEXT_CONTENT["AISTUDIO::PAGES::ASSISTANTS::T782102948"] = "Bias of the Day" @@ -2083,6 +2335,9 @@ UI_TEXT_CONTENT["AISTUDIO::PAGES::CHAT::T3745240468"] = "Your workspaces" -- Chat in Workspace UI_TEXT_CONTENT["AISTUDIO::PAGES::CHAT::T582100343"] = "Chat in Workspace" +-- Show your workspaces +UI_TEXT_CONTENT["AISTUDIO::PAGES::CHAT::T733672375"] = "Show your workspaces" + -- Unlike services like ChatGPT, which impose limits after intensive use, MindWork AI Studio offers unlimited usage through the providers API. UI_TEXT_CONTENT["AISTUDIO::PAGES::HOME::T1009708591"] = "Unlike services like ChatGPT, which impose limits after intensive use, MindWork AI Studio offers unlimited usage through the providers API." @@ -2104,6 +2359,9 @@ UI_TEXT_CONTENT["AISTUDIO::PAGES::HOME::T1614176092"] = "Assistants" -- Unrestricted usage UI_TEXT_CONTENT["AISTUDIO::PAGES::HOME::T1686815996"] = "Unrestricted usage" +-- Introduction +UI_TEXT_CONTENT["AISTUDIO::PAGES::HOME::T1702902297"] = "Introduction" + -- Vision UI_TEXT_CONTENT["AISTUDIO::PAGES::HOME::T1892426825"] = "Vision" @@ -2197,6 +2455,9 @@ UI_TEXT_CONTENT["AISTUDIO::PAGES::SUPPORTERS::T2410456125"] = "The first 10 supp -- Supporters UI_TEXT_CONTENT["AISTUDIO::PAGES::SUPPORTERS::T2929332068"] = "Supporters" +-- Content Contributors +UI_TEXT_CONTENT["AISTUDIO::PAGES::SUPPORTERS::T3060804484"] = "Content Contributors" + -- Financial Support UI_TEXT_CONTENT["AISTUDIO::PAGES::SUPPORTERS::T3061261435"] = "Financial Support" diff --git a/app/MindWork AI Studio/Components/ChatComponent.razor b/app/MindWork AI Studio/Components/ChatComponent.razor index fbcf1828..8973f9ac 100644 --- a/app/MindWork AI Studio/Components/ChatComponent.razor +++ b/app/MindWork AI Studio/Components/ChatComponent.razor @@ -58,19 +58,19 @@ this.SettingsManager.ConfigurationData.Workspace.StorageBehavior is not WorkspaceStorageBehavior.DISABLE_WORKSPACES && this.SettingsManager.ConfigurationData.Workspace.DisplayBehavior is WorkspaceDisplayBehavior.TOGGLE_OVERLAY) { - + } @if (this.SettingsManager.ConfigurationData.Workspace.StorageBehavior is WorkspaceStorageBehavior.STORE_CHATS_MANUALLY) { - + } - + @@ -102,7 +102,7 @@ @if (this.isStreaming && this.cancellationTokenSource is not null) { - + } diff --git a/app/MindWork AI Studio/Components/DataSourceSelection.razor b/app/MindWork AI Studio/Components/DataSourceSelection.razor index f99aa6fa..389e234f 100644 --- a/app/MindWork AI Studio/Components/DataSourceSelection.razor +++ b/app/MindWork AI Studio/Components/DataSourceSelection.razor @@ -1,9 +1,9 @@ @using AIStudio.Settings - +@inherits MSGComponentBase @if (this.SelectionMode is DataSourceSelectionMode.SELECTION_MODE) {
- + @if (this.PopoverTriggerMode is PopoverTriggerMode.ICON) { @@ -11,7 +11,7 @@ else { - Select data + @T("Select data") } @@ -22,9 +22,11 @@ - Data Source Selection + + @T("Data Source Selection") + - + @@ -40,57 +42,52 @@ else if (this.SettingsManager.ConfigurationData.DataSources.Count == 0) { - You haven't configured any data sources. To grant the AI access to your data, you need to - add such a source. However, if you wish to use data from your device, you first have to set up - a so-called embedding. This embedding is necessary so the AI can effectively search your data, - find and retrieve the correct information required for each task. In addition to local data, - you can also incorporate your company's data. To do so, your company must provide the data through - an ERI (External Retrieval Interface). + @T("You haven't configured any data sources. To grant the AI access to your data, you need to add such a source. However, if you wish to use data from your device, you first have to set up a so-called embedding. This embedding is necessary so the AI can effectively search your data, find and retrieve the correct information required for each task. In addition to local data, you can also incorporate your company's data. To do so, your company must provide the data through an ERI (External Retrieval Interface).") - Manage Data Sources + @T("Manage Data Sources") - Read more about ERI + @T("Read more about ERI") } else if (this.showDataSourceSelection) { - + @if (this.areDataSourcesEnabled) { - + @if (this.SettingsManager.ConfigurationData.AgentRetrievalContextValidation.EnableRetrievalContextValidation) { - + } @switch (this.aiBasedSourceSelection) { case true when this.availableDataSources.Count == 0: - Your data sources cannot be used with the LLM provider you selected due to data privacy, or they are currently unavailable. + @T("Your data sources cannot be used with the LLM provider you selected due to data privacy, or they are currently unavailable.") break; case true when this.DataSourcesAISelected.Count == 0: - The AI evaluates each of your inputs to determine whether and which data sources are necessary. Currently, the AI has not selected any source. + @T("The AI evaluates each of your inputs to determine whether and which data sources are necessary. Currently, the AI has not selected any source.") break; case false when this.availableDataSources.Count == 0: - Your data sources cannot be used with the LLM provider you selected due to data privacy, or they are currently unavailable. + @T("Your data sources cannot be used with the LLM provider you selected due to data privacy, or they are currently unavailable.") break; case false: - + @foreach (var source in this.availableDataSources) { @@ -104,7 +101,7 @@ case true: - + @foreach (var source in this.availableDataSources) { @@ -114,7 +111,7 @@ } - + @foreach (var source in this.DataSourcesAISelected) { @@ -141,7 +138,7 @@ - Close + @T("Close") @@ -152,7 +149,9 @@ else if (this.SelectionMode is DataSourceSelectionMode.CONFIGURATION_MODE) { - Data Source Selection + + @T("Data Source Selection") + @if (!string.IsNullOrWhiteSpace(this.ConfigurationHeaderMessage)) { @@ -161,12 +160,12 @@ else if (this.SelectionMode is DataSourceSelectionMode.CONFIGURATION_MODE) } - + @if (this.areDataSourcesEnabled) { - - - + + + @foreach (var source in this.availableDataSources) { diff --git a/app/MindWork AI Studio/Components/DataSourceSelection.razor.cs b/app/MindWork AI Studio/Components/DataSourceSelection.razor.cs index 22d4b0cb..5715d52f 100644 --- a/app/MindWork AI Studio/Components/DataSourceSelection.razor.cs +++ b/app/MindWork AI Studio/Components/DataSourceSelection.razor.cs @@ -9,7 +9,7 @@ using DialogOptions = AIStudio.Dialogs.DialogOptions; namespace AIStudio.Components; -public partial class DataSourceSelection : ComponentBase, IMessageBusReceiver, IDisposable +public partial class DataSourceSelection : MSGComponentBase { [Parameter] public DataSourceSelectionMode SelectionMode { get; set; } = DataSourceSelectionMode.SELECTION_MODE; @@ -38,12 +38,6 @@ public partial class DataSourceSelection : ComponentBase, IMessageBusReceiver, I [Parameter] public bool AutoSaveAppSettings { get; set; } - [Inject] - private SettingsManager SettingsManager { get; init; } = null!; - - [Inject] - private MessageBus MessageBus { get; init; } = null!; - [Inject] private DataSourceService DataSourceService { get; init; } = null!; @@ -63,8 +57,7 @@ public partial class DataSourceSelection : ComponentBase, IMessageBusReceiver, I protected override async Task OnInitializedAsync() { - this.MessageBus.RegisterComponent(this); - this.MessageBus.ApplyFilters(this, [], [ Event.COLOR_THEME_CHANGED, Event.RAG_AUTO_DATA_SOURCES_SELECTED ]); + this.ApplyFilters([], [ Event.RAG_AUTO_DATA_SOURCES_SELECTED ]); // // Load the settings: @@ -253,19 +246,12 @@ public partial class DataSourceSelection : ComponentBase, IMessageBusReceiver, I private void HideDataSourceSelection() => this.showDataSourceSelection = false; - #region Implementation of IMessageBusReceiver + #region Overrides of MSGComponentBase - public string ComponentName => nameof(ConfidenceInfo); - - public Task ProcessMessage(ComponentBase? sendingComponent, Event triggeredEvent, T? data) + protected override Task ProcessIncomingMessage(ComponentBase? sendingComponent, Event triggeredEvent, T? data) where T : default { switch (triggeredEvent) { - case Event.COLOR_THEME_CHANGED: - this.showDataSourceSelection = false; - this.StateHasChanged(); - break; - case Event.RAG_AUTO_DATA_SOURCES_SELECTED: if(data is IReadOnlyList aiSelectedDataSources) this.DataSourcesAISelected = aiSelectedDataSources; @@ -273,23 +259,9 @@ public partial class DataSourceSelection : ComponentBase, IMessageBusReceiver, I this.StateHasChanged(); break; } - + return Task.CompletedTask; } - public Task ProcessMessageWithResult(ComponentBase? sendingComponent, Event triggeredEvent, TPayload? data) - { - return Task.FromResult(default); - } - - #endregion - - #region Implementation of IDisposable - - public void Dispose() - { - this.MessageBus.Unregister(this); - } - #endregion } \ No newline at end of file diff --git a/app/MindWork AI Studio/Components/MSGComponentBase.cs b/app/MindWork AI Studio/Components/MSGComponentBase.cs index ad211203..739f6c68 100644 --- a/app/MindWork AI Studio/Components/MSGComponentBase.cs +++ b/app/MindWork AI Studio/Components/MSGComponentBase.cs @@ -35,6 +35,9 @@ public abstract class MSGComponentBase : ComponentBase, IDisposable, IMessageBus /// public string T(string fallbackEN) => this.GetText(this.Lang, fallbackEN); + + /// + public string T(string fallbackEN, string? typeNamespace, string? typeName) => this.GetText(this.Lang, fallbackEN, typeNamespace, typeName); #endregion @@ -73,20 +76,6 @@ public abstract class MSGComponentBase : ComponentBase, IDisposable, IMessageBus { return Task.FromResult(default); } - - protected virtual void DisposeResources() - { - } - - #region Implementation of IDisposable - - public void Dispose() - { - this.MessageBus.Unregister(this); - this.DisposeResources(); - } - - #endregion protected async Task SendMessage(Event triggeredEvent, T? data = default) { @@ -114,4 +103,18 @@ public abstract class MSGComponentBase : ComponentBase, IDisposable, IMessageBus this.MessageBus.ApplyFilters(this, filterComponents, eventsList.ToArray()); } + + protected virtual void DisposeResources() + { + } + + #region Implementation of IDisposable + + public void Dispose() + { + this.MessageBus.Unregister(this); + this.DisposeResources(); + } + + #endregion } \ No newline at end of file diff --git a/app/MindWork AI Studio/Components/MudTextList.razor b/app/MindWork AI Studio/Components/MudTextList.razor index f0ec6295..0b4a3fa3 100644 --- a/app/MindWork AI Studio/Components/MudTextList.razor +++ b/app/MindWork AI Studio/Components/MudTextList.razor @@ -2,7 +2,9 @@ @foreach(var item in this.Items) { - @item.Header: @item.Text + + @item.Header: @item.Text + } \ No newline at end of file diff --git a/app/MindWork AI Studio/Components/Vision.razor.cs b/app/MindWork AI Studio/Components/Vision.razor.cs index 73750d4a..b81c084a 100644 --- a/app/MindWork AI Studio/Components/Vision.razor.cs +++ b/app/MindWork AI Studio/Components/Vision.razor.cs @@ -1,10 +1,20 @@ +using Microsoft.AspNetCore.Components; + namespace AIStudio.Components; public partial class Vision : MSGComponentBase { - private readonly TextItem[] itemsVision; + private TextItem[] itemsVision = []; - public Vision() + #region Overrides of MSGComponentBase + + protected override async Task OnInitializedAsync() + { + await base.OnInitializedAsync(); + this.InitializeVisionItems(); + } + + private void InitializeVisionItems() { this.itemsVision = [ @@ -20,4 +30,17 @@ public partial class Vision : MSGComponentBase new(T("Browser usage"), T("We're working on offering AI Studio features in your browser via a plugin, allowing, e.g., for spell-checking or text rewriting directly in the browser.")), ]; } + + protected override async Task ProcessIncomingMessage(ComponentBase? sendingComponent, Event triggeredEvent, T? data) where T : default + { + switch (triggeredEvent) + { + case Event.PLUGINS_RELOADED: + this.InitializeVisionItems(); + await this.InvokeAsync(this.StateHasChanged); + break; + } + } + + #endregion } \ No newline at end of file diff --git a/app/MindWork AI Studio/Components/Workspaces.razor.cs b/app/MindWork AI Studio/Components/Workspaces.razor.cs index bcf95425..59e43144 100644 --- a/app/MindWork AI Studio/Components/Workspaces.razor.cs +++ b/app/MindWork AI Studio/Components/Workspaces.razor.cs @@ -39,6 +39,8 @@ public partial class Workspaces : MSGComponentBase protected override async Task OnInitializedAsync() { + await base.OnInitializedAsync(); + // // Notice: In order to get the server-based loading to work, we need to respect the following rules: // - We must have initial tree items @@ -46,7 +48,6 @@ public partial class Workspaces : MSGComponentBase // - When assigning the tree items to the MudTreeViewItem component, we must set the Value property to the value of the item // await this.LoadTreeItems(); - await base.OnInitializedAsync(); } #endregion @@ -504,4 +505,19 @@ public partial class Workspaces : MSGComponentBase await this.LoadChat(chatPath, switchToChat: true); await this.LoadTreeItems(); } + + #region Overrides of MSGComponentBase + + protected override async Task ProcessIncomingMessage(ComponentBase? sendingComponent, Event triggeredEvent, T? data) where T : default + { + switch (triggeredEvent) + { + case Event.PLUGINS_RELOADED: + await this.LoadTreeItems(); + await this.InvokeAsync(this.StateHasChanged); + break; + } + } + + #endregion } \ No newline at end of file diff --git a/app/MindWork AI Studio/Dialogs/ConfirmDialog.razor b/app/MindWork AI Studio/Dialogs/ConfirmDialog.razor index 3f757260..455ac41b 100644 --- a/app/MindWork AI Studio/Dialogs/ConfirmDialog.razor +++ b/app/MindWork AI Studio/Dialogs/ConfirmDialog.razor @@ -1,9 +1,16 @@ +@inherits MSGComponentBase - @this.Message + + @this.Message + - No - Yes + + @T("No") + + + @T("Yes") + \ No newline at end of file diff --git a/app/MindWork AI Studio/Dialogs/ConfirmDialog.razor.cs b/app/MindWork AI Studio/Dialogs/ConfirmDialog.razor.cs index 78fb9ad3..f022152e 100644 --- a/app/MindWork AI Studio/Dialogs/ConfirmDialog.razor.cs +++ b/app/MindWork AI Studio/Dialogs/ConfirmDialog.razor.cs @@ -1,3 +1,5 @@ +using AIStudio.Components; + using Microsoft.AspNetCore.Components; namespace AIStudio.Dialogs; @@ -5,7 +7,7 @@ namespace AIStudio.Dialogs; /// /// A confirmation dialog that can be used to ask the user for confirmation. /// -public partial class ConfirmDialog : ComponentBase +public partial class ConfirmDialog : MSGComponentBase { [CascadingParameter] private IMudDialogInstance MudDialog { get; set; } = null!; diff --git a/app/MindWork AI Studio/Dialogs/ProfileDialog.razor b/app/MindWork AI Studio/Dialogs/ProfileDialog.razor index fb44439a..b7440a40 100644 --- a/app/MindWork AI Studio/Dialogs/ProfileDialog.razor +++ b/app/MindWork AI Studio/Dialogs/ProfileDialog.razor @@ -1,29 +1,23 @@ +@inherits MSGComponentBase - Store personal data about yourself in various profiles so that the AIs know your personal context. - This saves you from having to explain your context each time, for example, in every chat. When you - have different roles, you can create a profile for each role. + @T("Store personal data about yourself in various profiles so that the AIs know your personal context. This saves you from having to explain your context each time, for example, in every chat. When you have different roles, you can create a profile for each role.") - Are you a project manager in a research facility? You might want to create a profile for your project - management activities, one for your scientific work, and a profile for when you need to write program - code. In these profiles, you can record how much experience you have or which methods you like or - dislike using. Later, you can choose when and where you want to use each profile. + @T("Are you a project manager in a research facility? You might want to create a profile for your project management activities, one for your scientific work, and a profile for when you need to write program code. In these profiles, you can record how much experience you have or which methods you like or dislike using. Later, you can choose when and where you want to use each profile.") - The name of the profile is mandatory. Each profile must have a unique name. Whether you provide - information about yourself or only fill out the actions is up to you. Only one of these pieces - is required. + @T("The name of the profile is mandatory. Each profile must have a unique name. Whether you provide information about yourself or only fill out the actions is up to you. Only one of these pieces is required.") @* ReSharper disable once CSharpWarnings::CS8974 *@ - Cancel + + @T("Cancel") + @if(this.IsEditing) { - @:Update + @T("Update") } else { - @:Add + @T("Add") } diff --git a/app/MindWork AI Studio/Dialogs/ProfileDialog.razor.cs b/app/MindWork AI Studio/Dialogs/ProfileDialog.razor.cs index 28b9b4b1..0b2a65a0 100644 --- a/app/MindWork AI Studio/Dialogs/ProfileDialog.razor.cs +++ b/app/MindWork AI Studio/Dialogs/ProfileDialog.razor.cs @@ -1,10 +1,11 @@ +using AIStudio.Components; using AIStudio.Settings; using Microsoft.AspNetCore.Components; namespace AIStudio.Dialogs; -public partial class ProfileDialog : ComponentBase +public partial class ProfileDialog : MSGComponentBase { [CascadingParameter] private IMudDialogInstance MudDialog { get; set; } = null!; @@ -45,9 +46,6 @@ public partial class ProfileDialog : ComponentBase [Parameter] public bool IsEditing { get; init; } - [Inject] - private SettingsManager SettingsManager { get; init; } = null!; - [Inject] private ILogger Logger { get; init; } = null!; @@ -129,10 +127,10 @@ public partial class ProfileDialog : ComponentBase private string? ValidateNeedToKnow(string text) { if (string.IsNullOrWhiteSpace(this.DataNeedToKnow) && string.IsNullOrWhiteSpace(this.DataActions)) - return "Please enter what the LLM should know about you and/or what actions it should take."; + return T("Please enter what the LLM should know about you and/or what actions it should take."); if(text.Length > 444) - return "The text must not exceed 444 characters."; + return T("The text must not exceed 444 characters."); return null; } @@ -140,10 +138,10 @@ public partial class ProfileDialog : ComponentBase private string? ValidateActions(string text) { if (string.IsNullOrWhiteSpace(this.DataNeedToKnow) && string.IsNullOrWhiteSpace(this.DataActions)) - return "Please enter what the LLM should know about you and/or what actions it should take."; + return T("Please enter what the LLM should know about you and/or what actions it should take."); if(text.Length > 256) - return "The text must not exceed 256 characters."; + return T("The text must not exceed 256 characters."); return null; } @@ -151,15 +149,15 @@ public partial class ProfileDialog : ComponentBase private string? ValidateName(string name) { if (string.IsNullOrWhiteSpace(name)) - return "Please enter a profile name."; + return T("Please enter a profile name."); if (name.Length > 40) - return "The profile name must not exceed 40 characters."; + return T("The profile name must not exceed 40 characters."); // The instance name must be unique: var lowerName = name.ToLowerInvariant(); if (lowerName != this.dataEditingPreviousName && this.UsedNames.Contains(lowerName)) - return "The profile name must be unique; the chosen name is already in use."; + return T("The profile name must be unique; the chosen name is already in use."); return null; } diff --git a/app/MindWork AI Studio/Dialogs/ProviderDialog.razor b/app/MindWork AI Studio/Dialogs/ProviderDialog.razor index 6e28d6fe..4b45637a 100644 --- a/app/MindWork AI Studio/Dialogs/ProviderDialog.razor +++ b/app/MindWork AI Studio/Dialogs/ProviderDialog.razor @@ -1,13 +1,13 @@ @using AIStudio.Provider @using AIStudio.Provider.HuggingFace @using AIStudio.Provider.SelfHosted - +@inherits MSGComponentBase @* ReSharper disable once CSharpWarnings::CS8974 *@ - + @foreach (LLMProviders provider in Enum.GetValues(typeof(LLMProviders))) { @@ -15,7 +15,9 @@ } - Create account + + @T("Create account") + @if (this.DataLLMProvider.IsAPIKeyNeeded(this.DataHost)) @@ -39,7 +41,7 @@ + @foreach (Host host in Enum.GetValues(typeof(Host))) { @@ -62,7 +64,7 @@ @if (this.DataLLMProvider.IsHFInstanceProviderNeeded()) { - + @foreach (HFInferenceProvider inferenceProvider in Enum.GetValues(typeof(HFInferenceProvider))) { @@ -71,7 +73,9 @@ } @* ReSharper disable Asp.Entity *@ - Please double-check if your model name matches the curl specifications provided by the inference provider. If it doesn't, you might get a Not Found error when trying to use the model. Here's a curl example. + + Please double-check if your model name matches the curl specifications provided by the inference provider. If it doesn't, you might get a Not Found error when trying to use the model. Here's a curl example. + @* ReSharper restore Asp.Entity *@ } @@ -80,12 +84,12 @@ @if (this.DataLLMProvider.IsLLMModelProvidedManually()) { - Show available models + @T("Show available models") - Load models + @T("Load models") @if(this.availableModels.Count is 0) { - No models loaded or available. + @T("No models loaded or available.") } else @@ -111,7 +115,9 @@ Adornment="Adornment.Start" Validation="@this.providerValidation.ValidatingModel"> @foreach (var model in this.availableModels) { - @model + + @model + } } @@ -123,7 +129,7 @@ - Cancel + + @T("Cancel") + @if(this.IsEditing) { - @:Update + @T("Update") } else { - @:Add + @T("Add") } diff --git a/app/MindWork AI Studio/Dialogs/ProviderDialog.razor.cs b/app/MindWork AI Studio/Dialogs/ProviderDialog.razor.cs index 5be79fa3..562e424e 100644 --- a/app/MindWork AI Studio/Dialogs/ProviderDialog.razor.cs +++ b/app/MindWork AI Studio/Dialogs/ProviderDialog.razor.cs @@ -1,6 +1,6 @@ +using AIStudio.Components; using AIStudio.Provider; using AIStudio.Provider.HuggingFace; -using AIStudio.Settings; using AIStudio.Tools.Services; using AIStudio.Tools.Validation; @@ -13,7 +13,7 @@ namespace AIStudio.Dialogs; /// /// The provider settings dialog. /// -public partial class ProviderDialog : ComponentBase, ISecretId +public partial class ProviderDialog : MSGComponentBase, ISecretId { [CascadingParameter] private IMudDialogInstance MudDialog { get; set; } = null!; @@ -78,9 +78,6 @@ public partial class ProviderDialog : ComponentBase, ISecretId [Parameter] public bool IsEditing { get; init; } - [Inject] - private SettingsManager SettingsManager { get; init; } = null!; - [Inject] private ILogger Logger { get; init; } = null!; @@ -182,7 +179,7 @@ public partial class ProviderDialog : ComponentBase, ISecretId this.dataAPIKey = string.Empty; if (this.DataLLMProvider is not LLMProviders.SELF_HOSTED) { - this.dataAPIKeyStorageIssue = $"Failed to load the API key from the operating system. The message was: {requestedSecret.Issue}. You might ignore this message and provide the API key again."; + this.dataAPIKeyStorageIssue = string.Format(T("Failed to load the API key from the operating system. The message was: {0}. You might ignore this message and provide the API key again."), requestedSecret.Issue); await this.form.Validate(); } } @@ -232,7 +229,7 @@ public partial class ProviderDialog : ComponentBase, ISecretId var storeResponse = await this.RustService.SetAPIKey(this, this.dataAPIKey); if (!storeResponse.Success) { - this.dataAPIKeyStorageIssue = $"Failed to store the API key in the operating system. The message was: {storeResponse.Issue}. Please try again."; + this.dataAPIKeyStorageIssue = string.Format(T("Failed to store the API key in the operating system. The message was: {0}. Please try again."), storeResponse.Issue); await this.form.Validate(); return; } @@ -244,7 +241,7 @@ public partial class ProviderDialog : ComponentBase, ISecretId private string? ValidateManuallyModel(string manuallyModel) { if ((this.DataLLMProvider is LLMProviders.FIREWORKS or LLMProviders.HUGGINGFACE) && string.IsNullOrWhiteSpace(manuallyModel)) - return "Please enter a model name."; + return T("Please enter a model name."); return null; } @@ -269,7 +266,7 @@ public partial class ProviderDialog : ComponentBase, ISecretId private string APIKeyText => this.DataLLMProvider switch { - LLMProviders.SELF_HOSTED => "(Optional) API Key", - _ => "API Key", + LLMProviders.SELF_HOSTED => T("(Optional) API Key"), + _ => T("API Key"), }; } \ No newline at end of file diff --git a/app/MindWork AI Studio/Dialogs/Settings/SettingsDialogBase.cs b/app/MindWork AI Studio/Dialogs/Settings/SettingsDialogBase.cs index 7fa14518..1dd94c1c 100644 --- a/app/MindWork AI Studio/Dialogs/Settings/SettingsDialogBase.cs +++ b/app/MindWork AI Studio/Dialogs/Settings/SettingsDialogBase.cs @@ -27,11 +27,13 @@ public abstract class SettingsDialogBase : MSGComponentBase /// protected override async Task OnInitializedAsync() { + await base.OnInitializedAsync(); + this.MudDialog.StateHasChanged(); + this.ApplyFilters([], [ Event.CONFIGURATION_CHANGED ]); this.UpdateProviders(); this.UpdateEmbeddingProviders(); - await base.OnInitializedAsync(); } #endregion diff --git a/app/MindWork AI Studio/Dialogs/Settings/SettingsDialogDataSources.razor.cs b/app/MindWork AI Studio/Dialogs/Settings/SettingsDialogDataSources.razor.cs index b35ce8f7..2c2eff67 100644 --- a/app/MindWork AI Studio/Dialogs/Settings/SettingsDialogDataSources.razor.cs +++ b/app/MindWork AI Studio/Dialogs/Settings/SettingsDialogDataSources.razor.cs @@ -12,13 +12,13 @@ public partial class SettingsDialogDataSources : SettingsDialogBase { var matchedEmbedding = this.SettingsManager.ConfigurationData.EmbeddingProviders.FirstOrDefault(x => x.Id == internalDataSource.EmbeddingId); if(matchedEmbedding == default) - return "T(No valid embedding)"; + return T("No valid embedding"); return matchedEmbedding.Name; } if(dataSource is IExternalDataSource) - return "T(External (ERI))"; + return T("External (ERI)"); return T("Unknown"); } diff --git a/app/MindWork AI Studio/Dialogs/Settings/SettingsDialogTranslation.razor b/app/MindWork AI Studio/Dialogs/Settings/SettingsDialogTranslation.razor index 259ddc52..f3db4a3c 100644 --- a/app/MindWork AI Studio/Dialogs/Settings/SettingsDialogTranslation.razor +++ b/app/MindWork AI Studio/Dialogs/Settings/SettingsDialogTranslation.razor @@ -8,7 +8,7 @@ - +