MAESTRO: i18n: extract hard-coded strings from internal/plugins/template/extension_registry.go

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
This commit is contained in:
Kayvan Sylvan
2026-02-13 23:52:59 -08:00
parent 7382ddaae5
commit c8ca1792b4
11 changed files with 242 additions and 41 deletions

View File

@@ -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"
}

View File

@@ -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"
}

View File

@@ -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"
}

View File

@@ -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"
}

View File

@@ -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"
}

View File

@@ -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"
}

View File

@@ -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"
}

View File

@@ -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"
}

View File

@@ -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"
}

View File

@@ -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"
}

View File

@@ -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