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
20 апреля 2025, 15:25
modx.pro
741
+6
Поблагодарить автора Отправить деньги

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

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

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



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

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

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

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

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

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

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

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

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

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

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

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

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