trypost/lang/fr/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' => 'L\'éditeur d\'automatisation fonctionne mieux sur un grand écran. Ouvrez-le sur un ordinateur pour créer votre workflow.',
'title' => 'Automatisations',
'default_name' => 'Nouvelle automatisation',
'actions' => [
'new' => 'Nouvelle automatisation',
'edit' => 'Modifier',
'save' => 'Enregistrer',
'activate' => 'Activer',
'pause' => 'Mettre en pause',
'delete' => 'Supprimer',
'retry' => 'Réessayer',
'guide' => 'Découvrir comment ça marche',
],
'tabs' => [
'build' => 'Construire',
'variables' => 'Variables',
'test' => 'Tester',
],
'nav' => [
'workflow' => 'Workflow',
'invocations' => 'Invocations',
'metrics' => 'Métriques',
'settings' => 'Paramètres',
],
'settings' => [
'general' => 'Général',
'general_description' => 'Renommez cette automatisation.',
'name_label' => 'Nom',
'name_saved' => 'Automatisation renommée.',
'status_title' => 'Statut',
'status_description' => 'Activez pour la lancer, ou mettez en pause pour l\'arrêter.',
'activated_at' => 'Activée le :date',
'paused_at' => 'Mise en pause le :date',
'created_at' => 'Créée le :date',
'danger_title' => 'Zone de danger',
'danger_description' => 'Actions irréversibles.',
'delete_title' => 'Supprimer cette automatisation',
'delete_description' => 'Supprime définitivement l\'automatisation et son historique d\'exécution.',
],
'status_run' => [
'pending' => 'En attente',
'running' => 'En cours',
'waiting' => 'En attente',
'completed' => 'Terminée',
'failed' => 'Échouée',
'cancelled' => 'Annulée',
],
'node_type' => [
'trigger' => 'Déclencheur',
'generate' => 'Générer du contenu',
'delay' => 'Délai',
'condition' => 'Condition',
'publish' => 'Publier',
'end' => 'Fin',
'fetch_rss' => 'Récupérer RSS',
'http_request' => 'Requête HTTP',
],
'invocations' => [
'empty' => 'Aucune invocation pour le moment.',
'refresh' => 'Actualiser',
'search_placeholder' => 'Rechercher par ID d\'exécution…',
'copied' => 'ID d\'exécution copié.',
'loading' => 'Chargement des étapes…',
'no_steps' => 'Aucune étape enregistrée.',
'load_error' => 'Impossible de charger les étapes.',
'steps' => '{0}Aucune étape|{1}:count étape|[2,*]:count étapes',
'filter' => [
'all' => 'Tous les statuts',
],
'columns' => [
'timestamp' => 'Horodatage',
'run' => 'Exécution',
'status' => 'Statut',
'message' => 'Dernier message',
'duration' => 'Durée',
],
'summary' => [
'completed' => 'Workflow terminé',
'failed' => 'Workflow échoué',
'running' => 'Workflow en cours',
'cancelled' => 'Workflow annulé',
'pending' => 'Workflow en attente',
],
],
'metrics' => [
'overview' => 'Vue d\'ensemble',
'runs_over_time' => 'Exécutions dans le temps',
'posts_by_platform' => 'Publications par plateforme',
'no_posts' => 'Aucune publication publiée sur cette période.',
'cards' => [
'runs' => 'Total des exécutions',
'completed' => 'Terminées',
'failed' => 'Échouées',
'in_progress' => 'En cours',
'success_rate' => 'Taux de réussite',
'avg_duration' => 'Durée moyenne',
'posts_created' => 'Publications créées',
],
'legend' => [
'started' => 'Démarrées',
'completed' => 'Terminées',
'failed' => 'Échouées',
],
],
'categories' => [
'sources' => 'Sources',
'content' => 'Contenu',
'flow' => 'Flux',
'output' => 'Sortie',
],
'variables' => [
'title' => 'Variables du workflow',
'hint' => 'Valeurs réutilisables référencées partout avec {{ variables.KEY }}. Stockées de manière chiffrée.',
'empty' => 'Aucune variable pour le moment.',
'key' => 'Clé',
'value' => 'Valeur',
'key_placeholder' => 'API_KEY',
'value_placeholder' => 'Valeur',
'add' => 'Nouvelle variable',
],
'expr' => [
'trigger_event' => 'Nom de l\'événement déclencheur',
'trigger_fired_at' => 'Moment du déclenchement',
'trigger_post_id' => 'ID de la publication déclencheuse',
'trigger_post_content' => 'Contenu de la publication déclencheuse',
'trigger_post_status' => 'Statut de la publication déclencheuse',
'trigger_post_scheduled_at' => 'Moment de programmation de la publication',
'trigger_post_published_at' => 'Moment de publication de la publication',
'fetched_title' => 'Titre de l\'élément récupéré',
'fetched_link' => 'Lien de l\'élément récupéré',
'fetched_date' => 'Date de publication de l\'élément récupéré',
'fetched_content' => 'Contenu complet de l\'élément récupéré',
'fetched_description' => 'Résumé de l\'élément récupéré',
'fetched_author' => 'Auteur de l\'élément récupéré',
'fetched_image' => 'URL de l\'image de l\'élément récupéré',
'fetched_categories' => 'Catégories de l\'élément récupéré',
'fetched_enclosure' => 'Média de l\'élément récupéré (audio/vidéo/fichier)',
'fetched_pubdate' => 'Date de publication de l\'élément récupéré',
'fetched_http' => 'Élément HTTP récupéré (ajoutez un champ)',
'generated_content' => 'Contenu de publication généré par l\'IA',
'generated_post_url' => 'URL de la publication générée par l\'IA',
'variable' => 'Variable du workflow',
'now' => 'Date et heure actuelles',
],
'test' => [
'description' => 'Exécute l\'automatisation de bout en bout à l\'aide d\'un déclencheur synthétisé. Utile pour valider chaque nœud sans attendre la programmation réelle ou le flux.',
'starting' => 'Démarrage du test…',
'in_progress' => 'En cours',
'completed' => 'Terminé',
'failed' => 'Échoué',
'waiting' => 'En attente',
'close' => 'Fermer',
'no_node_runs' => 'En attente du démarrage du premier nœud…',
'node_input' => 'Entrée',
'node_output' => 'Sortie',
'node_error' => 'Erreur',
'no_new_items' => 'Aucun nouvel élément — rien n\'a été exécuté en aval.',
'error_starting' => 'Impossible de démarrer le test.',
'with_real_data' => 'Avec des données réelles',
'run' => 'Lancer le test',
'idle_hint' => 'Cliquez sur Lancer le test pour exécuter l\'automatisation de bout en bout.',
'real_data_hint' => 'Ce test publiera des publications, fera avancer les repères de polling et déclenchera des effets externes.',
'dry_badge' => 'Simulation',
],
'status' => [
'draft' => 'Brouillon',
'active' => 'Active',
'paused' => 'En pause',
],
'index' => [
'empty_title' => 'Aucune automatisation pour le moment',
'empty_description' => 'Créez votre première automatisation pour commencer à publier en pilote automatique.',
'columns' => [
'name' => 'Nom',
'status' => 'Statut',
'created' => 'Créée le',
],
],
'form' => [
'activate_error_fallback' => 'Impossible d\'activer l\'automatisation.',
'pause_error_fallback' => 'Impossible de mettre en pause l\'automatisation.',
'save_error_fallback' => 'Impossible d\'enregistrer l\'automatisation.',
'save_success' => 'Automatisation enregistrée.',
'empty_canvas_title' => 'Commencez à construire votre automatisation',
'empty_canvas_description' => 'Faites glisser un nœud depuis le panneau de gauche pour commencer.',
'name_placeholder' => 'Automatisation sans titre',
],
'nodes' => [
'trigger' => 'Déclencheur',
'generate' => 'Générer',
'delay' => 'Délai',
'condition' => 'Condition',
'publish' => 'Publier',
'end' => 'Fin',
'end_summary' => 'Arrête l\'automatisation ici',
'fetch_rss' => 'Récupérer RSS',
'http_request' => 'Requête HTTP',
'handles' => [
'items' => 'a des éléments',
'no_items' => 'aucun élément',
],
],
'config' => [
'select_placeholder' => 'Sélectionner…',
'invalid_json' => 'Ce n\'est pas encore du JSON valide.',
'expand_editor' => 'Agrandir l\'éditeur',
'minimize_editor' => 'Réduire',
'trigger' => [
'type' => 'Type de déclencheur',
'types' => [
'schedule' => 'Programmation',
'post_published' => 'Lorsqu\'une publication est publiée',
'post_scheduled' => 'Lorsqu\'une publication est programmée',
],
'post_published_hint' => 'S\'exécute chaque fois qu\'une publication de cet espace de travail est publiée. La publication publiée est disponible via {{ trigger.post }} pour les nœuds en aval.',
'post_scheduled_hint' => 'S\'exécute chaque fois qu\'une publication de cet espace de travail est programmée. La publication programmée est disponible via {{ trigger.post }}.',
'schedule' => [
'field' => 'Intervalle de déclenchement',
'fields' => [
'minutes' => 'Minutes',
'hours' => 'Heures',
'days' => 'Jours',
'weeks' => 'Semaines',
'months' => 'Mois',
],
'minutes_interval' => 'Minutes entre les déclenchements',
'hours_interval' => 'Heures entre les déclenchements',
'days_interval' => 'Jours entre les déclenchements',
'hour' => 'Déclencher à l\'heure',
'minute' => 'Déclencher à la minute',
'weekdays' => 'Déclencher les jours de la semaine',
'day_of_month' => 'Jour du mois',
'weekday_names' => [
'sun' => 'Dim',
'mon' => 'Lun',
'tue' => 'Mar',
'wed' => 'Mer',
'thu' => 'Jeu',
'fri' => 'Ven',
'sat' => 'Sam',
],
'summary' => [
'every_n_minutes' => 'S\'exécute chaque minute|S\'exécute toutes les :count minutes',
'every_n_hours' => 'S\'exécute chaque heure à la minute :minute|S\'exécute toutes les :count heures à la minute :minute',
'every_n_days' => 'S\'exécute chaque jour à :time|S\'exécute tous les :count jours à :time',
'weekly' => 'S\'exécute chaque :days à :time',
'monthly' => 'S\'exécute le :day de chaque mois à :time',
],
],
],
'generate' => [
'social_accounts' => 'Comptes sociaux',
'social_accounts_empty' => 'Aucun compte social connecté. Connectez-en un d\'abord.',
'target_slide_count' => 'Diapositives à générer',
'prompt_template' => 'Modèle de prompt',
'prompt_template_hint' => 'Tapez {{ pour insérer des données des étapes précédentes.',
'image_count' => 'Images à générer',
'image_count_hint' => '0 = publication texte seul (sans image). 1 = image unique. 2+ = carrousel.',
'use_brand_voice' => 'Utiliser la voix de la marque',
'use_brand_voice_hint' => 'Appliquez la description et la voix de votre marque. Désactivez pour une curation fidèle de sources tierces (actualités, RSS).',
'use_brand_visuals' => 'Utiliser les visuels de la marque',
'use_brand_visuals_hint' => 'Orientez les images de l\'IA avec les couleurs et l\'identité de votre marque. Désactivez pour des visuels neutres guidés uniquement par le sujet de la publication.',
'style' => 'Style',
'account_summary' => ':count compte · :format|:count comptes · :format',
'formats' => [
'single' => 'unique',
'carousel' => 'carrousel',
],
],
'delay' => [
'duration' => 'Durée',
'unit' => 'Unité',
'units' => [
'minutes' => 'Minutes',
'hours' => 'Heures',
'days' => 'Jours',
],
],
'condition' => [
'field' => 'Champ',
'operator' => 'Opérateur',
'operators' => [
'contains' => 'contient',
'not_contains' => 'ne contient pas',
'equals' => 'égal à',
'not_equals' => 'différent de',
'matches' => 'correspond (regex)',
'greater_than' => 'supérieur à',
'less_than' => 'inférieur à',
],
'value' => 'Valeur',
],
'publish' => [
'mode' => 'Mode',
'modes' => [
'now' => 'Publier maintenant',
'scheduled' => 'Programmer',
'draft' => 'Enregistrer comme brouillon',
],
'scheduled_offset' => 'Décalage par rapport au déclencheur (minutes)',
'offset_summary' => ':mode · +:offset min',
],
'end' => [
'reason' => 'Raison (facultatif)',
'reason_placeholder' => 'par ex. Filtré par la condition',
],
'fetch_rss' => [
'feed_url' => 'URL du flux',
'feed_url_hint' => 'Lors de la première exécution, le repère est fixé à « maintenant » afin que les éléments historiques n\'inondent pas les nœuds en aval. Les exécutions suivantes ne voient que les éléments plus récents que le dernier relevé.',
'inspect' => 'Inspecter le flux',
'inspecting' => 'Inspection…',
'inspect_hint' => 'Récupérez un échantillon pour découvrir les champs disponibles pour les nœuds en aval.',
'inspect_error' => 'Impossible de lire ce flux. Vérifiez l\'URL et réessayez.',
'discovered_fields' => 'Champs disponibles',
'discovered_empty' => 'Aucun champ trouvé dans le dernier élément.',
],
'http_request' => [
'url' => 'URL',
'method' => 'Méthode',
'auth_type' => 'Authentification',
'auth' => [
'none' => 'Aucune (public)',
'bearer' => 'Jeton Bearer',
'basic' => 'Authentification basique',
'api_key' => 'En-tête de clé API',
],
'bearer_token' => 'Jeton Bearer',
'basic_username' => 'Nom d\'utilisateur',
'basic_password' => 'Mot de passe',
'api_key_header' => 'Nom de l\'en-tête',
'api_key_value' => 'Clé API',
'body_template' => 'Modèle de corps (JSON)',
'headers' => 'En-têtes',
'header_name' => 'Nom de l\'en-tête',
'header_value' => 'Valeur',
'add_header' => 'Ajouter un en-tête',
'polling_section' => 'Liste et déduplication (facultatif)',
'polling_hint' => 'Lorsque la réponse est une liste, chaque élément exécute le workflow séparément. Un objet unique s\'exécute une fois.',
'items_path' => 'Chemin des éléments',
'items_path_hint' => 'Laissez vide si la réponse est déjà un tableau. Utilisez un chemin à points (par ex. data.items) pour un tableau imbriqué, ou * pour un objet indexé par id.',
'item_key_path' => 'Chemin de la clé d\'élément',
'item_key_path_hint' => 'Chemin JSON vers un id unique (par ex. id). Les éléments déjà vus sont ignorés, de sorte qu\'un flux sans dates ne transmet que les nouvelles entrées.',
'item_date_path' => 'Chemin de la date d\'élément',
'item_date_path_hint' => 'Chemin JSON vers l\'horodatage de l\'élément (par ex. published_at). Privilégié au chemin de clé lorsqu\'il est disponible. Le premier relevé enregistre la référence et ne transmet rien, de sorte qu\'un flux existant n\'inonde jamais dès le premier jour.',
],
],
'delete' => [
'title' => 'Supprimer l\'automatisation',
'description' => 'Voulez-vous vraiment supprimer cette automatisation ? Toutes les exécutions et les éléments déclencheurs seront également supprimés. Cette action est irréversible.',
'confirm' => 'Supprimer',
'cancel' => 'Annuler',
],
'flash' => [
'deleted' => 'Automatisation supprimée avec succès !',
],
'errors' => [
'no_active_social_accounts' => 'Aucun compte social actif configuré pour cette automatisation.',
'must_have_one_trigger' => 'L\'automatisation doit comporter exactement un nœud déclencheur.',
'trigger_must_be_connected' => 'Le nœud déclencheur doit être connecté à au moins un nœud.',
'graph_contains_cycle' => 'Le graphe de l\'automatisation contient un cycle.',
'only_failed_can_retry' => 'Seules les exécutions échouées peuvent être relancées.',
'no_generated_post' => 'Aucune publication générée trouvée pour cette exécution.',
'url_not_allowed' => 'L\'URL de la requête pointe vers une adresse privée ou inaccessible et a été bloquée.',
'node_no_longer_exists' => 'Le nœud :node_id n\'existe plus dans l\'automatisation.',
'no_trigger_connection' => 'Aucun nœud connecté au nœud déclencheur.',
'fetch_rss_missing_url' => 'Il manque une URL de flux au nœud Récupérer RSS.',
'fetch_rss_request_failed' => 'La requête du flux RSS a échoué.',
'fetch_rss_malformed' => 'Le flux RSS est mal formé.',
'http_missing_url' => 'Il manque une URL au nœud de requête HTTP.',
'http_request_exception' => 'La requête HTTP a levé une exception.',
'http_request_failed' => 'La requête HTTP a échoué.',
'http_items_path_not_array' => 'Le chemin des éléments ne correspond pas à une liste.',
'generate_image_format_required' => 'La génération IA ne crée que des images. Choisissez un format image (pas vidéo).',
],
];