Как эффективно организовать маршрутизацию для многоязычного мультисайта в Symfony?

Здравствуйте! <br/> <br/> У меня есть вопрос по поводу реализации роутинга для многоязычного мультисайта, чтобы впоследствии другим программистам было легче с ним работать. <br/> Рассмотрим пример: у нас есть сайт на поддомене <b>dom1.site.com</b>, который поддерживает несколько языков: русский (является дефолтным) и английский (дополнительный). Я хотел бы, чтобы страницы на русском языке открывались без локали, например, по адресу <b>dom1.site.com/contact</b>, в то время как страницы на английском должны открываться с локалью, то есть по адресу <b>dom1.site.com/en/contact</b>. <br/> Теперь рассмотрим другой сайт <b>dom2.site.com</b>, где дефолтным языком является английский, а испанский — дополнительным. Таким образом, страницы на английском языке должны отображаться без локали, например, по адресу <b>dom2.site.com/contact</b>, а страницы на испанском языке — с локалью, то есть по адресу <b>dom2.site.com/es/contact</b>. <br/> <br/> Я не рассматриваю вариант отказа от локалей в адресе и хранения их в сессии, поскольку это может негативно отразиться на SEO, так как в итоге на сайте будет множество Title на разных языках одновременно.
  • 30 октября 2024 г. 14:33
Ответы на вопрос 2
Для реализации многоязычной маршрутизации в Symfony для мультисайта с учетом ваших требований, можно воспользоваться модулем `Routing` и использовать локали в качестве параметров. Вот шаги, которые помогут вам организовать маршрутизацию согласно вашим условиям:

### 1. Настройка маршрутов

Создайте маршруты в вашем файле маршрутизации (например, `config/routes.yaml`). Используйте параметр `requirements` для указания локалей, и создайте маршруты таким образом, чтобы они учитывали специфику разных поддоменов.

```yaml
# config/routes.yaml

dom1:
    resource: '../src/Controller/Dom1Controller.php'
    type: annotation
    defaults: { _locale: 'ru' }
    requirements:
        _locale: 'ru|en'

dom2:
    resource: '../src/Controller/Dom2Controller.php'
    type: annotation
    defaults: { _locale: 'en' }
    requirements:
        _locale: 'en|es'

# Основной маршрут для dom1
contact_dom1:
    path: /contact
    controller: App\Controller\Dom1Controller::contact
    defaults: { _locale: 'ru' }

contact_dom1_en:
    path: /en/contact
    controller: App\Controller\Dom1Controller::contact
    defaults: { _locale: 'en' }

# Основной маршрут для dom2
contact_dom2:
    path: /contact
    controller: App\Controller\Dom2Controller::contact
    defaults: { _locale: 'en' }

contact_dom2_es:
    path: /es/contact
    controller: App\Controller\Dom2Controller::contact
    defaults: { _locale: 'es' }
```

### 2. Настройка контроллеров

Создайте контроллеры для обработки маршрутов в зависимости от локали и поддомена.

```php
// src/Controller/Dom1Controller.php
namespace App\Controller;

use Symfony\Bundle\FrameworkBundle\Controller\AbstractController;
use Symfony\Component\HttpFoundation\Response;
use Symfony\Component\Routing\Annotation\Route;

class Dom1Controller extends AbstractController
{
    /**
     * @Route("/contact", name="contact_dom1")
     */
    public function contact(): Response
    {
        // Логика для русского языка
        return $this->render('dom1/contact.html.twig', []);
    }

    /**
     * @Route("/en/contact", name="contact_dom1_en")
     */
    public function contactEn(): Response
    {
        // Логика для английского языка
        return $this->render('dom1/contact_en.html.twig', []);
    }
}

// Аналогично для Dom2Controller
```

### 3. Конфигурация локали

Вам нужно убедиться, что ваша конфигурация Symfony правильно настроена для работы с локалями:

```yaml
# config/packages/translation.yaml

framework:
    translator: { fallbacks: ['en'] }
```

### 4. Обработка локалей на уровне запроса

Создайте специальный middleware или listener, который будет обрабатывать локали на уровне запроса и определять поддомен, чтобы проставлять корректную локаль в контексте.

Вы можете использовать слухай для проверки текущего поддомена и установки локали в зависимости от него. Например:

```php
// src/EventListener/LocaleListener.php
namespace App\EventListener;

use Symfony\Component\HttpKernel\Event\RequestEvent;
use Symfony\Component\HttpKernel\Event\ControllerEvent;
use Symfony\Component\HttpFoundation\Request;

class LocaleListener
{
    public function onKernelRequest(RequestEvent $event): void
    {
        $request = $event->getRequest();

        if (strpos($request->getHost(), 'dom1.') === 0) {
            $request->setLocale($request->getLocale() ?: 'ru');
        } elseif (strpos($request->getHost(), 'dom2.') === 0) {
            $request->setLocale($request->getLocale() ?: 'en');
        }
    }
}
```

### 5. Регистрация слушателя

Не забудьте зарегистрировать ваш слушатель в сервисах:

```yaml
# config/services.yaml

services:
    App\EventListener\LocaleListener:
        tags:
            - { name: kernel.event_listener, event: kernel.request, method: onKernelRequest }
```

### Заключение

Таким образом, вы создадите удобную и понятную многопользовательскую маршрутизацию с поддержкой локалей, сохраняя при этом поисковую оптимизацию. Важно придерживаться единообразия в коде и придерживаться стандартов, чтобы другие разработчики могли быстро разбираться в вашей реализации.
Не надо ничего придумывать. Надо просто следовать документации Symfony, и тогда другим программистам не в чем будет вас упрекать. 
Установите компонент "symfony/translation" и следуйте рекомендациям:
https://symfony.com/doc/current/translation.html#t...

P.S. Рассмотрите вариант не делать дефолтную локаль без языкового префикса. Пусть все локали будут иметь префикс, а при заходе на сайт по прямому адресу главной страницы без языкового префикса, будет сразу происходить редирект на главную страницу с префиксом дефолтной локали. Это упростит жизнь всем. Всегда будет чётко понятно, какой язык используется в данный момент.
Похожие вопросы