К содержанию

pbStudio: Подключаем мультиязычность в PageBlocks

Введение


PageBlocks поддерживает мультиязычность без контекстов. Достаточно указать языки, задать поля для перевода и, при необходимости, подключить автоперевод — остальное сделает PageBlocks.

Навигация по урокам:


Шаг 1. Настройка мультиязычности


Чтобы включить поддержку языков, измените следующие системные настройки:
  • pageblocks_context_aware = Да
  • pageblocks_contexts = [{«key»:«web»,«value»:«Russian»}, {«key»:«en»,«value»:«English»}]
В MODX 2 значения языков нужно задать вручную в формате JSON.
В MODX 3 доступна удобная таблица редактирования языков.

Также нужно указать, какие поля ресурса нужно переводить:
  • pageblocks_translate_resource_fields = pagetitle,longtitle,description,introtext,content,menutitle

Шаг 2. Настройка автоматического перевода (опционально)


Поддерживаются два переводчика:

ChatGPT

  • pageblocks_translator = ChatGPT
  • pageblocks_chatgpt_apikey = ваш API-ключ

DeepL

  • pageblocks_translator = DeepL
  • pageblocks_deepl_account = Free или Pro
  • pageblocks_deepl_apikey = ваш API-ключ

Шаг 3. Вывод переключателя языков на сайте


Добавьте в header.tpl следующий код:
<ul class="navbar-nav ms-auto d-flex align-items-center list-unstyled mb-0">
 {'!pbLang' | snippet: [
        'tpl' => '@INLINE <li class="nav-item">
                <a class="nav-link {$activeCls}" lang="{$key}" href="{$url}">{$value}</a>
            </li>',
        'showCurrent' => 1
    ]}
</ul>

Если у вас не используется маршрутизация, шаги 4 и 5 можно пропустить.

Шаг 4. Настройка маршрутов (опционально)


При переходе на URL вида /en/ без правильного маршрута вы получите ошибку 404. Чтобы это исправить, добавьте маршрут в web.php:
Route::get('/{context}/{alias?}', [ResourceController::class, 'context'])
    ->where('context', '[a-z]{2}');
->where('context', '[a-z]{2}') — указываем, что контекст должен состоять из двух букв.

Важно: разместите этот маршрут до основного, чтобы сначала обрабатывался контекст:
Route::get('/{alias?}', [ResourceController::class, 'index']);


Шаг 5. Контроллер ResourceController (опционально)


Добавим метод context в контроллер и сразу сделаем рефакторинг, чтобы убрать дублирования кода:

class ResourceController extends Controller
{
    public $classKey = \modResource::class;

    public function index(string $alias = '')
    {
        $resource = $this->getResource($alias);
        $this->modx->resource = updateResource($resource);

        $this->modx->config['site_url'] = $this->modx->getOption('site_url');
        $this->modx->config['cultureKey'] = $this->modx->getOption('cultureKey');
        $this->modx->context->set('key', $this->modx->getOption('default_context'));

        return response()->view('templates/base');
    }

    public function context(string $context, string $alias = '')
    {
        $resource = $this->getResource($alias);
        $this->modx->resource = updateResource($resource, $context);

        $this->modx->config['site_url'] = $this->modx->getOption('site_url') . "$context/";
        $this->modx->config['cultureKey'] = $context;
        $this->modx->context->set('key', $context);

        return response()->view('templates/base');
    }

    private function getResource(string $alias = '')
    {
        $where = [
            'published' => 1,
            'deleted' => 0,
        ];
        if (empty($alias)) {
            $where['id'] = $this->modx->getOption('site_start', null, 1, true);
        } else {
            $where['alias'] = $alias;
        }

        if (!$resource = $this->modx->getObject($this->classKey, $where)) {
            abort();
        }

        return $resource;
    }
}

Теперь маршрут /en/ работает и открывает главную страницу, но она пустая — для этого контекста ещё не добавлены блоки. Давайте это исправим.

Шаг 6. Работа с контентом


После включения pageblocks_context_aware, в интерфейсе блоков и таблиц появится выпадающий список контекстов:


Теперь можно:
  • Копировать блоки с одного языка на другой
  • Переводить их вручную или через ИИ


Шаг 7. Перевод ресурса


Переходим во вкладку «Переводы», добавляем нужные языки и, при необходимости, активируем автоперевод полей:


Заключение


Готово! PageBlocks берёт на себя всю сложную работу по мультиязычности:
  • Учитывает текущий язык во всех сниппетах
  • Сниппеты pbMenu и pbResources возвращают переведённые ресурсы
  • Вам остаётся лишь настроить языки и перевести контент
Aleksandr Huz
Aleksandr Huz
20 апреля 2025, 15:25
modx.pro
3 227
Поблагодарить автора Отправить деньги
Реклама

Комментарии: 12

Columb
Columb Старожил
22 апреля 2025, 22:05
Доброй ночи! Не нашел в документации снипета sitemap, есть какие-то особенности при мультиязычности?
    Aleksandr Huz
    Aleksandr Huz Эксперт
    23 апреля 2025, 09:40
    Привет.
    Сниппет для sitemap будет добавлен на этой неделе.

    есть какие-то особенности при мультиязычности?
    Например? Там все очень просто, но если возникнут сложности — я помогу.
      Columb
      Columb Старожил
      23 апреля 2025, 18:17
      Важно решить как управлять страницами при мультиязычности:
      — если нет перевода, то не отображать страницу
      
- если нет перевода, то показывать 404
      
- если нет перевода, то показывать «основную» локализацию



      Как правило, клиенты просят исключить (не отображать) не переведенные страницы. Эта логика должна учитываться, в том числе и при формировании sitemap.

      Также для мультиязычности необходим сниппет Canonical — sitemap, сanonical и переключатель языков (pbLang) базовые снипеты для мультиязычного сайта

      Желающие «переехать» на ваш компонент также столкнуться с еще одной проблемой — у многих сайты на субдоменах или того хуже — на разных доменах.

      PS Посмотрите в сторону Polylang, отличный компонент, но не поддерживает MODX 3.
        Aleksandr Huz
        Aleksandr Huz Эксперт
        23 апреля 2025, 19:12
        Важно решить как управлять страницами при мультиязычности:
        Сейчас, если перевода нет — показывается страница в основной локали.
        Остальные варианты пока не реализованы.

        pbLang — есть
        pbSitemap — есть
        pbCanonical — будет

        Желающие «переехать» на ваш компонент также столкнуться с еще одной проблемой — у многих сайты на субдоменах или того хуже — на разных доменах.
        Если используется роутинг — проблем вообще нет. А если по старинки, то да, нужно доработать.
          Aleksandr Huz
          Aleksandr Huz Эксперт
          24 апреля 2025, 14:54
          Важно решить как управлять страницами при мультиязычности:
          — если нет перевода, то не отображать страницу
          А что значит не отображать страницу? Показываем главную?
            Columb
            Columb Старожил
            24 апреля 2025, 15:10
            Вся логика в том, что локализованные версии сайта по своей сути отдельные сайты как для поисковых систем, так и для посетителей.

            Если страница не переведена, то она должна быть исключена из локализации — для поисковых систем это не релевантная страница в данной локализации, а для посетителя — не user friendly.

            В сниппетах Polylang для этого применяется параметр onlyWithLocalization:
            Исключение из результатов сниппетов ресурсов без локализации
            Если необходимо исключить из результатов работы сниппетов ресурсы которые не содержат для текущего языка локализаций, то добавьте в вызов сниппета параметр onlyWithLocalization с значением 1.
              Aleksandr Huz
              Aleksandr Huz Эксперт
              24 апреля 2025, 15:46
              Сниппеты исключают страницу, если нет перевода, даже если показываем 404 страницу.

              Поэтому у меня работает так:
              • redirect — если мы переходим на страницу без перевода, то срабатывает редирект на главную, и такие страницы исключаются из всех сниппетов.
              • 404 — то же самое, что и redirect, но показываем 404 страницу вместо главной
              • default — страницы без перевода учитываются в сниппетах, (pbLang, pbMenu), но не в pbSitemap. При переходе на такую страницу показываем страницу без перевода.

              За это будет отвечать системная настройка pageblocks_context_fallback
      Ruslan
      29 апреля 2025, 09:23
      Так же есть вопрос:

      При создании например полей в админ панели,
      Field::make('title')->label('Заголовок')
      Возможно ли, что бы данный заголовок тоже можно было менять, в зависимости от выбранного языка для перевода?
      Например если на сайте два языка, русский и английски, то для русской версии отображался бы «Заголовок» а для англ «Title».
        Aleksandr Huz
        Aleksandr Huz Эксперт
        29 апреля 2025, 11:50
        Пока невозможно, но я обязательно добавлю это.
          Ruslan
          29 апреля 2025, 12:42
          Было бы супер.

          А у вас есть в планах сделать что-то похожее на «Client Config» page?
          Ну то-есть будет какая то страница, где люди смогут создавать глобальные поля, вроде номера телефона или email. Мне кажется это был бы тоже приятное дополнение.
            Aleksandr Huz
            Aleksandr Huz Эксперт
            29 апреля 2025, 12:53
            А чем Client Config не устраивает?
              Ruslan
              29 апреля 2025, 13:30
              Все устраивает.

              Просто подумал что скачал один модуль, а там уже это тоже есть.
              И не надо ставить еще один модуль. ))
        Авторизуйтесь или зарегистрируйтесь, чтобы оставлять комментарии.
        12