From f66428b41efb000019c9babbea07ab17fb17cfaa Mon Sep 17 00:00:00 2001 From: Thorsten Sommer Date: Sun, 11 May 2025 16:55:47 +0200 Subject: [PATCH] Add localization for embedding configuration and dialogs --- .../Assistants/I18N/allTexts.lua | 108 ++++++++++++++++++ .../Settings/SettingsPanelEmbeddings.razor | 35 +++--- .../Settings/SettingsPanelEmbeddings.razor.cs | 8 +- .../Dialogs/EmbeddingProviderDialog.razor | 89 +++++++++------ .../Dialogs/EmbeddingProviderDialog.razor.cs | 16 ++- app/MindWork AI Studio/Provider/Model.cs | 6 +- .../wwwroot/changelog/v0.9.43.md | 1 + 7 files changed, 196 insertions(+), 67 deletions(-) diff --git a/app/MindWork AI Studio/Assistants/I18N/allTexts.lua b/app/MindWork AI Studio/Assistants/I18N/allTexts.lua index 12f3cc94..603c93ef 100644 --- a/app/MindWork AI Studio/Assistants/I18N/allTexts.lua +++ b/app/MindWork AI Studio/Assistants/I18N/allTexts.lua @@ -1120,6 +1120,57 @@ UI_TEXT_CONTENT["AISTUDIO::COMPONENTS::SETTINGS::SETTINGSPANELCHAT::T492357592"] -- When enabled, the latest message is shown after loading a chat. When disabled, the first (oldest) message is shown. UI_TEXT_CONTENT["AISTUDIO::COMPONENTS::SETTINGS::SETTINGSPANELCHAT::T582516016"] = "When enabled, the latest message is shown after loading a chat. When disabled, the first (oldest) message is shown." +-- Delete +UI_TEXT_CONTENT["AISTUDIO::COMPONENTS::SETTINGS::SETTINGSPANELEMBEDDINGS::T1469573738"] = "Delete" + +-- Add Embedding +UI_TEXT_CONTENT["AISTUDIO::COMPONENTS::SETTINGS::SETTINGSPANELEMBEDDINGS::T1738753945"] = "Add Embedding" + +-- Are you sure you want to delete the embedding provider '{0}'? +UI_TEXT_CONTENT["AISTUDIO::COMPONENTS::SETTINGS::SETTINGSPANELEMBEDDINGS::T1825371968"] = "Are you sure you want to delete the embedding provider '{0}'?" + +-- Add Embedding Provider +UI_TEXT_CONTENT["AISTUDIO::COMPONENTS::SETTINGS::SETTINGSPANELEMBEDDINGS::T190634634"] = "Add Embedding Provider" + +-- Model +UI_TEXT_CONTENT["AISTUDIO::COMPONENTS::SETTINGS::SETTINGSPANELEMBEDDINGS::T2189814010"] = "Model" + +-- Embeddings are a way to represent words, sentences, entire documents, or even images and videos as digital fingerprints. Just like each person has a unique fingerprint, embedding models create unique digital patterns that capture the meaning and characteristics of the content they analyze. When two things are similar in meaning or content, their digital fingerprints will look very similar. For example, the fingerprints for 'happy' and 'joyful' would be more alike than those for 'happy' and 'sad'. +UI_TEXT_CONTENT["AISTUDIO::COMPONENTS::SETTINGS::SETTINGSPANELEMBEDDINGS::T2419962612"] = "Embeddings are a way to represent words, sentences, entire documents, or even images and videos as digital fingerprints. Just like each person has a unique fingerprint, embedding models create unique digital patterns that capture the meaning and characteristics of the content they analyze. When two things are similar in meaning or content, their digital fingerprints will look very similar. For example, the fingerprints for 'happy' and 'joyful' would be more alike than those for 'happy' and 'sad'." + +-- Name +UI_TEXT_CONTENT["AISTUDIO::COMPONENTS::SETTINGS::SETTINGSPANELEMBEDDINGS::T266367750"] = "Name" + +-- This helps AI Studio understand and compare things in a way that's similar to how humans do. When you're working on something, AI Studio can automatically identify related documents and data by comparing their digital fingerprints. For instance, if you're writing about customer service, AI Studio can instantly find other documents in your data that discuss similar topics or experiences, even if they use different words. +UI_TEXT_CONTENT["AISTUDIO::COMPONENTS::SETTINGS::SETTINGSPANELEMBEDDINGS::T3251217940"] = "This helps AI Studio understand and compare things in a way that's similar to how humans do. When you're working on something, AI Studio can automatically identify related documents and data by comparing their digital fingerprints. For instance, if you're writing about customer service, AI Studio can instantly find other documents in your data that discuss similar topics or experiences, even if they use different words." + +-- Edit +UI_TEXT_CONTENT["AISTUDIO::COMPONENTS::SETTINGS::SETTINGSPANELEMBEDDINGS::T3267849393"] = "Edit" + +-- Configured Embeddings +UI_TEXT_CONTENT["AISTUDIO::COMPONENTS::SETTINGS::SETTINGSPANELEMBEDDINGS::T3526613453"] = "Configured Embeddings" + +-- Actions +UI_TEXT_CONTENT["AISTUDIO::COMPONENTS::SETTINGS::SETTINGSPANELEMBEDDINGS::T3865031940"] = "Actions" + +-- No embeddings configured yet. +UI_TEXT_CONTENT["AISTUDIO::COMPONENTS::SETTINGS::SETTINGSPANELEMBEDDINGS::T4068015588"] = "No embeddings configured yet." + +-- Edit Embedding Provider +UI_TEXT_CONTENT["AISTUDIO::COMPONENTS::SETTINGS::SETTINGSPANELEMBEDDINGS::T4264602229"] = "Edit Embedding Provider" + +-- Delete Embedding Provider +UI_TEXT_CONTENT["AISTUDIO::COMPONENTS::SETTINGS::SETTINGSPANELEMBEDDINGS::T511304264"] = "Delete Embedding Provider" + +-- Open Dashboard +UI_TEXT_CONTENT["AISTUDIO::COMPONENTS::SETTINGS::SETTINGSPANELEMBEDDINGS::T78223861"] = "Open Dashboard" + +-- Provider +UI_TEXT_CONTENT["AISTUDIO::COMPONENTS::SETTINGS::SETTINGSPANELEMBEDDINGS::T900237532"] = "Provider" + +-- Configure Embeddings +UI_TEXT_CONTENT["AISTUDIO::COMPONENTS::SETTINGS::SETTINGSPANELEMBEDDINGS::T970042679"] = "Configure Embeddings" + -- Edit Profile UI_TEXT_CONTENT["AISTUDIO::COMPONENTS::SETTINGS::SETTINGSPANELPROFILES::T1143111468"] = "Edit Profile" @@ -1447,6 +1498,60 @@ UI_TEXT_CONTENT["AISTUDIO::DIALOGS::CONFIRMDIALOG::T1642511898"] = "No" -- Yes UI_TEXT_CONTENT["AISTUDIO::DIALOGS::CONFIRMDIALOG::T3013883440"] = "Yes" +-- Failed to store the API key in the operating system. The message was: {0}. Please try again. +UI_TEXT_CONTENT["AISTUDIO::DIALOGS::EMBEDDINGPROVIDERDIALOG::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::EMBEDDINGPROVIDERDIALOG::T1324664716"] = "API Key" + +-- Create account +UI_TEXT_CONTENT["AISTUDIO::DIALOGS::EMBEDDINGPROVIDERDIALOG::T1356621346"] = "Create account" + +-- Please enter an embedding model name. +UI_TEXT_CONTENT["AISTUDIO::DIALOGS::EMBEDDINGPROVIDERDIALOG::T1661085403"] = "Please enter an embedding model name." + +-- Hostname +UI_TEXT_CONTENT["AISTUDIO::DIALOGS::EMBEDDINGPROVIDERDIALOG::T1727440780"] = "Hostname" + +-- Load +UI_TEXT_CONTENT["AISTUDIO::DIALOGS::EMBEDDINGPROVIDERDIALOG::T1756340745"] = "Load" + +-- Update +UI_TEXT_CONTENT["AISTUDIO::DIALOGS::EMBEDDINGPROVIDERDIALOG::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::EMBEDDINGPROVIDERDIALOG::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." + +-- Model +UI_TEXT_CONTENT["AISTUDIO::DIALOGS::EMBEDDINGPROVIDERDIALOG::T2189814010"] = "Model" + +-- (Optional) API Key +UI_TEXT_CONTENT["AISTUDIO::DIALOGS::EMBEDDINGPROVIDERDIALOG::T2331453405"] = "(Optional) API Key" + +-- Currently, we cannot query the embedding models of self-hosted systems. Therefore, enter the model name manually. +UI_TEXT_CONTENT["AISTUDIO::DIALOGS::EMBEDDINGPROVIDERDIALOG::T2615586687"] = "Currently, we cannot query the embedding models of self-hosted systems. Therefore, enter the model name manually." + +-- Add +UI_TEXT_CONTENT["AISTUDIO::DIALOGS::EMBEDDINGPROVIDERDIALOG::T2646845972"] = "Add" + +-- No models loaded or available. +UI_TEXT_CONTENT["AISTUDIO::DIALOGS::EMBEDDINGPROVIDERDIALOG::T2810182573"] = "No models loaded or available." + +-- Instance Name +UI_TEXT_CONTENT["AISTUDIO::DIALOGS::EMBEDDINGPROVIDERDIALOG::T2842060373"] = "Instance Name" + +-- Model selection +UI_TEXT_CONTENT["AISTUDIO::DIALOGS::EMBEDDINGPROVIDERDIALOG::T416738168"] = "Model selection" + +-- Host +UI_TEXT_CONTENT["AISTUDIO::DIALOGS::EMBEDDINGPROVIDERDIALOG::T808120719"] = "Host" + +-- Provider +UI_TEXT_CONTENT["AISTUDIO::DIALOGS::EMBEDDINGPROVIDERDIALOG::T900237532"] = "Provider" + +-- Cancel +UI_TEXT_CONTENT["AISTUDIO::DIALOGS::EMBEDDINGPROVIDERDIALOG::T900713019"] = "Cancel" + -- 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." @@ -2962,6 +3067,9 @@ UI_TEXT_CONTENT["AISTUDIO::PROVIDER::LLMPROVIDERSEXTENSIONS::T2897045472"] = "No -- Unknown UI_TEXT_CONTENT["AISTUDIO::PROVIDER::LLMPROVIDERSEXTENSIONS::T3424652889"] = "Unknown" +-- no model selected +UI_TEXT_CONTENT["AISTUDIO::PROVIDER::MODEL::T2234274832"] = "no model selected" + -- Navigation never expands, but there are tooltips UI_TEXT_CONTENT["AISTUDIO::SETTINGS::CONFIGURATIONSELECTDATAFACTORY::T1095779033"] = "Navigation never expands, but there are tooltips" diff --git a/app/MindWork AI Studio/Components/Settings/SettingsPanelEmbeddings.razor b/app/MindWork AI Studio/Components/Settings/SettingsPanelEmbeddings.razor index 1e200175..90d208c9 100644 --- a/app/MindWork AI Studio/Components/Settings/SettingsPanelEmbeddings.razor +++ b/app/MindWork AI Studio/Components/Settings/SettingsPanelEmbeddings.razor @@ -4,24 +4,17 @@ @if (PreviewFeatures.PRE_RAG_2024.IsEnabled(this.SettingsManager)) { - + - Configured Embeddings + @T("Configured Embeddings") - Embeddings are a way to represent words, sentences, entire documents, or even images and videos as digital - fingerprints. Just like each person has a unique fingerprint, embedding models create unique digital patterns - that capture the meaning and characteristics of the content they analyze. When two things are similar in meaning - or content, their digital fingerprints will look very similar. For example, the fingerprints for 'happy' and - 'joyful' would be more alike than those for 'happy' and 'sad'. + @T("Embeddings are a way to represent words, sentences, entire documents, or even images and videos as digital fingerprints. Just like each person has a unique fingerprint, embedding models create unique digital patterns that capture the meaning and characteristics of the content they analyze. When two things are similar in meaning or content, their digital fingerprints will look very similar. For example, the fingerprints for 'happy' and 'joyful' would be more alike than those for 'happy' and 'sad'.") - This helps AI Studio understand and compare things in a way that's similar to how humans do. When you're working on - something, AI Studio can automatically identify related documents and data by comparing their digital fingerprints. - For instance, if you're writing about customer service, AI Studio can instantly find other documents in your data that - discuss similar topics or experiences, even if they use different words. + @T("This helps AI Studio understand and compare things in a way that's similar to how humans do. When you're working on something, AI Studio can automatically identify related documents and data by comparing their digital fingerprints. For instance, if you're writing about customer service, AI Studio can instantly find other documents in your data that discuss similar topics or experiences, even if they use different words.") @@ -33,10 +26,10 @@ # - Name - Provider - Model - Actions + @T("Name") + @T("Provider") + @T("Model") + @T("Actions") @context.Num @@ -47,13 +40,13 @@ - Open Dashboard + @T("Open Dashboard") - Edit + @T("Edit") - Delete + @T("Delete") @@ -62,11 +55,13 @@ @if (this.SettingsManager.ConfigurationData.EmbeddingProviders.Count == 0) { - No embeddings configured yet. + + @T("No embeddings configured yet.") + } - Add Embedding + @T("Add Embedding") } \ No newline at end of file diff --git a/app/MindWork AI Studio/Components/Settings/SettingsPanelEmbeddings.razor.cs b/app/MindWork AI Studio/Components/Settings/SettingsPanelEmbeddings.razor.cs index 7520e596..5d80211c 100644 --- a/app/MindWork AI Studio/Components/Settings/SettingsPanelEmbeddings.razor.cs +++ b/app/MindWork AI Studio/Components/Settings/SettingsPanelEmbeddings.razor.cs @@ -39,7 +39,7 @@ public partial class SettingsPanelEmbeddings : SettingsPanelBase { x => x.IsEditing, false }, }; - var dialogReference = await this.DialogService.ShowAsync("Add Embedding Provider", dialogParameters, DialogOptions.FULLSCREEN); + var dialogReference = await this.DialogService.ShowAsync(T("Add Embedding Provider"), dialogParameters, DialogOptions.FULLSCREEN); var dialogResult = await dialogReference.Result; if (dialogResult is null || dialogResult.Canceled) return; @@ -69,7 +69,7 @@ public partial class SettingsPanelEmbeddings : SettingsPanelBase { x => x.DataHost, embeddingProvider.Host }, }; - var dialogReference = await this.DialogService.ShowAsync("Edit Embedding Provider", dialogParameters, DialogOptions.FULLSCREEN); + var dialogReference = await this.DialogService.ShowAsync(T("Edit Embedding Provider"), dialogParameters, DialogOptions.FULLSCREEN); var dialogResult = await dialogReference.Result; if (dialogResult is null || dialogResult.Canceled) return; @@ -92,10 +92,10 @@ public partial class SettingsPanelEmbeddings : SettingsPanelBase { var dialogParameters = new DialogParameters { - { "Message", $"Are you sure you want to delete the embedding provider '{provider.Name}'?" }, + { "Message", string.Format(T("Are you sure you want to delete the embedding provider '{0}'?"), provider.Name) }, }; - var dialogReference = await this.DialogService.ShowAsync("Delete Embedding Provider", dialogParameters, DialogOptions.FULLSCREEN); + var dialogReference = await this.DialogService.ShowAsync(T("Delete Embedding Provider"), dialogParameters, DialogOptions.FULLSCREEN); var dialogResult = await dialogReference.Result; if (dialogResult is null || dialogResult.Canceled) return; diff --git a/app/MindWork AI Studio/Dialogs/EmbeddingProviderDialog.razor b/app/MindWork AI Studio/Dialogs/EmbeddingProviderDialog.razor index c3a5b3bf..80a64e6d 100644 --- a/app/MindWork AI Studio/Dialogs/EmbeddingProviderDialog.razor +++ b/app/MindWork AI Studio/Dialogs/EmbeddingProviderDialog.razor @@ -1,12 +1,13 @@ @using AIStudio.Provider @using AIStudio.Provider.SelfHosted +@inherits MSGComponentBase @* ReSharper disable once CSharpWarnings::CS8974 *@ - + @foreach (LLMProviders provider in Enum.GetValues(typeof(LLMProviders))) { if (provider.ProvideEmbeddings() || provider is LLMProviders.NONE) @@ -17,7 +18,9 @@ } } - Create account + + @T("Create account") + @if (this.DataLLMProvider.IsAPIKeyNeeded(this.DataHost)) @@ -41,7 +44,7 @@ + @foreach (Host host in Enum.GetValues(typeof(Host))) { if (host.AreEmbeddingsSupported()) @@ -65,39 +68,57 @@ } - - @if (this.DataLLMProvider.IsEmbeddingModelProvidedManually(this.DataHost)) - { - - } - else - { - Load - - @foreach (var model in this.availableModels) + + + @if (this.DataLLMProvider.IsEmbeddingModelProvidedManually(this.DataHost)) + { + + } + else + { + + @T("Load") + + @if(this.availableModels.Count is 0) { - @model + + @T("No models loaded or available.") + } - - } - + else + { + + @foreach (var model in this.availableModels) + { + + @model + + } + + } + } + + @* 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/EmbeddingProviderDialog.razor.cs b/app/MindWork AI Studio/Dialogs/EmbeddingProviderDialog.razor.cs index 1d09fa52..d08ff0a7 100644 --- a/app/MindWork AI Studio/Dialogs/EmbeddingProviderDialog.razor.cs +++ b/app/MindWork AI Studio/Dialogs/EmbeddingProviderDialog.razor.cs @@ -1,3 +1,4 @@ +using AIStudio.Components; using AIStudio.Provider; using AIStudio.Settings; using AIStudio.Tools.Services; @@ -9,7 +10,7 @@ using Host = AIStudio.Provider.SelfHosted.Host; namespace AIStudio.Dialogs; -public partial class EmbeddingProviderDialog : ComponentBase, ISecretId +public partial class EmbeddingProviderDialog : MSGComponentBase, ISecretId { [CascadingParameter] private IMudDialogInstance MudDialog { get; set; } = null!; @@ -68,9 +69,6 @@ public partial class EmbeddingProviderDialog : ComponentBase, ISecretId [Parameter] public bool IsEditing { get; init; } - [Inject] - private SettingsManager SettingsManager { get; init; } = null!; - [Inject] private ILogger Logger { get; init; } = null!; @@ -175,7 +173,7 @@ public partial class EmbeddingProviderDialog : 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(); } } @@ -224,7 +222,7 @@ public partial class EmbeddingProviderDialog : 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; } @@ -236,7 +234,7 @@ public partial class EmbeddingProviderDialog : ComponentBase, ISecretId private string? ValidateManuallyModel(string manuallyModel) { if (this.DataLLMProvider is LLMProviders.SELF_HOSTED && string.IsNullOrWhiteSpace(manuallyModel)) - return "Please enter an embedding model name."; + return T("Please enter an embedding model name."); return null; } @@ -261,8 +259,8 @@ public partial class EmbeddingProviderDialog : 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"), }; private bool IsNoneProvider => this.DataLLMProvider is LLMProviders.NONE; diff --git a/app/MindWork AI Studio/Provider/Model.cs b/app/MindWork AI Studio/Provider/Model.cs index ff66933a..4e582f97 100644 --- a/app/MindWork AI Studio/Provider/Model.cs +++ b/app/MindWork AI Studio/Provider/Model.cs @@ -1,3 +1,5 @@ +using AIStudio.Tools.PluginSystem; + namespace AIStudio.Provider; /// @@ -7,6 +9,8 @@ namespace AIStudio.Provider; /// The model's display name. public readonly record struct Model(string Id, string? DisplayName) { + private static string TB(string fallbackEN) => I18N.I.T(fallbackEN, typeof(Model).Namespace, nameof(Model)); + #region Overrides of ValueType public override string ToString() @@ -17,7 +21,7 @@ public readonly record struct Model(string Id, string? DisplayName) if(!string.IsNullOrWhiteSpace(this.Id)) return this.Id; - return "no model selected"; + return TB("no model selected"); } #endregion diff --git a/app/MindWork AI Studio/wwwroot/changelog/v0.9.43.md b/app/MindWork AI Studio/wwwroot/changelog/v0.9.43.md index 65f7f1d1..052b06b2 100644 --- a/app/MindWork AI Studio/wwwroot/changelog/v0.9.43.md +++ b/app/MindWork AI Studio/wwwroot/changelog/v0.9.43.md @@ -1,5 +1,6 @@ # v0.9.43, build 218 (2025-05-xx xx:xx UTC) - Added the ability to select the new Google Gemini embeddings in the embedding configuration. +- Added localization for embedding configuration. - Improved the automatic German translation; thanks Peer (`peerschuett`) for contributing. - Improved Google Gemini LLM model selection by filtering out the new embedding models. - Improved the dialog for configuring embeddings: the API key is applied immediately, and provider formatting was enhanced. \ No newline at end of file