trypost/lang/es/automations.php
Paulo Castellano 58d8e066b5
Add workspace webhooks and drop the unused automation webhook node (#326)
* Add workspace webhooks and drop the unused automation webhook node.

Give workspaces HMAC-signed outgoing webhooks for the post lifecycle, with retry, auto-pause, replay, and live logs, and keep HTTP Request as the only outbound automation node.

* Tighten webhook controller and validation after review.

Drop the redundant workspace redirects, prune logs without counting, and validate events/status with Rule::enum.

* Move leftover webhook UI copy behind i18n.

HTTP status phrases, delete-cancel, and validation attribute names were still English literals.

* Build the webhook-paused email through Maizzle.

The hand-written Blade skipped the shared layout, header, and footer used by the other mail templates.

* Cover real webhook dispatch paths and restyle the webhook pages.

* Ask for the shared delete keyword when confirming a webhook delete.

The endpoint URL is a poor confirm string; posts and assets already use the common "delete" keyword.

* Fix webhook review blockers so CI can go green.

Drop leftover French automation keys, stop mutating Inertia log props, and show delivered_at instead of created_at.

* Close the remaining webhook review gaps.

Keep Echo log updates across infinite scroll, align the channel with the policy, persist log ids across retries, and fail unknown automation nodes without throwing.

* Stop webhook delivery after disable and record last sent only on success.

Queued jobs now skip paused or disabled endpoints unless the user replays, and changing the URL re-pings it first.

* Limit webhooks to owners and admins, and encrypt signing secrets.

Members can no longer create or inspect outgoing integrations, and secrets stay encrypted at rest.

* Cover webhook secret hiding, skip-ping, and failed-delivery edges.

* Send the full post on webhooks after labels and platforms are saved.

* Fix webhook payloads for integer media ids and type webhook status.

* Split the webhook show page into focused components.

* Reset live webhook logs when switching endpoints.

* Keep the newest webhook logs at the top after live merges.

* Cast media item ids to string without the extra scalar check.

* Add post.unscheduled webhooks and put the log id on the envelope.

Unscheduling is now a first-class event, and receivers can send the delivery id back so we can find the matching log.

* Translate webhook event names in the UI.

* Make the webhook show page full-width and stop stacking flash toasts.

* Translate remaining webhook UI copy in every locale.

* Sign webhook pings and drop author email from the payload.

* Send signed webhook tests after create instead of pinging on save.

Create and update only block private URLs so the receiver can copy the secret first. The show page then sends a signed webhook.test with an object data envelope.

* Polish webhook test UX and always mint the dispatch log id in the job.

Keep send-test in the actions menu (its own group) and drop the leftover constructor param so retries reuse the serialized id instead of a caller-supplied one.
2026-09-04 09:43:29 -03:00

402 lines
18 KiB
PHP

<?php
declare(strict_types=1);
return [
'mobile_notice' => 'El editor de automatizaciones funciona mejor en una pantalla más grande. Ábrelo en un ordenador para crear tu flujo de trabajo.',
'title' => 'Automatizaciones',
'default_name' => 'Nueva automatización',
'actions' => [
'new' => 'Nueva automatización',
'edit' => 'Editar',
'save' => 'Guardar',
'activate' => 'Activar',
'pause' => 'Pausar',
'delete' => 'Eliminar',
'retry' => 'Reintentar',
'guide' => 'Aprende cómo funciona',
],
'tabs' => [
'build' => 'Construir',
'variables' => 'Variables',
'test' => 'Probar',
],
'nav' => [
'workflow' => 'Workflow',
'invocations' => 'Invocaciones',
'metrics' => 'Métricas',
'settings' => 'Configuración',
],
'settings' => [
'general' => 'General',
'general_description' => 'Renombra esta automatización.',
'name_label' => 'Nombre',
'name_saved' => 'Automatización renombrada.',
'status_title' => 'Estado',
'status_description' => 'Actívala para que empiece a ejecutarse, o pausa para detenerla.',
'activated_at' => 'Activada el :date',
'paused_at' => 'Pausada el :date',
'created_at' => 'Creada el :date',
'danger_title' => 'Zona de peligro',
'danger_description' => 'Acciones irreversibles.',
'delete_title' => 'Eliminar esta automatización',
'delete_description' => 'Elimina permanentemente la automatización y su historial de ejecuciones.',
],
'status_run' => [
'pending' => 'Pendiente',
'running' => 'Ejecutando',
'waiting' => 'Esperando',
'completed' => 'Completado',
'failed' => 'Fallido',
'cancelled' => 'Cancelado',
],
'node_type' => [
'trigger' => 'Disparador',
'generate' => 'Generar contenido',
'delay' => 'Espera',
'condition' => 'Condición',
'publish' => 'Publicar',
'end' => 'Fin',
'fetch_rss' => 'Obtener RSS',
'http_request' => 'Petición HTTP',
],
'invocations' => [
'empty' => 'Aún no hay invocaciones.',
'refresh' => 'Actualizar',
'search_placeholder' => 'Buscar por ID de ejecución…',
'copied' => 'ID de ejecución copiado.',
'loading' => 'Cargando pasos…',
'no_steps' => 'Sin pasos registrados.',
'load_error' => 'No se pudieron cargar los pasos.',
'steps' => '{0}Sin pasos|{1}:count paso|[2,*]:count pasos',
'filter' => [
'all' => 'Todos los estados',
],
'columns' => [
'timestamp' => 'Fecha',
'run' => 'Ejecución',
'status' => 'Estado',
'message' => 'Último mensaje',
'duration' => 'Duración',
],
'summary' => [
'completed' => 'Workflow completado',
'failed' => 'Workflow fallido',
'running' => 'Workflow en ejecución',
'cancelled' => 'Workflow cancelado',
'pending' => 'Workflow pendiente',
],
],
'metrics' => [
'overview' => 'Resumen',
'runs_over_time' => 'Ejecuciones a lo largo del tiempo',
'posts_by_platform' => 'Posts por plataforma',
'no_posts' => 'No se publicaron posts en este período.',
'cards' => [
'runs' => 'Total de ejecuciones',
'completed' => 'Completadas',
'failed' => 'Fallidas',
'in_progress' => 'En progreso',
'success_rate' => 'Tasa de éxito',
'avg_duration' => 'Duración media',
'posts_created' => 'Posts creados',
],
'legend' => [
'started' => 'Iniciadas',
'completed' => 'Completadas',
'failed' => 'Fallidas',
],
],
'categories' => [
'sources' => 'Fuentes',
'content' => 'Contenido',
'flow' => 'Flujo',
'output' => 'Salida',
],
'variables' => [
'title' => 'Variables del workflow',
'hint' => 'Valores reutilizables referenciados en cualquier lugar con {{ variables.KEY }}. Almacenados cifrados.',
'empty' => 'Aún no hay variables.',
'key' => 'Clave',
'value' => 'Valor',
'key_placeholder' => 'API_KEY',
'value_placeholder' => 'Valor',
'add' => 'Nueva variable',
],
'expr' => [
'trigger_event' => 'Nombre del evento del disparador',
'trigger_fired_at' => 'Cuándo se disparó',
'trigger_post_id' => 'ID del post que disparó',
'trigger_post_content' => 'Contenido del post que disparó',
'trigger_post_status' => 'Estado del post que disparó',
'trigger_post_scheduled_at' => 'Cuándo está programado el post',
'trigger_post_published_at' => 'Cuándo se publicó el post',
'fetched_title' => 'Título del ítem obtenido',
'fetched_link' => 'Enlace del ítem obtenido',
'fetched_date' => 'Fecha de publicación del ítem obtenido',
'fetched_content' => 'Contenido completo del ítem obtenido',
'fetched_description' => 'Resumen del ítem obtenido',
'fetched_author' => 'Autor del ítem obtenido',
'fetched_image' => 'URL de la imagen del ítem obtenido',
'fetched_categories' => 'Categorías del ítem obtenido',
'fetched_enclosure' => 'Multimedia del ítem (audio/vídeo/archivo)',
'fetched_pubdate' => 'Fecha de publicación del ítem obtenido',
'fetched_http' => 'Ítem HTTP obtenido (añade un campo)',
'generated_content' => 'Contenido del post generado por IA',
'generated_post_url' => 'URL del post generado por IA',
'variable' => 'Variable del flujo',
'now' => 'Fecha y hora actuales',
],
'test' => [
'description' => 'Ejecuta la automatización de punta a punta usando un payload de disparo sintético. Útil para validar cada nodo sin esperar el cronograma o el feed real.',
'starting' => 'Iniciando ejecución de prueba…',
'in_progress' => 'En progreso',
'completed' => 'Completado',
'failed' => 'Fallido',
'waiting' => 'Esperando',
'close' => 'Cerrar',
'no_node_runs' => 'Esperando que el primer nodo comience…',
'node_input' => 'Entrada',
'node_output' => 'Salida',
'node_error' => 'Error',
'no_new_items' => 'Sin elementos nuevos — no se ejecutó nada después.',
'error_starting' => 'No se pudo iniciar la ejecución de prueba.',
'with_real_data' => 'Con datos reales',
'run' => 'Ejecutar prueba',
'idle_hint' => 'Pulsa Ejecutar prueba para correr la automatización de principio a fin.',
'real_data_hint' => 'Esta prueba publicará posts, avanzará marcadores de polling y disparará efectos secundarios externos.',
'dry_badge' => 'Prueba seca',
],
'status' => [
'draft' => 'Borrador',
'active' => 'Activa',
'paused' => 'Pausada',
],
'index' => [
'empty_title' => 'Aún no hay automatizaciones',
'empty_description' => 'Crea tu primera automatización para empezar a publicar en piloto automático.',
'columns' => [
'name' => 'Nombre',
'status' => 'Estado',
'created' => 'Creada',
],
],
'form' => [
'activate_error_fallback' => 'No se pudo activar la automatización.',
'pause_error_fallback' => 'No se pudo pausar la automatización.',
'save_error_fallback' => 'No se pudo guardar la automatización.',
'save_success' => 'Automatización guardada.',
'empty_canvas_title' => 'Empieza a construir tu automatización',
'empty_canvas_description' => 'Arrastra un nodo del panel izquierdo para empezar.',
'name_placeholder' => 'Automatización sin título',
],
'nodes' => [
'trigger' => 'Disparador',
'generate' => 'Generar',
'delay' => 'Retraso',
'condition' => 'Condición',
'publish' => 'Publicar',
'end' => 'Terminar',
'end_summary' => 'Termina la automatización aquí',
'fetch_rss' => 'Obtener RSS',
'http_request' => 'Petición HTTP',
'handles' => [
'items' => 'con elementos',
'no_items' => 'sin elementos',
],
],
'config' => [
'select_placeholder' => 'Selecciona…',
'invalid_json' => 'Esto aún no es un JSON válido.',
'expand_editor' => 'Expandir editor',
'minimize_editor' => 'Minimizar',
'trigger' => [
'type' => 'Tipo de disparador',
'types' => [
'schedule' => 'Programación',
'post_published' => 'Cuando un post se publica',
'post_scheduled' => 'Cuando un post se programa',
],
'post_published_hint' => 'Se ejecuta cada vez que un post en este workspace se publica. El post queda disponible en {{ trigger.post }} para los siguientes nodos.',
'post_scheduled_hint' => 'Se ejecuta cada vez que un post en este workspace se programa. El post queda disponible en {{ trigger.post }}.',
'schedule' => [
'field' => 'Intervalo de disparo',
'fields' => [
'minutes' => 'Minutos',
'hours' => 'Horas',
'days' => 'Días',
'weeks' => 'Semanas',
'months' => 'Meses',
],
'minutes_interval' => 'Minutos entre disparos',
'hours_interval' => 'Horas entre disparos',
'days_interval' => 'Días entre disparos',
'hour' => 'Disparar a la hora',
'minute' => 'Disparar al minuto',
'weekdays' => 'Disparar en días',
'day_of_month' => 'Día del mes',
'weekday_names' => [
'sun' => 'Dom',
'mon' => 'Lun',
'tue' => 'Mar',
'wed' => 'Mié',
'thu' => 'Jue',
'fri' => 'Vie',
'sat' => 'Sáb',
],
'summary' => [
'every_n_minutes' => 'Se ejecuta cada minuto|Se ejecuta cada :count minutos',
'every_n_hours' => 'Se ejecuta cada hora en el minuto :minute|Se ejecuta cada :count horas en el minuto :minute',
'every_n_days' => 'Se ejecuta cada día a las :time|Se ejecuta cada :count días a las :time',
'weekly' => 'Se ejecuta :days a las :time',
'monthly' => 'Se ejecuta el día :day de cada mes a las :time',
],
],
],
'generate' => [
'social_accounts' => 'Cuentas sociales',
'social_accounts_empty' => 'Sin cuentas sociales conectadas. Conecta una primero.',
'target_slide_count' => 'Diapositivas a generar',
'prompt_template' => 'Plantilla de prompt',
'prompt_template_hint' => 'Escribe {{ para insertar datos de pasos anteriores.',
'image_count' => 'Imágenes a generar',
'image_count_hint' => '0 = post solo texto (sin imagen). 1 = imagen única. 2+ = carrusel.',
'use_brand_voice' => 'Usar voz de marca',
'use_brand_voice_hint' => 'Aplica la descripción y la voz de tu marca. Desactiva para curaduría fiel de fuentes de terceros (noticias, RSS).',
'use_brand_visuals' => 'Usar visual de marca',
'use_brand_visuals_hint' => 'Guía las imágenes de IA con los colores e identidad de tu marca. Desactiva para imágenes neutrales, guiadas solo por el tema del post.',
'style' => 'Estilo',
'account_summary' => ':count cuenta · :format|:count cuentas · :format',
'formats' => [
'single' => 'único',
'carousel' => 'carrusel',
],
],
'delay' => [
'duration' => 'Duración',
'unit' => 'Unidad',
'units' => [
'minutes' => 'Minutos',
'hours' => 'Horas',
'days' => 'Días',
],
],
'condition' => [
'field' => 'Campo',
'operator' => 'Operador',
'operators' => [
'contains' => 'contiene',
'not_contains' => 'no contiene',
'equals' => 'es igual a',
'not_equals' => 'no es igual a',
'matches' => 'coincide (regex)',
'greater_than' => 'mayor que',
'less_than' => 'menor que',
],
'value' => 'Valor',
],
'publish' => [
'mode' => 'Modo',
'modes' => [
'now' => 'Publicar ahora',
'scheduled' => 'Programar',
'draft' => 'Guardar como borrador',
],
'scheduled_offset' => 'Diferencia desde el disparador (minutos)',
'offset_summary' => ':mode · +:offset min',
],
'end' => [
'reason' => 'Razón (opcional)',
'reason_placeholder' => 'p.ej. Filtrado por la condición',
],
'fetch_rss' => [
'feed_url' => 'URL del feed',
'feed_url_hint' => 'En la primera ejecución, el watermark se fija en "ahora" para no inundar los siguientes nodos con ítems históricos. Ejecuciones siguientes solo ven ítems nuevos.',
'inspect' => 'Inspeccionar feed',
'inspecting' => 'Inspeccionando…',
'inspect_hint' => 'Obtén una muestra para descubrir los campos disponibles para usar en los siguientes nodos.',
'inspect_error' => 'No se pudo leer este feed. Revisa la URL e inténtalo de nuevo.',
'discovered_fields' => 'Campos disponibles',
'discovered_empty' => 'No se encontraron campos en el último ítem.',
],
'http_request' => [
'url' => 'URL',
'method' => 'Método',
'auth_type' => 'Autenticación',
'auth' => [
'none' => 'Ninguna (pública)',
'bearer' => 'Bearer token',
'basic' => 'Basic auth',
'api_key' => 'Header de API key',
],
'bearer_token' => 'Bearer token',
'basic_username' => 'Usuario',
'basic_password' => 'Contraseña',
'api_key_header' => 'Nombre del header',
'api_key_value' => 'API key',
'body_template' => 'Plantilla del body (JSON)',
'headers' => 'Headers',
'header_name' => 'Nombre del header',
'header_value' => 'Valor',
'add_header' => 'Agregar header',
'polling_section' => 'Lista y deduplicación (opcional)',
'polling_hint' => 'Cuando la respuesta es una lista, cada ítem ejecuta el flujo por separado. Un objeto único se ejecuta una vez.',
'items_path' => 'Ruta de ítems',
'items_path_hint' => 'Deja vacío si la respuesta ya es un array. Usa una ruta con puntos (ej: data.items) para un array anidado, o * para un objeto con claves por id.',
'item_key_path' => 'Ruta de clave del ítem',
'item_key_path_hint' => 'Ruta JSON a un id único (ej: id). Los ítems ya vistos se omiten, así un feed sin fechas aún reenvía solo los nuevos.',
'item_date_path' => 'Ruta de fecha del ítem',
'item_date_path_hint' => 'Ruta JSON al timestamp del ítem (ej: published_at). Preferido sobre la ruta de clave cuando existe. La primera obtención registra el punto de partida y no reenvía nada, así un feed existente nunca inunda el primer día.',
],
],
'delete' => [
'title' => 'Eliminar automatización',
'description' => '¿Estás seguro de que deseas eliminar esta automatización? Todas las ejecuciones y elementos del disparador también serán eliminados. Esta acción no se puede deshacer.',
'confirm' => 'Eliminar',
'cancel' => 'Cancelar',
],
'flash' => [
'deleted' => '¡Automatización eliminada correctamente!',
],
'errors' => [
'no_active_social_accounts' => 'No hay cuentas sociales activas configuradas para esta automatización.',
'must_have_one_trigger' => 'La automatización debe tener exactamente un nodo disparador.',
'trigger_must_be_connected' => 'El nodo disparador debe estar conectado a al menos un nodo.',
'graph_contains_cycle' => 'El grafo de la automatización contiene un ciclo.',
'only_failed_can_retry' => 'Solo se pueden reintentar ejecuciones fallidas.',
'no_generated_post' => 'No se encontró un post generado en la ejecución.',
'url_not_allowed' => 'La URL de la petición apunta a una dirección privada o inaccesible y fue bloqueada.',
'node_no_longer_exists' => 'El nodo :node_id ya no existe en la automatización.',
'no_trigger_connection' => 'Ningún nodo está conectado al nodo disparador.',
'fetch_rss_missing_url' => 'Al nodo Obtener RSS le falta la URL del feed.',
'fetch_rss_request_failed' => 'La solicitud del feed RSS falló.',
'fetch_rss_malformed' => 'El feed RSS está mal formado.',
'http_missing_url' => 'Al nodo de petición HTTP le falta la URL.',
'http_request_exception' => 'La petición HTTP lanzó una excepción.',
'http_request_failed' => 'La petición HTTP falló.',
'http_items_path_not_array' => 'El items path no resolvió a una lista.',
'generate_image_format_required' => 'La generación con IA solo crea imágenes. Elige un formato de imagen (no vídeo).',
],
];