trypost/lang/de/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
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

<?php
declare(strict_types=1);
return [
'mobile_notice' => 'Der Automatisierungs-Editor funktioniert am besten auf einem größeren Bildschirm. Öffne ihn auf einem Desktop, um deinen Workflow zu erstellen.',
'title' => 'Automatisierungen',
'default_name' => 'Neue Automatisierung',
'actions' => [
'new' => 'Neue Automatisierung',
'edit' => 'Bearbeiten',
'save' => 'Speichern',
'activate' => 'Aktivieren',
'pause' => 'Pausieren',
'delete' => 'Löschen',
'retry' => 'Erneut versuchen',
'guide' => 'So funktioniert es',
],
'tabs' => [
'build' => 'Erstellen',
'variables' => 'Variablen',
'test' => 'Test',
],
'nav' => [
'workflow' => 'Workflow',
'invocations' => 'Ausführungen',
'metrics' => 'Kennzahlen',
'settings' => 'Einstellungen',
],
'settings' => [
'general' => 'Allgemein',
'general_description' => 'Benenne diese Automatisierung um.',
'name_label' => 'Name',
'name_saved' => 'Automatisierung umbenannt.',
'status_title' => 'Status',
'status_description' => 'Aktiviere sie, um sie auszuführen, oder pausiere sie, um sie zu stoppen.',
'activated_at' => 'Aktiviert :date',
'paused_at' => 'Pausiert :date',
'created_at' => 'Erstellt :date',
'danger_title' => 'Gefahrenzone',
'danger_description' => 'Unumkehrbare Aktionen.',
'delete_title' => 'Diese Automatisierung löschen',
'delete_description' => 'Entfernt die Automatisierung und ihren Ausführungsverlauf dauerhaft.',
],
'status_run' => [
'pending' => 'Ausstehend',
'running' => 'Läuft',
'waiting' => 'Wartet',
'completed' => 'Abgeschlossen',
'failed' => 'Fehlgeschlagen',
'cancelled' => 'Abgebrochen',
],
'node_type' => [
'trigger' => 'Trigger',
'generate' => 'Inhalt generieren',
'delay' => 'Verzögerung',
'condition' => 'Bedingung',
'publish' => 'Veröffentlichen',
'end' => 'Ende',
'fetch_rss' => 'RSS abrufen',
'http_request' => 'HTTP-Anfrage',
],
'invocations' => [
'empty' => 'Noch keine Ausführungen.',
'refresh' => 'Aktualisieren',
'search_placeholder' => 'Nach Ausführungs-ID suchen…',
'copied' => 'Ausführungs-ID kopiert.',
'loading' => 'Schritte werden geladen…',
'no_steps' => 'Keine Schritte aufgezeichnet.',
'load_error' => 'Schritte konnten nicht geladen werden.',
'steps' => '{0}Keine Schritte|{1}:count Schritt|[2,*]:count Schritte',
'filter' => [
'all' => 'Alle Status',
],
'columns' => [
'timestamp' => 'Zeitstempel',
'run' => 'Ausführung',
'status' => 'Status',
'message' => 'Letzte Meldung',
'duration' => 'Dauer',
],
'summary' => [
'completed' => 'Workflow abgeschlossen',
'failed' => 'Workflow fehlgeschlagen',
'running' => 'Workflow läuft',
'cancelled' => 'Workflow abgebrochen',
'pending' => 'Workflow ausstehend',
],
],
'metrics' => [
'overview' => 'Übersicht',
'runs_over_time' => 'Ausführungen im Zeitverlauf',
'posts_by_platform' => 'Beiträge nach Plattform',
'no_posts' => 'In diesem Zeitraum wurden keine Beiträge veröffentlicht.',
'cards' => [
'runs' => 'Ausführungen gesamt',
'completed' => 'Abgeschlossen',
'failed' => 'Fehlgeschlagen',
'in_progress' => 'In Bearbeitung',
'success_rate' => 'Erfolgsquote',
'avg_duration' => 'Durchschn. Dauer',
'posts_created' => 'Erstellte Beiträge',
],
'legend' => [
'started' => 'Gestartet',
'completed' => 'Abgeschlossen',
'failed' => 'Fehlgeschlagen',
],
],
'categories' => [
'sources' => 'Quellen',
'content' => 'Inhalt',
'flow' => 'Ablauf',
'output' => 'Ausgabe',
],
'variables' => [
'title' => 'Workflow-Variablen',
'hint' => 'Wiederverwendbare Werte, die überall mit {{ variables.KEY }} referenziert werden. Verschlüsselt gespeichert.',
'empty' => 'Noch keine Variablen.',
'key' => 'Schlüssel',
'value' => 'Wert',
'key_placeholder' => 'API_KEY',
'value_placeholder' => 'Wert',
'add' => 'Neue Variable',
],
'expr' => [
'trigger_event' => 'Name des Trigger-Events',
'trigger_fired_at' => 'Wann der Trigger ausgelöst wurde',
'trigger_post_id' => 'ID des auslösenden Beitrags',
'trigger_post_content' => 'Inhalt des auslösenden Beitrags',
'trigger_post_status' => 'Status des auslösenden Beitrags',
'trigger_post_scheduled_at' => 'Wann der Beitrag geplant ist',
'trigger_post_published_at' => 'Wann der Beitrag veröffentlicht wurde',
'fetched_title' => 'Titel des abgerufenen Eintrags',
'fetched_link' => 'Link des abgerufenen Eintrags',
'fetched_date' => 'Veröffentlichungsdatum des abgerufenen Eintrags',
'fetched_content' => 'Vollständiger Inhalt des abgerufenen Eintrags',
'fetched_description' => 'Zusammenfassung des abgerufenen Eintrags',
'fetched_author' => 'Autor des abgerufenen Eintrags',
'fetched_image' => 'Bild-URL des abgerufenen Eintrags',
'fetched_categories' => 'Kategorien des abgerufenen Eintrags',
'fetched_enclosure' => 'Medien des abgerufenen Eintrags (Audio/Video/Datei)',
'fetched_pubdate' => 'Veröffentlichungsdatum des abgerufenen Eintrags',
'fetched_http' => 'Abgerufener HTTP-Eintrag (Feld anhängen)',
'generated_content' => 'KI-generierter Beitragsinhalt',
'generated_post_url' => 'URL des KI-generierten Beitrags',
'variable' => 'Workflow-Variable',
'now' => 'Aktuelles Datum & Uhrzeit',
],
'test' => [
'description' => 'Führt die Automatisierung durchgängig mit einer synthetisierten Trigger-Nutzlast aus. Nützlich, um jeden Node zu validieren, ohne auf den echten Zeitplan oder Feed zu warten.',
'starting' => 'Testlauf wird gestartet…',
'in_progress' => 'In Bearbeitung',
'completed' => 'Abgeschlossen',
'failed' => 'Fehlgeschlagen',
'waiting' => 'Wartet',
'close' => 'Schließen',
'no_node_runs' => 'Warten auf den Start des ersten Nodes…',
'node_input' => 'Eingabe',
'node_output' => 'Ausgabe',
'node_error' => 'Fehler',
'no_new_items' => 'Keine neuen Einträge nichts Nachgelagertes wurde ausgeführt.',
'error_starting' => 'Der Testlauf konnte nicht gestartet werden.',
'with_real_data' => 'Mit echten Daten',
'run' => 'Test ausführen',
'idle_hint' => 'Klicke auf „Test ausführen", um die Automatisierung durchgängig auszuführen.',
'real_data_hint' => 'Dieser Test veröffentlicht Beiträge, setzt Polling-Markierungen fort und löst externe Seiteneffekte aus.',
'dry_badge' => 'Probelauf',
],
'status' => [
'draft' => 'Entwurf',
'active' => 'Aktiv',
'paused' => 'Pausiert',
],
'index' => [
'empty_title' => 'Noch keine Automatisierungen',
'empty_description' => 'Erstelle deine erste Automatisierung, um auf Autopilot zu veröffentlichen.',
'columns' => [
'name' => 'Name',
'status' => 'Status',
'created' => 'Erstellt',
],
],
'form' => [
'activate_error_fallback' => 'Automatisierung konnte nicht aktiviert werden.',
'pause_error_fallback' => 'Automatisierung konnte nicht pausiert werden.',
'save_error_fallback' => 'Automatisierung konnte nicht gespeichert werden.',
'save_success' => 'Automatisierung gespeichert.',
'empty_canvas_title' => 'Beginne mit dem Aufbau deiner Automatisierung',
'empty_canvas_description' => 'Ziehe einen Node aus dem linken Bereich, um zu starten.',
'name_placeholder' => 'Unbenannte Automatisierung',
],
'nodes' => [
'trigger' => 'Trigger',
'generate' => 'Generieren',
'delay' => 'Verzögerung',
'condition' => 'Bedingung',
'publish' => 'Veröffentlichen',
'end' => 'Ende',
'end_summary' => 'Stoppt die Automatisierung hier',
'fetch_rss' => 'RSS abrufen',
'http_request' => 'HTTP-Anfrage',
'handles' => [
'items' => 'hat Einträge',
'no_items' => 'keine Einträge',
],
],
'config' => [
'select_placeholder' => 'Auswählen…',
'invalid_json' => 'Das ist noch kein gültiges JSON.',
'expand_editor' => 'Editor vergrößern',
'minimize_editor' => 'Verkleinern',
'trigger' => [
'type' => 'Trigger-Typ',
'types' => [
'schedule' => 'Zeitplan',
'post_published' => 'Wenn ein Beitrag veröffentlicht wird',
'post_scheduled' => 'Wenn ein Beitrag geplant wird',
],
'post_published_hint' => 'Läuft, wann immer ein Beitrag in diesem Workspace veröffentlicht wird. Der veröffentlichte Beitrag steht unter {{ trigger.post }} für nachgelagerte Nodes zur Verfügung.',
'post_scheduled_hint' => 'Läuft, wann immer ein Beitrag in diesem Workspace geplant wird. Der geplante Beitrag steht unter {{ trigger.post }} zur Verfügung.',
'schedule' => [
'field' => 'Trigger-Intervall',
'fields' => [
'minutes' => 'Minuten',
'hours' => 'Stunden',
'days' => 'Tage',
'weeks' => 'Wochen',
'months' => 'Monate',
],
'minutes_interval' => 'Minuten zwischen den Triggern',
'hours_interval' => 'Stunden zwischen den Triggern',
'days_interval' => 'Tage zwischen den Triggern',
'hour' => 'Auslösen zur Stunde',
'minute' => 'Auslösen zur Minute',
'weekdays' => 'An Wochentagen auslösen',
'day_of_month' => 'Tag des Monats',
'weekday_names' => [
'sun' => 'So',
'mon' => 'Mo',
'tue' => 'Di',
'wed' => 'Mi',
'thu' => 'Do',
'fri' => 'Fr',
'sat' => 'Sa',
],
'summary' => [
'every_n_minutes' => 'Läuft jede Minute|Läuft alle :count Minuten',
'every_n_hours' => 'Läuft jede Stunde zur Minute :minute|Läuft alle :count Stunden zur Minute :minute',
'every_n_days' => 'Läuft täglich um :time|Läuft alle :count Tage um :time',
'weekly' => 'Läuft :days um :time',
'monthly' => 'Läuft an Tag :day jedes Monats um :time',
],
],
],
'generate' => [
'social_accounts' => 'Social-Media-Konten',
'social_accounts_empty' => 'Keine verbundenen Social-Media-Konten. Verbinde zuerst eines.',
'target_slide_count' => 'Zu generierende Slides',
'prompt_template' => 'Prompt-Vorlage',
'prompt_template_hint' => 'Tippe {{, um Daten aus vorherigen Schritten einzufügen.',
'image_count' => 'Zu generierende Bilder',
'image_count_hint' => '0 = reiner Textbeitrag (kein Bild). 1 = einzelnes Bild. 2+ = Karussell.',
'use_brand_voice' => 'Markenton verwenden',
'use_brand_voice_hint' => 'Wende deine Markenbeschreibung und deinen Markenton an. Deaktiviere dies für die originalgetreue Kuratierung von Drittquellen (News, RSS).',
'use_brand_visuals' => 'Marken-Visuals verwenden',
'use_brand_visuals_hint' => 'Steuere KI-Bilder mit deinen Markenfarben und deiner Markenidentität. Deaktiviere dies für neutrale Bilder, die nur vom Beitragsthema bestimmt werden.',
'style' => 'Stil',
'account_summary' => ':count Konto · :format|:count Konten · :format',
'formats' => [
'single' => 'Einzeln',
'carousel' => 'Karussell',
],
],
'delay' => [
'duration' => 'Dauer',
'unit' => 'Einheit',
'units' => [
'minutes' => 'Minuten',
'hours' => 'Stunden',
'days' => 'Tage',
],
],
'condition' => [
'field' => 'Feld',
'operator' => 'Operator',
'operators' => [
'contains' => 'enthält',
'not_contains' => 'enthält nicht',
'equals' => 'ist gleich',
'not_equals' => 'ist ungleich',
'matches' => 'entspricht (Regex)',
'greater_than' => 'größer als',
'less_than' => 'kleiner als',
],
'value' => 'Wert',
],
'publish' => [
'mode' => 'Modus',
'modes' => [
'now' => 'Jetzt veröffentlichen',
'scheduled' => 'Planen',
'draft' => 'Als Entwurf speichern',
],
'scheduled_offset' => 'Versatz zum Trigger (Minuten)',
'offset_summary' => ':mode · +:offset Min.',
],
'end' => [
'reason' => 'Grund (optional)',
'reason_placeholder' => 'z. B. Durch Bedingung herausgefiltert',
],
'fetch_rss' => [
'feed_url' => 'Feed-URL',
'feed_url_hint' => 'Beim ersten Durchlauf wird die Markierung auf "now" gesetzt, damit historische Einträge die nachgelagerten Nodes nicht überfluten. Nachfolgende Durchläufe sehen nur Einträge, die neuer sind als die vorherige Abfrage.',
'inspect' => 'Feed prüfen',
'inspecting' => 'Wird geprüft…',
'inspect_hint' => 'Rufe ein Beispiel ab, um die verfügbaren Felder für nachgelagerte Nodes zu ermitteln.',
'inspect_error' => 'Dieser Feed konnte nicht gelesen werden. Prüfe die URL und versuche es erneut.',
'discovered_fields' => 'Verfügbare Felder',
'discovered_empty' => 'Keine Felder im neuesten Eintrag gefunden.',
],
'http_request' => [
'url' => 'URL',
'method' => 'Methode',
'auth_type' => 'Authentifizierung',
'auth' => [
'none' => 'Keine (öffentlich)',
'bearer' => 'Bearer-Token',
'basic' => 'Basic Auth',
'api_key' => 'API-Key-Header',
],
'bearer_token' => 'Bearer-Token',
'basic_username' => 'Benutzername',
'basic_password' => 'Passwort',
'api_key_header' => 'Header-Name',
'api_key_value' => 'API-Key',
'body_template' => 'Body-Vorlage (JSON)',
'headers' => 'Header',
'header_name' => 'Header-Name',
'header_value' => 'Wert',
'add_header' => 'Header hinzufügen',
'polling_section' => 'Liste & Deduplizierung (optional)',
'polling_hint' => 'Wenn die Antwort eine Liste ist, durchläuft jeder Eintrag den Workflow separat. Ein einzelnes Objekt wird einmal ausgeführt.',
'items_path' => 'Pfad zu den Einträgen',
'items_path_hint' => 'Leer lassen, wenn die Antwort bereits ein Array ist. Verwende einen Punkt-Pfad (z. B. data.items) für ein verschachteltes Array oder * für ein nach ID indiziertes Objekt.',
'item_key_path' => 'Pfad zum Eintragsschlüssel',
'item_key_path_hint' => 'JSON-Pfad zu einer eindeutigen ID (z. B. id). Bereits gesehene Einträge werden übersprungen, sodass ein Feed ohne Datumsangaben trotzdem nur neue Einträge weiterleitet.',
'item_date_path' => 'Pfad zum Eintragsdatum',
'item_date_path_hint' => 'JSON-Pfad zum Zeitstempel des Eintrags (z. B. published_at). Wird, sofern verfügbar, dem Schlüssel-Pfad vorgezogen. Die erste Abfrage erfasst den Ausgangswert und leitet nichts weiter, sodass ein bestehender Feed am ersten Tag niemals überflutet.',
],
],
'delete' => [
'title' => 'Automatisierung löschen',
'description' => 'Möchtest du diese Automatisierung wirklich löschen? Alle Ausführungen und Trigger-Einträge werden ebenfalls entfernt. Diese Aktion kann nicht rückgängig gemacht werden.',
'confirm' => 'Löschen',
'cancel' => 'Abbrechen',
],
'flash' => [
'deleted' => 'Automatisierung erfolgreich gelöscht!',
],
'errors' => [
'no_active_social_accounts' => 'Für diese Automatisierung sind keine aktiven Social-Media-Konten konfiguriert.',
'must_have_one_trigger' => 'Eine Automatisierung muss genau einen Trigger-Node haben.',
'trigger_must_be_connected' => 'Der Trigger-Node muss mit mindestens einem Node verbunden sein.',
'graph_contains_cycle' => 'Der Automatisierungsgraph enthält einen Zyklus.',
'only_failed_can_retry' => 'Nur fehlgeschlagene Ausführungen können wiederholt werden.',
'no_generated_post' => 'Bei der Ausführung wurde kein generierter Beitrag gefunden.',
'url_not_allowed' => 'Die Anfrage-URL verweist auf eine private oder nicht erreichbare Adresse und wurde blockiert.',
'node_no_longer_exists' => 'Node :node_id existiert in der Automatisierung nicht mehr.',
'no_trigger_connection' => 'Kein Node mit dem Trigger-Node verbunden.',
'fetch_rss_missing_url' => 'Dem Node „RSS abrufen" fehlt eine Feed-URL.',
'fetch_rss_request_failed' => 'Die Anfrage an den RSS-Feed ist fehlgeschlagen.',
'fetch_rss_malformed' => 'Der RSS-Feed ist fehlerhaft.',
'http_missing_url' => 'Dem HTTP-Anfrage-Node fehlt eine URL.',
'http_request_exception' => 'Die HTTP-Anfrage hat eine Ausnahme ausgelöst.',
'http_request_failed' => 'Die HTTP-Anfrage ist fehlgeschlagen.',
'http_items_path_not_array' => 'Der Pfad zu den Einträgen ergab keine Liste.',
'generate_image_format_required' => 'KI-Generierung erstellt nur Bilder. Wähle ein Bildformat (kein Video).',
],
];