Translate the interface into 12 languages
Add full lang/ translations for fr, de, it, nl, pl, el, ja, ko, zh, ru,
tr, and ar — all 23 base files each, with identical key trees to lang/en,
preserved :placeholders and plural forms, and native product terminology.
2026-07-03 18:38:40 +00:00
< ? php
declare ( strict_types = 1 );
return [
'title' => 'Beiträge' ,
'search' => 'Beiträge suchen...' ,
'all_posts' => 'Alle Beiträge' ,
'new_post' => 'Neuer Beitrag' ,
'no_posts' => 'Keine Beiträge gefunden' ,
'no_search_results' => 'Keine Beiträge passen zu deiner Suche' ,
'try_different_search' => 'Versuche ein anderes Stichwort oder setze die Suche zurück.' ,
'start_creating' => 'Beginne, indem du deinen ersten Beitrag erstellst.' ,
'filter_by_label' => 'Nach Label filtern' ,
'label_search_placeholder' => 'Labels suchen...' ,
'no_labels' => 'Keine Labels gefunden.' ,
'clear_label_filter' => 'Label-Filter zurücksetzen' ,
'table' => [
'post' => 'Beitrag' ,
'status' => 'Status' ,
'content' => 'Inhalt' ,
'platforms' => 'Plattformen' ,
'labels' => 'Labels' ,
'scheduled_at' => 'Datum' ,
'actions' => '' ,
],
'manage_posts' => 'Verwalte all deine Beiträge' ,
'delete_confirm' => 'Möchtest du diesen Beitrag wirklich löschen?' ,
'by' => 'von' ,
'actions' => [
'view' => 'Beitrag ansehen' ,
'delete' => 'Löschen' ,
'duplicate' => 'Duplizieren' ,
'copy_id' => 'ID kopieren' ,
'copied' => 'ID in die Zwischenablage kopiert' ,
],
'form' => [
'post_type' => 'Beitragstyp' ,
'board' => 'Pinnwand' ,
'select_board' => 'Pinnwand auswählen' ,
'search_board' => 'Pinnwand suchen...' ,
'no_board_found' => 'Keine Pinnwand gefunden' ,
'media' => 'Medien' ,
'min' => 'Min.' ,
'uploading' => 'Wird hochgeladen...' ,
'drop_to_upload' => 'Zum Hochladen ablegen' ,
'drag_and_drop' => 'Ziehen & ablegen oder zum Hochladen klicken' ,
'photos_and_videos' => 'Fotos und Videos' ,
'photos_only' => 'Nur Fotos' ,
'videos_only' => 'Nur Videos' ,
'drag_to_reorder' => 'Zum Neuordnen ziehen' ,
'caption' => 'Bildunterschrift' ,
'write_caption' => 'Schreibe deine Bildunterschrift...' ,
'content_exceeds_platform' => ':platform: um :over Zeichen zu lang (max. :limit).' ,
'tiktok' => [
'settings' => 'TikTok-Einstellungen' ,
'variant_label' => 'Beitragstyp' ,
'variant' => [
'video' => 'Video' ,
'photo' => 'Foto-Karussell' ,
],
'posting_to' => 'Veröffentlichen auf' ,
'privacy_level' => 'Wer kann dieses Video sehen?' ,
'privacy_placeholder' => 'Wähle, wer diesen Beitrag sehen kann' ,
'privacy' => [
'public' => 'Öffentlich für alle' ,
'friends' => 'Freunde, denen du gegenseitig folgst' ,
'followers' => 'Follower' ,
'private' => 'Nur ich' ,
'private_disabled_branded' => 'Die Sichtbarkeit von Branded Content kann nicht auf privat gesetzt werden.' ,
],
'privacy_hint' => 'Die verfügbaren Optionen hängen von deinen TikTok-Kontoeinstellungen ab.' ,
'auto_add_music' => 'Musik automatisch hinzufügen' ,
'auto_add_music_hint' => 'Diese Funktion ist nur für Fotos verfügbar. Sie fügt eine Standardmusik hinzu, die du später ändern kannst.' ,
'yes' => 'Ja' ,
'no' => 'Nein' ,
'allow_users' => 'Nutzern erlauben:' ,
'comments' => 'Kommentieren' ,
'duet' => 'Duett' ,
'stitch' => 'Stitch' ,
'is_aigc' => 'Mit KI erstelltes Video' ,
'disclose' => 'Videoinhalt offenlegen' ,
'disclose_hint' => 'Aktivieren, um offenzulegen, dass dieses Video Waren oder Dienstleistungen gegen einen Gegenwert bewirbt. Dein Video kann dich selbst, einen Dritten oder beide bewerben.' ,
'promotional_organic_title' => 'Dein Foto/Video wird als „Werbeinhalt" gekennzeichnet.' ,
'promotional_paid_title' => 'Dein Foto/Video wird als „Bezahlte Partnerschaft" gekennzeichnet.' ,
'promotional_description' => 'Dies kann nach der Veröffentlichung deines Videos nicht mehr geändert werden.' ,
'compliance_incomplete' => 'Du musst angeben, ob dein Inhalt dich selbst, einen Dritten oder beide bewirbt.' ,
'privacy_required' => 'Bei der Veröffentlichung ist die TikTok-Datenschutzstufe erforderlich.' ,
'branded_cleared_private' => 'Die Privatsphäre wurde zurückgesetzt, da Branded Content nicht privat sein kann.' ,
'interaction_disabled_by_creator' => 'In deinen TikTok-Kontoeinstellungen deaktiviert' ,
'max_duration_exceeded' => 'Das Video ist :duration s lang, aber dieses Konto kann nur Videos mit bis zu :max s veröffentlichen.' ,
'processing_hint' => 'Nach der Veröffentlichung kann es einige Minuten dauern, bis der Inhalt verarbeitet ist und in deinem TikTok-Profil erscheint.' ,
'brand_organic' => 'Deine Marke' ,
'brand_organic_hint' => 'Du bewirbst dich selbst oder deine eigene Marke. Dieses Video wird als Brand Organic klassifiziert.' ,
'brand_content' => 'Branded Content' ,
'brand_content_hint' => 'Du bewirbst eine andere Marke oder einen Dritten. Dieses Video wird als Branded Content klassifiziert.' ,
'compliance' => [
'agree' => 'Mit dem Veröffentlichen akzeptierst du TikToks' ,
'music_usage' => 'Bestätigung zur Musiknutzung' ,
'and' => 'und' ,
'branded_policy' => 'Richtlinie für Branded Content' ,
],
],
'instagram' => [
'settings' => 'Instagram-Einstellungen' ,
'posting_to' => 'Veröffentlichen auf' ,
'variant_label' => 'Beitragstyp' ,
'variant' => [
'feed' => 'Feed-Beitrag' ,
'reel' => 'Reel' ,
'story' => 'Story' ,
],
'aspect_label' => 'Seitenverhältnis' ,
'aspect' => [
'square' => 'Quadratisch (1:1)' ,
'portrait' => 'Hochformat (4:5)' ,
'landscape' => 'Querformat (16:9)' ,
'original' => 'Original' ,
],
],
'facebook' => [
'settings' => 'Facebook-Einstellungen' ,
'posting_to' => 'Veröffentlichen auf' ,
'variant_label' => 'Beitragstyp' ,
'variant' => [
'post' => 'Beitrag' ,
'reel' => 'Reel' ,
'story' => 'Story' ,
],
'aspect_label' => 'Seitenverhältnis' ,
'aspect' => [
'square' => 'Quadratisch (1:1)' ,
'portrait' => 'Hochformat (4:5)' ,
'landscape' => 'Querformat (16:9)' ,
'original' => 'Original' ,
],
],
'linkedin' => [
'settings' => 'LinkedIn-Einstellungen' ,
'settings_page' => 'LinkedIn-Seiteneinstellungen' ,
'posting_to' => 'Veröffentlichen auf' ,
'document_title' => 'Dokumenttitel' ,
'document_title_placeholder' => 'Wird bei deinem PDF-Dokument-Beitrag angezeigt' ,
],
'pinterest' => [
'settings' => 'Pinterest-Einstellungen' ,
'posting_to' => 'Veröffentlichen auf' ,
'variant_label' => 'Pin-Typ' ,
'variant' => [
'pin' => 'Pin' ,
'video_pin' => 'Video-Pin' ,
'carousel' => 'Karussell' ,
],
'board' => 'Pinnwand' ,
'select_board' => 'Pinnwand auswählen' ,
'no_boards' => 'Keine Pinterest-Pinnwände gefunden. Erstelle zuerst eine in deinem Pinterest-Konto.' ,
2026-07-25 02:02:40 +00:00
'boards_truncated' => 'Einige Pinnwände konnten nicht geladen werden. Fehlt deine, öffne Pinterest und versuche es erneut.' ,
Translate the interface into 12 languages
Add full lang/ translations for fr, de, it, nl, pl, el, ja, ko, zh, ru,
tr, and ar — all 23 base files each, with identical key trees to lang/en,
preserved :placeholders and plural forms, and native product terminology.
2026-07-03 18:38:40 +00:00
'search_board' => 'Pinnwände suchen...' ,
'no_board_found' => 'Keine Pinnwand passt zu deiner Suche.' ,
'board_required' => 'Wähle eine Pinterest-Pinnwand, um diesen Beitrag zu veröffentlichen.' ,
Add optional Pinterest pin title and destination link (#232)
* Add optional Pinterest pin title, description, and link.
Expose title/description/link across web, API, and MCP; seed description from caption into meta on save, and publish description only from meta.
Co-authored-by: Cursor <cursoragent@cursor.com>
* Expand Pinterest title/description/link test coverage.
Cover web draft persistence and validation bounds, API/MCP update merge and seed, and publisher payload fields on video and carousel pins.
Co-authored-by: Cursor <cursoragent@cursor.com>
* Simplify Pinterest: description is post content again.
Keep optional title and link in meta/settings only. Remove the separate description textarea, seed logic, and meta.description path so Pinterest follows the shared caption pattern.
Co-authored-by: Cursor <cursoragent@cursor.com>
* Refactor Pinterest meta handling and validation.
- Update CreatePost and UpdatePost actions to filter out null values from meta fields.
- Introduce a new method in PinterestPublisher to resolve board IDs, ensuring required fields are validated.
- Enhance PinterestSettings component to manage title and link inputs, including validation for HTTP URLs.
- Update PostPlatformMetaRules to enforce URL validation for Pinterest links.
- Add tests for clearing Pinterest title and link, and for rejecting invalid links during scheduling.
This refactor improves the handling of Pinterest metadata and enhances user experience by ensuring proper validation and error handling.
* Add validation messages and attributes for Pinterest meta fields
- Introduced custom validation messages and friendly attribute names for Pinterest link and title fields in PostPlatformMetaRules.
- Updated StorePostRequest, UpdatePostRequest, and related tools to utilize these new messages and attributes.
- Enhanced tests to assert correct error messages for invalid Pinterest links and title length constraints.
This update improves user feedback during post creation and editing, ensuring clarity in validation errors.
* Remove click.prevent directive from Pinterest link in PinterestPreview component.
This change simplifies the link behavior, allowing default click actions to occur, which may enhance user interaction with the Pinterest link.
* Update validation error messages for Pinterest meta fields in tests
- Refined the assertions in PostApiPlatformMetaTest to include localized validation messages for Pinterest title and link fields.
- Ensured that error messages reflect the updated validation rules, enhancing clarity for users during post creation and editing.
---------
Co-authored-by: Cursor <cursoragent@cursor.com>
2026-08-05 21:15:50 +00:00
'title' => 'Titel' ,
'title_placeholder' => 'Optionaler Pin-Titel' ,
'link' => 'Ziel-Link' ,
'link_placeholder' => 'https://beispiel.com' ,
'link_invalid' => 'Gib einen gültigen Ziel-Link ein (http oder https).' ,
'title_max' => 'Der Titel darf höchstens 100 Zeichen lang sein.' ,
'link_max' => 'Der Ziel-Link darf höchstens 2048 Zeichen lang sein.' ,
Translate the interface into 12 languages
Add full lang/ translations for fr, de, it, nl, pl, el, ja, ko, zh, ru,
tr, and ar — all 23 base files each, with identical key trees to lang/en,
preserved :placeholders and plural forms, and native product terminology.
2026-07-03 18:38:40 +00:00
],
'discord' => [
'settings' => 'Discord-Einstellungen' ,
'posting_to' => 'Veröffentlichen auf' ,
'channel' => 'Kanal' ,
'select_channel' => 'Kanal auswählen' ,
'loading_channels' => 'Kanäle werden geladen…' ,
'search_channel' => 'Kanäle suchen…' ,
'no_channels' => 'Keine Kanäle gefunden.' ,
'channel_required' => 'Wähle einen Discord-Kanal, um diesen Beitrag zu veröffentlichen.' ,
'mentions' => 'Erwähnungen' ,
'search_mention' => 'Eine Rolle oder ein Mitglied erwähnen…' ,
'embeds' => 'Embeds' ,
'embed' => 'Embed' ,
'add_embed' => 'Embed hinzufügen' ,
'embed_title' => 'Embed-Titel' ,
'embed_description' => 'Embed-Beschreibung' ,
'embed_url' => 'Embed-URL' ,
'embed_image' => 'Bild-URL' ,
'embed_color' => 'Farbe' ,
],
'warnings' => [
'no_variant' => 'Wähle einen Beitragstyp, um fortzufahren.' ,
'requires_media' => 'Dieser Beitragstyp erfordert mindestens ein Bild oder Video.' ,
'max_files_exceeded' => 'Dieser Beitragstyp akzeptiert bis zu :max Mediendateien (du hast :current).' ,
'min_files_required' => 'Dieser Beitragstyp erfordert mindestens :min Mediendateien (du hast :current).' ,
'no_video_allowed' => 'Dieser Beitragstyp akzeptiert keine Videos.' ,
'no_image_allowed' => 'Dieser Beitragstyp akzeptiert nur Videos.' ,
'no_document_allowed' => 'Dieser Beitragstyp akzeptiert keine PDF-Dokumente.' ,
'no_mixed_media' => 'Bilder und ein Video können nicht im selben Beitrag kombiniert werden.' ,
'document_not_alone' => 'Ein PDF muss einzeln veröffentlicht werden, ohne andere Bilder oder Videos.' ,
'gif_not_allowed' => 'Diese Plattform akzeptiert keine GIFs. Entferne das GIF oder wähle ein anderes Netzwerk.' ,
'image_too_large' => 'Das Bild überschreitet das Limit von :max für diesen Beitragstyp (deins hat :current).' ,
'video_too_large' => 'Das Video überschreitet das Limit von :max für diesen Beitragstyp (deins hat :current).' ,
'document_too_large' => 'Das PDF überschreitet das Limit von :max für diesen Beitragstyp (deins hat :current).' ,
'video_too_long' => 'Das Video ist :current lang, aber dieser Beitragstyp erlaubt bis zu :max.' ,
'aspect_ratio_too_narrow' => 'Das Seitenverhältnis :current ist zu hoch für diesen Beitragstyp (min. :min).' ,
'aspect_ratio_too_wide' => 'Das Seitenverhältnis :current ist zu breit für diesen Beitragstyp (max. :max).' ,
],
],
'status' => [
'pending' => 'Ausstehend' ,
'draft' => 'Entwurf' ,
'scheduled' => 'Geplant' ,
'publishing' => 'Wird veröffentlicht' ,
'retrying' => 'Erneuter Versuch' ,
'published' => 'Veröffentlicht' ,
'partially_published' => 'Teilweise veröffentlicht' ,
'failed' => 'Fehlgeschlagen' ,
],
'descriptions' => [
'draft' => 'Beiträge, die auf Planung warten' ,
'scheduled' => 'Zur Veröffentlichung geplante Beiträge' ,
'published' => 'Bereits veröffentlichte Beiträge' ,
],
'ai' => [
'generate' => [
'button_tooltip' => 'Mit KI generieren' ,
'title' => 'Beitrag mit KI generieren' ,
'description' => 'Beschreibe, worum es in dem Beitrag gehen soll. Die KI verwendet deinen Markenkontext, um ihn zu schreiben.' ,
'prompt_label' => 'Worum geht es in diesem Beitrag?' ,
'prompt_placeholder' => 'z. B. Unser neues Bildgenerierungs-Feature für Karussells ankündigen' ,
'preview_label' => 'Vorschau' ,
'start' => 'Generieren' ,
'apply' => 'Diesen Inhalt verwenden' ,
'retry' => 'Erneut versuchen' ,
'cancel' => 'Abbrechen' ,
fix: subscribe to AI generation channel before dispatching the job (#269)
* fix: subscribe to AI generation channel before dispatching the job
AiGenerateDialog posted the generate request and only subscribed to the
broadcast channel once the response came back. Reverb's plain Channel
(vendor/laravel/reverb/.../Channels/Channel.php) delivers broadcasts by
iterating the in-memory connection list at send time only — no history,
no replay. If the queued job started streaming text_delta/stream_end
events before the private-channel subscribe handshake finished, those
events were gone for good and the dialog hung on 'streaming' forever.
Generate the generation_id client-side, await channel subscription
confirmation (Echo's channel.subscribed(), backed by
pusher:subscription_succeeded) before sending the generate request, and
have the backend use the client-supplied id instead of minting its own.
Related to #218.
* fix: handle subscribe failure, dialog-close race, and i18n hardcoded strings
Code review on the previous commit surfaced real gaps:
- useAiStream only handled the subscribe-success path (.subscribed()).
A definitive pusher:subscription_error (expired session, CSRF
mismatch) fell through to the 5s timeout and was treated as success,
reproducing the exact #218 hang via a different trigger. subscribe()
now returns a boolean: true on confirm-or-ambiguous-timeout (proceed
optimistically), false only on an explicit error (don't dispatch work
nothing will ever hear).
- AiGenerateDialog now bails without dispatching if the dialog is
closed while awaiting subscription confirmation (up to 5s), and
unsubscribes on a post-subscribe dispatch failure so stale listeners
can't flip status to 'completed' after an error was already shown.
- Extracted aiGenerationChannel() so the frontend has one place to
update if the channel format changes, and cross-referenced the two
remaining backend copies (PostAiGenerateController, StreamPostContent).
- Replaced the two hardcoded English fallback error strings with i18n
keys (posts.ai.generate.errors.*) across all 16 locales — this app
only ships translated copy.
- Simplified subscribe(): dropped a redundant "already settled" guard
and the clearTimeout bookkeeping — Promise.resolve() already no-ops
after the first call, so there was nothing to guard.
* fix: subscribe before dispatch in AI post creation and image regeneration flows
Extracts subscribePrivateChannel as a shared helper and applies the same
subscribe-before-dispatch fix from the post edit flow (issue #218) to the
other two flows that stream over private channels.
Post creation wizard moves the StreamPostCreation dispatch out of
AiPostWizard.vue and into Loading.vue, so the channel is subscribed before
the job that broadcasts on it is dispatched — previously a full page
navigation happened between dispatch and subscribe with no timeout
fallback, so a lost event hung the page forever.
* refactor: trim explanatory comments added in the subscribe-before-dispatch fix
Rationale lives in the commit history, not scattered inline comments.
* refactor: trim remaining explanatory comments from the subscribe-before-dispatch fix
Same cleanup as the previous commit, applied to the files from the
original post-edit-flow fix.
* fix: dedup post-creation dispatch, surface field-level AI errors, harden edge cases
Uses ShouldBeUnique on StreamPostCreation (scoped per-user) instead of an
ad-hoc cache guard, matching the pattern already used by
PublishToSocialPlatform and VerifyUpcomingPostConnections.
Field-level validation errors (prompt/instruction) now render inline via
InputError, matching how every other form in the app surfaces them, instead
of a generic status banner. Also fixes a 422 response missing the `errors`
key that Inertia's client silently swallows, adds error handling around the
wizard's navigation to the loading page, and extracts the duplicated
error-message parsing into a shared helper.
2026-08-10 19:06:37 +00:00
'errors' => [
'start_failed' => 'Generierung konnte nicht gestartet werden.' ,
'generation_failed' => 'KI-Generierung fehlgeschlagen.' ,
],
Translate the interface into 12 languages
Add full lang/ translations for fr, de, it, nl, pl, el, ja, ko, zh, ru,
tr, and ar — all 23 base files each, with identical key trees to lang/en,
preserved :placeholders and plural forms, and native product terminology.
2026-07-03 18:38:40 +00:00
],
'review' => [
'button_tooltip' => 'Mit KI prüfen' ,
'title' => 'Beitrag mit KI prüfen' ,
'description' => 'Die KI prüft Grammatik, Rechtschreibung und Verständlichkeit. Übernimm die Vorschläge, denen du zustimmst.' ,
'loading' => 'Dein Text wird geprüft...' ,
'no_issues' => 'Keine Probleme gefunden. Sieht gut aus.' ,
'original' => 'Original' ,
'suggestion' => 'Vorschlag' ,
'apply' => 'Übernehmen' ,
'apply_all' => 'Alle übernehmen' ,
'applied' => 'Übernommen' ,
'cancel' => 'Abbrechen' ,
],
'image_regenerate' => [
'button' => 'Anpassen' ,
'title' => 'KI-Bild anpassen' ,
'description' => 'Beschreibe die Korrektur. Das neue Bild ersetzt das aktuelle und behält seine Position im Karussell.' ,
'instruction_label' => 'Anweisung' ,
'instruction_placeholder' => 'z. B. Korrigiere den Tippfehler in der Überschrift und mache den Hintergrund heller.' ,
'processing' => 'Bild wird neu generiert... das kann einige Sekunden dauern.' ,
'submit' => 'Bild neu generieren' ,
'cancel' => 'Abbrechen' ,
'success' => 'Bild aktualisiert. Die neue Version hat die vorherige in deinem Beitrag ersetzt.' ,
'fallback_title' => 'Diesen Bildtext verbessern' ,
'errors' => [
'required' => 'Eine Anweisung ist erforderlich.' ,
'start_failed' => 'Neugenerierung konnte nicht gestartet werden.' ,
'unavailable' => 'Dieses Bild kann derzeit nicht neu generiert werden.' ,
'timeout' => 'Die Neugenerierung dauert länger als erwartet. Versuche es gleich noch einmal.' ,
'media_not_found' => 'Medienelement nicht gefunden.' ,
'not_ai_media' => 'Nur KI-generierte Medien können neu generiert werden.' ,
],
],
'templates' => [
'image_card' => [
'name' => 'Bildbeitrag' ,
'description' => 'KI-Bild mit Überschrift und Bildunterschrift.' ,
],
'carousel' => [
'name' => 'Karussell' ,
'description' => 'Karussell mit mehreren Slides und einer Bildunterschrift.' ,
],
'tweet_card' => [
'name' => 'Tweet-Karte' ,
'description' => 'Dein Beitrag im Stil eines X/Twitter-Beitrags.' ,
],
'tweet_card_image' => [
'name' => 'Tweet-Karte mit Foto' ,
'description' => 'Dein Beitrag als X/Twitter-Karte über einem unscharfen Foto.' ,
],
],
],
'show' => [
'title' => 'Beitragsdetails' ,
'edit' => 'Bearbeiten' ,
'back' => 'Zurück' ,
'no_content' => 'Keine Bildunterschrift' ,
'platforms' => 'Plattformen' ,
'no_platforms' => 'Keine Plattformen ausgewählt.' ,
'view_on_platform' => 'Auf der Plattform ansehen' ,
'published_on' => 'Veröffentlicht am :date' ,
'scheduled_for' => 'Geplant für :date' ,
'draft' => 'Entwurf' ,
'status_pending' => 'Ausstehend' ,
'metrics' => 'Kennzahlen' ,
'metrics_loading' => 'Kennzahlen werden geladen…' ,
'metrics_unavailable' => 'Kennzahlen für diese Plattform sind noch nicht verfügbar.' ,
'metrics_empty' => 'Keine Kennzahlen zurückgegeben.' ,
],
'edit' => [
'title' => 'Beitrag bearbeiten' ,
'view_title' => 'Beitrag ansehen' ,
'labels' => 'Labels' ,
'no_labels' => 'Noch keine Labels erstellt' ,
'schedule' => 'Planen' ,
'pick_time' => 'Uhrzeit wählen' ,
'pick_time_past' => 'Wähle ein zukünftiges Datum und eine zukünftige Uhrzeit.' ,
'post_now' => 'Jetzt veröffentlichen' ,
'time' => 'Uhrzeit' ,
'cancel' => 'Abbrechen' ,
'delete' => 'Löschen' ,
'schedule_for' => 'Planen für' ,
'schedule_date' => 'Datum planen' ,
'unschedule' => 'Planung aufheben' ,
'saving' => 'Wird gespeichert...' ,
'saved' => 'Gespeichert' ,
'draft' => 'Entwurf' ,
'media' => 'Medien' ,
'add_media' => 'Medien hinzufügen' ,
'caption' => 'Bildunterschrift' ,
'caption_placeholder' => 'Schreibe deine Bildunterschrift...' ,
'compose_title' => 'Beitrag erstellen' ,
'compose_subtitle' => 'Verfasse deine Nachricht und füge Medien hinzu' ,
'preview_empty' => [
'title' => 'Keine Plattform ausgewählt' ,
'description' => 'Wähle eine Plattform zum Veröffentlichen, um die Vorschau zu sehen.' ,
],
'drop_zone_title' => 'Medien hinzufügen' ,
'drop_zone_subtitle' => 'Dateien ziehen & ablegen oder zum Durchsuchen klicken' ,
'add' => 'Hinzufügen' ,
'publish_to' => 'Veröffentlichen auf' ,
'organize' => 'Organisieren' ,
'signatures' => 'Signaturen' ,
'view_on_platform' => 'Auf der Plattform ansehen' ,
'platform_status' => 'Plattform-Status' ,
'compliance_incomplete' => 'Einige Plattform-Einstellungen sind unvollständig oder nicht mit den angehängten Medien kompatibel.' ,
'compliance' => [
'requires_content_or_media' => 'Füge Text oder Medien hinzu, um zu veröffentlichen.' ,
'requires_media' => 'Füge ein Bild oder Video hinzu, um hier zu veröffentlichen.' ,
'too_many_files' => 'Für dieses Format sind nur :max Datei(en) erlaubt.' ,
'too_few_files' => 'Füge mindestens :min Dateien für dieses Format hinzu.' ,
'no_videos' => 'Für dieses Format sind nur Bilder erlaubt.' ,
'no_images' => 'Für dieses Format sind nur Videos erlaubt.' ,
'no_mixed_media' => 'Bilder und Videos können nicht im selben Beitrag kombiniert werden.' ,
'no_gifs' => 'GIFs werden hier nicht unterstützt.' ,
'no_documents' => 'PDF-Dokumente werden von diesem Format nicht unterstützt.' ,
'document_not_alone' => 'Ein PDF muss einzeln veröffentlicht werden, ohne andere Bilder oder Videos.' ,
'video_too_large' => 'Das Video überschreitet das Größenlimit für diese Plattform.' ,
'video_too_long' => 'Das Video muss für dieses Format kürzer als :seconds Sekunden sein.' ,
'image_too_large' => 'Das Bild überschreitet das Größenlimit für diese Plattform.' ,
'document_too_large' => 'Das PDF überschreitet das Größenlimit für diese Plattform.' ,
'aspect_ratio_invalid' => 'Das Seitenverhältnis wird von diesem Format nicht unterstützt.' ,
'no_content_type' => 'Wähle einen Inhaltstyp für diese Plattform.' ,
'requires_text' => 'Füge Text hinzu – dieses Format benötigt einen Titel.' ,
],
'publishing' => 'Wird veröffentlicht...' ,
'publishing_overlay_title' => 'Dein Beitrag wird veröffentlicht' ,
'publishing_overlay_subtitle' => 'Das kann einen Moment dauern. Du kannst diese Seite bedenkenlos verlassen.' ,
'scheduled_overlay_title' => 'Dieser Beitrag ist geplant' ,
'scheduled_overlay_subtitle' => 'Geplant für :date. Hebe die Planung zuerst auf, um Änderungen vorzunehmen.' ,
'unschedule_cta' => 'Zum Bearbeiten Planung aufheben' ,
'tabs' => [
2026-07-17 21:38:20 +00:00
'compose' => 'Verfassen' ,
Translate the interface into 12 languages
Add full lang/ translations for fr, de, it, nl, pl, el, ja, ko, zh, ru,
tr, and ar — all 23 base files each, with identical key trees to lang/en,
preserved :placeholders and plural forms, and native product terminology.
2026-07-03 18:38:40 +00:00
'preview' => 'Vorschau' ,
'channels' => 'Kanäle' ,
'comments' => 'Kommentare' ,
'comments_empty' => 'Noch keine Kommentare.' ,
],
'media_picker' => [
'title' => 'Aus Galerie auswählen' ,
'search' => 'Medien suchen...' ,
'empty' => 'Noch keine Medien in deiner Galerie' ,
'cancel' => 'Abbrechen' ,
'add' => 'Hinzufügen' ,
'add_count' => ':count hinzufügen' ,
],
2026-07-11 12:45:52 +00:00
'alt_text' => [
'label' => 'Alternativtext' ,
'edit' => 'Alternativtext bearbeiten' ,
'placeholder' => 'Beschreibe dieses Bild für Menschen, die Screenreader verwenden' ,
'hint' => 'Wird auf Plattformen veröffentlicht, die Bildbeschreibungen unterstützen.' ,
'save' => 'Speichern' ,
],
Translate the interface into 12 languages
Add full lang/ translations for fr, de, it, nl, pl, el, ja, ko, zh, ru,
tr, and ar — all 23 base files each, with identical key trees to lang/en,
preserved :placeholders and plural forms, and native product terminology.
2026-07-03 18:38:40 +00:00
'emoji_picker' => [
'search' => 'Emoji suchen' ,
'empty' => 'Keine Emojis gefunden' ,
'recent' => 'Häufig verwendet' ,
'smileys' => 'Smileys & Emotionen' ,
'people' => 'Menschen & Körper' ,
'nature' => 'Tiere & Natur' ,
'food' => 'Essen & Trinken' ,
'activities' => 'Aktivitäten' ,
'travel' => 'Reisen & Orte' ,
'objects' => 'Objekte' ,
'symbols' => 'Symbole' ,
'flags' => 'Flaggen' ,
],
'status' => [
'pending' => 'Ausstehend' ,
'scheduled' => 'Geplant' ,
'published' => 'Veröffentlicht' ,
'publishing' => 'Wird veröffentlicht...' ,
'retrying' => 'Erneuter Versuch...' ,
'failed' => 'Fehlgeschlagen' ,
],
'delete_modal' => [
'title' => 'Beitrag löschen' ,
'description' => 'Möchtest du diesen Beitrag wirklich löschen? Diese Aktion kann nicht rückgängig gemacht werden.' ,
'action' => 'Löschen' ,
'cancel' => 'Abbrechen' ,
],
'sync_enable' => [
'title' => 'Synchronisierung aktivieren?' ,
'description' => 'Alle Plattformen teilen denselben Inhalt. Alle individuellen Anpassungen an einzelnen Plattformen werden durch den aktuellen Inhalt ersetzt.' ,
'cancel' => 'Abbrechen' ,
'action' => 'Synchronisierung aktivieren' ,
],
'sync_disable' => [
'title' => 'Synchronisierung deaktivieren?' ,
'description' => 'Jede Plattform behält ihren aktuellen Inhalt, aber zukünftige Änderungen gelten nur für die Plattform, die du gerade bearbeitest.' ,
'customize_note' => 'Du kannst den Inhalt für jede Plattform einzeln anpassen.' ,
'cancel' => 'Abbrechen' ,
'action' => 'Synchronisierung deaktivieren' ,
],
'platforms_dialog' => [
'title' => 'Plattformen auswählen' ,
'description' => 'Wähle, auf welchen Plattformen dieser Beitrag veröffentlicht werden soll.' ,
],
'signatures_modal' => [
'search' => 'Signaturen suchen...' ,
'no_results' => 'Keine Signaturen gefunden.' ,
],
'validation' => [
'select_board' => 'Pinnwand auswählen' ,
'images_not_supported' => 'Bilder nicht unterstützt' ,
'videos_not_supported' => 'Videos nicht unterstützt' ,
'max_images' => 'Max. :count Bilder' ,
'requires_media' => 'Medien erforderlich' ,
'requires_content' => 'Textinhalt ist erforderlich' ,
'exceeded' => ':count überschritten' ,
'does_not_support_images' => ':platform unterstützt keine Bilder' ,
'supports_up_to_images' => ':platform unterstützt bis zu :count Bilder' ,
'does_not_support_videos' => ':platform unterstützt keine Videos' ,
],
],
'content_types' => [
'instagram_feed' => [
'label' => 'Feed-Beitrag' ,
'description' => 'Erscheint in deinem Feed und Profil' ,
],
'instagram_reel' => [
'label' => 'Reel' ,
2026-07-25 00:21:39 +00:00
'description' => 'Kurzes Video bis zu 15 Minuten' ,
Translate the interface into 12 languages
Add full lang/ translations for fr, de, it, nl, pl, el, ja, ko, zh, ru,
tr, and ar — all 23 base files each, with identical key trees to lang/en,
preserved :placeholders and plural forms, and native product terminology.
2026-07-03 18:38:40 +00:00
],
'instagram_story' => [
'label' => 'Story' ,
'description' => 'Verschwindet nach 24 Stunden' ,
],
'linkedin_post' => [
'label' => 'Beitrag' ,
'description' => 'Standardbeitrag – Einzelbild, mehrere Bilder, Video oder PDF' ,
],
'linkedin_page_post' => [
'label' => 'Beitrag' ,
'description' => 'Standardbeitrag – Einzelbild, mehrere Bilder, Video oder PDF' ,
],
'facebook_post' => [
'label' => 'Beitrag' ,
'description' => 'Standardbeitrag auf deiner Seite' ,
],
'facebook_reel' => [
'label' => 'Reel' ,
'description' => 'Kurzes Video bis zu 90 Sekunden' ,
],
'facebook_story' => [
'label' => 'Story' ,
'description' => 'Vertikale Videostory, bis zu 60 Sekunden' ,
],
'tiktok_video' => [
'label' => 'Video' ,
'description' => 'Kurzvideo-Inhalt' ,
],
'tiktok_photo' => [
'label' => 'Foto-Karussell' ,
'description' => 'Bis zu 35 Fotos als wischbares Karussell' ,
],
'youtube_short' => [
'label' => 'Short' ,
2026-07-23 15:06:15 +00:00
'description' => 'Vertikales Video bis zu 3 Minuten' ,
Translate the interface into 12 languages
Add full lang/ translations for fr, de, it, nl, pl, el, ja, ko, zh, ru,
tr, and ar — all 23 base files each, with identical key trees to lang/en,
preserved :placeholders and plural forms, and native product terminology.
2026-07-03 18:38:40 +00:00
],
'x_post' => [
'label' => 'Beitrag' ,
'description' => 'Tweet mit Text und Medien' ,
],
'threads_post' => [
'label' => 'Beitrag' ,
'description' => 'Textbeitrag mit optionalen Medien' ,
],
'pinterest_pin' => [
'label' => 'Pin' ,
'description' => 'Standard-Bild-Pin' ,
],
'pinterest_video_pin' => [
'label' => 'Video-Pin' ,
'description' => 'Video-Pin (4 Sek. – 15 Min.)' ,
],
'pinterest_carousel' => [
'label' => 'Karussell' ,
'description' => 'Karussell mit mehreren Bildern (2– 5 Bilder)' ,
],
'bluesky_post' => [
'label' => 'Beitrag' ,
'description' => 'Textbeitrag mit optionalen Bildern' ,
],
'mastodon_post' => [
'label' => 'Beitrag' ,
'description' => 'Textbeitrag mit optionalen Medien' ,
],
'telegram_post' => [
'label' => 'Beitrag' ,
'description' => 'Textbeitrag mit optionalen Medien' ,
],
'discord_message' => [
'label' => 'Nachricht' ,
'description' => 'Nachricht an einen Discord-Kanal mit optionalen Medien & Embeds' ,
],
],
'platforms' => [
'linkedin' => 'LinkedIn' ,
'linkedin-page' => 'LinkedIn-Seite' ,
'x' => 'X' ,
'tiktok' => 'TikTok' ,
'youtube' => 'YouTube Shorts' ,
'facebook' => 'Facebook-Seite' ,
'instagram' => 'Instagram' ,
'threads' => 'Threads' ,
'pinterest' => 'Pinterest' ,
'bluesky' => 'Bluesky' ,
'mastodon' => 'Mastodon' ,
],
'flash' => [
'scheduled' => 'Beitrag erfolgreich geplant!' ,
'deleted' => 'Beitrag erfolgreich gelöscht!' ,
'duplicated' => 'Beitrag als Entwurf dupliziert.' ,
'cannot_edit_finalized' => 'Dieser Beitrag wurde bereits verarbeitet und kann nicht erneut veröffentlicht werden. Dupliziere ihn, um es noch einmal zu versuchen.' ,
'cannot_delete_published' => 'Veröffentlichte Beiträge können nicht gelöscht werden.' ,
'connect_first' => 'Verbinde mindestens ein soziales Netzwerk, bevor du einen Beitrag erstellst.' ,
],
'errors' => [
'account_disconnected' => 'Social-Media-Konto ist getrennt' ,
'account_inactive' => 'Social-Media-Konto ist deaktiviert' ,
'account_token_expired' => 'Sitzung des Social-Media-Kontos abgelaufen – bitte erneut verbinden' ,
fix: Pinterest video processing timeout — longer poll + retry (#246)
* fix: give Pinterest video processing more time and retry on timeout
A valid ~54s video pin failed after ~90s of polling while Pinterest was
still processing. Extend the poll window to ~5 minutes and treat timeout
as platform unavailable so PublishToSocialPlatform reschedules instead of
failing the post on the first attempt.
Co-authored-by: Cursor <cursoragent@cursor.com>
* refactor: use Laravel Sleep for Pinterest media processing polls
Co-authored-by: Cursor <cursoragent@cursor.com>
* refactor: inline Pinterest video processing poll constants
Co-authored-by: Cursor <cursoragent@cursor.com>
* refactor: map Pinterest media upload statuses to an enum
Use the official MediaUploadStatus values (registered, processing,
succeeded, failed) instead of comparing raw strings in the publisher.
Co-authored-by: Cursor <cursoragent@cursor.com>
* refactor: trim Pinterest media processing docblock
* fix: cap platform-unavailable retries and recover stuck retrying posts
Stop infinite reschedules after 6 attempts with a user-safe failure
message, keep technical detail in error_context, recover Retrying
platforms in social:recover-stuck-posts, and drop unused isTerminal().
Co-authored-by: Cursor <cursoragent@cursor.com>
* refactor: remove unused failedCount in RecoverStuckPosts
Co-authored-by: Cursor <cursoragent@cursor.com>
* fix: skip final Pinterest poll sleep and localize recover timeout
Co-authored-by: Cursor <cursoragent@cursor.com>
* fix: raise publish job timeout headroom and ignore already-failed platforms
Give social publish jobs 15 minutes so Pinterest media polling fits under
the worker limit, bump Horizon/redis retry_after above that timeout, and
skip handle/failed when the platform is already Failed so delayed jobs
cannot revive posts recovered by social:recover-stuck-posts.
Co-authored-by: Cursor <cursoragent@cursor.com>
* fix: restore social-publishing and ai-assistant horizon supervisors
Co-authored-by: Cursor <cursoragent@cursor.com>
* fix: harden Pinterest 401 handling, unique publish jobs, and recover JSON
Treat media-status 401 as TokenExpired, make PublishToSocialPlatform
unique per platform+attempt so retries still queue, and persist recover
error_context via Eloquent casts instead of manual json_encode.
Co-authored-by: Cursor <cursoragent@cursor.com>
* refactor: mass-update stuck post platforms without per-row each
Eloquent query updates already bind JSON arrays correctly here, so one
UPDATE is enough — no manual json_encode and no N model writes.
Co-authored-by: Cursor <cursoragent@cursor.com>
* refactor: simplify Pinterest media processing poll loop
Co-authored-by: Cursor <cursoragent@cursor.com>
* refactor: simplify publish job retry and terminal status checks
Co-authored-by: Cursor <cursoragent@cursor.com>
* fix: do not finalize posts while platforms are still retrying
Co-authored-by: Cursor <cursoragent@cursor.com>
* test: cover Pinterest timeout, unique jobs, and recover edge cases
Co-authored-by: Cursor <cursoragent@cursor.com>
* fix: retry Pinterest media poll on connection errors and tighten tests
Co-authored-by: Cursor <cursoragent@cursor.com>
* fix: remove ineffective TypeError import that breaks CI
Co-authored-by: Cursor <cursoragent@cursor.com>
---------
Co-authored-by: Cursor <cursoragent@cursor.com>
2026-08-06 23:49:37 +00:00
'platform_unavailable' => 'Die Plattform ist vorübergehend nicht verfügbar. Wir versuchen es in Kürze erneut.' ,
'platform_unavailable_exhausted' => 'Die Plattform blieb nach mehreren Versuchen nicht verfügbar. Bitte später erneut versuchen.' ,
'publishing_timed_out' => 'Die Veröffentlichung ist abgelaufen. Bitte erneut versuchen.' ,
Translate the interface into 12 languages
Add full lang/ translations for fr, de, it, nl, pl, el, ja, ko, zh, ru,
tr, and ar — all 23 base files each, with identical key trees to lang/en,
preserved :placeholders and plural forms, and native product terminology.
2026-07-03 18:38:40 +00:00
],
'delete' => [
'title' => 'Beitrag löschen?' ,
'description' => 'Diese Aktion kann nicht rückgängig gemacht werden. Der Beitrag und alle zugehörigen Medien werden dauerhaft entfernt.' ,
'confirm' => 'Ja, löschen' ,
'cancel' => 'Abbrechen' ,
],
'create' => [
'title' => 'Neuen Beitrag erstellen' ,
'description' => 'Wähle, wie du beginnen möchtest.' ,
'scratch_title' => 'Von Grund auf beginnen' ,
'scratch_description' => 'Öffne einen leeren Beitrag und schreibe alles selbst.' ,
'ai_title' => 'Mit KI generieren' ,
'ai_description' => 'Beschreibe, was du möchtest, und die KI generiert den Inhalt für dich.' ,
'ai_configure_description' => 'Wähle ein Format und beschreibe den Beitrag, den du erstellen möchtest.' ,
'ai_pick_template_description' => 'Wähle einen Stil für deinen KI-generierten Beitrag.' ,
'coming_soon' => 'Demnächst verfügbar' ,
'preview' => [
'image_title' => 'Bildtitel' ,
'image_body' => 'Bildtext' ,
],
'steps' => [
'template_picker_title' => 'Wähle einen Stil' ,
'format_title' => 'Wähle ein Format' ,
'format_description' => 'Wähle die Art des Beitrags, den du erstellen möchtest.' ,
'account_title' => 'Wähle ein Konto' ,
'account_description' => 'Wähle das Social-Media-Konto zum Veröffentlichen.' ,
'media_title' => 'Medienoptionen' ,
'media_carousel' => 'Wie viele Slides?' ,
'media_optional' => 'Bilder einbeziehen?' ,
'media_optional_label' => 'Wie viele Bilder?' ,
'media_none' => 'Keine' ,
'media_count_label' => 'Anzahl der Bilder' ,
2026-07-18 18:12:26 +00:00
'brand_colors_label' => 'Markenfarben' ,
'brand_colors_description' => 'Wende die Markenpalette deines Workspace auf die generierten Bilder an. Deaktiviere die Option, damit die KI passende Farben zum Inhalt wählt.' ,
Translate the interface into 12 languages
Add full lang/ translations for fr, de, it, nl, pl, el, ja, ko, zh, ru,
tr, and ar — all 23 base files each, with identical key trees to lang/en,
preserved :placeholders and plural forms, and native product terminology.
2026-07-03 18:38:40 +00:00
'prompt_title' => 'Beschreibe deinen Beitrag' ,
'prompt_label' => 'Worum geht es in diesem Beitrag?' ,
'prompt_placeholder' => 'z. B. Unser neues Karussell-Feature für Instagram ankündigen' ,
'preview_error' => 'Etwas ist schiefgelaufen. Bitte versuche es erneut.' ,
'loading_page_title' => 'Dein Beitrag wird generiert' ,
'loading_eta' => 'Geschätzte Zeit: etwa :minutes.' ,
'loading_eta_minute_one' => '1 Minute' ,
'loading_eta_minute_other' => ':count Minuten' ,
'loading_leave_title' => 'Du kannst weiterarbeiten.' ,
'loading_leave_body' => 'Wir benachrichtigen dich, wenn der Beitrag fertig ist.' ,
'loading_leave_cta' => 'Zum Kalender' ,
'loading_create_another_cta' => 'Weiteren Beitrag erstellen' ,
'loading_tip_credits' => 'Jedes KI-Bild verbraucht etwa 15 Credits.' ,
'loading_tip_edit' => 'Du kannst alles bearbeiten, sobald der Beitrag fertig ist.' ,
'loading_tip_draft' => 'Generierte Beiträge landen in deinen Entwürfen.' ,
'loading_tip_brand' => 'Passe deine Markeneinstellungen an, um zukünftige Beiträge zu beeinflussen.' ,
'loading_tip_carousel' => 'Karussells liefern pro hochgeladenem Bild ein Slide.' ,
'loading_tip_quality' => 'Die Bildqualität ist auf ein Gleichgewicht aus Geschwindigkeit und Kosten eingestellt.' ,
'create' => 'Beitrag erstellen' ,
'back' => 'Zurück' ,
'next' => 'Weiter' ,
'cancel' => 'Abbrechen' ,
'discard' => 'Verwerfen' ,
'retry' => 'Erneut versuchen' ,
'no_platforms' => 'Keine verbundenen Konten' ,
'connect_first' => 'Verbinde mindestens ein Social-Media-Konto, um die KI-Generierung zu nutzen.' ,
'no_account_for_template' => 'Verbinde ein kompatibles Konto, um diese Vorlage zu verwenden.' ,
'format' => [
'instagram_feed' => 'Instagram-Feed-Beitrag' ,
'instagram_carousel' => 'Instagram-Karussell' ,
'linkedin_post' => 'LinkedIn-Beitrag' ,
'linkedin_page_post' => 'LinkedIn-Seiten-Beitrag' ,
'x_post' => 'X-Beitrag' ,
'bluesky_post' => 'Bluesky-Beitrag' ,
'threads_post' => 'Threads-Beitrag' ,
'mastodon_post' => 'Mastodon-Beitrag' ,
'telegram_post' => 'Telegram-Beitrag' ,
'discord_message' => 'Discord-Nachricht' ,
'facebook_post' => 'Facebook-Beitrag' ,
'pinterest_pin' => 'Pinterest-Pin' ,
'instagram_story' => 'Instagram-Story' ,
'facebook_story' => 'Facebook-Story' ,
],
],
],
];