Add comprehensive multilingual UI messages and enhance server test configuration: Update localization files with extensive UI translations in multiple languages, dynamically bind test server port, and refactor UI tests to improve literal text handling.

This commit is contained in:
2026-01-09 16:47:05 +00:00
parent 02bb7d7e66
commit 8754bf9c68
6 changed files with 645 additions and 34 deletions

View File

@@ -15,5 +15,156 @@
"confirm_tool_execution": "¿Desea ejecutar {name} con {args}? [y/N]: ",
"info_tool_skipped": "Omitiendo herramienta: {name}",
"info_dry_run_skipping": "DRY RUN: Omitiendo herramienta de modificación de estado {name}",
"info_second_pass": "Realizando un segundo paso con los resultados de la herramienta..."
"info_second_pass": "Realizando un segundo paso con los resultados de la herramienta...",
"ui.app.title": "Panel de AutoMetabuilder",
"ui.app.name": "AutoMetabuilder",
"ui.nav.dashboard": "Panel",
"ui.nav.workflow": "Flujo de trabajo",
"ui.nav.prompt": "Prompt",
"ui.nav.settings": "Configuración",
"ui.nav.translations": "Traducciones",
"ui.theme_toggle": "Cambiar tema",
"ui.actions.add": "Añadir",
"ui.actions.save": "Guardar",
"ui.actions.reset": "Restablecer",
"ui.actions.delete": "Eliminar",
"ui.actions.edit": "Editar",
"ui.actions.refresh": "Actualizar",
"ui.common.select_placeholder": "Seleccionar...",
"ui.choices.search_placeholder": "Escribe para buscar...",
"ui.choices.no_results": "No se encontraron resultados",
"ui.choices.no_choices": "No hay opciones disponibles",
"ui.dashboard.title": "Panel",
"ui.dashboard.subtitle": "Controla el bot y supervisa la actividad del sistema",
"ui.dashboard.bot_control": "Control del bot",
"ui.dashboard.run_strategy": "Estrategia de ejecución",
"ui.dashboard.run.single.title": "Iteración única",
"ui.dashboard.run.single.desc": "Una pasada completa por el flujo de trabajo.",
"ui.dashboard.run.repeat.title": "Repetir",
"ui.dashboard.run.repeat.desc": "Ejecuta un número fijo de ciclos.",
"ui.dashboard.run.repeat.label": "Iteraciones",
"ui.dashboard.run.yolo.title": "YOLO",
"ui.dashboard.run.yolo.desc": "Sigue iterando hasta que lo detengas.",
"ui.dashboard.automation": "Automatización",
"ui.dashboard.auto_approve.title": "Autoaprobar herramientas",
"ui.dashboard.auto_approve.desc": "Omite confirmaciones para que el bot ejecute más rápido.",
"ui.dashboard.stop_mvp.title": "Detener en MVP",
"ui.dashboard.stop_mvp.desc": "Pausa automáticamente cuando se alcance el hito MVP.",
"ui.dashboard.start_bot": "Iniciar bot",
"ui.dashboard.status.title": "Estado",
"ui.dashboard.status.bot_label": "Estado del bot",
"ui.dashboard.status.running": "En ejecución",
"ui.dashboard.status.idle": "Inactivo",
"ui.dashboard.status.mvp_label": "Hito MVP",
"ui.dashboard.status.mvp_reached": "Alcanzado",
"ui.dashboard.status.mvp_progress": "En progreso",
"ui.dashboard.logs.title": "Registros recientes",
"ui.workflow.title": "Constructor de flujo de trabajo",
"ui.workflow.subtitle": "Diseña el flujo de ejecución de tareas del bot",
"ui.workflow.card.title": "Tareas y pasos",
"ui.workflow.toggle_json": "Alternar JSON",
"ui.workflow.save": "Guardar flujo de trabajo",
"ui.workflow.empty": "Aún no hay tareas. Haz clic en \"Añadir tarea\" para crear tu primera tarea de flujo de trabajo.",
"ui.workflow.task_label": "Tarea {number}",
"ui.workflow.task_name_placeholder": "Nombre de la tarea",
"ui.workflow.type.standard": "Estándar",
"ui.workflow.type.loop": "Bucle",
"ui.workflow.max_label": "Máx.",
"ui.workflow.move_up": "Mover arriba",
"ui.workflow.move_down": "Mover abajo",
"ui.workflow.delete_task": "Eliminar tarea",
"ui.workflow.add_step": "Añadir paso",
"ui.workflow.add_task": "Añadir tarea",
"ui.workflow.select_action": "Selecciona una acción...",
"ui.workflow.step_type_placeholder": "Selecciona el tipo de acción...",
"ui.workflow.field.enable": "Habilitar",
"ui.workflow.remove_step": "Eliminar paso",
"ui.workflow.new_task": "Nueva tarea",
"ui.workflow.delete_task_confirm": "¿Eliminar esta tarea y todos sus pasos?",
"ui.workflow.untitled_task": "Tarea sin título",
"ui.prompt.title": "Constructor de prompts",
"ui.prompt.subtitle": "Define cómo piensa, habla y decide el asistente",
"ui.prompt.card.title": "Constructor de prompts",
"ui.prompt.step1.title": "Define al asistente",
"ui.prompt.step1.desc": "Describe quién es el asistente y cómo debe comportarse.",
"ui.prompt.step1.placeholder": "Eres un ingeniero de software senior que prefiere cambios pequeños y seguros.",
"ui.prompt.chip.senior.label": "Ingeniero senior",
"ui.prompt.chip.senior.snippet": "Eres un ingeniero de software senior centrado en la corrección y la claridad.",
"ui.prompt.chip.ask.label": "Hacer preguntas",
"ui.prompt.chip.ask.snippet": "Haz preguntas aclaratorias antes de hacer cambios arriesgados.",
"ui.prompt.chip.minimal.label": "Cambios mínimos",
"ui.prompt.chip.minimal.snippet": "Prefiere cambios mínimos y explica las compensaciones.",
"ui.prompt.step2.title": "Da la misión",
"ui.prompt.step2.desc": "Explica lo que el bot debe lograr ahora.",
"ui.prompt.step2.placeholder": "Revisa el repositorio, mejora la UI y resume lo que cambió.",
"ui.prompt.chip.ux.label": "Pulido UX",
"ui.prompt.chip.ux.snippet": "Céntrate en pulir la UX y evita grandes refactorizaciones.",
"ui.prompt.chip.tests.label": "Añadir tests",
"ui.prompt.chip.tests.snippet": "Añade tests cuando sea posible, pero evita mucho andamiaje.",
"ui.prompt.chip.summarize.label": "Resumir",
"ui.prompt.chip.summarize.snippet": "Resume los cambios y sugiere próximos pasos.",
"ui.prompt.model.label": "Elige un modelo",
"ui.prompt.model.desc": "Elige el equilibrio entre calidad y velocidad que se ajuste a la tarea.",
"ui.prompt.model.recommended": "Recomendado",
"ui.prompt.model.faster": "Más rápido",
"ui.prompt.raw.label": "YAML avanzado",
"ui.prompt.raw.desc": "Edita el YAML completo solo si necesitas un control fino.",
"ui.prompt.save": "Guardar prompt",
"ui.prompt.advanced_yaml": "YAML avanzado",
"ui.prompt.guidance.title": "Guía",
"ui.prompt.guidance.keep_human.title": "Manténlo humano",
"ui.prompt.guidance.keep_human.desc": "Escribe instrucciones como si estuvieras explicándolas a un compañero.",
"ui.prompt.guidance.be_specific.title": "Sé específico",
"ui.prompt.guidance.be_specific.desc": "Menciona restricciones como tiempo, alcance o expectativas de pruebas.",
"ui.prompt.guidance.raw.title": "Usa YAML avanzado con moderación",
"ui.prompt.guidance.raw.desc": "Cambia a YAML bruto solo si necesitas control total.",
"ui.settings.title": "Configuración",
"ui.settings.subtitle": "Configura servicios, seguridad y preferencias del entorno",
"ui.settings.callout.title": "Configuración clara",
"ui.settings.callout.body": "Cada campo explica qué hace. Añade descripciones en metadata.json para mantener legibles los ajustes personalizados.",
"ui.settings.api_keys": "Claves API",
"ui.settings.configuration": "Configuración",
"ui.settings.web_access": "Acceso a la interfaz web",
"ui.settings.other": "Otros ajustes",
"ui.settings.custom_default_desc": "Ajuste de entorno personalizado. Añade una descripción en metadata.json para verla aquí.",
"ui.settings.add.title": "Añadir nuevo ajuste",
"ui.settings.add.desc": "Usa claves en mayúsculas con guiones bajos, como API_TIMEOUT.",
"ui.settings.add.placeholder_key": "CLAVE",
"ui.settings.add.placeholder_value": "Valor",
"ui.settings.save_all": "Guardar todos los ajustes",
"ui.translations.title": "Traducciones",
"ui.translations.subtitle": "Crea, edita y mantiene archivos de idioma para los mensajes del bot",
"ui.translations.languages": "Idiomas",
"ui.translations.add_language_placeholder": "Añadir idioma...",
"ui.translations.select_language_placeholder": "Selecciona un idioma...",
"ui.translations.editor.title": "Editor de traducciones",
"ui.translations.editing_label": "Editando",
"ui.translations.missing_count": "{count} faltantes",
"ui.translations.all_set": "Todo listo",
"ui.translations.actions.fill_missing": "Rellenar faltantes",
"ui.translations.empty.title": "Elige un idioma",
"ui.translations.empty.body": "Selecciona un idioma de la lista para empezar a editar traducciones.",
"ui.translations.search.placeholder": "Buscar claves o texto...",
"ui.translations.toggle_missing": "Mostrar claves faltantes",
"ui.translations.add.key_placeholder": "nueva.clave",
"ui.translations.add.value_placeholder": "Texto de traducción",
"ui.translations.add.use_english": "Usar inglés",
"ui.translations.add.add_key": "Añadir clave",
"ui.translations.table.key": "Clave",
"ui.translations.table.translation": "Traducción",
"ui.translations.table.delete_title": "Eliminar clave",
"ui.translations.missing_label": "Faltante",
"ui.translations.hint_prefix": "EN:",
"ui.translations.prompt.enter_key": "Introduce primero un nombre de clave.",
"ui.translations.prompt.no_english": "No se encontró texto en inglés para esta clave.",
"ui.translations.confirm.replace_key": "Esta clave ya existe. ¿Reemplazarla?",
"ui.translations.confirm.delete_key": "¿Eliminar la clave de traducción \"{key}\"?",
"ui.translations.confirm.delete_translation": "¿Seguro que quieres eliminar la traducción \"{lang}\"?",
"ui.translations.errors.load": "No se pudo cargar la traducción",
"ui.translations.errors.load_prefix": "Error al cargar la traducción: ",
"ui.translations.errors.save": "No se pudo guardar",
"ui.translations.errors.save_prefix": "Error al guardar la traducción: ",
"ui.translations.errors.delete": "No se pudo eliminar",
"ui.translations.errors.delete_prefix": "Error al eliminar la traducción: ",
"ui.translations.notice.saved": "¡Traducción \"{lang}\" guardada correctamente!"
}

View File

@@ -15,5 +15,156 @@
"confirm_tool_execution": "Voulez-vous exécuter {name} avec {args} ? [y/N] : ",
"info_tool_skipped": "Omission de l'outil : {name}",
"info_dry_run_skipping": "DRY RUN : Omission de l'outil de modification d'état {name}",
"info_second_pass": "Deuxième passage avec les résultats de l'outil..."
"info_second_pass": "Deuxième passage avec les résultats de l'outil...",
"ui.app.title": "Tableau de bord AutoMetabuilder",
"ui.app.name": "AutoMetabuilder",
"ui.nav.dashboard": "Tableau de bord",
"ui.nav.workflow": "Flux de travail",
"ui.nav.prompt": "Prompt",
"ui.nav.settings": "Paramètres",
"ui.nav.translations": "Traductions",
"ui.theme_toggle": "Basculer le thème",
"ui.actions.add": "Ajouter",
"ui.actions.save": "Enregistrer",
"ui.actions.reset": "Réinitialiser",
"ui.actions.delete": "Supprimer",
"ui.actions.edit": "Modifier",
"ui.actions.refresh": "Actualiser",
"ui.common.select_placeholder": "Sélectionner...",
"ui.choices.search_placeholder": "Tapez pour rechercher...",
"ui.choices.no_results": "Aucun résultat",
"ui.choices.no_choices": "Aucune option disponible",
"ui.dashboard.title": "Tableau de bord",
"ui.dashboard.subtitle": "Contrôlez le bot et surveillez l'activité du système",
"ui.dashboard.bot_control": "Contrôle du bot",
"ui.dashboard.run_strategy": "Stratégie d'exécution",
"ui.dashboard.run.single.title": "Itération unique",
"ui.dashboard.run.single.desc": "Un passage complet dans le workflow.",
"ui.dashboard.run.repeat.title": "Répéter",
"ui.dashboard.run.repeat.desc": "Exécuter un nombre fixe de cycles.",
"ui.dashboard.run.repeat.label": "Itérations",
"ui.dashboard.run.yolo.title": "YOLO",
"ui.dashboard.run.yolo.desc": "Continuez à itérer jusqu'à l'arrêt.",
"ui.dashboard.automation": "Automatisation",
"ui.dashboard.auto_approve.title": "Auto-approuver les outils",
"ui.dashboard.auto_approve.desc": "Ignore les confirmations pour accélérer le bot.",
"ui.dashboard.stop_mvp.title": "Arrêter au MVP",
"ui.dashboard.stop_mvp.desc": "Mettre en pause automatiquement lorsque le jalon MVP est atteint.",
"ui.dashboard.start_bot": "Démarrer le bot",
"ui.dashboard.status.title": "Statut",
"ui.dashboard.status.bot_label": "Statut du bot",
"ui.dashboard.status.running": "En cours",
"ui.dashboard.status.idle": "Inactif",
"ui.dashboard.status.mvp_label": "Jalon MVP",
"ui.dashboard.status.mvp_reached": "Atteint",
"ui.dashboard.status.mvp_progress": "En cours",
"ui.dashboard.logs.title": "Logs récents",
"ui.workflow.title": "Constructeur de workflow",
"ui.workflow.subtitle": "Concevez le pipeline d'exécution des tâches du bot",
"ui.workflow.card.title": "Tâches et étapes",
"ui.workflow.toggle_json": "Basculer le JSON",
"ui.workflow.save": "Enregistrer le workflow",
"ui.workflow.empty": "Aucune tâche pour l'instant. Cliquez sur \"Ajouter une tâche\" pour créer votre première tâche de workflow.",
"ui.workflow.task_label": "Tâche {number}",
"ui.workflow.task_name_placeholder": "Nom de la tâche",
"ui.workflow.type.standard": "Standard",
"ui.workflow.type.loop": "Boucle",
"ui.workflow.max_label": "Max",
"ui.workflow.move_up": "Monter",
"ui.workflow.move_down": "Descendre",
"ui.workflow.delete_task": "Supprimer la tâche",
"ui.workflow.add_step": "Ajouter une étape",
"ui.workflow.add_task": "Ajouter une tâche",
"ui.workflow.select_action": "Sélectionnez une action...",
"ui.workflow.step_type_placeholder": "Sélectionnez un type d'action...",
"ui.workflow.field.enable": "Activer",
"ui.workflow.remove_step": "Supprimer l'étape",
"ui.workflow.new_task": "Nouvelle tâche",
"ui.workflow.delete_task_confirm": "Supprimer cette tâche et toutes ses étapes ?",
"ui.workflow.untitled_task": "Tâche sans titre",
"ui.prompt.title": "Constructeur de prompts",
"ui.prompt.subtitle": "Définissez comment l'assistant pense, parle et décide",
"ui.prompt.card.title": "Constructeur de prompts",
"ui.prompt.step1.title": "Définir l'assistant",
"ui.prompt.step1.desc": "Décrivez qui est l'assistant et comment il doit se comporter.",
"ui.prompt.step1.placeholder": "Vous êtes un ingénieur logiciel senior qui préfère des changements petits et sûrs.",
"ui.prompt.chip.senior.label": "Ingénieur senior",
"ui.prompt.chip.senior.snippet": "Vous êtes un ingénieur logiciel senior axé sur la justesse et la clarté.",
"ui.prompt.chip.ask.label": "Poser des questions",
"ui.prompt.chip.ask.snippet": "Posez des questions de clarification avant d'apporter des changements risqués.",
"ui.prompt.chip.minimal.label": "Diffs minimales",
"ui.prompt.chip.minimal.snippet": "Préférez des diffs minimales et expliquez les compromis.",
"ui.prompt.step2.title": "Donner la mission",
"ui.prompt.step2.desc": "Expliquez ce que le bot doit accomplir maintenant.",
"ui.prompt.step2.placeholder": "Examinez le dépôt, améliorez l'UI et résumez ce qui a changé.",
"ui.prompt.chip.ux.label": "Finition UX",
"ui.prompt.chip.ux.snippet": "Concentrez-vous sur la finition UX et évitez les grosses refactorisations.",
"ui.prompt.chip.tests.label": "Ajouter des tests",
"ui.prompt.chip.tests.snippet": "Ajoutez des tests quand c'est possible, mais évitez trop de scaffolding.",
"ui.prompt.chip.summarize.label": "Résumer",
"ui.prompt.chip.summarize.snippet": "Résumez les changements et proposez les prochaines étapes.",
"ui.prompt.model.label": "Choisir un modèle",
"ui.prompt.model.desc": "Choisissez l'équilibre qualité/vitesse adapté à la tâche.",
"ui.prompt.model.recommended": "Recommandé",
"ui.prompt.model.faster": "Plus rapide",
"ui.prompt.raw.label": "YAML avancé",
"ui.prompt.raw.desc": "Modifiez le YAML complet seulement si vous avez besoin d'un contrôle fin.",
"ui.prompt.save": "Enregistrer le prompt",
"ui.prompt.advanced_yaml": "YAML avancé",
"ui.prompt.guidance.title": "Conseils",
"ui.prompt.guidance.keep_human.title": "Restez humain",
"ui.prompt.guidance.keep_human.desc": "Rédigez les instructions comme si vous briefiez un collègue.",
"ui.prompt.guidance.be_specific.title": "Soyez précis",
"ui.prompt.guidance.be_specific.desc": "Mentionnez des contraintes comme le temps, le périmètre ou les attentes de tests.",
"ui.prompt.guidance.raw.title": "Utilisez le YAML avancé avec parcimonie",
"ui.prompt.guidance.raw.desc": "Basculez vers le YAML brut uniquement si vous avez besoin d'un contrôle total.",
"ui.settings.title": "Paramètres",
"ui.settings.subtitle": "Configurez les services, la sécurité et les préférences d'environnement",
"ui.settings.callout.title": "Paramètres compréhensibles",
"ui.settings.callout.body": "Chaque champ explique son rôle. Ajoutez des descriptions dans metadata.json pour rendre les paramètres personnalisés lisibles.",
"ui.settings.api_keys": "Clés API",
"ui.settings.configuration": "Configuration",
"ui.settings.web_access": "Accès à l'interface web",
"ui.settings.other": "Autres paramètres",
"ui.settings.custom_default_desc": "Paramètre d'environnement personnalisé. Ajoutez une description dans metadata.json pour l'afficher ici.",
"ui.settings.add.title": "Ajouter un paramètre",
"ui.settings.add.desc": "Utilisez des clés en majuscules avec des underscores, comme API_TIMEOUT.",
"ui.settings.add.placeholder_key": "CLÉ",
"ui.settings.add.placeholder_value": "Valeur",
"ui.settings.save_all": "Enregistrer tous les paramètres",
"ui.translations.title": "Traductions",
"ui.translations.subtitle": "Créez, éditez et maintenez les fichiers de langue pour les messages du bot",
"ui.translations.languages": "Langues",
"ui.translations.add_language_placeholder": "Ajouter une langue...",
"ui.translations.select_language_placeholder": "Sélectionnez une langue...",
"ui.translations.editor.title": "Éditeur de traductions",
"ui.translations.editing_label": "Modification",
"ui.translations.missing_count": "{count} manquants",
"ui.translations.all_set": "Tout est prêt",
"ui.translations.actions.fill_missing": "Compléter les manquants",
"ui.translations.empty.title": "Choisir une langue",
"ui.translations.empty.body": "Sélectionnez une langue dans la liste pour commencer à éditer les traductions.",
"ui.translations.search.placeholder": "Rechercher des clés ou du texte...",
"ui.translations.toggle_missing": "Afficher les clés manquantes",
"ui.translations.add.key_placeholder": "nouvelle.cle",
"ui.translations.add.value_placeholder": "Texte de traduction",
"ui.translations.add.use_english": "Utiliser l'anglais",
"ui.translations.add.add_key": "Ajouter une clé",
"ui.translations.table.key": "Clé",
"ui.translations.table.translation": "Traduction",
"ui.translations.table.delete_title": "Supprimer la clé",
"ui.translations.missing_label": "Manquant",
"ui.translations.hint_prefix": "EN:",
"ui.translations.prompt.enter_key": "Saisissez d'abord un nom de clé.",
"ui.translations.prompt.no_english": "Aucun texte anglais trouvé pour cette clé.",
"ui.translations.confirm.replace_key": "Cette clé existe déjà. La remplacer ?",
"ui.translations.confirm.delete_key": "Supprimer la clé de traduction \"{key}\" ?",
"ui.translations.confirm.delete_translation": "Voulez-vous vraiment supprimer la traduction \"{lang}\" ?",
"ui.translations.errors.load": "Échec du chargement de la traduction",
"ui.translations.errors.load_prefix": "Erreur lors du chargement de la traduction : ",
"ui.translations.errors.save": "Échec de l'enregistrement",
"ui.translations.errors.save_prefix": "Erreur lors de l'enregistrement : ",
"ui.translations.errors.delete": "Échec de la suppression",
"ui.translations.errors.delete_prefix": "Erreur lors de la suppression : ",
"ui.translations.notice.saved": "Traduction \"{lang}\" enregistrée avec succès !"
}

View File

@@ -15,5 +15,156 @@
"confirm_tool_execution": "Wilt u {name} uitvoeren met {args}? [y/N]: ",
"info_tool_skipped": "Overslaan van tool: {name}",
"info_dry_run_skipping": "DRY RUN: Overslaan van statuswijzigende tool {name}",
"info_second_pass": "Tweede ronde uitvoeren met tool-resultaten..."
"info_second_pass": "Tweede ronde uitvoeren met tool-resultaten...",
"ui.app.title": "AutoMetabuilder-dashboard",
"ui.app.name": "AutoMetabuilder",
"ui.nav.dashboard": "Dashboard",
"ui.nav.workflow": "Workflow",
"ui.nav.prompt": "Prompt",
"ui.nav.settings": "Instellingen",
"ui.nav.translations": "Vertalingen",
"ui.theme_toggle": "Thema wisselen",
"ui.actions.add": "Toevoegen",
"ui.actions.save": "Opslaan",
"ui.actions.reset": "Resetten",
"ui.actions.delete": "Verwijderen",
"ui.actions.edit": "Bewerken",
"ui.actions.refresh": "Vernieuwen",
"ui.common.select_placeholder": "Selecteer...",
"ui.choices.search_placeholder": "Typ om te zoeken...",
"ui.choices.no_results": "Geen resultaten gevonden",
"ui.choices.no_choices": "Geen opties beschikbaar",
"ui.dashboard.title": "Dashboard",
"ui.dashboard.subtitle": "Beheer de bot en bewaak de systeemactiviteit",
"ui.dashboard.bot_control": "Botbediening",
"ui.dashboard.run_strategy": "Uitvoeringsstrategie",
"ui.dashboard.run.single.title": "Enkele iteratie",
"ui.dashboard.run.single.desc": "Eén volledige ronde door de workflow.",
"ui.dashboard.run.repeat.title": "Herhalen",
"ui.dashboard.run.repeat.desc": "Voer een vast aantal cycli uit.",
"ui.dashboard.run.repeat.label": "Iteraties",
"ui.dashboard.run.yolo.title": "YOLO",
"ui.dashboard.run.yolo.desc": "Blijf itereren totdat je stopt.",
"ui.dashboard.automation": "Automatisering",
"ui.dashboard.auto_approve.title": "Tools automatisch goedkeuren",
"ui.dashboard.auto_approve.desc": "Sla bevestigingen over zodat de bot sneller kan draaien.",
"ui.dashboard.stop_mvp.title": "Stop bij MVP",
"ui.dashboard.stop_mvp.desc": "Pauzeer automatisch wanneer het MVP-mijlpunt is bereikt.",
"ui.dashboard.start_bot": "Start bot",
"ui.dashboard.status.title": "Status",
"ui.dashboard.status.bot_label": "Botstatus",
"ui.dashboard.status.running": "Actief",
"ui.dashboard.status.idle": "Inactief",
"ui.dashboard.status.mvp_label": "MVP-mijlpaal",
"ui.dashboard.status.mvp_reached": "Bereikt",
"ui.dashboard.status.mvp_progress": "Bezig",
"ui.dashboard.logs.title": "Recente logs",
"ui.workflow.title": "Workflowbouwer",
"ui.workflow.subtitle": "Ontwerp de taakuitvoeringspijplijn van de bot",
"ui.workflow.card.title": "Taken en stappen",
"ui.workflow.toggle_json": "JSON wisselen",
"ui.workflow.save": "Workflow opslaan",
"ui.workflow.empty": "Nog geen taken. Klik op \"Taak toevoegen\" om je eerste workflowtaak te maken.",
"ui.workflow.task_label": "Taak {number}",
"ui.workflow.task_name_placeholder": "Taaknaam",
"ui.workflow.type.standard": "Standaard",
"ui.workflow.type.loop": "Lus",
"ui.workflow.max_label": "Max",
"ui.workflow.move_up": "Omhoog",
"ui.workflow.move_down": "Omlaag",
"ui.workflow.delete_task": "Taak verwijderen",
"ui.workflow.add_step": "Stap toevoegen",
"ui.workflow.add_task": "Taak toevoegen",
"ui.workflow.select_action": "Selecteer een actie...",
"ui.workflow.step_type_placeholder": "Selecteer een actietype...",
"ui.workflow.field.enable": "Inschakelen",
"ui.workflow.remove_step": "Stap verwijderen",
"ui.workflow.new_task": "Nieuwe taak",
"ui.workflow.delete_task_confirm": "Deze taak en alle stappen verwijderen?",
"ui.workflow.untitled_task": "Naamloze taak",
"ui.prompt.title": "Promptbouwer",
"ui.prompt.subtitle": "Bepaal hoe de assistent denkt, praat en beslist",
"ui.prompt.card.title": "Promptbouwer",
"ui.prompt.step1.title": "Definieer de assistent",
"ui.prompt.step1.desc": "Beschrijf wie de assistent is en hoe hij zich moet gedragen.",
"ui.prompt.step1.placeholder": "Je bent een senior software engineer die kleine, veilige wijzigingen verkiest.",
"ui.prompt.chip.senior.label": "Senior engineer",
"ui.prompt.chip.senior.snippet": "Je bent een senior software engineer gericht op correctheid en duidelijkheid.",
"ui.prompt.chip.ask.label": "Vragen stellen",
"ui.prompt.chip.ask.snippet": "Stel verduidelijkende vragen voordat je riskante wijzigingen aanbrengt.",
"ui.prompt.chip.minimal.label": "Minimale diffs",
"ui.prompt.chip.minimal.snippet": "Geef de voorkeur aan minimale diffs en leg de afwegingen uit.",
"ui.prompt.step2.title": "Geef de missie",
"ui.prompt.step2.desc": "Leg uit wat de bot nu moet bereiken.",
"ui.prompt.step2.placeholder": "Beoordeel de repo, verbeter de UI en vat samen wat er is veranderd.",
"ui.prompt.chip.ux.label": "UX-polish",
"ui.prompt.chip.ux.snippet": "Richt je op UX-polish en vermijd grote refactors.",
"ui.prompt.chip.tests.label": "Tests toevoegen",
"ui.prompt.chip.tests.snippet": "Voeg tests toe waar mogelijk, maar vermijd zware scaffolding.",
"ui.prompt.chip.summarize.label": "Samenvatten",
"ui.prompt.chip.summarize.snippet": "Vat de wijzigingen samen en stel vervolgstappen voor.",
"ui.prompt.model.label": "Kies een model",
"ui.prompt.model.desc": "Kies de balans tussen kwaliteit en snelheid die bij de taak past.",
"ui.prompt.model.recommended": "Aanbevolen",
"ui.prompt.model.faster": "Sneller",
"ui.prompt.raw.label": "Geavanceerde YAML",
"ui.prompt.raw.desc": "Bewerk de volledige YAML alleen als je fijne controle nodig hebt.",
"ui.prompt.save": "Prompt opslaan",
"ui.prompt.advanced_yaml": "Geavanceerde YAML",
"ui.prompt.guidance.title": "Richtlijnen",
"ui.prompt.guidance.keep_human.title": "Houd het menselijk",
"ui.prompt.guidance.keep_human.desc": "Schrijf instructies alsof je een collega brief.",
"ui.prompt.guidance.be_specific.title": "Wees specifiek",
"ui.prompt.guidance.be_specific.desc": "Noem beperkingen zoals tijd, scope of testverwachtingen.",
"ui.prompt.guidance.raw.title": "Gebruik geavanceerde YAML spaarzaam",
"ui.prompt.guidance.raw.desc": "Schakel alleen over naar ruwe YAML als je volledige controle nodig hebt.",
"ui.settings.title": "Instellingen",
"ui.settings.subtitle": "Configureer services, beveiliging en omgevingsvoorkeuren",
"ui.settings.callout.title": "Mensvriendelijke instellingen",
"ui.settings.callout.body": "Elk veld legt uit wat het doet. Voeg beschrijvingen toe in metadata.json om aangepaste instellingen leesbaar te houden.",
"ui.settings.api_keys": "API-sleutels",
"ui.settings.configuration": "Configuratie",
"ui.settings.web_access": "Toegang tot webinterface",
"ui.settings.other": "Andere instellingen",
"ui.settings.custom_default_desc": "Aangepaste omgevingsinstelling. Voeg een beschrijving toe in metadata.json om dit hier te tonen.",
"ui.settings.add.title": "Nieuwe instelling toevoegen",
"ui.settings.add.desc": "Gebruik hoofdletters met underscores, zoals API_TIMEOUT.",
"ui.settings.add.placeholder_key": "SLEUTEL",
"ui.settings.add.placeholder_value": "Waarde",
"ui.settings.save_all": "Alle instellingen opslaan",
"ui.translations.title": "Vertalingen",
"ui.translations.subtitle": "Maak, bewerk en onderhoud taalbestanden voor botberichten",
"ui.translations.languages": "Talen",
"ui.translations.add_language_placeholder": "Taal toevoegen...",
"ui.translations.select_language_placeholder": "Selecteer taal...",
"ui.translations.editor.title": "Vertalingseditor",
"ui.translations.editing_label": "Bewerken",
"ui.translations.missing_count": "{count} ontbrekend",
"ui.translations.all_set": "Alles geregeld",
"ui.translations.actions.fill_missing": "Ontbrekende invullen",
"ui.translations.empty.title": "Kies een taal",
"ui.translations.empty.body": "Selecteer een taal uit de lijst om vertalingen te bewerken.",
"ui.translations.search.placeholder": "Zoek naar sleutels of tekst...",
"ui.translations.toggle_missing": "Ontbrekende sleutels tonen",
"ui.translations.add.key_placeholder": "nieuwe.sleutel",
"ui.translations.add.value_placeholder": "Vertaaltekst",
"ui.translations.add.use_english": "Gebruik Engels",
"ui.translations.add.add_key": "Sleutel toevoegen",
"ui.translations.table.key": "Sleutel",
"ui.translations.table.translation": "Vertaling",
"ui.translations.table.delete_title": "Sleutel verwijderen",
"ui.translations.missing_label": "Ontbrekend",
"ui.translations.hint_prefix": "EN:",
"ui.translations.prompt.enter_key": "Voer eerst een sleutelnaam in.",
"ui.translations.prompt.no_english": "Geen Engelse tekst gevonden voor deze sleutel.",
"ui.translations.confirm.replace_key": "Deze sleutel bestaat al. Vervangen?",
"ui.translations.confirm.delete_key": "Vertalingssleutel \"{key}\" verwijderen?",
"ui.translations.confirm.delete_translation": "Weet je zeker dat je de vertaling \"{lang}\" wilt verwijderen?",
"ui.translations.errors.load": "Vertaling laden mislukt",
"ui.translations.errors.load_prefix": "Fout bij laden van vertaling: ",
"ui.translations.errors.save": "Opslaan mislukt",
"ui.translations.errors.save_prefix": "Fout bij opslaan: ",
"ui.translations.errors.delete": "Verwijderen mislukt",
"ui.translations.errors.delete_prefix": "Fout bij verwijderen: ",
"ui.translations.notice.saved": "Vertaling \"{lang}\" is succesvol opgeslagen!"
}

View File

@@ -15,5 +15,156 @@
"confirm_tool_execution": "Do ye want to fire {name} with {args}? [y/N]: ",
"info_tool_skipped": "Lettin' {name} sail by.",
"info_dry_run_skipping": "DRY RUN: Stoppin' the crew from changin' the ship's course {name}",
"info_second_pass": "Making a second tack with the tool's findings..."
"info_second_pass": "Making a second tack with the tool's findings...",
"ui.app.title": "AutoMetabuilder Cap'n's Deck",
"ui.app.name": "AutoMetabuilder",
"ui.nav.dashboard": "Deck",
"ui.nav.workflow": "Flow o' Work",
"ui.nav.prompt": "Prompt",
"ui.nav.settings": "Settings",
"ui.nav.translations": "Tongues",
"ui.theme_toggle": "Hoist the theme",
"ui.actions.add": "Add",
"ui.actions.save": "Stow",
"ui.actions.reset": "Reset",
"ui.actions.delete": "Scuttle",
"ui.actions.edit": "Tweak",
"ui.actions.refresh": "Refresh",
"ui.common.select_placeholder": "Choose...",
"ui.choices.search_placeholder": "Type t' search...",
"ui.choices.no_results": "No loot found",
"ui.choices.no_choices": "No choices aboard",
"ui.dashboard.title": "Deck",
"ui.dashboard.subtitle": "Command the bot and watch the ship's activity",
"ui.dashboard.bot_control": "Bot Helm",
"ui.dashboard.run_strategy": "Run Tactics",
"ui.dashboard.run.single.title": "Single Run",
"ui.dashboard.run.single.desc": "One full pass through the workflow.",
"ui.dashboard.run.repeat.title": "Repeat",
"ui.dashboard.run.repeat.desc": "Run a fixed number o' cycles.",
"ui.dashboard.run.repeat.label": "Iterations",
"ui.dashboard.run.yolo.title": "YOLO",
"ui.dashboard.run.yolo.desc": "Keep iteratin' till ye stop it.",
"ui.dashboard.automation": "Auto-magic",
"ui.dashboard.auto_approve.title": "Auto-approve tools",
"ui.dashboard.auto_approve.desc": "Skip confirmations so the bot sails faster.",
"ui.dashboard.stop_mvp.title": "Stop at MVP",
"ui.dashboard.stop_mvp.desc": "Heave to when the MVP milestone be reached.",
"ui.dashboard.start_bot": "Hoist the Bot",
"ui.dashboard.status.title": "Status",
"ui.dashboard.status.bot_label": "Bot Status",
"ui.dashboard.status.running": "Running",
"ui.dashboard.status.idle": "Idle",
"ui.dashboard.status.mvp_label": "MVP Milestone",
"ui.dashboard.status.mvp_reached": "Reached",
"ui.dashboard.status.mvp_progress": "In Progress",
"ui.dashboard.logs.title": "Recent Logs",
"ui.workflow.title": "Workflow Builder",
"ui.workflow.subtitle": "Chart the bot's task pipeline",
"ui.workflow.card.title": "Tasks & Steps",
"ui.workflow.toggle_json": "Toggle JSON",
"ui.workflow.save": "Stow Workflow",
"ui.workflow.empty": "No tasks yet. Click \"Add Task\" to chart yer first workflow task.",
"ui.workflow.task_label": "Task {number}",
"ui.workflow.task_name_placeholder": "Task Name",
"ui.workflow.type.standard": "Standard",
"ui.workflow.type.loop": "Loop",
"ui.workflow.max_label": "Max",
"ui.workflow.move_up": "Move up",
"ui.workflow.move_down": "Move down",
"ui.workflow.delete_task": "Scuttle task",
"ui.workflow.add_step": "Add Step",
"ui.workflow.add_task": "Add Task",
"ui.workflow.select_action": "Select action...",
"ui.workflow.step_type_placeholder": "Select action type...",
"ui.workflow.field.enable": "Enable",
"ui.workflow.remove_step": "Remove step",
"ui.workflow.new_task": "New Task",
"ui.workflow.delete_task_confirm": "Scuttle this task and all its steps?",
"ui.workflow.untitled_task": "Untitled Task",
"ui.prompt.title": "Prompt Builder",
"ui.prompt.subtitle": "Shape how the matey thinks, speaks, and decides",
"ui.prompt.card.title": "Prompt Builder",
"ui.prompt.step1.title": "Define the matey",
"ui.prompt.step1.desc": "Describe who the matey be and how it should behave.",
"ui.prompt.step1.placeholder": "Ye be a senior software engineer who prefers small, safe changes.",
"ui.prompt.chip.senior.label": "Senior engineer",
"ui.prompt.chip.senior.snippet": "Ye be a senior software engineer focused on correctness and clarity.",
"ui.prompt.chip.ask.label": "Ask questions",
"ui.prompt.chip.ask.snippet": "Ask clarifying questions before makin' risky changes.",
"ui.prompt.chip.minimal.label": "Minimal diffs",
"ui.prompt.chip.minimal.snippet": "Prefer minimal diffs and explain trade-offs.",
"ui.prompt.step2.title": "Give the mission",
"ui.prompt.step2.desc": "Explain what the bot should accomplish right now.",
"ui.prompt.step2.placeholder": "Review the repo, improve the UI, and summarize what changed.",
"ui.prompt.chip.ux.label": "UX polish",
"ui.prompt.chip.ux.snippet": "Focus on UX polish, and avoid major refactors.",
"ui.prompt.chip.tests.label": "Add tests",
"ui.prompt.chip.tests.snippet": "Add tests when possible, but avoid heavy scaffolding.",
"ui.prompt.chip.summarize.label": "Summarize",
"ui.prompt.chip.summarize.snippet": "Summarize changes and suggest next steps.",
"ui.prompt.model.label": "Choose a model",
"ui.prompt.model.desc": "Pick the balance of quality and speed that fits the task.",
"ui.prompt.model.recommended": "Recommended",
"ui.prompt.model.faster": "Faster",
"ui.prompt.raw.label": "Advanced YAML",
"ui.prompt.raw.desc": "Edit the full YAML only if ye need fine control.",
"ui.prompt.save": "Save Prompt",
"ui.prompt.advanced_yaml": "Advanced YAML",
"ui.prompt.guidance.title": "Guidance",
"ui.prompt.guidance.keep_human.title": "Keep it human",
"ui.prompt.guidance.keep_human.desc": "Write instructions the way ye would brief a crewmate.",
"ui.prompt.guidance.be_specific.title": "Be specific",
"ui.prompt.guidance.be_specific.desc": "Mention constraints like time, scope, or testing expectations.",
"ui.prompt.guidance.raw.title": "Use advanced YAML sparingly",
"ui.prompt.guidance.raw.desc": "Only switch to raw YAML if ye need full control.",
"ui.settings.title": "Settings",
"ui.settings.subtitle": "Set services, security, and environment preferences",
"ui.settings.callout.title": "Crew-friendly settings",
"ui.settings.callout.body": "Each field explains what it does. Add descriptions in metadata.json to keep custom settings readable fer the crew.",
"ui.settings.api_keys": "API Keys",
"ui.settings.configuration": "Configuration",
"ui.settings.web_access": "Web UI Access",
"ui.settings.other": "Other Settings",
"ui.settings.custom_default_desc": "Custom environment setting. Add a description in metadata.json to show it here.",
"ui.settings.add.title": "Add New Setting",
"ui.settings.add.desc": "Use uppercase keys with underscores, like API_TIMEOUT.",
"ui.settings.add.placeholder_key": "KEY",
"ui.settings.add.placeholder_value": "Value",
"ui.settings.save_all": "Save All Settings",
"ui.translations.title": "Translations",
"ui.translations.subtitle": "Create, edit, and keep language files fer bot messages",
"ui.translations.languages": "Languages",
"ui.translations.add_language_placeholder": "Add language...",
"ui.translations.select_language_placeholder": "Select language...",
"ui.translations.editor.title": "Translation Editor",
"ui.translations.editing_label": "Editing",
"ui.translations.missing_count": "{count} missing",
"ui.translations.all_set": "All set",
"ui.translations.actions.fill_missing": "Fill Missing",
"ui.translations.empty.title": "Pick a language",
"ui.translations.empty.body": "Select a language from the list to start editing translations.",
"ui.translations.search.placeholder": "Search keys or text...",
"ui.translations.toggle_missing": "Show missing keys",
"ui.translations.add.key_placeholder": "new.key",
"ui.translations.add.value_placeholder": "Translation text",
"ui.translations.add.use_english": "Use English",
"ui.translations.add.add_key": "Add Key",
"ui.translations.table.key": "Key",
"ui.translations.table.translation": "Translation",
"ui.translations.table.delete_title": "Delete key",
"ui.translations.missing_label": "Missing",
"ui.translations.hint_prefix": "EN:",
"ui.translations.prompt.enter_key": "Enter a key name first.",
"ui.translations.prompt.no_english": "No English text found for this key.",
"ui.translations.confirm.replace_key": "This key already exists. Replace it?",
"ui.translations.confirm.delete_key": "Delete translation key \"{key}\"?",
"ui.translations.confirm.delete_translation": "Be ye sure ye want to delete the \"{lang}\" translation?",
"ui.translations.errors.load": "Failed to load translation",
"ui.translations.errors.load_prefix": "Error loading translation: ",
"ui.translations.errors.save": "Failed to save",
"ui.translations.errors.save_prefix": "Error saving translation: ",
"ui.translations.errors.delete": "Failed to delete",
"ui.translations.errors.delete_prefix": "Error deleting translation: ",
"ui.translations.notice.saved": "Translation \"{lang}\" saved successfully!"
}

View File

@@ -1,21 +1,31 @@
import os
import time
import socket
import multiprocessing
import pytest
import uvicorn
from autometabuilder.web.server import app
def run_server():
multiprocessing.set_start_method("spawn", force=True)
def run_server(port):
os.environ["MOCK_WEB_UI"] = "true"
os.environ["WEB_USER"] = "testuser"
os.environ["WEB_PASSWORD"] = "testpass"
uvicorn.run(app, host="127.0.0.1", port=8001, log_level="error")
os.environ["APP_LANG"] = "en"
uvicorn.run(app, host="127.0.0.1", port=port, log_level="error")
def get_free_port():
with socket.socket(socket.AF_INET, socket.SOCK_STREAM) as sock:
sock.bind(("127.0.0.1", 0))
return sock.getsockname()[1]
@pytest.fixture(scope="session")
def server():
proc = multiprocessing.Process(target=run_server, daemon=True)
port = get_free_port()
proc = multiprocessing.Process(target=run_server, args=(port,), daemon=True)
proc.start()
# Give the server a moment to start
time.sleep(2)
yield "http://127.0.0.1:8001"
yield f"http://127.0.0.1:{port}"
proc.terminate()

View File

@@ -4,13 +4,20 @@ import os
import re
from playwright.sync_api import Page, expect
UI_MESSAGES_PATH = os.path.join(os.path.dirname(__file__), "../../src/autometabuilder/messages_en.json")
with open(UI_MESSAGES_PATH, "r", encoding="utf-8") as f:
UI_MESSAGES = json.load(f)
def t(key, fallback=None):
return UI_MESSAGES.get(key, fallback or key)
def test_login_and_dashboard(page: Page, server: str):
# Go to the server with auth
auth_url = server.replace("http://", "http://testuser:testpass@")
page.goto(auth_url)
# Check if we are on the dashboard - select h1 in the active section
expect(page.locator("#dashboard.active h1")).to_contain_text("Dashboard")
expect(page.locator("#dashboard.active h1")).to_contain_text(t("ui.dashboard.title"))
# User info is now in sidebar footer
expect(page.locator(".amb-sidebar-footer")).to_contain_text("testuser")
@@ -41,21 +48,20 @@ def test_update_prompt(page: Page, server: str):
page.click("[data-section='prompt']")
page.wait_for_selector("#prompt.active")
# Find prompt textarea - specifically in the prompt section
textarea = page.locator("#prompt textarea[name='content']")
original_content = textarea.input_value()
new_content = original_content + "\n# Test Comment"
textarea.fill(new_content)
system_prompt = page.locator("#prompt textarea[name='system_content']")
user_prompt = page.locator("#prompt textarea[name='user_content']")
system_prompt.fill("Test system prompt")
user_prompt.fill("Test user prompt")
# Click save prompt
page.click("#prompt button:has-text('Save Prompt')")
page.click(f"#prompt button:has-text('{t('ui.prompt.save')}')")
# Verify it updated
page.reload()
page.click("[data-section='prompt']")
page.wait_for_selector("#prompt.active")
expect(page.locator("#prompt textarea[name='content']")).to_have_value(new_content)
expect(page.locator("#prompt textarea[name='system_content']")).to_have_value("Test system prompt")
expect(page.locator("#prompt textarea[name='user_content']")).to_have_value("Test user prompt")
def test_update_settings(page: Page, server: str):
auth_url = server.replace("http://", "http://testuser:testpass@")
@@ -68,26 +74,17 @@ def test_update_settings(page: Page, server: str):
# Wait for Choices.js to initialize
page.wait_for_timeout(1000)
# Add a new setting using Choices.js select
# Click on the outer .choices wrapper (first match only)
key_choices = page.locator("#settings select[name='new_env_key']").locator("xpath=ancestor::div[@class='choices' or contains(@class, 'choices ')]").first
key_choices.click()
page.keyboard.type("GITHUB_TOKEN")
page.keyboard.press("Enter")
# Add a new setting using text inputs
page.fill("#settings input[name='new_env_key']", "TEST_SETTING")
page.fill("#settings input[name='new_env_value']", "42")
# For new_env_value
value_choices = page.locator("#settings select[name='new_env_value']").locator("xpath=ancestor::div[@class='choices' or contains(@class, 'choices ')]").first
value_choices.click()
page.keyboard.type("DEBUG")
page.keyboard.press("Enter")
page.click("#settings button:has-text('Save Settings')")
page.click(f"#settings button:has-text('{t('ui.settings.save_all')}')")
# Verify it appeared in the table
page.reload()
page.click("[data-section='settings']")
page.wait_for_selector("#settings.active")
expect(page.locator("#settings code:has-text('GITHUB_TOKEN')")).to_be_visible()
expect(page.locator("#settings input[name='env_TEST_SETTING']")).to_be_visible()
def test_navigation_sections(page: Page, server: str):
"""Test that sidebar navigation works correctly"""
@@ -205,11 +202,11 @@ def test_workflow_builder_renders(page: Page, server: str):
page.wait_for_selector("#workflow-builder")
# Should have at least the "Add Task" button
expect(page.locator("#workflow-builder button:has-text('Add Task')")).to_be_visible()
expect(page.locator(f"#workflow-builder button:has-text('{t('ui.workflow.add_task')}')")).to_be_visible()
# Toggle raw JSON should work
page.click("#workflow button:has-text('Toggle Raw JSON')")
page.click(f"#workflow button:has-text('{t('ui.workflow.toggle_json')}')")
expect(page.locator("#workflow-content")).to_be_visible()
page.click("#workflow button:has-text('Toggle Raw JSON')")
page.click(f"#workflow button:has-text('{t('ui.workflow.toggle_json')}')")
expect(page.locator("#workflow-content")).not_to_be_visible()