refactor: replace fmt.Errorf("%s", ...) with errors.New() and normalize i18n strings

- Replace `fmt.Errorf("%s", ...)` with `errors.New()` across all packages
- Add `errors` import where needed, remove unused `fmt` imports
- Lowercase error message strings in i18n locale files for Go conventions
- Add `plugin_registry_run_setup_select_defaults` i18n key for setup prompt
- Add `plugin_registry_could_not_find_vendor` i18n key for vendor errors
- Internationalize hardcoded English strings in `plugin_registry.go`
- Update `db_error_loading_env_file` format verb from `%s` to `%w` for wrapping
- Normalize error casing in en, de, es, fr, it, ja, pt-BR, pt-PT, zh, fa locales
This commit is contained in:
Kayvan Sylvan 2026-02-21 15:48:01 -08:00
parent b6e3a476e8
commit e84edd935b
38 changed files with 264 additions and 220 deletions

View file

@ -1,6 +1,7 @@
package cli
import (
"errors"
"fmt"
"os"
"os/exec"
@ -185,7 +186,7 @@ func sendNotification(options *domain.ChatOptions, patternName, result string) e
// Use built-in notification system
notificationManager := notifications.NewNotificationManager()
if !notificationManager.IsAvailable() {
return fmt.Errorf("%s", i18n.T("no_notification_system_available"))
return errors.New(i18n.T("no_notification_system_available"))
}
return notificationManager.Send(title, message)

View file

@ -373,7 +373,7 @@ func validateImageParameters(imagePath, size, quality, background string, compre
if imagePath == "" {
// Check if any image parameters are specified without --image-file
if size != "" || quality != "" || background != "" || compression != 0 {
return fmt.Errorf("%s", i18n.T("image_parameters_require_image_file"))
return errors.New(i18n.T("image_parameters_require_image_file"))
}
return nil
}

View file

@ -1,6 +1,7 @@
package cli
import (
"errors"
"fmt"
"github.com/danielmiessler/fabric/internal/core"
@ -12,7 +13,7 @@ import (
func handleToolProcessing(currentFlags *Flags, registry *core.PluginRegistry) (messageTools string, err error) {
if currentFlags.YouTube != "" {
if !registry.YouTube.IsConfigured() {
err = fmt.Errorf("%s", i18n.T("youtube_not_configured"))
err = errors.New(i18n.T("youtube_not_configured"))
return
}
@ -59,7 +60,7 @@ func handleToolProcessing(currentFlags *Flags, registry *core.PluginRegistry) (m
if currentFlags.ScrapeURL != "" || currentFlags.ScrapeQuestion != "" {
if !registry.Jina.IsConfigured() {
err = fmt.Errorf("%s", i18n.T("scraping_not_configured"))
err = errors.New(i18n.T("scraping_not_configured"))
return
}
// Check if the scrape_url flag is set and call ScrapeURL
@ -90,7 +91,7 @@ func handleToolProcessing(currentFlags *Flags, registry *core.PluginRegistry) (m
// Handle Spotify podcast/episode metadata
if currentFlags.Spotify != "" {
if !registry.Spotify.IsConfigured() {
err = fmt.Errorf("%s", i18n.T("spotify_not_configured"))
err = errors.New(i18n.T("spotify_not_configured"))
return
}

View file

@ -2,6 +2,7 @@ package cli
import (
"context"
"errors"
"fmt"
"github.com/danielmiessler/fabric/internal/core"
@ -28,7 +29,7 @@ func handleTranscription(flags *Flags, registry *core.PluginRegistry) (message s
}
model := flags.TranscribeModel
if model == "" {
return "", fmt.Errorf("%s", i18n.T("transcription_model_required"))
return "", errors.New(i18n.T("transcription_model_required"))
}
if message, err = tr.TranscribeFile(context.Background(), flags.TranscribeFile, model, flags.SplitMediaFile); err != nil {
return

View file

@ -48,7 +48,7 @@ func (o *Chatter) Send(request *domain.ChatRequest, opts *domain.ChatOptions) (s
return
}
}
err = fmt.Errorf("%s", i18n.T("chatter_error_no_messages_provided"))
err = errors.New(i18n.T("chatter_error_no_messages_provided"))
return
}
@ -136,7 +136,7 @@ func (o *Chatter) Send(request *domain.ChatRequest, opts *domain.ChatOptions) (s
if message == "" {
session = nil
err = fmt.Errorf("%s", i18n.T("chatter_error_empty_response"))
err = errors.New(i18n.T("chatter_error_empty_response"))
return
}

View file

@ -2,6 +2,7 @@ package core
import (
"bytes"
"errors"
"fmt"
"io"
"os"
@ -300,7 +301,7 @@ func (o *PluginRegistry) runVendorSetup() (err error) {
}
if setupQuestion.Value == "" {
return fmt.Errorf("%s", i18n.T("setup_no_ai_provider_selected"))
return errors.New(i18n.T("setup_no_ai_provider_selected"))
}
number, parseErr := strconv.Atoi(setupQuestion.Value)
@ -576,9 +577,9 @@ func (o *PluginRegistry) GetChatter(model string, modelContextLength int, vendor
if ret.vendor == nil {
var errMsg string
if defaultModel == "" || defaultVendor == "" {
errMsg = "Please run, fabric --setup, and select default model and vendor."
errMsg = i18n.T("plugin_registry_run_setup_select_defaults")
} else {
errMsg = "could not find vendor."
errMsg = i18n.T("plugin_registry_could_not_find_vendor")
}
err = fmt.Errorf(
" Requested Model = %s\n Default Model = %s\n Default Vendor = %s.\n\n%s",

View file

@ -5,6 +5,7 @@ import (
"crypto/sha256"
"encoding/base64"
"encoding/json"
"errors"
"fmt"
"io"
"net/http"
@ -74,7 +75,7 @@ func (a *Attachment) ResolveType() (ret string, err error) {
ret = mimetype.Detect(a.Content).String()
return
}
err = fmt.Errorf("%s", i18n.T("attachment_no_type_no_content"))
err = errors.New(i18n.T("attachment_no_type_no_content"))
return
}
@ -100,7 +101,7 @@ func (a *Attachment) ContentBytes() (ret []byte, err error) {
}
return
}
err = fmt.Errorf("%s", i18n.T("attachment_no_content_available"))
err = errors.New(i18n.T("attachment_no_content_available"))
return
}
@ -154,7 +155,7 @@ func detectMimeTypeFromURL(url string) (string, error) {
defer resp.Body.Close()
mimeType := resp.Header.Get("Content-Type")
if mimeType == "" {
return "", fmt.Errorf("%s", i18n.T("attachment_could_not_determine_mimetype"))
return "", errors.New(i18n.T("attachment_could_not_determine_mimetype"))
}
return mimeType, nil
}

View file

@ -20,9 +20,9 @@
"azure_api_version_question": "Geben Sie die Azure API-Version ein (leer lassen für Standard)",
"azure_base_url_question": "API Basis-URL",
"azure_base_url_required": "Azure Basis-URL ist erforderlich",
"azure_credential_failure": "Fehler beim Erstellen der Azure-Anmeldeinformationen",
"azure_credential_failure": "Azure-Anmeldeinformationen konnten nicht erstellt werden",
"azure_deployments_question": "Geben Sie Ihre Azure-Bereitstellungsnamen ein (kommagetrennt)",
"azure_deployments_required": "Mindestens ein Azure-Bereitstellungsname ist erforderlich",
"azure_deployments_required": "mindestens ein Azure-Bereitstellungsname ist erforderlich",
"azure_failed_extract_deployment": "Bereitstellungsname konnte nicht aus der Anfrage extrahiert werden",
"azure_model_field_empty": "Modellfeld ist im Anfragekörper leer",
"azure_request_body_nil": "Anfragekörper ist nil",
@ -88,7 +88,7 @@
"custom_patterns_label": "Benutzerdefinierte Patterns",
"custom_patterns_setup_description": "Benutzerdefinierte Patterns - Verzeichnis für Ihre benutzerdefinierten Patterns festlegen",
"custom_patterns_warning_create_directory": "Warnung: Benutzerdefiniertes Musterverzeichnis %s konnte nicht erstellt werden: %v\n",
"db_error_loading_env_file": "Fehler beim Laden der .env-Datei: %s",
"db_error_loading_env_file": "fehler beim Laden der .env-Datei: %w",
"defaults_model_context_length_question": "Geben Sie die Kontextlänge des Modells ein",
"defaults_model_question": "Geben Sie den Index oder den Namen Ihres Standardmodells ein",
"defaults_setup_description": "Standard-KI-Anbieter und -Modell",
@ -208,8 +208,8 @@
"help_message": "Diese Hilfenachricht anzeigen",
"help_options_header": "Hilfe-Optionen:",
"html_readability_error": "verwende ursprüngliche Eingabe, da HTML-Lesbarkeit nicht angewendet werden kann",
"i18n_download_failed": "Fehler beim Herunterladen der Übersetzung für Sprache '%s': %v",
"i18n_load_failed": "Fehler beim Laden der Übersetzungsdatei: %v",
"i18n_download_failed": "fehler beim Herunterladen der Übersetzung für Sprache '%s': %v",
"i18n_load_failed": "fehler beim Laden der Übersetzungsdatei: %v",
"image_compression_jpeg_webp_only": "Bildkomprimierung kann nur mit JPEG- und WebP-Formaten verwendet werden, nicht %s",
"image_compression_range_error": "Bildkomprimierung muss zwischen 0 und 100 liegen, erhalten: %d",
"image_dimensions_help": "Bildabmessungen: 1024x1024, 1536x1024, 1024x1536, auto (Standard: auto)",
@ -260,17 +260,17 @@
"ollama_cannot_parse_url": "URL '%s' kann nicht geparst werden: %v",
"ollama_chat_request_failed": "Chat-Anfrage fehlgeschlagen: %v",
"ollama_empty_address": "Leere Adresse",
"ollama_error_building_chat_url": "Fehler beim Erstellen der /chat URL: %v",
"ollama_error_creating_chat_request": "Fehler beim Erstellen der /chat Anfrage: %v",
"ollama_error_building_chat_url": "fehler beim Erstellen der /chat URL: %v",
"ollama_error_creating_chat_request": "fehler beim Erstellen der /chat Anfrage: %v",
"ollama_error_endpoint": "Endpunkt wird getestet",
"ollama_error_getting_chat_body": "Fehler beim Abrufen des /chat Bodys: %v",
"ollama_error_marshalling_body": "Fehler beim Marshalling des Bodys: %v",
"ollama_error_getting_chat_body": "fehler beim Abrufen des /chat Bodys: %v",
"ollama_error_marshalling_body": "fehler beim Marshalling des Bodys: %v",
"ollama_error_parse_upstream_response": "Fehler: Upstream-Antwort konnte nicht geparst werden",
"ollama_error_prefix": "Fehler: %s",
"ollama_error_reading_body": "Fehler beim Lesen des Bodys: %v",
"ollama_error_scanning_body": "Fehler beim Scannen des Bodys: %v",
"ollama_error_unmarshalling_body": "Fehler beim Unmarshalling des Bodys: %v",
"ollama_error_writing_response": "Fehler beim Schreiben der Antwort: %v",
"ollama_error_reading_body": "fehler beim Lesen des Bodys: %v",
"ollama_error_scanning_body": "fehler beim Scannen des Bodys: %v",
"ollama_error_unmarshalling_body": "fehler beim Unmarshalling des Bodys: %v",
"ollama_error_writing_response": "fehler beim Schreiben der Antwort: %v",
"ollama_failed_create_request": "Fehler beim Erstellen der Anfrage",
"ollama_failed_decode_data_url": "Data-URL konnte nicht dekodiert werden: %v",
"ollama_failed_fetch_image": "Bild konnte nicht von %s abgerufen werden: %s",
@ -282,7 +282,7 @@
"ollama_invalid_address_missing_hostname": "Ungültige Adresse: Hostname fehlt",
"ollama_invalid_address_path_not_allowed": "Ungültige Adresse: Pfadkomponente in bloßer Adresse nicht zulässig",
"ollama_invalid_data_url_format": "ungültiges Data-URL-Format",
"ollama_invalid_http_timeout_using_default": "Ungültiges HTTP-Zeitlimit '%s': %v, verwende Standardwert",
"ollama_invalid_http_timeout_using_default": "ungültiges HTTP-Zeitlimit '%s': %v, verwende Standardwert",
"ollama_invalid_num_ctx_in_request": "Ungültiger num_ctx in Anfrage: %v",
"ollama_no_content_from_upstream": "Kein Inhalt vom Upstream Fabric Server erhalten",
"ollama_num_ctx_exceeds_maximum": "num_ctx überschreitet den maximal zulässigen Wert von %d",
@ -419,7 +419,7 @@
"server_chat_error": "Fehler: %v",
"server_error_marshaling_response": "Fehler beim Serialisieren der Antwort: %v",
"server_error_writing_response": "Fehler beim Schreiben der Antwort: %v",
"server_invalid_request_format": "Ungültiges Anfrageformat: %v",
"server_invalid_request_format": "ungültiges Anfrageformat: %v",
"sessions_creating_new": "Erstelle neue Sitzung: %s\n",
"set_debug_level": "Debug-Level festlegen (0=aus, 1=grundlegend, 2=detailliert, 3=Trace)",
"set_frequency_penalty": "Häufigkeitsstrafe festlegen",
@ -650,5 +650,7 @@
"youtube_url_is_playlist_not_video": "URL ist eine Playlist, kein Video",
"youtube_video_id_title_header": "VideoID: Titel",
"youtube_ytdlp_not_found": "yt-dlp wurde nicht in PATH gefunden. Bitte installiere yt-dlp, um die YouTube-Transkript-Funktionalität zu nutzen",
"youtube_ytdlp_stderr_error": "Fehler beim Lesen von yt-dlp stderr"
}
"youtube_ytdlp_stderr_error": "fehler beim Lesen von yt-dlp stderr",
"plugin_registry_run_setup_select_defaults": "bitte führen Sie 'fabric --setup' aus und wählen Sie Standardmodell und -anbieter",
"plugin_registry_could_not_find_vendor": "Anbieter konnte nicht gefunden werden"
}

View file

@ -20,9 +20,9 @@
"azure_api_version_question": "Enter the Azure API version (leave blank for default)",
"azure_base_url_question": "API Base URL",
"azure_base_url_required": "Azure base URL is required",
"azure_credential_failure": "Failed to create Azure credential",
"azure_credential_failure": "failed to create Azure credential",
"azure_deployments_question": "Enter your Azure deployment names (comma-separated)",
"azure_deployments_required": "At least one Azure deployment name is required",
"azure_deployments_required": "at least one Azure deployment name is required",
"azure_failed_extract_deployment": "failed to extract deployment name from request",
"azure_model_field_empty": "model field is empty in request body",
"azure_request_body_nil": "request body is nil",
@ -68,7 +68,7 @@
"config_file_not_found": "config file not found: %s",
"convert_html_readability": "Convert HTML input into a clean, readable view",
"copilot_debug_created_conversation": "Created Copilot conversation: %s",
"copilot_debug_failed_parse_sse_event": "Failed to parse SSE event: %v",
"copilot_debug_failed_parse_sse_event": "failed to parse SSE event: %v",
"copilot_error_chat_request": "chat request failed: %s - %s",
"copilot_error_create_conversation": "failed to create conversation: %s - %s",
"copilot_error_reading_stream": "error reading stream: %w",
@ -88,7 +88,7 @@
"custom_patterns_label": "Custom Patterns",
"custom_patterns_setup_description": "Custom Patterns - Set directory for your custom patterns",
"custom_patterns_warning_create_directory": "Warning: Could not create custom patterns directory %s: %v\n",
"db_error_loading_env_file": "error loading .env file: %s",
"db_error_loading_env_file": "error loading .env file: %w",
"defaults_model_context_length_question": "Enter model context length",
"defaults_model_question": "Enter the index or the name of your default model",
"defaults_setup_description": "Default AI Vendor and Model",
@ -208,8 +208,8 @@
"help_message": "Show this help message",
"help_options_header": "Help Options:",
"html_readability_error": "use original input, because can't apply html readability",
"i18n_download_failed": "Failed to download translation for language '%s': %v",
"i18n_load_failed": "Failed to load translation file: %v",
"i18n_download_failed": "failed to download translation for language '%s': %v",
"i18n_load_failed": "failed to load translation file: %v",
"image_compression_jpeg_webp_only": "image compression can only be used with JPEG and WebP formats, not %s",
"image_compression_range_error": "image compression must be between 0 and 100, got %d",
"image_dimensions_help": "Image dimensions: 1024x1024, 1536x1024, 1024x1536, auto (default: auto)",
@ -257,20 +257,20 @@
"no_notification_system_available": "no notification system available",
"notifications_no_provider_available": "no notification provider available",
"number_of_latest_patterns": "Number of latest patterns to list",
"ollama_cannot_parse_url": "Cannot parse URL '%s': %v",
"ollama_cannot_parse_url": "cannot parse URL '%s': %v",
"ollama_chat_request_failed": "Chat request failed: %v",
"ollama_empty_address": "empty address",
"ollama_error_building_chat_url": "Error building /chat URL: %v",
"ollama_error_creating_chat_request": "Error creating /chat request: %v",
"ollama_error_building_chat_url": "error building /chat URL: %v",
"ollama_error_creating_chat_request": "error creating /chat request: %v",
"ollama_error_endpoint": "testing endpoint",
"ollama_error_getting_chat_body": "Error getting /chat body: %v",
"ollama_error_marshalling_body": "Error marshalling body: %v",
"ollama_error_getting_chat_body": "error getting /chat body: %v",
"ollama_error_marshalling_body": "error marshalling body: %v",
"ollama_error_parse_upstream_response": "Error: failed to parse upstream response",
"ollama_error_prefix": "Error: %s",
"ollama_error_reading_body": "Error reading body: %v",
"ollama_error_scanning_body": "Error scanning body: %v",
"ollama_error_unmarshalling_body": "Error unmarshalling body: %v",
"ollama_error_writing_response": "Error writing response: %v",
"ollama_error_reading_body": "error reading body: %v",
"ollama_error_scanning_body": "error scanning body: %v",
"ollama_error_unmarshalling_body": "error unmarshalling body: %v",
"ollama_error_writing_response": "error writing response: %v",
"ollama_failed_create_request": "failed to create request",
"ollama_failed_decode_data_url": "failed to decode data URL: %v",
"ollama_failed_fetch_image": "failed to fetch image from %s: %s",
@ -282,8 +282,8 @@
"ollama_invalid_address_missing_hostname": "invalid address: missing hostname",
"ollama_invalid_address_path_not_allowed": "invalid address: path component not allowed in bare address",
"ollama_invalid_data_url_format": "invalid data URL format",
"ollama_invalid_http_timeout_using_default": "Invalid HTTP timeout '%s': %v, using default",
"ollama_invalid_num_ctx_in_request": "Invalid num_ctx in request: %v",
"ollama_invalid_http_timeout_using_default": "invalid HTTP timeout '%s': %v, using default",
"ollama_invalid_num_ctx_in_request": "invalid num_ctx in request: %v",
"ollama_no_content_from_upstream": "no content received from upstream Fabric server",
"ollama_num_ctx_exceeds_maximum": "num_ctx exceeds maximum allowed value of %d",
"ollama_num_ctx_invalid_type": "num_ctx must be a number, got invalid type",
@ -419,7 +419,7 @@
"server_chat_error": "Error: %v",
"server_error_marshaling_response": "error marshaling response: %v",
"server_error_writing_response": "error writing response: %v",
"server_invalid_request_format": "Invalid request format: %v",
"server_invalid_request_format": "invalid request format: %v",
"sessions_creating_new": "Creating new session: %s\n",
"set_debug_level": "Set debug level (0=off, 1=basic, 2=detailed, 3=trace)",
"set_frequency_penalty": "Set frequency penalty",
@ -628,7 +628,7 @@
"youtube_error_parsing_duration": "error parsing video duration: %v",
"youtube_error_saving_csv": "error saving videos to CSV: %v",
"youtube_failed_create_temp_dir": "failed to create temp directory: %v",
"youtube_failed_fetch_comments": "Failed to fetch comments: %v",
"youtube_failed_fetch_comments": "failed to fetch comments: %v",
"youtube_failed_walk_directory": "failed to walk directory: %v",
"youtube_invalid_duration_string": "invalid duration string: %s",
"youtube_invalid_seconds_format": "invalid seconds format %q: %w",
@ -650,5 +650,7 @@
"youtube_url_is_playlist_not_video": "URL is a playlist, not a video",
"youtube_video_id_title_header": "VideoID: Title",
"youtube_ytdlp_not_found": "yt-dlp not found in PATH. Please install yt-dlp to use YouTube transcript functionality",
"youtube_ytdlp_stderr_error": "Error reading yt-dlp stderr"
"youtube_ytdlp_stderr_error": "error reading yt-dlp stderr",
"plugin_registry_run_setup_select_defaults": "please run 'fabric --setup' and select default model and vendor",
"plugin_registry_could_not_find_vendor": "could not find vendor"
}

View file

@ -16,16 +16,16 @@
"available_models_header": "Modelos disponibles",
"available_transcription_models": "Modelos de transcripción disponibles:",
"available_vendors_header": "Proveedores Disponibles:",
"azure_api_key_required": "Se requiere la clave API de Azure",
"azure_api_key_required": "se requiere la clave API de Azure",
"azure_api_version_question": "Ingrese la versión de la API de Azure (deje en blanco para el valor predeterminado)",
"azure_base_url_question": "URL base de la API",
"azure_base_url_required": "Se requiere la URL base de Azure",
"azure_base_url_required": "se requiere la URL base de Azure",
"azure_deployments_question": "Ingrese los nombres de sus implementaciones de Azure (separados por comas)",
"azure_deployments_required": "Se requiere al menos un nombre de implementación de Azure",
"azure_deployments_required": "se requiere al menos un nombre de implementación de Azure",
"azure_failed_extract_deployment": "no se pudo extraer el nombre de la implementación de la solicitud",
"azure_model_field_empty": "el campo de modelo está vacío en el cuerpo de la solicitud",
"azure_request_body_nil": "el cuerpo de la solicitud es nil",
"azure_credential_failure": "Error al crear la credencial de Azure",
"azure_credential_failure": "no se pudo crear la credencial de Azure",
"background_type_help": "Tipo de fondo: opaque, transparent (predeterminado: opaque, solo para PNG/WebP)",
"bedrock_aws_region_label": "Región de AWS",
"bedrock_converse_failed": "bedrock converse falló para el modelo %s: %w",
@ -68,7 +68,7 @@
"config_file_not_found": "archivo de configuración no encontrado: %s",
"convert_html_readability": "Convertir entrada HTML en una vista limpia y legible",
"copilot_debug_created_conversation": "Conversación de Copilot creada: %s",
"copilot_debug_failed_parse_sse_event": "Error al analizar el evento SSE: %v",
"copilot_debug_failed_parse_sse_event": "error al analizar el evento SSE: %v",
"copilot_error_chat_request": "solicitud de chat fallida: %s - %s",
"copilot_error_create_conversation": "error al crear la conversación: %s - %s",
"copilot_error_reading_stream": "error al leer la transmisión: %w",
@ -88,12 +88,12 @@
"custom_patterns_label": "Patrones personalizados",
"custom_patterns_setup_description": "Patrones personalizados - Establecer directorio para tus patrones personalizados",
"custom_patterns_warning_create_directory": "Advertencia: No se pudo crear el directorio de patrones personalizados %s: %v\n",
"db_error_loading_env_file": "Error al cargar el archivo .env: %s",
"db_error_loading_env_file": "error al cargar el archivo .env: %w",
"defaults_model_context_length_question": "Introduce la longitud del contexto del modelo",
"defaults_model_question": "Introduce el índice o el nombre de tu modelo predeterminado",
"defaults_setup_description": "Proveedor y modelo de IA predeterminados",
"digitalocean_failed_parse_control_plane_url": "No se pudo analizar la URL del plano de control de DigitalOcean: %w",
"digitalocean_model_list_unavailable": "Lista de modelos de DigitalOcean no disponible. Configure DIGITALOCEAN_TOKEN para obtener modelos del plano de control",
"digitalocean_model_list_unavailable": "lista de modelos de DigitalOcean no disponible. Configure DIGITALOCEAN_TOKEN para obtener modelos del plano de control",
"disable_openai_responses_api": "Deshabilitar API de Respuestas de OpenAI (predeterminado: false)",
"disable_pattern_variable_replacement": "Deshabilitar reemplazo de variables de patrón",
"enable_web_search_tool": "Habilitar herramienta de búsqueda web para modelos soportados (Anthropic, OpenAI, Gemini)",
@ -208,8 +208,8 @@
"help_message": "Mostrar este mensaje de ayuda",
"help_options_header": "Opciones de Ayuda:",
"html_readability_error": "usa la entrada original, porque no se puede aplicar la legibilidad de html",
"i18n_download_failed": "Error al descargar traducción para el idioma '%s': %v",
"i18n_load_failed": "Error al cargar archivo de traducción: %v",
"i18n_download_failed": "error al descargar traducción para el idioma '%s': %v",
"i18n_load_failed": "error al cargar archivo de traducción: %v",
"image_compression_jpeg_webp_only": "la compresión de imagen solo puede usarse con formatos JPEG y WebP, no %s",
"image_compression_range_error": "la compresión de imagen debe estar entre 0 y 100, se obtuvo %d",
"image_dimensions_help": "Dimensiones de imagen: 1024x1024, 1536x1024, 1024x1536, auto (predeterminado: auto)",
@ -260,17 +260,17 @@
"ollama_cannot_parse_url": "No se puede analizar la URL '%s': %v",
"ollama_chat_request_failed": "Solicitud de chat fallida: %v",
"ollama_empty_address": "dirección vacía",
"ollama_error_building_chat_url": "Error al construir la URL /chat: %v",
"ollama_error_creating_chat_request": "Error al crear la solicitud /chat: %v",
"ollama_error_building_chat_url": "error al construir la URL /chat: %v",
"ollama_error_creating_chat_request": "error al crear la solicitud /chat: %v",
"ollama_error_endpoint": "probando endpoint",
"ollama_error_getting_chat_body": "Error al obtener el cuerpo /chat: %v",
"ollama_error_marshalling_body": "Error al serializar el cuerpo: %v",
"ollama_error_getting_chat_body": "error al obtener el cuerpo /chat: %v",
"ollama_error_marshalling_body": "error al serializar el cuerpo: %v",
"ollama_error_parse_upstream_response": "Error: no se pudo analizar la respuesta upstream",
"ollama_error_prefix": "Error: %s",
"ollama_error_reading_body": "Error al leer el cuerpo: %v",
"ollama_error_scanning_body": "Error al escanear el cuerpo: %v",
"ollama_error_unmarshalling_body": "Error al deserializar el cuerpo: %v",
"ollama_error_writing_response": "Error al escribir la respuesta: %v",
"ollama_error_reading_body": "error al leer el cuerpo: %v",
"ollama_error_scanning_body": "error al escanear el cuerpo: %v",
"ollama_error_unmarshalling_body": "error al deserializar el cuerpo: %v",
"ollama_error_writing_response": "error al escribir la respuesta: %v",
"ollama_failed_create_request": "error al crear la solicitud",
"ollama_failed_decode_data_url": "no se pudo decodificar la URL de datos: %v",
"ollama_failed_fetch_image": "no se pudo obtener la imagen de %s: %s",
@ -381,7 +381,7 @@
"patterns_unique_file_created": "📝 Archivo de patrones únicos creado con %d patrones\\n",
"patterns_warning_custom_directory": "Advertencia: no se pudo leer el directorio de patrones personalizado %s: %v\\n",
"patterns_warning_remove_test_folder": "Advertencia: no se pudo eliminar la carpeta temporal de prueba '%s': %v\\n",
"perplexity_api_key_not_configured": "Clave API no configurada para %s. Configure la variable de entorno %s o ejecute 'fabric --setup' para configurar %s",
"perplexity_api_key_not_configured": "clave API no configurada para %s. Configure la variable de entorno %s o ejecute 'fabric --setup' para configurar %s",
"perplexity_api_request_failed": "solicitud a la API de Perplexity fallida: %w",
"perplexity_citations_header": "\n\n**Citas:**\n",
"perplexity_failed_configure": "no se pudo configurar Perplexity: %w",
@ -419,7 +419,7 @@
"server_chat_error": "Error: %v",
"server_error_marshaling_response": "error al serializar la respuesta: %v",
"server_error_writing_response": "error al escribir la respuesta: %v",
"server_invalid_request_format": "Formato de solicitud no válido: %v",
"server_invalid_request_format": "formato de solicitud no válido: %v",
"sessions_creating_new": "Creando nueva sesión: %s\n",
"set_debug_level": "Establecer nivel de depuración (0=apagado, 1=básico, 2=detallado, 3=rastreo)",
"set_frequency_penalty": "Establecer penalización de frecuencia",
@ -619,7 +619,7 @@
"vertexai_stream_error": "Error: %v",
"wipe_context": "Limpiar contexto",
"wipe_session": "Limpiar sesión",
"youtube_api_key_required": "Se requiere clave API de YouTube para comentarios y metadatos. Ejecute 'fabric --setup' para configurar",
"youtube_api_key_required": "se requiere clave API de YouTube para comentarios y metadatos. Ejecute 'fabric --setup' para configurar",
"youtube_auth_required_bot_detection": "YouTube requiere autenticación (detección de bot). Usa --yt-dlp-args='--cookies-from-browser BROWSER' donde BROWSER puede ser chrome, firefox, brave, etc.",
"youtube_empty_seconds_string": "cadena de segundos vacía",
"youtube_error_getting_comments": "error al obtener comentarios: %v",
@ -647,8 +647,10 @@
"youtube_rate_limit_exceeded": "Límite de tasa de YouTube excedido. Intenta de nuevo más tarde o usa diferentes argumentos de yt-dlp como '--sleep-requests 1' para ralentizar las solicitudes.",
"youtube_setup_description": "YouTube - para obtener transcripciones de video (vía yt-dlp) y comentarios/metadatos (vía API de YouTube)",
"youtube_url_help": "Video de YouTube o \"URL\" de lista de reproducción para obtener transcripción, comentarios y enviar al chat o imprimir en la consola y almacenar en el archivo de salida",
"youtube_url_is_playlist_not_video": "La URL es una lista de reproducción, no un video",
"youtube_url_is_playlist_not_video": "la URL es una lista de reproducción, no un video",
"youtube_video_id_title_header": "VideoID: Título",
"youtube_ytdlp_not_found": "yt-dlp no encontrado en PATH. Por favor instala yt-dlp para usar la funcionalidad de transcripción de YouTube",
"youtube_ytdlp_stderr_error": "Error al leer stderr de yt-dlp"
"youtube_ytdlp_stderr_error": "error al leer stderr de yt-dlp",
"plugin_registry_run_setup_select_defaults": "ejecute 'fabric --setup' y seleccione el modelo y proveedor predeterminados",
"plugin_registry_could_not_find_vendor": "no se pudo encontrar el proveedor"
}

View file

@ -88,7 +88,7 @@
"custom_patterns_label": "الگوهای سفارشی",
"custom_patterns_setup_description": "الگوهای سفارشی - تنظیم دایرکتوری برای الگوهای سفارشی شما",
"custom_patterns_warning_create_directory": "هشدار: امکان ایجاد پوشه الگوهای سفارشی %s وجود ندارد: %v\n",
"db_error_loading_env_file": "خطا در بارگذاری فایل .env: %s",
"db_error_loading_env_file": "خطا در بارگذاری فایل .env: %w",
"defaults_model_context_length_question": "طول زمینه مدل را وارد کنید",
"defaults_model_question": "شاخص یا نام مدل پیش‌فرض خود را وارد کنید",
"defaults_setup_description": "ارائه‌دهنده و مدل هوش مصنوعی پیش‌فرض",
@ -650,5 +650,7 @@
"youtube_url_is_playlist_not_video": "URL یک فهرست پخش است، نه یک ویدیو",
"youtube_video_id_title_header": "شناسه ویدیو: عنوان",
"youtube_ytdlp_not_found": "yt-dlp در PATH یافت نشد. لطفاً yt-dlp را نصب کنید تا از قابلیت رونویسی یوتیوب استفاده کنید",
"youtube_ytdlp_stderr_error": "خطا در خواندن stderr yt-dlp"
"youtube_ytdlp_stderr_error": "خطا در خواندن stderr yt-dlp",
"plugin_registry_run_setup_select_defaults": "لطفاً 'fabric --setup' را اجرا کنید و مدل و ارائه‌دهنده پیش‌فرض را انتخاب کنید",
"plugin_registry_could_not_find_vendor": "ارائه‌دهنده پیدا نشد"
}

View file

@ -16,13 +16,13 @@
"available_models_header": "Modèles disponibles",
"available_transcription_models": "Modèles de transcription disponibles :",
"available_vendors_header": "Fournisseurs disponibles :",
"azure_api_key_required": "La clé API Azure est requise",
"azure_api_key_required": "la clé API Azure est requise",
"azure_api_version_question": "Entrez la version de l'API Azure (laissez vide pour la valeur par défaut)",
"azure_base_url_question": "URL de base de l'API",
"azure_base_url_required": "L'URL de base Azure est requise",
"azure_credential_failure": "Échec de la création des identifiants Azure",
"azure_base_url_required": "l'URL de base Azure est requise",
"azure_credential_failure": "échec de la création des identifiants Azure",
"azure_deployments_question": "Entrez les noms de vos déploiements Azure (séparés par des virgules)",
"azure_deployments_required": "Au moins un nom de déploiement Azure est requis",
"azure_deployments_required": "au moins un nom de déploiement Azure est requis",
"azure_failed_extract_deployment": "échec de l'extraction du nom de déploiement de la requête",
"azure_model_field_empty": "le champ modèle est vide dans le corps de la requête",
"azure_request_body_nil": "le corps de la requête est nil",
@ -88,12 +88,12 @@
"custom_patterns_label": "Patrons personnalisés",
"custom_patterns_setup_description": "Patrons personnalisés - Définir le répertoire pour vos patrons personnalisés",
"custom_patterns_warning_create_directory": "Avertissement : Impossible de créer le répertoire de modèles personnalisés %s : %v\n",
"db_error_loading_env_file": "Erreur lors du chargement du fichier .env : %s",
"db_error_loading_env_file": "erreur lors du chargement du fichier .env : %w",
"defaults_model_context_length_question": "Saisissez la longueur du contexte du modèle",
"defaults_model_question": "Saisissez l'index ou le nom de votre modèle par défaut",
"defaults_setup_description": "Fournisseur et modèle d'IA par défaut",
"digitalocean_failed_parse_control_plane_url": "Impossible d'analyser l'URL du plan de contrôle DigitalOcean : %w",
"digitalocean_model_list_unavailable": "Liste des modèles DigitalOcean non disponible. Définissez DIGITALOCEAN_TOKEN pour récupérer les modèles depuis le plan de contrôle",
"digitalocean_model_list_unavailable": "liste des modèles DigitalOcean non disponible. Définissez DIGITALOCEAN_TOKEN pour récupérer les modèles depuis le plan de contrôle",
"disable_openai_responses_api": "Désactiver l'API OpenAI Responses (par défaut : false)",
"disable_pattern_variable_replacement": "Désactiver le remplacement des variables de motif",
"enable_web_search_tool": "Activer l'outil de recherche web pour les modèles pris en charge (Anthropic, OpenAI, Gemini)",
@ -260,17 +260,17 @@
"ollama_cannot_parse_url": "Impossible d'analyser l'URL '%s' : %v",
"ollama_chat_request_failed": "Requête de chat échouée : %v",
"ollama_empty_address": "adresse vide",
"ollama_error_building_chat_url": "Erreur lors de la construction de l'URL /chat : %v",
"ollama_error_creating_chat_request": "Erreur lors de la création de la requête /chat : %v",
"ollama_error_building_chat_url": "erreur lors de la construction de l'URL /chat : %v",
"ollama_error_creating_chat_request": "erreur lors de la création de la requête /chat : %v",
"ollama_error_endpoint": "test du point de terminaison",
"ollama_error_getting_chat_body": "Erreur lors de l'obtention du corps /chat : %v",
"ollama_error_marshalling_body": "Erreur lors de l'encodage du corps : %v",
"ollama_error_getting_chat_body": "erreur lors de l'obtention du corps /chat : %v",
"ollama_error_marshalling_body": "erreur lors de l'encodage du corps : %v",
"ollama_error_parse_upstream_response": "Erreur : échec de l'analyse de la réponse en amont",
"ollama_error_prefix": "Erreur : %s",
"ollama_error_reading_body": "Erreur lors de la lecture du corps : %v",
"ollama_error_scanning_body": "Erreur lors de l'analyse du corps : %v",
"ollama_error_unmarshalling_body": "Erreur lors du décodage du corps : %v",
"ollama_error_writing_response": "Erreur lors de l'écriture de la réponse : %v",
"ollama_error_reading_body": "erreur lors de la lecture du corps : %v",
"ollama_error_scanning_body": "erreur lors de l'analyse du corps : %v",
"ollama_error_unmarshalling_body": "erreur lors du décodage du corps : %v",
"ollama_error_writing_response": "erreur lors de l'écriture de la réponse : %v",
"ollama_failed_create_request": "échec de création de la requête",
"ollama_failed_decode_data_url": "échec du décodage de l'URL de données : %v",
"ollama_failed_fetch_image": "échec de la récupération de l'image depuis %s : %s",
@ -381,7 +381,7 @@
"patterns_unique_file_created": "📝 Fichier de patrons uniques créé avec %d patrons\\n",
"patterns_warning_custom_directory": "Avertissement : impossible de lire le répertoire de patrons personnalisé %s : %v\\n",
"patterns_warning_remove_test_folder": "Avertissement : impossible de supprimer le dossier temporaire de test '%s' : %v\\n",
"perplexity_api_key_not_configured": "Clé API non configurée pour %s. Définissez la variable d'environnement %s ou exécutez 'fabric --setup' pour configurer %s",
"perplexity_api_key_not_configured": "clé API non configurée pour %s. Définissez la variable d'environnement %s ou exécutez 'fabric --setup' pour configurer %s",
"perplexity_api_request_failed": "requête API Perplexity échouée : %w",
"perplexity_citations_header": "\n\n**Citations :**\n",
"perplexity_failed_configure": "échec de la configuration de Perplexity : %w",
@ -419,7 +419,7 @@
"server_chat_error": "Erreur : %v",
"server_error_marshaling_response": "erreur de sérialisation de la réponse : %v",
"server_error_writing_response": "erreur d'écriture de la réponse : %v",
"server_invalid_request_format": "Format de requête invalide : %v",
"server_invalid_request_format": "format de requête invalide : %v",
"sessions_creating_new": "Création d'une nouvelle session : %s\n",
"set_debug_level": "Définir le niveau de débogage (0=désactivé, 1=basique, 2=détaillé, 3=trace)",
"set_frequency_penalty": "Définir la pénalité de fréquence",
@ -619,7 +619,7 @@
"vertexai_stream_error": "Erreur : %v",
"wipe_context": "Effacer le contexte",
"wipe_session": "Effacer la session",
"youtube_api_key_required": "Clé API YouTube requise pour les commentaires et métadonnées. Exécutez 'fabric --setup' pour configurer",
"youtube_api_key_required": "clé API YouTube requise pour les commentaires et métadonnées. Exécutez 'fabric --setup' pour configurer",
"youtube_auth_required_bot_detection": "YouTube nécessite une authentification (détection de bot). Utilisez --yt-dlp-args='--cookies-from-browser BROWSER' où BROWSER peut être chrome, firefox, brave, etc.",
"youtube_empty_seconds_string": "chaîne de secondes vide",
"youtube_error_getting_comments": "erreur lors de l'obtention des commentaires : %v",
@ -647,8 +647,10 @@
"youtube_rate_limit_exceeded": "Limite de taux YouTube dépassée. Réessayez plus tard ou utilisez différents arguments yt-dlp comme '--sleep-requests 1' pour ralentir les requêtes.",
"youtube_setup_description": "YouTube - pour récupérer les transcriptions vidéo (via yt-dlp) et les commentaires/métadonnées (via l'API YouTube)",
"youtube_url_help": "Vidéo YouTube ou \"URL\" de liste de lecture pour récupérer la transcription, les commentaires et envoyer au chat ou afficher dans la console et stocker dans le fichier de sortie",
"youtube_url_is_playlist_not_video": "L'URL est une liste de lecture, pas une vidéo",
"youtube_url_is_playlist_not_video": "l'URL est une liste de lecture, pas une vidéo",
"youtube_video_id_title_header": "VideoID : Titre",
"youtube_ytdlp_not_found": "yt-dlp introuvable dans PATH. Veuillez installer yt-dlp pour utiliser la fonctionnalité de transcription YouTube",
"youtube_ytdlp_stderr_error": "Erreur lors de la lecture du stderr de yt-dlp"
"youtube_ytdlp_stderr_error": "erreur lors de la lecture du stderr de yt-dlp",
"plugin_registry_run_setup_select_defaults": "veuillez exécuter 'fabric --setup' et sélectionner le modèle et le fournisseur par défaut",
"plugin_registry_could_not_find_vendor": "fournisseur introuvable"
}

View file

@ -16,13 +16,13 @@
"available_models_header": "Modelli disponibili",
"available_transcription_models": "Modelli di trascrizione disponibili:",
"available_vendors_header": "Fornitori disponibili:",
"azure_api_key_required": "La chiave API di Azure è obbligatoria",
"azure_api_key_required": "la chiave API di Azure è obbligatoria",
"azure_api_version_question": "Inserire la versione dell'API Azure (lasciare vuoto per il valore predefinito)",
"azure_base_url_question": "URL base dell'API",
"azure_base_url_required": "L'URL base di Azure è obbligatorio",
"azure_credential_failure": "Impossibile creare le credenziali Azure",
"azure_base_url_required": "l'URL base di Azure è obbligatorio",
"azure_credential_failure": "impossibile creare le credenziali Azure",
"azure_deployments_question": "Inserire i nomi delle distribuzioni Azure (separati da virgola)",
"azure_deployments_required": "È necessario almeno un nome di distribuzione Azure",
"azure_deployments_required": "è necessario almeno un nome di distribuzione Azure",
"azure_failed_extract_deployment": "impossibile estrarre il nome della distribuzione dalla richiesta",
"azure_model_field_empty": "il campo modello è vuoto nel corpo della richiesta",
"azure_request_body_nil": "il corpo della richiesta è nil",
@ -88,12 +88,12 @@
"custom_patterns_label": "Pattern personalizzati",
"custom_patterns_setup_description": "Pattern personalizzati - Imposta la directory per i tuoi pattern personalizzati",
"custom_patterns_warning_create_directory": "Avviso: Impossibile creare la directory dei modelli personalizzati %s: %v\n",
"db_error_loading_env_file": "Errore nel caricamento del file .env: %s",
"db_error_loading_env_file": "errore nel caricamento del file .env: %w",
"defaults_model_context_length_question": "Inserisci la lunghezza del contesto del modello",
"defaults_model_question": "Inserisci l'indice o il nome del tuo modello predefinito",
"defaults_setup_description": "Fornitore e modello AI predefiniti",
"digitalocean_failed_parse_control_plane_url": "Impossibile analizzare l'URL del piano di controllo DigitalOcean: %w",
"digitalocean_model_list_unavailable": "Lista modelli DigitalOcean non disponibile. Impostare DIGITALOCEAN_TOKEN per recuperare i modelli dal piano di controllo",
"digitalocean_model_list_unavailable": "lista modelli DigitalOcean non disponibile. Impostare DIGITALOCEAN_TOKEN per recuperare i modelli dal piano di controllo",
"disable_openai_responses_api": "Disabilita API OpenAI Responses (predefinito: false)",
"disable_pattern_variable_replacement": "Disabilita sostituzione variabili pattern",
"enable_web_search_tool": "Abilita strumento di ricerca web per modelli supportati (Anthropic, OpenAI, Gemini)",
@ -260,17 +260,17 @@
"ollama_cannot_parse_url": "Impossibile analizzare l'URL '%s': %v",
"ollama_chat_request_failed": "Richiesta di chat fallita: %v",
"ollama_empty_address": "indirizzo vuoto",
"ollama_error_building_chat_url": "Errore nella costruzione dell'URL /chat: %v",
"ollama_error_creating_chat_request": "Errore nella creazione della richiesta /chat: %v",
"ollama_error_building_chat_url": "errore nella costruzione dell'URL /chat: %v",
"ollama_error_creating_chat_request": "errore nella creazione della richiesta /chat: %v",
"ollama_error_endpoint": "test dell'endpoint",
"ollama_error_getting_chat_body": "Errore nell'ottenere il corpo /chat: %v",
"ollama_error_marshalling_body": "Errore nella serializzazione del corpo: %v",
"ollama_error_getting_chat_body": "errore nell'ottenere il corpo /chat: %v",
"ollama_error_marshalling_body": "errore nella serializzazione del corpo: %v",
"ollama_error_parse_upstream_response": "Errore: impossibile analizzare la risposta upstream",
"ollama_error_prefix": "Errore: %s",
"ollama_error_reading_body": "Errore nella lettura del corpo: %v",
"ollama_error_scanning_body": "Errore nella scansione del corpo: %v",
"ollama_error_unmarshalling_body": "Errore nella deserializzazione del corpo: %v",
"ollama_error_writing_response": "Errore nella scrittura della risposta: %v",
"ollama_error_reading_body": "errore nella lettura del corpo: %v",
"ollama_error_scanning_body": "errore nella scansione del corpo: %v",
"ollama_error_unmarshalling_body": "errore nella deserializzazione del corpo: %v",
"ollama_error_writing_response": "errore nella scrittura della risposta: %v",
"ollama_failed_create_request": "impossibile creare la richiesta",
"ollama_failed_decode_data_url": "decodifica dell'URL dati fallita: %v",
"ollama_failed_fetch_image": "recupero dell'immagine da %s fallito: %s",
@ -381,7 +381,7 @@
"patterns_unique_file_created": "📝 File dei pattern univoci creato con %d pattern\\n",
"patterns_warning_custom_directory": "Avviso: impossibile leggere la directory dei pattern personalizzata %s: %v\\n",
"patterns_warning_remove_test_folder": "Avviso: impossibile rimuovere la cartella temporanea di test '%s': %v\\n",
"perplexity_api_key_not_configured": "Chiave API non configurata per %s. Imposta la variabile d'ambiente %s o esegui 'fabric --setup' per configurare %s",
"perplexity_api_key_not_configured": "chiave API non configurata per %s. Imposta la variabile d'ambiente %s o esegui 'fabric --setup' per configurare %s",
"perplexity_api_request_failed": "richiesta API Perplexity fallita: %w",
"perplexity_citations_header": "\n\n**Citazioni:**\n",
"perplexity_failed_configure": "configurazione di Perplexity fallita: %w",
@ -419,7 +419,7 @@
"server_chat_error": "Errore: %v",
"server_error_marshaling_response": "errore nella serializzazione della risposta: %v",
"server_error_writing_response": "errore nella scrittura della risposta: %v",
"server_invalid_request_format": "Formato della richiesta non valido: %v",
"server_invalid_request_format": "formato della richiesta non valido: %v",
"sessions_creating_new": "Creazione nuova sessione: %s\n",
"set_debug_level": "Imposta livello di debug (0=spento, 1=base, 2=dettagliato, 3=traccia)",
"set_frequency_penalty": "Imposta penalità di frequenza",
@ -619,7 +619,7 @@
"vertexai_stream_error": "Errore: %v",
"wipe_context": "Cancella contesto",
"wipe_session": "Cancella sessione",
"youtube_api_key_required": "Chiave API YouTube richiesta per commenti e metadati. Eseguire 'fabric --setup' per configurare",
"youtube_api_key_required": "chiave API YouTube richiesta per commenti e metadati. Eseguire 'fabric --setup' per configurare",
"youtube_auth_required_bot_detection": "YouTube richiede autenticazione (rilevamento bot). Usa --yt-dlp-args='--cookies-from-browser BROWSER' dove BROWSER può essere chrome, firefox, brave, ecc.",
"youtube_empty_seconds_string": "stringa di secondi vuota",
"youtube_error_getting_comments": "errore nell'ottenere i commenti: %v",
@ -647,8 +647,10 @@
"youtube_rate_limit_exceeded": "Limite di richieste YouTube superato. Riprova più tardi o usa argomenti yt-dlp diversi come '--sleep-requests 1' per rallentare le richieste.",
"youtube_setup_description": "YouTube - per ottenere trascrizioni video (tramite yt-dlp) e commenti/metadati (tramite API YouTube)",
"youtube_url_help": "Video YouTube o \"URL\" della playlist per ottenere trascrizioni, commenti e inviarli alla chat o stamparli sulla console e memorizzarli nel file di output",
"youtube_url_is_playlist_not_video": "L'URL è una playlist, non un video",
"youtube_url_is_playlist_not_video": "l'URL è una playlist, non un video",
"youtube_video_id_title_header": "VideoID: Titolo",
"youtube_ytdlp_not_found": "yt-dlp non trovato in PATH. Per favore installa yt-dlp per usare la funzionalità di trascrizione YouTube",
"youtube_ytdlp_stderr_error": "Errore durante la lettura dello stderr di yt-dlp"
"youtube_ytdlp_stderr_error": "errore durante la lettura dello stderr di yt-dlp",
"plugin_registry_run_setup_select_defaults": "eseguire 'fabric --setup' e selezionare modello e fornitore predefiniti",
"plugin_registry_could_not_find_vendor": "impossibile trovare il fornitore"
}

View file

@ -20,7 +20,7 @@
"azure_api_version_question": "Azure APIバージョンを入力してくださいデフォルトの場合は空白のまま",
"azure_base_url_question": "API ベース URL",
"azure_base_url_required": "Azure ベースURLが必要です",
"azure_credential_failure": "Azure 認証情報の作成に失敗しました",
"azure_credential_failure": "Azure資格情報の作成に失敗しました",
"azure_deployments_question": "Azureデプロイメント名を入力してくださいカンマ区切り",
"azure_deployments_required": "少なくとも1つのAzureデプロイメント名が必要です",
"azure_failed_extract_deployment": "リクエストからデプロイメント名を抽出できませんでした",
@ -88,7 +88,7 @@
"custom_patterns_label": "カスタムパターン",
"custom_patterns_setup_description": "カスタムパターン - カスタムパターン用のディレクトリを設定",
"custom_patterns_warning_create_directory": "警告: カスタムパターンディレクトリ%sを作成できませんでした: %v\n",
"db_error_loading_env_file": ".envファイルの読み込みエラー: %s",
"db_error_loading_env_file": ".envファイルの読み込みエラー: %w",
"defaults_model_context_length_question": "モデルのコンテキスト長を入力してください",
"defaults_model_question": "デフォルトモデルのインデックスまたは名前を入力してください",
"defaults_setup_description": "デフォルトのAIプロバイダーとモデル",
@ -650,5 +650,7 @@
"youtube_url_is_playlist_not_video": "URLはプレイリストであり、動画ではありません",
"youtube_video_id_title_header": "動画ID: タイトル",
"youtube_ytdlp_not_found": "PATHにyt-dlpが見つかりません。YouTubeトランスクリプト機能を使用するにはyt-dlpをインストールしてください",
"youtube_ytdlp_stderr_error": "yt-dlp stderrの読み取りエラー"
"youtube_ytdlp_stderr_error": "yt-dlp stderrの読み取りエラー",
"plugin_registry_run_setup_select_defaults": "'fabric --setup' を実行して、デフォルトのモデルとベンダーを選択してください",
"plugin_registry_could_not_find_vendor": "ベンダーが見つかりません"
}

View file

@ -16,13 +16,13 @@
"available_models_header": "Modelos disponíveis",
"available_transcription_models": "Modelos de transcrição disponíveis:",
"available_vendors_header": "Fornecedores disponíveis:",
"azure_api_key_required": "A chave API do Azure é obrigatória",
"azure_api_key_required": "a chave API do Azure é obrigatória",
"azure_api_version_question": "Insira a versão da API do Azure (deixe em branco para o padrão)",
"azure_base_url_question": "URL base da API",
"azure_base_url_required": "A URL base do Azure é obrigatória",
"azure_credential_failure": "Falha ao criar a credencial do Azure",
"azure_base_url_required": "a URL base do Azure é obrigatória",
"azure_credential_failure": "falha ao criar credencial do Azure",
"azure_deployments_question": "Insira os nomes das implantações do Azure (separados por vírgula)",
"azure_deployments_required": "Pelo menos um nome de implantação do Azure é obrigatório",
"azure_deployments_required": "pelo menos um nome de implantação do Azure é obrigatório",
"azure_failed_extract_deployment": "falha ao extrair o nome da implantação da requisição",
"azure_model_field_empty": "o campo de modelo está vazio no corpo da requisição",
"azure_request_body_nil": "o corpo da requisição é nil",
@ -88,12 +88,12 @@
"custom_patterns_label": "Padrões personalizados",
"custom_patterns_setup_description": "Padrões personalizados - Definir diretório para seus padrões personalizados",
"custom_patterns_warning_create_directory": "Aviso: Não foi possível criar o diretório de padrões personalizados %s: %v\n",
"db_error_loading_env_file": "Erro ao carregar o arquivo .env: %s",
"db_error_loading_env_file": "erro ao carregar o arquivo .env: %w",
"defaults_model_context_length_question": "Informe o comprimento do contexto do modelo",
"defaults_model_question": "Informe o índice ou o nome do seu modelo padrão",
"defaults_setup_description": "Provedor e modelo de IA padrão",
"digitalocean_failed_parse_control_plane_url": "Falha ao analisar a URL do plano de controle do DigitalOcean: %w",
"digitalocean_model_list_unavailable": "Lista de modelos do DigitalOcean indisponível. Defina DIGITALOCEAN_TOKEN para buscar modelos do plano de controle",
"digitalocean_model_list_unavailable": "lista de modelos do DigitalOcean indisponível. Defina DIGITALOCEAN_TOKEN para buscar modelos do plano de controle",
"disable_openai_responses_api": "Desabilitar API OpenAI Responses (padrão: false)",
"disable_pattern_variable_replacement": "Desabilitar substituição de variáveis de padrão",
"enable_web_search_tool": "Habilitar ferramenta de busca web para modelos suportados (Anthropic, OpenAI, Gemini)",
@ -260,17 +260,17 @@
"ollama_cannot_parse_url": "Não é possível analisar a URL '%s': %v",
"ollama_chat_request_failed": "Requisição de chat falhou: %v",
"ollama_empty_address": "endereço vazio",
"ollama_error_building_chat_url": "Erro ao construir a URL /chat: %v",
"ollama_error_creating_chat_request": "Erro ao criar a requisição /chat: %v",
"ollama_error_building_chat_url": "erro ao construir a URL /chat: %v",
"ollama_error_creating_chat_request": "erro ao criar a requisição /chat: %v",
"ollama_error_endpoint": "testando endpoint",
"ollama_error_getting_chat_body": "Erro ao obter o corpo /chat: %v",
"ollama_error_marshalling_body": "Erro ao serializar o corpo: %v",
"ollama_error_getting_chat_body": "erro ao obter o corpo /chat: %v",
"ollama_error_marshalling_body": "erro ao serializar o corpo: %v",
"ollama_error_parse_upstream_response": "Erro: falha ao analisar resposta upstream",
"ollama_error_prefix": "Erro: %s",
"ollama_error_reading_body": "Erro ao ler o corpo: %v",
"ollama_error_scanning_body": "Erro ao escanear o corpo: %v",
"ollama_error_unmarshalling_body": "Erro ao desserializar o corpo: %v",
"ollama_error_writing_response": "Erro ao escrever resposta: %v",
"ollama_error_reading_body": "erro ao ler o corpo: %v",
"ollama_error_scanning_body": "erro ao escanear o corpo: %v",
"ollama_error_unmarshalling_body": "erro ao desserializar o corpo: %v",
"ollama_error_writing_response": "erro ao escrever resposta: %v",
"ollama_failed_create_request": "falha ao criar a requisição",
"ollama_failed_decode_data_url": "falha ao decodificar URL de dados: %v",
"ollama_failed_fetch_image": "falha ao buscar imagem de %s: %s",
@ -381,7 +381,7 @@
"patterns_unique_file_created": "📝 Arquivo de padrões únicos criado com %d padrões\\n",
"patterns_warning_custom_directory": "Aviso: não foi possível ler o diretório de padrões personalizado %s: %v\\n",
"patterns_warning_remove_test_folder": "Aviso: não foi possível remover a pasta temporária de teste '%s': %v\\n",
"perplexity_api_key_not_configured": "Chave API não configurada para %s. Defina a variável de ambiente %s ou execute 'fabric --setup' para configurar %s",
"perplexity_api_key_not_configured": "chave API não configurada para %s. Defina a variável de ambiente %s ou execute 'fabric --setup' para configurar %s",
"perplexity_api_request_failed": "requisição à API Perplexity falhou: %w",
"perplexity_citations_header": "\n\n**Citações:**\n",
"perplexity_failed_configure": "falha ao configurar Perplexity: %w",
@ -419,7 +419,7 @@
"server_chat_error": "Erro: %v",
"server_error_marshaling_response": "erro ao serializar resposta: %v",
"server_error_writing_response": "erro ao escrever resposta: %v",
"server_invalid_request_format": "Formato de solicitação inválido: %v",
"server_invalid_request_format": "formato de solicitação inválido: %v",
"sessions_creating_new": "Criando nova sessão: %s\n",
"set_debug_level": "Definir nível de debug (0=desligado, 1=básico, 2=detalhado, 3=rastreamento)",
"set_frequency_penalty": "Definir penalidade de frequência",
@ -619,7 +619,7 @@
"vertexai_stream_error": "Erro: %v",
"wipe_context": "Limpar contexto",
"wipe_session": "Limpar sessão",
"youtube_api_key_required": "Chave de API do YouTube necessária para comentários e metadados. Execute 'fabric --setup' para configurar",
"youtube_api_key_required": "chave de API do YouTube necessária para comentários e metadados. Execute 'fabric --setup' para configurar",
"youtube_auth_required_bot_detection": "YouTube requer autenticação (detecção de bot). Use --yt-dlp-args='--cookies-from-browser BROWSER' onde BROWSER pode ser chrome, firefox, brave, etc.",
"youtube_empty_seconds_string": "string de segundos vazia",
"youtube_error_getting_comments": "erro ao obter comentários: %v",
@ -647,8 +647,10 @@
"youtube_rate_limit_exceeded": "Limite de taxa do YouTube excedido. Tente novamente mais tarde ou use argumentos diferentes do yt-dlp como '--sleep-requests 1' para desacelerar as requisições.",
"youtube_setup_description": "YouTube - para obter transcrições de vídeo (via yt-dlp) e comentários/metadados (via API do YouTube)",
"youtube_url_help": "Vídeo do YouTube ou URL da playlist para obter transcrição, comentários e enviar ao chat ou imprimir no console e armazenar no arquivo de saída",
"youtube_url_is_playlist_not_video": "A URL é uma playlist, não um vídeo",
"youtube_url_is_playlist_not_video": "a URL é uma playlist, não um vídeo",
"youtube_video_id_title_header": "VideoID: Título",
"youtube_ytdlp_not_found": "yt-dlp não encontrado no PATH. Por favor instale o yt-dlp para usar a funcionalidade de transcrição do YouTube",
"youtube_ytdlp_stderr_error": "Erro ao ler stderr do yt-dlp"
"youtube_ytdlp_stderr_error": "erro ao ler stderr do yt-dlp",
"plugin_registry_run_setup_select_defaults": "execute 'fabric --setup' e selecione o modelo e fornecedor padrão",
"plugin_registry_could_not_find_vendor": "não foi possível encontrar o fornecedor"
}

View file

@ -16,13 +16,13 @@
"available_models_header": "Modelos disponíveis",
"available_transcription_models": "Modelos de transcrição disponíveis:",
"available_vendors_header": "Fornecedores disponíveis:",
"azure_api_key_required": "A chave API do Azure é obrigatória",
"azure_api_key_required": "a chave API do Azure é obrigatória",
"azure_api_version_question": "Introduza a versão da API do Azure (deixe vazio para o padrão)",
"azure_base_url_question": "URL base da API",
"azure_base_url_required": "O URL base do Azure é obrigatório",
"azure_credential_failure": "Falha ao criar a credencial do Azure",
"azure_base_url_required": "o URL base do Azure é obrigatório",
"azure_credential_failure": "falha ao criar credencial do Azure",
"azure_deployments_question": "Introduza os nomes das implementações do Azure (separados por vírgula)",
"azure_deployments_required": "É necessário pelo menos um nome de implementação do Azure",
"azure_deployments_required": "é necessário pelo menos um nome de implementação do Azure",
"azure_failed_extract_deployment": "falha ao extrair o nome da implementação do pedido",
"azure_model_field_empty": "o campo de modelo está vazio no corpo do pedido",
"azure_request_body_nil": "o corpo do pedido é nil",
@ -88,12 +88,12 @@
"custom_patterns_label": "Padrões personalizados",
"custom_patterns_setup_description": "Padrões personalizados - Definir diretório para os seus padrões personalizados",
"custom_patterns_warning_create_directory": "Aviso: Não foi possível criar o diretório de padrões personalizados %s: %v\n",
"db_error_loading_env_file": "Erro ao carregar o ficheiro .env: %s",
"db_error_loading_env_file": "erro ao carregar o ficheiro .env: %w",
"defaults_model_context_length_question": "Indique o comprimento do contexto do modelo",
"defaults_model_question": "Indique o índice ou o nome do seu modelo padrão",
"defaults_setup_description": "Fornecedor e modelo de IA padrão",
"digitalocean_failed_parse_control_plane_url": "Falha ao analisar o URL do plano de controlo do DigitalOcean: %w",
"digitalocean_model_list_unavailable": "Lista de modelos do DigitalOcean indisponível. Defina DIGITALOCEAN_TOKEN para obter modelos do plano de controlo",
"digitalocean_model_list_unavailable": "lista de modelos do DigitalOcean indisponível. Defina DIGITALOCEAN_TOKEN para obter modelos do plano de controlo",
"disable_openai_responses_api": "Desabilitar API OpenAI Responses (por omissão: false)",
"disable_pattern_variable_replacement": "Desabilitar substituição de variáveis de padrão",
"enable_web_search_tool": "Habilitar ferramenta de pesquisa web para modelos suportados (Anthropic, OpenAI, Gemini)",
@ -260,17 +260,17 @@
"ollama_cannot_parse_url": "Não é possível analisar o URL '%s': %v",
"ollama_chat_request_failed": "Pedido de chat falhou: %v",
"ollama_empty_address": "endereço vazio",
"ollama_error_building_chat_url": "Erro ao construir a URL /chat: %v",
"ollama_error_creating_chat_request": "Erro ao criar o pedido /chat: %v",
"ollama_error_building_chat_url": "erro ao construir a URL /chat: %v",
"ollama_error_creating_chat_request": "erro ao criar o pedido /chat: %v",
"ollama_error_endpoint": "a testar endpoint",
"ollama_error_getting_chat_body": "Erro ao obter o corpo /chat: %v",
"ollama_error_marshalling_body": "Erro ao serializar o corpo: %v",
"ollama_error_getting_chat_body": "erro ao obter o corpo /chat: %v",
"ollama_error_marshalling_body": "erro ao serializar o corpo: %v",
"ollama_error_parse_upstream_response": "Erro: falha ao analisar resposta upstream",
"ollama_error_prefix": "Erro: %s",
"ollama_error_reading_body": "Erro ao ler o corpo: %v",
"ollama_error_scanning_body": "Erro ao analisar o corpo: %v",
"ollama_error_unmarshalling_body": "Erro ao desserializar o corpo: %v",
"ollama_error_writing_response": "Erro ao escrever resposta: %v",
"ollama_error_reading_body": "erro ao ler o corpo: %v",
"ollama_error_scanning_body": "erro ao analisar o corpo: %v",
"ollama_error_unmarshalling_body": "erro ao desserializar o corpo: %v",
"ollama_error_writing_response": "erro ao escrever resposta: %v",
"ollama_failed_create_request": "falha ao criar o pedido",
"ollama_failed_decode_data_url": "falha ao descodificar URL de dados: %v",
"ollama_failed_fetch_image": "falha ao obter imagem de %s: %s",
@ -381,7 +381,7 @@
"patterns_unique_file_created": "📝 Ficheiro de padrões únicos criado com %d padrões\\n",
"patterns_warning_custom_directory": "Aviso: não foi possível ler o directório de padrões personalizado %s: %v\\n",
"patterns_warning_remove_test_folder": "Aviso: não foi possível remover a pasta temporária de teste '%s': %v\\n",
"perplexity_api_key_not_configured": "Chave API não configurada para %s. Defina a variável de ambiente %s ou execute 'fabric --setup' para configurar %s",
"perplexity_api_key_not_configured": "chave API não configurada para %s. Defina a variável de ambiente %s ou execute 'fabric --setup' para configurar %s",
"perplexity_api_request_failed": "pedido à API Perplexity falhou: %w",
"perplexity_citations_header": "\n\n**Citações:**\n",
"perplexity_failed_configure": "falha ao configurar Perplexity: %w",
@ -419,7 +419,7 @@
"server_chat_error": "Erro: %v",
"server_error_marshaling_response": "erro ao serializar resposta: %v",
"server_error_writing_response": "erro ao escrever resposta: %v",
"server_invalid_request_format": "Formato de pedido inválido: %v",
"server_invalid_request_format": "formato de pedido inválido: %v",
"sessions_creating_new": "A criar nova sessão: %s\n",
"set_debug_level": "Definir nível de debug (0=desligado, 1=básico, 2=detalhado, 3=rastreio)",
"set_frequency_penalty": "Definir penalidade de frequência",
@ -619,7 +619,7 @@
"vertexai_stream_error": "Erro: %v",
"wipe_context": "Limpar contexto",
"wipe_session": "Limpar sessão",
"youtube_api_key_required": "Chave de API do YouTube necessária para comentários e metadados. Execute 'fabric --setup' para configurar",
"youtube_api_key_required": "chave de API do YouTube necessária para comentários e metadados. Execute 'fabric --setup' para configurar",
"youtube_auth_required_bot_detection": "YouTube requer autenticação (deteção de bot). Use --yt-dlp-args='--cookies-from-browser BROWSER' onde BROWSER pode ser chrome, firefox, brave, etc.",
"youtube_empty_seconds_string": "cadeia de segundos vazia",
"youtube_error_getting_comments": "erro ao obter comentários: %v",
@ -647,8 +647,10 @@
"youtube_rate_limit_exceeded": "Limite de taxa do YouTube excedido. Tente novamente mais tarde ou utilize argumentos diferentes do yt-dlp como '--sleep-requests 1' para desacelerar os pedidos.",
"youtube_setup_description": "YouTube - para obter transcrições de vídeo (via yt-dlp) e comentários/metadados (via API do YouTube)",
"youtube_url_help": "Vídeo do YouTube ou \"URL\" de playlist para obter transcrição, comentários e enviar ao chat ou imprimir na consola e armazenar no ficheiro de saída",
"youtube_url_is_playlist_not_video": "O URL é uma lista de reprodução, não um vídeo",
"youtube_url_is_playlist_not_video": "o URL é uma lista de reprodução, não um vídeo",
"youtube_video_id_title_header": "VideoID: Título",
"youtube_ytdlp_not_found": "yt-dlp não encontrado no PATH. Por favor instale o yt-dlp para usar a funcionalidade de transcrição do YouTube",
"youtube_ytdlp_stderr_error": "Erro ao ler stderr do yt-dlp"
"youtube_ytdlp_stderr_error": "erro ao ler stderr do yt-dlp",
"plugin_registry_run_setup_select_defaults": "execute 'fabric --setup' e selecione o modelo e fornecedor padrão",
"plugin_registry_could_not_find_vendor": "não foi possível encontrar o fornecedor"
}

View file

@ -20,7 +20,7 @@
"azure_api_version_question": "请输入 Azure API 版本(留空使用默认值)",
"azure_base_url_question": "API 基础 URL",
"azure_base_url_required": "Azure 基础 URL 是必需的",
"azure_credential_failure": "创建 Azure 凭据失败",
"azure_credential_failure": "Azure凭据创建失败",
"azure_deployments_question": "请输入您的 Azure 部署名称(用逗号分隔)",
"azure_deployments_required": "至少需要一个 Azure 部署名称",
"azure_failed_extract_deployment": "无法从请求中提取部署名称",
@ -88,7 +88,7 @@
"custom_patterns_label": "自定义模式",
"custom_patterns_setup_description": "自定义模式 - 设置您的自定义模式目录",
"custom_patterns_warning_create_directory": "警告:无法创建自定义模式目录%s%v\n",
"db_error_loading_env_file": "加载.env文件错误%s",
"db_error_loading_env_file": "加载.env文件错误%w",
"defaults_model_context_length_question": "请输入模型上下文长度",
"defaults_model_question": "请输入您的默认模型的索引或名称",
"defaults_setup_description": "默认 AI 提供商和模型",
@ -650,5 +650,7 @@
"youtube_url_is_playlist_not_video": "URL 是播放列表,而不是视频",
"youtube_video_id_title_header": "视频ID: 标题",
"youtube_ytdlp_not_found": "在 PATH 中未找到 yt-dlp。请安装 yt-dlp 以使用 YouTube 转录功能",
"youtube_ytdlp_stderr_error": "读取 yt-dlp stderr 时出错"
"youtube_ytdlp_stderr_error": "读取 yt-dlp stderr 时出错",
"plugin_registry_run_setup_select_defaults": "请运行 'fabric --setup' 并选择默认模型和供应商",
"plugin_registry_could_not_find_vendor": "找不到供应商"
}

View file

@ -1,7 +1,7 @@
package azure
import (
"fmt"
"errors"
"strings"
"github.com/danielmiessler/fabric/internal/i18n"
@ -35,17 +35,17 @@ type Client struct {
func (oi *Client) configure() error {
oi.apiDeployments = azurecommon.ParseDeployments(oi.ApiDeployments.Value)
if len(oi.apiDeployments) == 0 {
return fmt.Errorf("%s", i18n.T("azure_deployments_required"))
return errors.New(i18n.T("azure_deployments_required"))
}
apiKey := strings.TrimSpace(oi.ApiKey.Value)
if apiKey == "" {
return fmt.Errorf("%s", i18n.T("azure_api_key_required"))
return errors.New(i18n.T("azure_api_key_required"))
}
baseURL := strings.TrimSpace(oi.ApiBaseURL.Value)
if baseURL == "" {
return fmt.Errorf("%s", i18n.T("azure_base_url_required"))
return errors.New(i18n.T("azure_base_url_required"))
}
apiVersion := strings.TrimSpace(oi.ApiVersion.Value)

View file

@ -1,6 +1,7 @@
package azure_entra
import (
"errors"
"fmt"
"strings"
@ -39,12 +40,12 @@ type Client struct {
func (c *Client) configure() error {
c.apiDeployments = azurecommon.ParseDeployments(c.ApiDeployments.Value)
if len(c.apiDeployments) == 0 {
return fmt.Errorf("%s", i18n.T("azure_deployments_required"))
return errors.New(i18n.T("azure_deployments_required"))
}
baseURL := strings.TrimSpace(c.ApiBaseURL.Value)
if baseURL == "" {
return fmt.Errorf("%s", i18n.T("azure_base_url_required"))
return errors.New(i18n.T("azure_base_url_required"))
}
apiVersion := strings.TrimSpace(c.ApiVersion.Value)

View file

@ -3,6 +3,7 @@ package azurecommon
import (
"bytes"
"encoding/json"
"errors"
"fmt"
"io"
"net/http"
@ -78,7 +79,7 @@ func AzureDeploymentMiddleware(req *http.Request, next option.MiddlewareNext) (*
// and restores the body for subsequent use.
func ExtractDeploymentFromBody(req *http.Request) (string, error) {
if req.Body == nil {
return "", fmt.Errorf("%s", i18n.T("azure_request_body_nil"))
return "", errors.New(i18n.T("azure_request_body_nil"))
}
bodyBytes, err := io.ReadAll(req.Body)
@ -96,7 +97,7 @@ func ExtractDeploymentFromBody(req *http.Request) (string, error) {
}
if payload.Model == "" {
return "", fmt.Errorf("%s", i18n.T("azure_model_field_empty"))
return "", errors.New(i18n.T("azure_model_field_empty"))
}
return payload.Model, nil

View file

@ -16,6 +16,7 @@ import (
"bytes"
"context"
"encoding/json"
"errors"
"fmt"
"io"
"net/http"
@ -107,7 +108,7 @@ type Client struct {
// configure initializes the client with OAuth2 configuration.
func (c *Client) configure() error {
if c.TenantID.Value == "" || c.ClientID.Value == "" {
return fmt.Errorf("%s", i18n.T("copilot_tenant_client_id_required"))
return errors.New(i18n.T("copilot_tenant_client_id_required"))
}
// Build OAuth2 configuration

View file

@ -3,6 +3,7 @@ package digitalocean
import (
"context"
"encoding/json"
"errors"
"fmt"
"io"
"net/http"
@ -63,7 +64,7 @@ func (c *Client) ListModels() ([]string, error) {
err,
)
}
return nil, fmt.Errorf("%s", i18n.T("digitalocean_model_list_unavailable"))
return nil, errors.New(i18n.T("digitalocean_model_list_unavailable"))
}
return c.fetchModelsFromControlPlane(context.Background())
}

View file

@ -5,6 +5,7 @@ import (
"bytes"
"context"
"encoding/json"
"errors"
"fmt"
"io"
"net/http"
@ -244,18 +245,18 @@ func (c *Client) Send(ctx context.Context, msgs []*chat.ChatCompletionMessage, o
var choices []any
var ok bool
if choices, ok = result["choices"].([]any); !ok || len(choices) == 0 {
err = fmt.Errorf("%s", i18n.T("lmstudio_invalid_response_missing_choices"))
err = errors.New(i18n.T("lmstudio_invalid_response_missing_choices"))
return
}
var message map[string]any
if message, ok = choices[0].(map[string]any)["message"].(map[string]any); !ok {
err = fmt.Errorf("%s", i18n.T("lmstudio_invalid_response_missing_message"))
err = errors.New(i18n.T("lmstudio_invalid_response_missing_message"))
return
}
if content, ok = message["content"].(string); !ok {
err = fmt.Errorf("%s", i18n.T("lmstudio_invalid_response_missing_content"))
err = errors.New(i18n.T("lmstudio_invalid_response_missing_content"))
return
}
@ -307,12 +308,12 @@ func (c *Client) Complete(ctx context.Context, prompt string, opts *domain.ChatO
var choices []any
var ok bool
if choices, ok = result["choices"].([]any); !ok || len(choices) == 0 {
err = fmt.Errorf("%s", i18n.T("lmstudio_invalid_response_missing_choices"))
err = errors.New(i18n.T("lmstudio_invalid_response_missing_choices"))
return
}
if text, ok = choices[0].(map[string]any)["text"].(string); !ok {
err = fmt.Errorf("%s", i18n.T("lmstudio_invalid_response_missing_text"))
err = errors.New(i18n.T("lmstudio_invalid_response_missing_text"))
return
}
@ -367,7 +368,7 @@ func (c *Client) GetEmbeddings(ctx context.Context, input string, opts *domain.C
}
if len(result.Data) == 0 {
err = fmt.Errorf("%s", i18n.T("lmstudio_no_embeddings_returned"))
err = errors.New(i18n.T("lmstudio_no_embeddings_returned"))
return
}

View file

@ -3,6 +3,7 @@ package ollama
import (
"context"
"encoding/base64"
"errors"
"fmt"
"io"
"net/http"
@ -226,7 +227,7 @@ func (o *Client) loadImageBytes(ctx context.Context, imageURL string) (ret []byt
if strings.HasPrefix(imageURL, "data:") {
parts := strings.SplitN(imageURL, ",", 2)
if len(parts) != 2 {
err = fmt.Errorf("%s", i18n.T("ollama_invalid_data_url_format"))
err = errors.New(i18n.T("ollama_invalid_data_url_format"))
return
}
if ret, err = base64.StdEncoding.DecodeString(parts[1]); err != nil {

View file

@ -3,6 +3,7 @@ package openai
import (
"bytes"
"context"
"errors"
"fmt"
"os"
"os/exec"
@ -141,7 +142,7 @@ func (o *Client) TranscribeFile(ctx context.Context, filePath, model string, spl
// It returns the list of chunk file paths and a cleanup function.
func splitAudioFile(src, ext string, maxSize int64) (files []string, cleanup func(), err error) {
if _, err = exec.LookPath("ffmpeg"); err != nil {
return nil, nil, fmt.Errorf("%s", i18n.T("openai_audio_ffmpeg_not_found_install"))
return nil, nil, errors.New(i18n.T("openai_audio_ffmpeg_not_found_install"))
}
var dir string
@ -184,7 +185,7 @@ func splitAudioFile(src, ext string, maxSize int64) (files []string, cleanup fun
_ = os.Remove(f)
}
if segmentTime <= 1 {
return nil, cleanup, fmt.Errorf("%s", i18n.T("openai_audio_unable_to_split_acceptable_size_chunks"))
return nil, cleanup, errors.New(i18n.T("openai_audio_unable_to_split_acceptable_size_chunks"))
}
segmentTime /= 2
}

View file

@ -3,6 +3,7 @@ package ai
import (
"bytes"
"context"
"errors"
"fmt"
"sort"
"strings"
@ -75,7 +76,7 @@ func (o *VendorsManager) FindByName(name string) Vendor {
func (o *VendorsManager) readModels() (err error) {
if len(o.Vendors) == 0 {
err = fmt.Errorf("%s", i18n.T("vendors_no_ai_vendors_configured_read_models"))
err = errors.New(i18n.T("vendors_no_ai_vendors_configured_read_models"))
return
}

View file

@ -2,6 +2,7 @@ package strategy
import (
"encoding/json"
"errors"
"fmt"
"io/fs"
"os"
@ -218,7 +219,7 @@ func LoadStrategy(filename string) (*Strategy, error) {
// ListStrategies prints available strategies
func (sm *StrategiesManager) ListStrategies(shellCompleteList bool) error {
if len(sm.Strategies) == 0 {
return fmt.Errorf("%s", i18n.T("strategies_none_found"))
return errors.New(i18n.T("strategies_none_found"))
}
if !shellCompleteList {
fmt.Print(i18n.T("strategies_available_header"), "\n\n")

View file

@ -2,6 +2,7 @@
package template
import (
"errors"
"fmt"
"strconv"
"time"
@ -104,7 +105,7 @@ func (p *DateTimePlugin) handleRelative(now time.Time, value string) (string, er
debugf("DateTime: handling relative time value=%q", value)
if value == "" {
return "", fmt.Errorf("%s", i18n.T("template_datetime_error_relative_requires_value"))
return "", errors.New(i18n.T("template_datetime_error_relative_requires_value"))
}
// Try standard duration first (hours, minutes)
@ -116,7 +117,7 @@ func (p *DateTimePlugin) handleRelative(now time.Time, value string) (string, er
// Handle date units
if len(value) < 2 {
return "", fmt.Errorf("%s", i18n.T("template_datetime_error_invalid_relative_format"))
return "", errors.New(i18n.T("template_datetime_error_invalid_relative_format"))
}
unit := value[len(value)-1:]

View file

@ -3,6 +3,7 @@ package template
import (
"bytes"
"context"
"errors"
"fmt"
"os"
"os/exec"
@ -48,7 +49,7 @@ func (e *ExtensionExecutor) Execute(name, operation, value string) (string, erro
// Split the command string into command and arguments
cmdParts := strings.Fields(cmdStr)
if len(cmdParts) < 1 {
return "", fmt.Errorf("%s", i18n.T("extension_empty_command"))
return "", errors.New(i18n.T("extension_empty_command"))
}
// Create command with the Executable and formatted arguments
@ -128,7 +129,7 @@ func (e *ExtensionExecutor) executeWithFile(cmd *exec.Cmd, ext *ExtensionDefinit
fileConfig := ext.GetFileConfig()
if fileConfig == nil {
return "", fmt.Errorf("%s", i18n.T("extension_no_file_config"))
return "", errors.New(i18n.T("extension_no_file_config"))
}
// Handle path from stdout case
@ -141,7 +142,7 @@ func (e *ExtensionExecutor) executeWithFile(cmd *exec.Cmd, ext *ExtensionDefinit
outputFile, _ := fileConfig["output_file"].(string)
if outputFile == "" {
return "", fmt.Errorf("%s", i18n.T("extension_no_output_file"))
return "", errors.New(i18n.T("extension_no_output_file"))
}
// Set working directory if specified

View file

@ -1,6 +1,7 @@
package template
import (
"errors"
"fmt"
"os"
"path/filepath"
@ -30,7 +31,7 @@ func NewExtensionManager(configDir string) *ExtensionManager {
// ListExtensions handles the listextensions flag action
func (em *ExtensionManager) ListExtensions() error {
if em.registry == nil || em.registry.registry.Extensions == nil {
return fmt.Errorf("%s", i18n.T("extension_registry_not_initialized"))
return errors.New(i18n.T("extension_registry_not_initialized"))
}
for name, entry := range em.registry.registry.Extensions {

View file

@ -3,6 +3,7 @@ package template
import (
"crypto/sha256"
"encoding/hex"
"errors"
"fmt"
"io"
"os"
@ -116,7 +117,7 @@ func (r *ExtensionRegistry) Register(configPath string) error {
// Validate extension name
if ext.Name == "" {
return fmt.Errorf("%s", i18n.T("extension_name_empty"))
return errors.New(i18n.T("extension_name_empty"))
}
if strings.Contains(ext.Name, " ") {
@ -159,13 +160,13 @@ func (r *ExtensionRegistry) Register(configPath string) error {
func (r *ExtensionRegistry) validateExtensionDefinition(ext *ExtensionDefinition) error {
// Validate required fields
if ext.Name == "" {
return fmt.Errorf("%s", i18n.T("extension_name_required"))
return errors.New(i18n.T("extension_name_required"))
}
if ext.Executable == "" {
return fmt.Errorf("%s", i18n.T("extension_executable_required"))
return errors.New(i18n.T("extension_executable_required"))
}
if ext.Type == "" {
return fmt.Errorf("%s", i18n.T("extension_type_required"))
return errors.New(i18n.T("extension_type_required"))
}
// Validate timeout format
@ -177,7 +178,7 @@ func (r *ExtensionRegistry) validateExtensionDefinition(ext *ExtensionDefinition
// Validate operations
if len(ext.Operations) == 0 {
return fmt.Errorf("%s", i18n.T("extension_operation_required"))
return errors.New(i18n.T("extension_operation_required"))
}
for name, op := range ext.Operations {
if op.CmdTemplate == "" {

View file

@ -5,6 +5,7 @@ package template
import (
"bufio"
"errors"
"fmt"
"os"
"path/filepath"
@ -30,7 +31,7 @@ func (p *FilePlugin) safePath(path string) (string, error) {
// Basic security check - no path traversal
if strings.Contains(path, "..") {
return "", fmt.Errorf("%s", i18n.T("template_file_error_path_contains_parent_ref"))
return "", errors.New(i18n.T("template_file_error_path_contains_parent_ref"))
}
// Expand home directory if needed
@ -61,7 +62,7 @@ func (p *FilePlugin) Apply(operation string, value string) (string, error) {
case "tail":
parts := strings.Split(value, "|")
if len(parts) != 2 {
return "", fmt.Errorf("%s", i18n.T("template_file_error_tail_requires_path_lines"))
return "", errors.New(i18n.T("template_file_error_tail_requires_path_lines"))
}
path, err := p.safePath(parts[0])
@ -75,7 +76,7 @@ func (p *FilePlugin) Apply(operation string, value string) (string, error) {
}
if n < 1 {
return "", fmt.Errorf("%s", i18n.T("template_file_error_line_count_positive"))
return "", errors.New(i18n.T("template_file_error_line_count_positive"))
}
lines, err := p.lastNLines(path, n)

View file

@ -2,6 +2,7 @@
package template
import (
"errors"
"fmt"
"os"
"os/user"
@ -58,7 +59,7 @@ func (p *SysPlugin) Apply(operation string, value string) (string, error) {
case "env":
if value == "" {
debugf("Sys: env error: missing variable name")
return "", fmt.Errorf("%s", i18n.T("template_sys_error_env_requires_var"))
return "", errors.New(i18n.T("template_sys_error_env_requires_var"))
}
result := os.Getenv(value)
debugf("Sys: env %q=%q", value, result)

View file

@ -1,6 +1,7 @@
package template
import (
"errors"
"fmt"
"os"
"path/filepath"
@ -143,7 +144,7 @@ func ApplyTemplate(content string, variables map[string]string, input string) (s
}
if !progress {
return "", fmt.Errorf("%s", i18n.T("template_processing_stuck"))
return "", errors.New(i18n.T("template_processing_stuck"))
}
}

View file

@ -4,6 +4,7 @@ import (
"bufio"
"bytes"
"encoding/json"
"errors"
"fmt"
"io"
"log"
@ -109,28 +110,28 @@ func parseOllamaNumCtx(options map[string]any) (int, error) {
switch v := val.(type) {
case float64:
if math.IsNaN(v) || math.IsInf(v, 0) {
return 0, fmt.Errorf("%s", i18n.T("ollama_num_ctx_must_be_finite"))
return 0, errors.New(i18n.T("ollama_num_ctx_must_be_finite"))
}
if math.Trunc(v) != v {
return 0, fmt.Errorf("%s", i18n.T("ollama_num_ctx_must_be_integer"))
return 0, errors.New(i18n.T("ollama_num_ctx_must_be_integer"))
}
// Check for overflow on 32-bit systems (negative values handled by validation at line 166)
if v > float64(maxInt) {
return 0, fmt.Errorf("%s", i18n.T("ollama_num_ctx_value_out_of_range"))
return 0, errors.New(i18n.T("ollama_num_ctx_value_out_of_range"))
}
contextLength = int(v)
case float32:
f64 := float64(v)
if math.IsNaN(f64) || math.IsInf(f64, 0) {
return 0, fmt.Errorf("%s", i18n.T("ollama_num_ctx_must_be_finite"))
return 0, errors.New(i18n.T("ollama_num_ctx_must_be_finite"))
}
if math.Trunc(f64) != f64 {
return 0, fmt.Errorf("%s", i18n.T("ollama_num_ctx_must_be_integer"))
return 0, errors.New(i18n.T("ollama_num_ctx_must_be_integer"))
}
// Check for overflow on 32-bit systems (negative values handled by validation at line 177)
if f64 > float64(maxInt) {
return 0, fmt.Errorf("%s", i18n.T("ollama_num_ctx_value_out_of_range"))
return 0, errors.New(i18n.T("ollama_num_ctx_value_out_of_range"))
}
contextLength = int(v)
@ -149,7 +150,7 @@ func parseOllamaNumCtx(options map[string]any) (int, error) {
case json.Number:
i64, err := v.Int64()
if err != nil {
return 0, fmt.Errorf("%s", i18n.T("ollama_num_ctx_must_be_valid_number"))
return 0, errors.New(i18n.T("ollama_num_ctx_must_be_valid_number"))
}
if i64 < 0 {
return 0, fmt.Errorf(i18n.T("ollama_num_ctx_must_be_positive"), i64)
@ -172,7 +173,7 @@ func parseOllamaNumCtx(options map[string]any) (int, error) {
contextLength = parsed
default:
return 0, fmt.Errorf("%s", i18n.T("ollama_num_ctx_invalid_type"))
return 0, errors.New(i18n.T("ollama_num_ctx_invalid_type"))
}
if contextLength <= 0 {
@ -493,7 +494,7 @@ func buildFinalOllamaResponse(model string, content string, duration int64) Olla
// contains a path component.
func buildFabricChatURL(addr string) (string, error) {
if addr == "" {
return "", fmt.Errorf("%s", i18n.T("ollama_empty_address"))
return "", errors.New(i18n.T("ollama_empty_address"))
}
if strings.HasPrefix(addr, "http://") || strings.HasPrefix(addr, "https://") {
parsed, err := url.Parse(addr)
@ -501,10 +502,10 @@ func buildFabricChatURL(addr string) (string, error) {
return "", fmt.Errorf(i18n.T("ollama_invalid_address"), err)
}
if parsed.Host == "" {
return "", fmt.Errorf("%s", i18n.T("ollama_invalid_address_missing_host"))
return "", errors.New(i18n.T("ollama_invalid_address_missing_host"))
}
if strings.HasPrefix(parsed.Host, ":") {
return "", fmt.Errorf("%s", i18n.T("ollama_invalid_address_missing_hostname"))
return "", errors.New(i18n.T("ollama_invalid_address_missing_hostname"))
}
return strings.TrimRight(parsed.String(), "/"), nil
}
@ -517,14 +518,14 @@ func buildFabricChatURL(addr string) (string, error) {
return "", fmt.Errorf(i18n.T("ollama_invalid_address"), err)
}
if parsed.Host == "" {
return "", fmt.Errorf("%s", i18n.T("ollama_invalid_address_missing_host"))
return "", errors.New(i18n.T("ollama_invalid_address_missing_host"))
}
if strings.HasPrefix(parsed.Host, ":") {
return "", fmt.Errorf("%s", i18n.T("ollama_invalid_address_missing_hostname"))
return "", errors.New(i18n.T("ollama_invalid_address_missing_hostname"))
}
// Bare addresses should be host[:port] only - reject path components
if parsed.Path != "" && parsed.Path != "/" {
return "", fmt.Errorf("%s", i18n.T("ollama_invalid_address_path_not_allowed"))
return "", errors.New(i18n.T("ollama_invalid_address_path_not_allowed"))
}
return strings.TrimRight(parsed.String(), "/"), nil
}

View file

@ -1,7 +1,7 @@
package notifications
import (
"fmt"
"errors"
"os"
"os/exec"
"runtime"
@ -45,7 +45,7 @@ func NewNotificationManager() *NotificationManager {
// Send sends a notification using the configured provider
func (nm *NotificationManager) Send(title, message string) error {
if nm.provider == nil {
return fmt.Errorf("%s", i18n.T("notifications_no_provider_available"))
return errors.New(i18n.T("notifications_no_provider_available"))
}
return nm.provider.Send(title, message)
}

View file

@ -13,6 +13,7 @@ package spotify
import (
"encoding/base64"
"encoding/json"
"errors"
"fmt"
"io"
"net/http"
@ -89,7 +90,7 @@ func (s *Spotify) initClient() error {
// refreshAccessToken obtains a new access token using Client Credentials flow.
func (s *Spotify) refreshAccessToken() error {
if s.ClientId.Value == "" || s.ClientSecret.Value == "" {
return fmt.Errorf("%s", i18n.T("spotify_not_configured"))
return errors.New(i18n.T("spotify_not_configured"))
}
// Prepare the token request

View file

@ -15,6 +15,7 @@ import (
"context"
"encoding/csv"
"flag"
"errors"
"fmt"
"io"
"log"
@ -86,7 +87,7 @@ type YouTube struct {
func (o *YouTube) initService() (err error) {
if o.service == nil {
if o.ApiKey.Value == "" {
err = fmt.Errorf("%s", i18n.T("youtube_api_key_required"))
err = errors.New(i18n.T("youtube_api_key_required"))
return
}
o.normalizeRegex = regexp.MustCompile(`[^a-zA-Z0-9]+`)
@ -124,10 +125,10 @@ func (o *YouTube) extractAndValidateVideoId(url string) (videoId string, err err
return "", err
}
if videoId == "" && playlistId != "" {
return "", fmt.Errorf("%s", i18n.T("youtube_url_is_playlist_not_video"))
return "", errors.New(i18n.T("youtube_url_is_playlist_not_video"))
}
if videoId == "" {
return "", fmt.Errorf("%s", i18n.T("youtube_no_video_id_found"))
return "", errors.New(i18n.T("youtube_no_video_id_found"))
}
return videoId, nil
}
@ -192,7 +193,7 @@ func detectError(ytOutput io.Reader) error {
}
}
if err := scanner.Err(); err != nil {
return fmt.Errorf("%s", i18n.T("youtube_ytdlp_stderr_error"))
return errors.New(i18n.T("youtube_ytdlp_stderr_error"))
}
return nil
}
@ -218,7 +219,7 @@ func noLangs(args []string) []string {
func (o *YouTube) tryMethodYtDlpInternal(videoId string, language string, additionalArgs string, processVTTFileFunc func(filename string) (string, error)) (ret string, err error) {
// Check if yt-dlp is available
if _, err = exec.LookPath("yt-dlp"); err != nil {
err = fmt.Errorf("%s", i18n.T("youtube_ytdlp_not_found"))
err = errors.New(i18n.T("youtube_ytdlp_not_found"))
return
}
@ -328,7 +329,7 @@ func (o *YouTube) readAndCleanVTTFile(filename string) (ret string, err error) {
ret = strings.TrimSpace(textBuilder.String())
if ret == "" {
err = fmt.Errorf("%s", i18n.T("youtube_no_transcript_content"))
err = errors.New(i18n.T("youtube_no_transcript_content"))
}
return
}
@ -398,7 +399,7 @@ func (o *YouTube) readAndFormatVTTWithTimestamps(filename string) (ret string, e
ret = strings.TrimSpace(textBuilder.String())
if ret == "" {
err = fmt.Errorf("%s", i18n.T("youtube_no_transcript_content"))
err = errors.New(i18n.T("youtube_no_transcript_content"))
}
return
}
@ -476,7 +477,7 @@ func parseTimestampToSeconds(timestamp string) (int, error) {
func parseSeconds(secondsStr string) (int, error) {
if secondsStr == "" {
return 0, fmt.Errorf("%s", i18n.T("youtube_empty_seconds_string"))
return 0, errors.New(i18n.T("youtube_empty_seconds_string"))
}
// Extract integer part (before decimal point if present)
@ -723,7 +724,7 @@ func (o *YouTube) findVTTFilesWithFallback(dir, requestedLanguage string) ([]str
}
if len(vttFiles) == 0 {
return nil, fmt.Errorf("%s", i18n.T("youtube_no_vtt_files_found"))
return nil, errors.New(i18n.T("youtube_no_vtt_files_found"))
}
// If no specific language requested, return the first file