Zum Hauptinhalt springen

Mehrsprachigkeit (i18n)

Postbox ist zweisprachig: Deutsch (primär) und Englisch. Deutsch ist die führende Sprache — bestehende URLs ohne Prefix leiten per 301 auf /de/ um.


Architektur

URL-Strategie

BereichLocale-QuelleBeispiel
Öffentliche SeitenURL-Prefix (/de/, /en/)/de/explorer, /en/explorer
App-Bereich (eingeloggt)users.locale Column (DB)/dashboard (kein Prefix)
Admin-BereichDeutsch (nicht übersetzt)/admin/*
API / WebhooksKein Locale/api/*, /webhooks/*

Middleware-Stack

MiddlewareBereichFunktion
RedirectToLocalizedUrlGlobal (GET)301-Redirect von /explorer/de/explorer
SetLocaleFromUrlÖffentliche RoutenLiest {locale} aus URL, setzt app()->setLocale()
SetLocaleFromUserAuth-RoutenLiest users.locale aus DB, setzt Locale

Fallback-Kette

  • Öffentlich: URL-Prefix → /de/ (Default per 301)
  • Eingeloggt: users.localede (Default)
  • Übersetzungen: EN-Key vorhanden → EN, sonst Fallback auf DE

Translation-Dateien

lang/
├── de.json → ~280 UI-Strings (Deutsch = Key-Sprache)
├── en.json → ~450 EN-Übersetzungen
├── de/
│ ├── validation.php → Validierungs-Meldungen
│ ├── auth.php → Auth-Meldungen
│ ├── passwords.php → Passwort-Reset
│ └── pagination.php → Pagination
└── en/
├── validation.php → EN Validierung
├── auth.php → EN Auth
├── passwords.php → EN Passwort-Reset
├── pagination.php → EN Pagination
└── mail.php → EN Mail-Strings

String-Pattern

Blade:

<flux:heading>{{ __('Übersicht') }}</flux:heading>
<flux:button>{{ __('Speichern') }}</flux:button>

PHP (Toast/Flash):

Flux::toast(__('Profil erfolgreich hinzugefügt.'));

Parametrisiert:

__('Zu viele Anfragen. Bitte warte :minutes Minuten.', ['minutes' => $minutes])

Locale-Verwaltung

Registrierung

Bei der Account-Erstellung wird die Browser-Sprache (Accept-Language Header) einmalig in users.locale geschrieben:

// app/Actions/Fortify/CreateNewUser.php
$browserLocale = request()->getPreferredLanguage(User::SUPPORTED_LOCALES) ?? 'de';

Einstellungen

User können ihre Sprache in den Profil-Einstellungen (/settings/profile) ändern. Ein flux:select-Dropdown bietet Deutsch und English zur Auswahl.

Unterstützte Locales

// app/Models/User.php
public const SUPPORTED_LOCALES = ['de', 'en'];

SEO

hreflang-Tags

Alle öffentlichen Seiten erhalten automatisch hreflang-Tags im <head>:

<link rel="alternate" hreflang="de" href="https://example.com/de/explorer" />
<link rel="alternate" hreflang="en" href="https://example.com/en/explorer" />
<link rel="alternate" hreflang="x-default" href="https://example.com/de/explorer" />

x-default zeigt auf /de/ (Deutsch als Default für unbekannte Sprachen).

Open Graph

<meta property="og:locale" content="de_DE"> <!-- oder en_US -->
<meta property="og:locale:alternate" content="en_US"> <!-- oder de_DE -->

Sitemap

Die Sitemap enthält für jede URL bidirektionale hreflang-Annotationen:

<url>
<loc>https://example.com/de/explorer/username_y123</loc>
<xhtml:link rel="alternate" hreflang="de" href="...de..." />
<xhtml:link rel="alternate" hreflang="en" href="...en..." />
<xhtml:link rel="alternate" hreflang="x-default" href="...de..." />
</url>

301-Redirects

Alle bestehenden URLs ohne Locale-Prefix leiten permanent auf /de/ um. Kein Browser-Sniffing — Google-Empfehlung wird befolgt.


CMS-Pages

Datenbank-Design

Deutsch bleibt in den bestehenden Feldern (Rückwärtskompatibilität), Englisch in _en-Spalten:

Feld (DE, primär)Feld (EN)
titletitle_en
contentcontent_en
meta_descriptionmeta_description_en
slugslug_en

AI-Übersetzung

Im Admin-Editor (/admin/pages/{id}/edit) gibt es einen "KI-Übersetzung generieren"-Button, der den PageTranslator-Service aufruft. Dieser übersetzt die deutschen Inhalte per Gemini AI ins Englische — HTML-Struktur wird beibehalten.

Locale-Methoden (Page Model)

$page->getLocalizedTitle('en');      // EN-Titel oder DE-Fallback
$page->getLocalizedContent('en'); // EN-Content oder DE-Fallback
$page->getLocalizedMetaDescription('en');
$page->hasEnglishTranslation(); // true wenn title_en + content_en gesetzt

AI-Beschreibungen

Profil-AI-Beschreibungen werden locale-aware ausgespielt — sowohl auf SocialProfile als auch auf PublicExplorerProfile:

$profile->getAiDescriptionForLocale(app()->getLocale());

SocialProfile (social_profiles Tabelle):

LocaleFeldFallback
deai_description_deai_description (EN)
enai_description

PublicExplorerProfile (public_explorer_profiles Tabelle):

LocaleFeldFallback
deai_description_deai_description (EN)
enai_description

Beim public-explorer:refresh werden beide Sprachversionen aus dem SocialProfile in die denormalisierte Tabelle synchronisiert.


Fortify-Integration

  • Auth-Views (Login, Register, etc.) laufen unter /{locale}/login, /{locale}/register
  • POST-Actions bleiben auf Root-Level (POST /login) — werden NICHT redirected
  • Post-Login: Redirect auf /dashboard (Locale aus DB via SetLocaleFromUser)
  • Post-Logout: Redirect auf /{user.locale}/ via LogoutResponse + CaptureLogoutLocale Listener

Helper

localized_route()

Generiert URLs mit Locale-Prefix für öffentliche Routen:

localized_route('public-explorer.index')
// → /de/explorer (wenn Locale = de)

localized_route('public-explorer.show', ['path' => 'user_y123'])
// → /en/explorer/user_y123 (wenn Locale = en)

Abgedeckte Bereiche

BereichStatusAnmerkung
Öffentliche Seiten (Explorer, Landing, CMS)✅ VollständigURL-Prefix + hreflang
Auth (Login, Register, 2FA, Passwort)✅ VollständigFortify-Integration
Dashboard✅ Vollständig
Watcher (Index + Detail + Charts)✅ VollständigInkl. Video Performance, Tooltips, Admin-Diagnose
Settings (Profil, Workspaces)✅ Vollständig
Compare✅ Vollständig
Discover✅ Vollständig
Video-Trends✅ Vollständig
Tops/Flops✅ Vollständig
Feedback✅ Vollständig
Shared Components (Slider-Cards, Workspace-Modal)✅ Vollständig
Mail-Templates✅ Vollständiglang/en/mail.php
Admin-Bereich (/admin/*)❌ Bewusst nichtNur interne Nutzung

Admin-Bereich

Admin-Seiten (/admin/*) werden nicht übersetzt. Sie bleiben auf Deutsch, da nur interne Nutzung (1-2 Admins, beide deutschsprachig).


Dateien

DateiBeschreibung
app/Http/Middleware/SetLocaleFromUrl.phpLocale aus URL für öffentliche Seiten
app/Http/Middleware/SetLocaleFromUser.phpLocale aus DB für eingeloggte User
app/Http/Middleware/RedirectToLocalizedUrl.php301-Redirect für alte URLs
app/helpers.phplocalized_route() Helper
app/Services/AI/PageTranslator.phpCMS-Page AI-Übersetzung (DE→EN)
app/Http/Responses/LogoutResponse.phpLocale-aware Logout-Redirect
app/Listeners/CaptureLogoutLocale.phpLocale vor Session-Invalidierung sichern
resources/views/components/language-switcher.blade.phpSprachwechsler UI-Component
resources/views/components/layouts/public.blade.phphreflang + og:locale Tags
lang/en.jsonEnglische UI-Übersetzungen
lang/en/mail.phpEnglische Mail-Strings