diff --git a/internal/i18n/locales/de.json b/internal/i18n/locales/de.json index 3541135d..716ddffc 100644 --- a/internal/i18n/locales/de.json +++ b/internal/i18n/locales/de.json @@ -362,5 +362,25 @@ "lmstudio_invalid_response_missing_message": "Ungültiges Antwortformat: Nachricht in der ersten Auswahl fehlt", "lmstudio_invalid_response_missing_content": "Ungültiges Antwortformat: Inhalt in der Nachricht fehlt oder ist kein String", "lmstudio_invalid_response_missing_text": "Ungültiges Antwortformat: Text in der ersten Auswahl fehlt oder ist kein String", - "lmstudio_no_embeddings_returned": "Keine Einbettungen zurückgegeben" + "lmstudio_no_embeddings_returned": "Keine Einbettungen zurückgegeben", + "extension_warning_load_registry": "Warnung: Erweiterungsregistrierung konnte nicht geladen werden: %v\n", + "extension_name_empty": "Erweiterungsname darf nicht leer sein", + "extension_name_contains_spaces": "Erweiterungsname '%s' enthält Leerzeichen - Namen dürfen keine Leerzeichen enthalten", + "extension_executable_not_found": "Programmdatei nicht gefunden: %w", + "extension_failed_get_absolute_path": "absoluter Pfad konnte nicht ermittelt werden: %w", + "extension_failed_hash_executable": "Programmdatei-Hash konnte nicht berechnet werden: %w", + "extension_invalid_definition": "ungültige Erweiterungsdefinition: %w", + "extension_name_required": "Erweiterungsname ist erforderlich", + "extension_executable_required": "Pfad zur Programmdatei ist erforderlich", + "extension_type_required": "Erweiterungstyp ist erforderlich", + "extension_invalid_timeout_format": "ungültiges Zeitlimit-Format: %w", + "extension_operation_required": "mindestens eine Operation muss definiert sein", + "extension_cmd_template_required": "Befehlsvorlage ist für Operation %s erforderlich", + "extension_not_found": "Erweiterung %s nicht gefunden", + "extension_config_hash_mismatch": "Hash-Abweichung der Konfigurationsdatei für %s", + "extension_failed_verify_executable": "Programmdatei konnte nicht verifiziert werden: %w", + "extension_executable_hash_mismatch": "Hash-Abweichung der Programmdatei für %s", + "extension_failed_marshal_registry": "Erweiterungsregistrierung konnte nicht serialisiert werden: %w", + "extension_failed_read_registry": "Erweiterungsregistrierung konnte nicht gelesen werden: %w", + "extension_failed_parse_registry": "Erweiterungsregistrierung konnte nicht geparst werden: %w" } diff --git a/internal/i18n/locales/en.json b/internal/i18n/locales/en.json index 82299768..8f89bd34 100644 --- a/internal/i18n/locales/en.json +++ b/internal/i18n/locales/en.json @@ -362,5 +362,25 @@ "lmstudio_invalid_response_missing_message": "invalid response format: missing message in first choice", "lmstudio_invalid_response_missing_content": "invalid response format: missing or non-string content in message", "lmstudio_invalid_response_missing_text": "invalid response format: missing or non-string text in first choice", - "lmstudio_no_embeddings_returned": "no embeddings returned" + "lmstudio_no_embeddings_returned": "no embeddings returned", + "extension_warning_load_registry": "Warning: could not load extension registry: %v\n", + "extension_name_empty": "extension name cannot be empty", + "extension_name_contains_spaces": "extension name '%s' contains spaces - names must not contain spaces", + "extension_executable_not_found": "executable not found: %w", + "extension_failed_get_absolute_path": "failed to get absolute path: %w", + "extension_failed_hash_executable": "failed to hash executable: %w", + "extension_invalid_definition": "invalid extension definition: %w", + "extension_name_required": "extension name is required", + "extension_executable_required": "executable path is required", + "extension_type_required": "extension type is required", + "extension_invalid_timeout_format": "invalid timeout format: %w", + "extension_operation_required": "at least one operation must be defined", + "extension_cmd_template_required": "command template is required for operation %s", + "extension_not_found": "extension %s not found", + "extension_config_hash_mismatch": "config file hash mismatch for %s", + "extension_failed_verify_executable": "failed to verify executable: %w", + "extension_executable_hash_mismatch": "executable hash mismatch for %s", + "extension_failed_marshal_registry": "failed to marshal extension registry: %w", + "extension_failed_read_registry": "failed to read extension registry: %w", + "extension_failed_parse_registry": "failed to parse extension registry: %w" } diff --git a/internal/i18n/locales/es.json b/internal/i18n/locales/es.json index b15785b3..8d4fab73 100644 --- a/internal/i18n/locales/es.json +++ b/internal/i18n/locales/es.json @@ -362,5 +362,25 @@ "lmstudio_invalid_response_missing_message": "formato de respuesta inválido: mensaje ausente en la primera opción", "lmstudio_invalid_response_missing_content": "formato de respuesta inválido: contenido ausente o no es una cadena en el mensaje", "lmstudio_invalid_response_missing_text": "formato de respuesta inválido: texto ausente o no es una cadena en la primera opción", - "lmstudio_no_embeddings_returned": "no se devolvieron incrustaciones" + "lmstudio_no_embeddings_returned": "no se devolvieron incrustaciones", + "extension_warning_load_registry": "Advertencia: no se pudo cargar el registro de extensiones: %v\n", + "extension_name_empty": "el nombre de la extensión no puede estar vacío", + "extension_name_contains_spaces": "el nombre de la extensión '%s' contiene espacios - los nombres no deben contener espacios", + "extension_executable_not_found": "ejecutable no encontrado: %w", + "extension_failed_get_absolute_path": "no se pudo obtener la ruta absoluta: %w", + "extension_failed_hash_executable": "no se pudo calcular el hash del ejecutable: %w", + "extension_invalid_definition": "definición de extensión inválida: %w", + "extension_name_required": "el nombre de la extensión es obligatorio", + "extension_executable_required": "la ruta del ejecutable es obligatoria", + "extension_type_required": "el tipo de extensión es obligatorio", + "extension_invalid_timeout_format": "formato de tiempo límite inválido: %w", + "extension_operation_required": "se debe definir al menos una operación", + "extension_cmd_template_required": "la plantilla de comando es obligatoria para la operación %s", + "extension_not_found": "extensión %s no encontrada", + "extension_config_hash_mismatch": "discrepancia de hash del archivo de configuración para %s", + "extension_failed_verify_executable": "no se pudo verificar el ejecutable: %w", + "extension_executable_hash_mismatch": "discrepancia de hash del ejecutable para %s", + "extension_failed_marshal_registry": "no se pudo serializar el registro de extensiones: %w", + "extension_failed_read_registry": "no se pudo leer el registro de extensiones: %w", + "extension_failed_parse_registry": "no se pudo analizar el registro de extensiones: %w" } diff --git a/internal/i18n/locales/fa.json b/internal/i18n/locales/fa.json index 115b601c..ddb05182 100644 --- a/internal/i18n/locales/fa.json +++ b/internal/i18n/locales/fa.json @@ -354,5 +354,25 @@ "lmstudio_invalid_response_missing_message": "فرمت پاسخ نامعتبر: پیام در اولین گزینه وجود ندارد", "lmstudio_invalid_response_missing_content": "فرمت پاسخ نامعتبر: محتوا در پیام وجود ندارد یا رشته نیست", "lmstudio_invalid_response_missing_text": "فرمت پاسخ نامعتبر: متن در اولین گزینه وجود ندارد یا رشته نیست", - "lmstudio_no_embeddings_returned": "هیچ بردار جاسازی بازگردانده نشد" + "lmstudio_no_embeddings_returned": "هیچ بردار جاسازی بازگردانده نشد", + "extension_warning_load_registry": "هشدار: بارگذاری رجیستری افزونه‌ها ممکن نبود: %v\n", + "extension_name_empty": "نام افزونه نمی‌تواند خالی باشد", + "extension_name_contains_spaces": "نام افزونه '%s' حاوی فاصله است - نام‌ها نباید فاصله داشته باشند", + "extension_executable_not_found": "فایل اجرایی یافت نشد: %w", + "extension_failed_get_absolute_path": "دریافت مسیر مطلق ناموفق بود: %w", + "extension_failed_hash_executable": "محاسبه هش فایل اجرایی ناموفق بود: %w", + "extension_invalid_definition": "تعریف افزونه نامعتبر: %w", + "extension_name_required": "نام افزونه الزامی است", + "extension_executable_required": "مسیر فایل اجرایی الزامی است", + "extension_type_required": "نوع افزونه الزامی است", + "extension_invalid_timeout_format": "فرمت مهلت زمانی نامعتبر: %w", + "extension_operation_required": "حداقل یک عملیات باید تعریف شود", + "extension_cmd_template_required": "الگوی دستور برای عملیات %s الزامی است", + "extension_not_found": "افزونه %s یافت نشد", + "extension_config_hash_mismatch": "عدم تطابق هش فایل پیکربندی برای %s", + "extension_failed_verify_executable": "تأیید فایل اجرایی ناموفق بود: %w", + "extension_executable_hash_mismatch": "عدم تطابق هش فایل اجرایی برای %s", + "extension_failed_marshal_registry": "سریال‌سازی رجیستری افزونه‌ها ناموفق بود: %w", + "extension_failed_read_registry": "خواندن رجیستری افزونه‌ها ناموفق بود: %w", + "extension_failed_parse_registry": "تجزیه رجیستری افزونه‌ها ناموفق بود: %w" } diff --git a/internal/i18n/locales/fr.json b/internal/i18n/locales/fr.json index 76867888..3ba1c1e4 100644 --- a/internal/i18n/locales/fr.json +++ b/internal/i18n/locales/fr.json @@ -362,5 +362,25 @@ "lmstudio_invalid_response_missing_message": "format de réponse invalide : message manquant dans le premier choix", "lmstudio_invalid_response_missing_content": "format de réponse invalide : contenu manquant ou non-chaîne dans le message", "lmstudio_invalid_response_missing_text": "format de réponse invalide : texte manquant ou non-chaîne dans le premier choix", - "lmstudio_no_embeddings_returned": "aucun embedding retourné" + "lmstudio_no_embeddings_returned": "aucun embedding retourné", + "extension_warning_load_registry": "Attention : impossible de charger le registre d'extensions : %v\n", + "extension_name_empty": "le nom de l'extension ne peut pas être vide", + "extension_name_contains_spaces": "le nom de l'extension '%s' contient des espaces - les noms ne doivent pas contenir d'espaces", + "extension_executable_not_found": "exécutable introuvable : %w", + "extension_failed_get_absolute_path": "impossible d'obtenir le chemin absolu : %w", + "extension_failed_hash_executable": "impossible de calculer le hash de l'exécutable : %w", + "extension_invalid_definition": "définition d'extension invalide : %w", + "extension_name_required": "le nom de l'extension est requis", + "extension_executable_required": "le chemin de l'exécutable est requis", + "extension_type_required": "le type d'extension est requis", + "extension_invalid_timeout_format": "format de délai invalide : %w", + "extension_operation_required": "au moins une opération doit être définie", + "extension_cmd_template_required": "le modèle de commande est requis pour l'opération %s", + "extension_not_found": "extension %s introuvable", + "extension_config_hash_mismatch": "discordance de hash du fichier de configuration pour %s", + "extension_failed_verify_executable": "impossible de vérifier l'exécutable : %w", + "extension_executable_hash_mismatch": "discordance de hash de l'exécutable pour %s", + "extension_failed_marshal_registry": "impossible de sérialiser le registre d'extensions : %w", + "extension_failed_read_registry": "impossible de lire le registre d'extensions : %w", + "extension_failed_parse_registry": "impossible d'analyser le registre d'extensions : %w" } diff --git a/internal/i18n/locales/it.json b/internal/i18n/locales/it.json index 29ad2203..eaddfcd8 100644 --- a/internal/i18n/locales/it.json +++ b/internal/i18n/locales/it.json @@ -362,5 +362,25 @@ "lmstudio_invalid_response_missing_message": "formato di risposta non valido: messaggio mancante nella prima scelta", "lmstudio_invalid_response_missing_content": "formato di risposta non valido: contenuto mancante o non stringa nel messaggio", "lmstudio_invalid_response_missing_text": "formato di risposta non valido: testo mancante o non stringa nella prima scelta", - "lmstudio_no_embeddings_returned": "nessun embedding restituito" + "lmstudio_no_embeddings_returned": "nessun embedding restituito", + "extension_warning_load_registry": "Attenzione: impossibile caricare il registro estensioni: %v\n", + "extension_name_empty": "il nome dell'estensione non può essere vuoto", + "extension_name_contains_spaces": "il nome dell'estensione '%s' contiene spazi - i nomi non devono contenere spazi", + "extension_executable_not_found": "eseguibile non trovato: %w", + "extension_failed_get_absolute_path": "impossibile ottenere il percorso assoluto: %w", + "extension_failed_hash_executable": "impossibile calcolare l'hash dell'eseguibile: %w", + "extension_invalid_definition": "definizione estensione non valida: %w", + "extension_name_required": "il nome dell'estensione è obbligatorio", + "extension_executable_required": "il percorso dell'eseguibile è obbligatorio", + "extension_type_required": "il tipo di estensione è obbligatorio", + "extension_invalid_timeout_format": "formato timeout non valido: %w", + "extension_operation_required": "deve essere definita almeno un'operazione", + "extension_cmd_template_required": "il modello di comando è obbligatorio per l'operazione %s", + "extension_not_found": "estensione %s non trovata", + "extension_config_hash_mismatch": "discrepanza hash del file di configurazione per %s", + "extension_failed_verify_executable": "impossibile verificare l'eseguibile: %w", + "extension_executable_hash_mismatch": "discrepanza hash dell'eseguibile per %s", + "extension_failed_marshal_registry": "impossibile serializzare il registro estensioni: %w", + "extension_failed_read_registry": "impossibile leggere il registro estensioni: %w", + "extension_failed_parse_registry": "impossibile analizzare il registro estensioni: %w" } diff --git a/internal/i18n/locales/ja.json b/internal/i18n/locales/ja.json index 106ffe15..6ff05f3b 100644 --- a/internal/i18n/locales/ja.json +++ b/internal/i18n/locales/ja.json @@ -362,5 +362,25 @@ "lmstudio_invalid_response_missing_message": "無効なレスポンス形式: 最初の選択肢にメッセージがありません", "lmstudio_invalid_response_missing_content": "無効なレスポンス形式: メッセージにコンテンツがないか文字列ではありません", "lmstudio_invalid_response_missing_text": "無効なレスポンス形式: 最初の選択肢にテキストがないか文字列ではありません", - "lmstudio_no_embeddings_returned": "埋め込みが返されませんでした" + "lmstudio_no_embeddings_returned": "埋め込みが返されませんでした", + "extension_warning_load_registry": "警告: 拡張機能レジストリを読み込めませんでした: %v\n", + "extension_name_empty": "拡張機能名は空にできません", + "extension_name_contains_spaces": "拡張機能名 '%s' にスペースが含まれています - 名前にスペースは使用できません", + "extension_executable_not_found": "実行ファイルが見つかりません: %w", + "extension_failed_get_absolute_path": "絶対パスの取得に失敗しました: %w", + "extension_failed_hash_executable": "実行ファイルのハッシュ計算に失敗しました: %w", + "extension_invalid_definition": "無効な拡張機能定義: %w", + "extension_name_required": "拡張機能名は必須です", + "extension_executable_required": "実行ファイルパスは必須です", + "extension_type_required": "拡張機能タイプは必須です", + "extension_invalid_timeout_format": "無効なタイムアウト形式: %w", + "extension_operation_required": "少なくとも1つの操作を定義する必要があります", + "extension_cmd_template_required": "操作 %s にはコマンドテンプレートが必要です", + "extension_not_found": "拡張機能 %s が見つかりません", + "extension_config_hash_mismatch": "%s の設定ファイルのハッシュが一致しません", + "extension_failed_verify_executable": "実行ファイルの検証に失敗しました: %w", + "extension_executable_hash_mismatch": "%s の実行ファイルのハッシュが一致しません", + "extension_failed_marshal_registry": "拡張機能レジストリのシリアル化に失敗しました: %w", + "extension_failed_read_registry": "拡張機能レジストリの読み込みに失敗しました: %w", + "extension_failed_parse_registry": "拡張機能レジストリの解析に失敗しました: %w" } diff --git a/internal/i18n/locales/pt-BR.json b/internal/i18n/locales/pt-BR.json index 93e3a789..c2389068 100644 --- a/internal/i18n/locales/pt-BR.json +++ b/internal/i18n/locales/pt-BR.json @@ -362,5 +362,25 @@ "lmstudio_invalid_response_missing_message": "formato de resposta inválido: mensagem ausente na primeira escolha", "lmstudio_invalid_response_missing_content": "formato de resposta inválido: conteúdo ausente ou não é uma string na mensagem", "lmstudio_invalid_response_missing_text": "formato de resposta inválido: texto ausente ou não é uma string na primeira escolha", - "lmstudio_no_embeddings_returned": "nenhum embedding retornado" + "lmstudio_no_embeddings_returned": "nenhum embedding retornado", + "extension_warning_load_registry": "Aviso: não foi possível carregar o registro de extensões: %v\n", + "extension_name_empty": "o nome da extensão não pode estar vazio", + "extension_name_contains_spaces": "o nome da extensão '%s' contém espaços - nomes não devem conter espaços", + "extension_executable_not_found": "executável não encontrado: %w", + "extension_failed_get_absolute_path": "falha ao obter o caminho absoluto: %w", + "extension_failed_hash_executable": "falha ao calcular o hash do executável: %w", + "extension_invalid_definition": "definição de extensão inválida: %w", + "extension_name_required": "o nome da extensão é obrigatório", + "extension_executable_required": "o caminho do executável é obrigatório", + "extension_type_required": "o tipo da extensão é obrigatório", + "extension_invalid_timeout_format": "formato de tempo limite inválido: %w", + "extension_operation_required": "pelo menos uma operação deve ser definida", + "extension_cmd_template_required": "o modelo de comando é obrigatório para a operação %s", + "extension_not_found": "extensão %s não encontrada", + "extension_config_hash_mismatch": "discrepância de hash do arquivo de configuração para %s", + "extension_failed_verify_executable": "falha ao verificar o executável: %w", + "extension_executable_hash_mismatch": "discrepância de hash do executável para %s", + "extension_failed_marshal_registry": "falha ao serializar o registro de extensões: %w", + "extension_failed_read_registry": "falha ao ler o registro de extensões: %w", + "extension_failed_parse_registry": "falha ao analisar o registro de extensões: %w" } diff --git a/internal/i18n/locales/pt-PT.json b/internal/i18n/locales/pt-PT.json index 36e94ddf..ff4c4f47 100644 --- a/internal/i18n/locales/pt-PT.json +++ b/internal/i18n/locales/pt-PT.json @@ -362,5 +362,25 @@ "lmstudio_invalid_response_missing_message": "formato de resposta inválido: mensagem ausente na primeira escolha", "lmstudio_invalid_response_missing_content": "formato de resposta inválido: conteúdo ausente ou não é uma string na mensagem", "lmstudio_invalid_response_missing_text": "formato de resposta inválido: texto ausente ou não é uma string na primeira escolha", - "lmstudio_no_embeddings_returned": "nenhum embedding retornado" + "lmstudio_no_embeddings_returned": "nenhum embedding retornado", + "extension_warning_load_registry": "Aviso: não foi possível carregar o registo de extensões: %v\n", + "extension_name_empty": "o nome da extensão não pode estar vazio", + "extension_name_contains_spaces": "o nome da extensão '%s' contém espaços - os nomes não devem conter espaços", + "extension_executable_not_found": "executável não encontrado: %w", + "extension_failed_get_absolute_path": "falha ao obter o caminho absoluto: %w", + "extension_failed_hash_executable": "falha ao calcular o hash do executável: %w", + "extension_invalid_definition": "definição de extensão inválida: %w", + "extension_name_required": "o nome da extensão é obrigatório", + "extension_executable_required": "o caminho do executável é obrigatório", + "extension_type_required": "o tipo da extensão é obrigatório", + "extension_invalid_timeout_format": "formato de tempo limite inválido: %w", + "extension_operation_required": "deve ser definida pelo menos uma operação", + "extension_cmd_template_required": "o modelo de comando é obrigatório para a operação %s", + "extension_not_found": "extensão %s não encontrada", + "extension_config_hash_mismatch": "discrepância de hash do ficheiro de configuração para %s", + "extension_failed_verify_executable": "falha ao verificar o executável: %w", + "extension_executable_hash_mismatch": "discrepância de hash do executável para %s", + "extension_failed_marshal_registry": "falha ao serializar o registo de extensões: %w", + "extension_failed_read_registry": "falha ao ler o registo de extensões: %w", + "extension_failed_parse_registry": "falha ao analisar o registo de extensões: %w" } diff --git a/internal/i18n/locales/zh.json b/internal/i18n/locales/zh.json index 6e258cc0..471ca2a3 100644 --- a/internal/i18n/locales/zh.json +++ b/internal/i18n/locales/zh.json @@ -362,5 +362,25 @@ "lmstudio_invalid_response_missing_message": "无效的响应格式:第一个选项中缺少消息", "lmstudio_invalid_response_missing_content": "无效的响应格式:消息中的内容缺失或不是字符串", "lmstudio_invalid_response_missing_text": "无效的响应格式:第一个选项中的文本缺失或不是字符串", - "lmstudio_no_embeddings_returned": "未返回嵌入向量" + "lmstudio_no_embeddings_returned": "未返回嵌入向量", + "extension_warning_load_registry": "警告:无法加载扩展注册表:%v\n", + "extension_name_empty": "扩展名称不能为空", + "extension_name_contains_spaces": "扩展名称 '%s' 包含空格 - 名称不能包含空格", + "extension_executable_not_found": "未找到可执行文件:%w", + "extension_failed_get_absolute_path": "获取绝对路径失败:%w", + "extension_failed_hash_executable": "计算可执行文件哈希失败:%w", + "extension_invalid_definition": "无效的扩展定义:%w", + "extension_name_required": "扩展名称为必填项", + "extension_executable_required": "可执行文件路径为必填项", + "extension_type_required": "扩展类型为必填项", + "extension_invalid_timeout_format": "无效的超时格式:%w", + "extension_operation_required": "必须定义至少一个操作", + "extension_cmd_template_required": "操作 %s 需要命令模板", + "extension_not_found": "未找到扩展 %s", + "extension_config_hash_mismatch": "%s 的配置文件哈希不匹配", + "extension_failed_verify_executable": "验证可执行文件失败:%w", + "extension_executable_hash_mismatch": "%s 的可执行文件哈希不匹配", + "extension_failed_marshal_registry": "序列化扩展注册表失败:%w", + "extension_failed_read_registry": "读取扩展注册表失败:%w", + "extension_failed_parse_registry": "解析扩展注册表失败:%w" } diff --git a/internal/plugins/template/extension_registry.go b/internal/plugins/template/extension_registry.go index 38906427..2673d381 100644 --- a/internal/plugins/template/extension_registry.go +++ b/internal/plugins/template/extension_registry.go @@ -10,6 +10,7 @@ import ( "strings" "time" + "github.com/danielmiessler/fabric/internal/i18n" debuglog "github.com/danielmiessler/fabric/internal/log" "gopkg.in/yaml.v3" @@ -88,7 +89,7 @@ func NewExtensionRegistry(configDir string) *ExtensionRegistry { r.ensureConfigDir() if err := r.loadRegistry(); err != nil { - debuglog.Log("Warning: could not load extension registry: %v\n", err) + debuglog.Log(i18n.T("extension_warning_load_registry"), err) } return r @@ -105,44 +106,44 @@ func (r *ExtensionRegistry) Register(configPath string) error { // Read and parse the extension definition to verify it data, err := os.ReadFile(configPath) if err != nil { - return fmt.Errorf("failed to read config file: %w", err) + return fmt.Errorf(i18n.T("extension_failed_read_config"), err) } var ext ExtensionDefinition if err := yaml.Unmarshal(data, &ext); err != nil { - return fmt.Errorf("failed to parse config file: %w", err) + return fmt.Errorf(i18n.T("extension_failed_parse_config"), err) } // Validate extension name if ext.Name == "" { - return fmt.Errorf("extension name cannot be empty") + return fmt.Errorf("%s", i18n.T("extension_name_empty")) } if strings.Contains(ext.Name, " ") { - return fmt.Errorf("extension name '%s' contains spaces - names must not contain spaces", ext.Name) + return fmt.Errorf("%s", fmt.Sprintf(i18n.T("extension_name_contains_spaces"), ext.Name)) } // Verify executable exists if _, err := os.Stat(ext.Executable); err != nil { - return fmt.Errorf("executable not found: %w", err) + return fmt.Errorf(i18n.T("extension_executable_not_found"), err) } // Get absolute path to config absPath, err := filepath.Abs(configPath) if err != nil { - return fmt.Errorf("failed to get absolute path: %w", err) + return fmt.Errorf(i18n.T("extension_failed_get_absolute_path"), err) } // Calculate hashes configHash := ComputeStringHash(string(data)) executableHash, err := ComputeHash(ext.Executable) if err != nil { - return fmt.Errorf("failed to hash executable: %w", err) + return fmt.Errorf(i18n.T("extension_failed_hash_executable"), err) } // Validate full extension definition (ensures operations and cmd_template present) if err := r.validateExtensionDefinition(&ext); err != nil { - return fmt.Errorf("invalid extension definition: %w", err) + return fmt.Errorf(i18n.T("extension_invalid_definition"), err) } // Store entry @@ -158,29 +159,29 @@ func (r *ExtensionRegistry) Register(configPath string) error { func (r *ExtensionRegistry) validateExtensionDefinition(ext *ExtensionDefinition) error { // Validate required fields if ext.Name == "" { - return fmt.Errorf("extension name is required") + return fmt.Errorf("%s", i18n.T("extension_name_required")) } if ext.Executable == "" { - return fmt.Errorf("executable path is required") + return fmt.Errorf("%s", i18n.T("extension_executable_required")) } if ext.Type == "" { - return fmt.Errorf("extension type is required") + return fmt.Errorf("%s", i18n.T("extension_type_required")) } // Validate timeout format if ext.Timeout != "" { if _, err := time.ParseDuration(ext.Timeout); err != nil { - return fmt.Errorf("invalid timeout format: %w", err) + return fmt.Errorf(i18n.T("extension_invalid_timeout_format"), err) } } // Validate operations if len(ext.Operations) == 0 { - return fmt.Errorf("at least one operation must be defined") + return fmt.Errorf("%s", i18n.T("extension_operation_required")) } for name, op := range ext.Operations { if op.CmdTemplate == "" { - return fmt.Errorf("command template is required for operation %s", name) + return fmt.Errorf("%s", fmt.Sprintf(i18n.T("extension_cmd_template_required"), name)) } } @@ -189,7 +190,7 @@ func (r *ExtensionRegistry) validateExtensionDefinition(ext *ExtensionDefinition func (r *ExtensionRegistry) Remove(name string) error { if _, exists := r.registry.Extensions[name]; !exists { - return fmt.Errorf("extension %s not found", name) + return fmt.Errorf("%s", fmt.Sprintf(i18n.T("extension_not_found"), name)) } delete(r.registry.Extensions, name) @@ -201,35 +202,35 @@ func (r *ExtensionRegistry) Verify(name string) error { // Get the registry entry entry, exists := r.registry.Extensions[name] if !exists { - return fmt.Errorf("extension %s not found", name) + return fmt.Errorf("%s", fmt.Sprintf(i18n.T("extension_not_found"), name)) } // Load and parse the config file data, err := os.ReadFile(entry.ConfigPath) if err != nil { - return fmt.Errorf("failed to read config file: %w", err) + return fmt.Errorf(i18n.T("extension_failed_read_config"), err) } // Verify config hash currentConfigHash := ComputeStringHash(string(data)) if currentConfigHash != entry.ConfigHash { - return fmt.Errorf("config file hash mismatch for %s", name) + return fmt.Errorf("%s", fmt.Sprintf(i18n.T("extension_config_hash_mismatch"), name)) } // Parse to get executable path var ext ExtensionDefinition if err := yaml.Unmarshal(data, &ext); err != nil { - return fmt.Errorf("failed to parse config file: %w", err) + return fmt.Errorf(i18n.T("extension_failed_parse_config"), err) } // Verify executable hash currentExecutableHash, err := ComputeHash(ext.Executable) if err != nil { - return fmt.Errorf("failed to verify executable: %w", err) + return fmt.Errorf(i18n.T("extension_failed_verify_executable"), err) } if currentExecutableHash != entry.ExecutableHash { - return fmt.Errorf("executable hash mismatch for %s", name) + return fmt.Errorf("%s", fmt.Sprintf(i18n.T("extension_executable_hash_mismatch"), name)) } return nil @@ -238,35 +239,35 @@ func (r *ExtensionRegistry) Verify(name string) error { func (r *ExtensionRegistry) GetExtension(name string) (*ExtensionDefinition, error) { entry, exists := r.registry.Extensions[name] if !exists { - return nil, fmt.Errorf("extension %s not found", name) + return nil, fmt.Errorf("%s", fmt.Sprintf(i18n.T("extension_not_found"), name)) } // Read current config file data, err := os.ReadFile(entry.ConfigPath) if err != nil { - return nil, fmt.Errorf("failed to read config file: %w", err) + return nil, fmt.Errorf(i18n.T("extension_failed_read_config"), err) } // Verify config hash currentHash := ComputeStringHash(string(data)) if currentHash != entry.ConfigHash { - return nil, fmt.Errorf("config file hash mismatch for %s", name) + return nil, fmt.Errorf("%s", fmt.Sprintf(i18n.T("extension_config_hash_mismatch"), name)) } // Parse config var ext ExtensionDefinition if err := yaml.Unmarshal(data, &ext); err != nil { - return nil, fmt.Errorf("failed to parse config file: %w", err) + return nil, fmt.Errorf(i18n.T("extension_failed_parse_config"), err) } // Verify executable hash currentExecHash, err := ComputeHash(ext.Executable) if err != nil { - return nil, fmt.Errorf("failed to verify executable: %w", err) + return nil, fmt.Errorf(i18n.T("extension_failed_verify_executable"), err) } if currentExecHash != entry.ExecutableHash { - return nil, fmt.Errorf("executable hash mismatch for %s", name) + return nil, fmt.Errorf("%s", fmt.Sprintf(i18n.T("extension_executable_hash_mismatch"), name)) } return &ext, nil @@ -307,7 +308,7 @@ func (r *ExtensionRegistry) calculateFileHash(path string) (string, error) { func (r *ExtensionRegistry) saveRegistry() error { data, err := yaml.Marshal(r.registry) if err != nil { - return fmt.Errorf("failed to marshal extension registry: %w", err) + return fmt.Errorf(i18n.T("extension_failed_marshal_registry"), err) } registryPath := filepath.Join(r.configDir, "extensions", "extensions.yaml") @@ -321,12 +322,12 @@ func (r *ExtensionRegistry) loadRegistry() error { if os.IsNotExist(err) { return nil // New registry } - return fmt.Errorf("failed to read extension registry: %w", err) + return fmt.Errorf(i18n.T("extension_failed_read_registry"), err) } // Need to unmarshal the data into our registry if err := yaml.Unmarshal(data, &r.registry); err != nil { - return fmt.Errorf("failed to parse extension registry: %w", err) + return fmt.Errorf(i18n.T("extension_failed_parse_registry"), err) } return nil