Je nach Domain-Endung (TopLevelDomain) die passende Sprache anzuzeigen gehört gerade unter den größeren Marken zum guten Ton sofern man international agiert. So wird auf der *.de Domain die deutsche, unter *.com die englische und *.es die spanische Fassung angezeigt. Kleinere Unternehmen insbesondere auch solche, die gar keine Marke im gesetzlichen Sinne besitzen, setzen bei mehrsprachigen Projekten lediglich meistens auf „Verzeichnisebene“ auf die unterschiedlichen Sprachversionen.
Kürzlich musste ich in einem Projekt genau diesen Fall umsetzen. Eine Domain mit unterschiedlichen TLDs; *.de für die deutsche Fassung, *.es für die spanische und die *.com als Hauptdomain für die englische Fassung. Das Projekt sollte mit dem Symfony Framework Version 5.x umgesetzt werden, benötigte deshalb ein passendes Entwicklungsdesign nach den üblichen Standards.
Mit Event-Subscriber auf Host Ebene reagieren
Die Lösung war klar, ein Event-Subscriber muss her, der bereits beim Initialisieren des Systems erkennt, auf welchem Host (Domain inkl. TLD) man sich befindet. Darauf kann der Event-Subscriber entsprechend reagieren und die passende Locale laden. Also machte ich mich auf die Suche, wie man das in Symfony richtigerweise umsetzen könnte, fand dabei aber nur Lösungsansätze in älteren Versionen und teils auch ganz eigenartige Konstellationen.
Schlussendlich habe ich ein Event-Subscriber im Service registriert, der noch vor dem Locale-Listener im Kernel geladen wird. Die Standard-Sprache sowie ob der Event-Subscriber reagieren soll wird über die .env an den Subscriber übergeben.
<?php declare(strict_types=1);
namespace App\EventSubscriber;
use Symfony\Component\EventDispatcher\EventSubscriberInterface;
use Symfony\Component\HttpKernel\Event\RequestEvent;
use Symfony\Component\HttpKernel\KernelEvents;
use Symfony\Contracts\Translation\TranslatorInterface;
class LocaleSubscriber implements EventSubscriberInterface
{
private $translator;
private $defaultLocale;
private $activate;
private $domains = ["domain.de" => "de", "domain.es" => "es", "domain.com" => "en"];
public function __construct(string $defaultLocale, bool $activate, TranslatorInterface $translator) : void
{
$this->defaultLocale = $defaultLocale;
$this->activate = $activate ?? false;
$this->translator = $translator;
}
public function onKernelRequest(RequestEvent $event) : void
{
// falls nicht aktiviert, nichts weiter tun
if (!$this->activate) return;
$request = $event->getRequest();
$languageUsed = null;
// gehe das Domain Array durch und schlüssel nach Domain und Sprache auf
foreach($this->domains as $host => $lang) {
// Wenn die Domain $host im globalen Server HTTP_HOST vorkommt, benutze die
// die Sprache $lang
if (strstr(strtolower($_SERVER['HTTP_HOST']), strtolower($host))) {
$languageUsed = $lang;
}
}
// Sofern $languageUsed != null ist, nehme die gesetzte Sprache,
// andernfalls benutze die konfigurierte Standard-Sprache aus
// config/packages/translation.yaml
$request->setLocale($languageUsed ?? $this->defaultLocale);
$this->translator->setLocale($languageUsed ?? $this->defaultLocale);
}
/**
* Event vor dem Locale Listener registrieren
* @return \array[][]
*/
public static function getSubscribedEvents(): array
{
return [ KernelEvents::REQUEST => [['onKernelRequest', 20]] ];
}
}
Nun müssen wir den Event-Subscriber noch über die config/services.yaml dem Kernel hinzufügen:
...
services:
...
App\EventSubscriber\LocaleSubscriber:
# mit %kernel.default_locale% übergeben wir die Standard eingestellte Sprache die über
# die default_locale in der config/packages/translation.yaml eingestellt wurde (ist
# standardmäßig en).
#
# Aus unserer .env holen wir mit %env(LANG_REDIRECT)% unsere Einstellung LANG_REDIRECT
# die wir mit LANG_REDIRECT=true oder LANG_REDIRECT=false angeben können (Aktivierung)
arguments: ['%kernel.default_locale%', '%env(LANG_REDIRECT)%']
Damit war es das schon und das System lädt je nach Domain-TLD die entsprechende definierte Sprache. Mir ist schon klar, dass das nicht gerade „schön“ ist, dass Host ./. Sprach Array direkt in den Subscriber zu definieren. Sicherlich hätte man hier notfalls noch mit einem Service die Auflösung der konfigurierten Domains und Sprachen ermitteln können, war bei dem Projekt allerdings absolut nicht nötig.
Eventuell gebe ich anderen deutschen Symfony Entwicklern die gerade vor diesem Task sitzen einen Lösungsansatz und erspare stundenlanges durchforsten von Google nach möglichen Lösungen ;-)