Настройка мультиязычности и Webspaces Sulu

Наша компания занимается разработкой, поддержкой и обслуживанием сайтов любой сложности. От простых одностраничных сайтов до масштабных кластерных систем построенных на микро сервисах. Опыт разработчиков подтвержден сертификатами от вендоров.

Разработка и обслуживание любых видов сайтов:

Информационные сайты или веб-приложения
Сайты визитки, landing page, корпоративные сайты, онлайн каталоги, квиз, промо-сайты, блоги, новостные ресурсы, информационные порталы, форумы, агрегаторы
Сайты или веб-приложения электронной коммерции
Интернет-магазины, B2B-порталы, маркетплейсы, онлайн-обменники, кэшбэк-сайты, биржи, дропшиппинг-платформы, парсеры товаров
Веб-приложения для управления бизнес-процессами
CRM-системы, ERP-системы, корпоративные порталы, системы управления производством, парсеры информации
Сайты или веб-приложения электронных услуг
Доски объявлений, онлайн-школы, онлайн-кинотеатры, конструкторы сайтов, порталы предоставления электронных услуг, видеохостинги, тематические порталы

Это лишь некоторые из технических типов сайтов, с которыми мы работаем, и каждый из них может иметь свои специфические особенности и функциональность, а также быть адаптированным под конкретные потребности и цели клиента

Предлагаемые услуги
Показано 1 из 1 услугВсе 2065 услуг
Настройка мультиязычности и Webspaces Sulu
Средняя
~2-3 рабочих дня
Часто задаваемые вопросы

Наши компетенции:

Этапы разработки

Последние работы

  • image_website-b2b-advance_0.png
    Разработка сайта компании B2B ADVANCE
    1262
  • image_web-applications_feedme_466_0.webp
    Разработка веб-приложения для компании FEEDME
    1171
  • image_websites_belfingroup_462_0.webp
    Разработка веб-сайта для компании БЕЛФИНГРУПП
    874
  • image_ecommerce_furnoro_435_0.webp
    Разработка интернет магазина для компании FURNORO
    1094
  • image_crm_enviok_479_0.webp
    Разработка веб-приложения для компании Enviok
    831
  • image_bitrix-bitrix-24-1c_fixper_448_0.png
    Разработка веб-сайта для компании ФИКСПЕР
    851

Настройка мультиязычности и Webspaces Sulu

Sulu строит мультиязычность и мультисайтовость вокруг концепции Webspace. Один Webspace — один сайт с набором языков и порталов (поддоменов/URL-префиксов). Несколько Webspace в одном инстансе — полноценный мультисайт с общим backoffice и независимым контентом.

Принципы Webspace

  • Webspace — логический сайт (example.com, shop.example.com)
  • Portal — вариант доступа к Webspace (production URL, staging URL)
  • Localization — язык контента (ru, en, de)
  • URL — привязка языка к домену или пути

Один Webspace может обслуживаться с нескольких доменов. Обратное невозможно — один домен всегда принадлежит одному Webspace.

Мультиязычный Webspace

<!-- config/packages/webspaces/main.xml -->
<?xml version="1.0" encoding="utf-8"?>
<webspace xmlns="http://schemas.sulu.io/webspace/webspace"
          xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
          xsi:schemaLocation="http://schemas.sulu.io/webspace/webspace
          http://schemas.sulu.io/webspace/webspace-1.1.xsd">

    <name>Main Site</name>
    <key>main</key>

    <localizations>
        <localization language="ru" default="true" xDefault="true"/>
        <localization language="en"/>
        <localization language="de"/>
    </localizations>

    <shadow-base-language>ru</shadow-base-language>

    <default-templates>
        <default-template type="page">default</default-template>
        <default-template type="home">homepage</default-template>
    </default-templates>

    <templates>
        <template type="page">default</template>
        <template type="page">article</template>
        <template type="home">homepage</template>
    </templates>

    <excluded-templates>
        <excluded-template>overview</excluded-template>
    </excluded-templates>

    <portals>
        <portal>
            <name>Main</name>
            <key>main</key>
            <environments>
                <environment type="prod">
                    <urls>
                        <url language="ru" redirect="false">example.com</url>
                        <url language="en">en.example.com</url>
                        <url language="de">de.example.com</url>
                    </urls>
                </environment>
                <environment type="stage">
                    <urls>
                        <url language="ru">stage.example.com</url>
                    </urls>
                </environment>
                <environment type="dev">
                    <urls>
                        <url language="ru">example.localhost</url>
                        <url language="en">en.example.localhost</url>
                    </urls>
                </environment>
            </environments>
        </portal>
    </portals>
</webspace>

Мультисайт: несколько Webspace

<!-- config/packages/webspaces/blog.xml -->
<webspace>
    <name>Blog</name>
    <key>blog</key>

    <localizations>
        <localization language="ru" default="true"/>
    </localizations>

    <portals>
        <portal>
            <name>Blog</name>
            <key>blog</key>
            <environments>
                <environment type="prod">
                    <urls>
                        <url language="ru">blog.example.com</url>
                    </urls>
                </environment>
            </environments>
        </portal>
    </portals>
</webspace>

Каждый Webspace имеет независимое дерево контента. В backoffice они отображаются как отдельные сайты. Медиабиблиотека при этом общая.

Конфигурация security per Webspace

# config/packages/security.yaml
sulu_security:
    checker:
        enabled: true

security:
    providers:
        sulu_backend:
            id: sulu_security.user_provider
    firewalls:
        admin:
            pattern: /admin
            provider: sulu_backend
            # ...
        main:
            pattern: '^/'
            stateless: false

Права доступа редактора можно ограничить конкретным Webspace:

Backoffice → Users → Edit User → Webspace Permissions

Shadow Pages — синхронизация контента

Shadow позволяет сделать страницу одного языка «тенью» другого — она отображает контент базового языка без создания отдельного перевода.

// Программное создание shadow через API
$document = $this->documentManager->find('/cmf/main/contents/about', 'en');
$document->setShadowLocale('ru');     // взять контент из ru
$document->setShadowLocalesEnabled(true);
$this->documentManager->persist($document, 'en');
$this->documentManager->flush();

В backoffice — переключатель "Shadow Page" на каждой странице.

Переключатель языков в Twig

{# templates/snippets/language-switcher.html.twig #}
{% set currentLocale = app.request.locale %}

<nav class="lang-switcher">
    {% for locale in ['ru', 'en', 'de'] %}
        {% set url = sulu_content_path(null, webspace, locale) %}
        <a
            href="{{ url }}"
            hreflang="{{ locale }}"
            lang="{{ locale }}"
            class="{{ locale == currentLocale ? 'active' : '' }}"
            {% if locale == currentLocale %}aria-current="page"{% endif %}
        >
            {{ locale|upper }}
        </a>
    {% endfor %}
</nav>

{# hreflang в <head> для SEO #}
{% block hreflang %}
    {% for locale in ['ru', 'en', 'de'] %}
        <link rel="alternate"
              hreflang="{{ locale }}"
              href="{{ sulu_content_path(null, webspace, locale) }}">
    {% endfor %}
    <link rel="alternate"
          hreflang="x-default"
          href="{{ sulu_content_path(null, webspace, 'ru') }}">
{% endblock %}

Навигация с учётом языка

// src/Twig/NavigationExtension.php
class NavigationExtension extends AbstractExtension
{
    public function __construct(
        private readonly NavigationMapperInterface $navigationMapper
    ) {}

    public function getFunctions(): array
    {
        return [
            new TwigFunction('app_navigation', [$this, 'getNavigation']),
        ];
    }

    public function getNavigation(
        string $context,
        string $webspaceKey,
        string $locale,
        int $depth = 2
    ): array {
        return $this->navigationMapper->getNavigation(
            null,
            $webspaceKey,
            $locale,
            $depth,
            false,
            $context
        );
    }
}
{% set nav = app_navigation('main', webspace, locale, 2) %}
{% for item in nav %}
    <a href="{{ item.url }}"
       {% if item.uuid == content.uuid %}aria-current="page"{% endif %}>
        {{ item.title }}
    </a>
    {% if item.children %}
        <ul>
        {% for child in item.children %}
            <li><a href="{{ child.url }}">{{ child.title }}</a></li>
        {% endfor %}
        </ul>
    {% endif %}
{% endfor %}

URL-стратегии для языков

Три варианта настройки URL:

Поддомены: ru.example.com, en.example.com — разные URL в Webspace portal.

Префикс пути:

<url language="ru">/</url>
<url language="en">/en</url>
<url language="de">/de</url>

Отдельный домен на язык:

<url language="ru">example.ru</url>
<url language="en">example.com</url>
<url language="de">example.de</url>

Инициализация после изменения Webspace

php bin/console cache:clear
php bin/console sulu:document:initialize
php bin/console sulu:phpcr:init --user=admin
php bin/console sulu:webspace:copy-locale main --from=ru --to=en

sulu:webspace:copy-locale копирует структуру дерева страниц с одного языка на другой — удобно при добавлении нового языка к уже заполненному сайту.

Сроки

Добавить второй язык к работающему сайту: 1–2 дня. Настройка мультисайта с двумя Webspace с нуля: 2–3 дня. Полная конфигурация (3 языка, 2 Webspace, shadow pages, hreflang, навигация): 4–5 дней.