MODX мультиязычность на основе Babel

MODX мультиязычность на основе Babel MODX Revo
В данном уроке разберем как в MODX Revo организовать мультиязычность: добавим дополнительный язык для сайта.

Перед тем как начать рекомендую сделать полный бэкап сайта (если ваш хостинг не делает их автоматически).

В рамках данного урока будем использовать компонент Babel — установите его с основного репозитория. Опции установки оставляем по умолчанию.

Установка Babel 3

Настройки контекстов

Реализовывать мультиязычность будем на примере английского языка. Т.е. есть русский сайт site.ru с контентом, добавим в него английский язык который будет открываться по адресу site.ru/en/. Сейчас у нас получается есть контент WEB на нем русский язык — отредактируем его и дадим ему имя “Русский”.

Переходим в «Системные настройки» (шестеренка в правом верхнем углу) и выбираем «Контексты». Щелкаем по контексу WEB правой кнопкой мыши и выбираем «Редактировать контекст».

Редактируем контекст WEB

Правим название и сохраняем.

Даем новое название контексту

Теперь создадим контекст с ключом EN, а имя ему дадим “Английский”.

Создание нового контекста в MODX

Теперь необходимо настроить данные контексты. Для этого кликаем по контексту в дереве ресурсов правой кнопкой мыши и выбираем “редактировать”. В открывшемся окне переключаемся на вкладку “Настройки контекста” и добавляем глобальные настройки системы — которые мы получается будем переопределять.

Добавляем системные настройки в контекст

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

Ключ Название Значение для Web Значение для EN
base_url Базовый URL сайта относительно корня / /en/
cultureKey Ключ языка ru en
site_start ID главной страницы сайта 1 ID главной страницы
site_url URL сайта https://alex87.ru/ https://alex87.ru/en/
locale Настройка локали ru_RU.UTF8 en_US.UTF8
error_page ID страницы 404 ошибки ID страницы ID страницы

Пример настройки контекста WEB

site_start и error_page для контекста EN оставил пока пустым — его заполним после того как создадим ресурсы в данном контенте.

Пример настройки контекста EN

Примечание по поводу site_url — здесь замените мой домен alex87.ru на свой, да и смотрите мой сайт переведен на https — если вы это не сделали то адрес будет через http://. А если хотите сделать мультидоменый сайт, тогда в доп. контекстах указываете адреса поддоменов.

После выставления всех настроек в контексте, не забывайте нажать кнопку “Сохранить”.

Настройка .htaccess

В корне сайта должен быть файл .htaccess, если его нет тогда ищем ht.access и переименовываем его в .htaccess (из админки по умолчанию переименовать так нельзя, поэтому воспользуйтесь FTP клиентом или файловым менеджером хостинга).

Далее открываем этот файл и удаляем из него строки:

RewriteCond %{REQUEST_FILENAME} !-f
RewriteCond %{REQUEST_FILENAME} !-d
RewriteRule ^(.*)$ index.php?q=$1 [L,QSA]

А лучше комментируем их — добавив перед ними знак #.

Пример комментирования правил в htaccess

И ниже добавляем следующие правила.

RewriteCond %{REQUEST_FILENAME} !-d
RewriteCond %{REQUEST_FILENAME} !-f
RewriteRule ^(ru|en)/favicon.ico$ favicon.ico [L,QSA]

RewriteCond %{REQUEST_FILENAME} !-d
RewriteCond %{REQUEST_FILENAME} !-f
RewriteRule ^(ru|en)/assets(.*)$ assets$2 [L,QSA]

RewriteCond %{REQUEST_FILENAME} !-f
RewriteCond %{REQUEST_FILENAME} !-d
RewriteRule ^(ru|en)?/?(.*)$ index.php?cultureKey=$1&q=$2 [L,QSA]

Где (ru|en) должны совпадать с: ru для корневой директории http://site.ru/ , а en — с http://site.ru/en/ (прописывали в настройках контекста выше).

Вот такой получился у меня .htaccess файл

RewriteEngine On
RewriteBase /

# 301 редирект на версию с https (должен быть установлен SSL сертификат)
RewriteCond %{SERVER_PORT} !^443$ 
RewriteRule ^(.*)$ https://alex87.ru/$1 [R=301,L]

# 301 редирект с www.domain.com на domain.com
RewriteCond %{HTTP_HOST} .
RewriteCond %{HTTP_HOST} !^alex87\.ru [NC]
RewriteRule (.*) https://alex87.ru/$1 [R=301,L]

# The Friendly URLs part
#RewriteCond %{REQUEST_FILENAME} !-f
#RewriteCond %{REQUEST_FILENAME} !-d
#RewriteRule ^(.*)$ index.php?q=$1 [L,QSA]

RewriteCond %{REQUEST_FILENAME} !-d
RewriteCond %{REQUEST_FILENAME} !-f
RewriteRule ^(ru|en)/favicon.ico$ favicon.ico [L,QSA]

RewriteCond %{REQUEST_FILENAME} !-d
RewriteCond %{REQUEST_FILENAME} !-f
RewriteRule ^(ru|en)/assets(.*)$ assets$2 [L,QSA]

RewriteCond %{REQUEST_FILENAME} !-f
RewriteCond %{REQUEST_FILENAME} !-d
RewriteRule ^(ru|en)?/?(.*)$ index.php?cultureKey=$1&q=$2 [L,QSA]

# Скрываем конфиг файлы
RewriteCond %{REQUEST_URI} ^/config.core.php*
RewriteRule ^(.*)$ [R=404]
php_flag display_errors off

Внимание! У меня сайт работает на хостинге бегет, мои правила 301 редиректа могут не работать на другом хостинге — и не забудьте в них изменить домен. Если не работают можете их закомментировать или переписать под свой хостинг.

Пишем плагин-обработчик

Чтобы мультиязычность работала нам нужен плагин для связки языка с контекстом. Создадим его. Идем в дереве во вкладку «Элементы» и нажимаем на иконку «Новый плагин». С именем switchContext и следующим содержимым:

<?php
/* Запускаем плагин только на фронтенде и с включенными sef-url */
if ($modx->context->key == 'mgr' || !$modx->getOption('friendly_urls') || $modx->event->name != 'OnHandleRequest') {
return;
}

/* Определяем текущий язык в cultureKey */
switch ($_REQUEST['cultureKey']) {
/* Переключаем контекст */
case 'en':
$modx->switchContext('en');
break;

/* Добавляем дополнительные языки в плагин, если нужно
case 'ua':
$modx->switchContext('ua');
break;
*/

/* Устанавливаем контекст по умолчанию */
default:
$modx->switchContext('web');
break;
}

/* Очищаем GET-параметр чтобы не допустить появлении ссылки вида cultureKey=xy при генерации URL других компонентов */
unset($_GET['cultureKey']);
?>

Создаем плагин switchContext

И вешаем его на Системное событие «onHandleRequest» и Сохраняем.

Добавляем плагину системное событие onHandleRequest

Корректируем настройки Babel

Идем в системные настройки — babel и добавляем в настройку Context Keys, после web, через запятую созданные ранее контексты.

меняем Context Keys

Создание мультиязычного контента

Как добавлять страницы сайта на других языках?

В панели управления сайта, во вкладке «Ресурсы», мы видим контексты (их имена, которые вы заполнили при создании/редактировании контекста). Ресурсы каждого из контекстов отвечают за ресурсы языковых версий сайта.

Имена контекстов

Теперь нам нужно создать переводы для уже созданных страниц (или связать перевод) — в этом поможет Babel.

При создании или редактировании ресурса в правом верхнем углу появятся кнопки, отвечающие за языковые версии («Создать перевод», «Связать с существующим ресурсом»). Через эти кнопки создаются и связываются ресурсы в другом контексте (языковой версии).

создание переводов

После нажатия на «Создать перевод», Babel создаст дубль этой страницы в новом контексте — вам остается перевести и сохранить.

Создаем перед ресурса

Вам сейчас в первую очередь нужно создать переводы Полученные id ресурсов для страниц Главная и 404 и внести их ID в настройки контекста.

Донастраиваем контекст

Переключатель языков на сайте.

Чтобы сделать переключалку языковых версий на сайте, выведите в нужном месте (шаблон, чанк) следующую конструкцию:

<ul>
[[BabelLinks?
&showCurrent=`1`
]]
</ul>

Либо если используете fenom:

<ul>
{$_modx->runSnippet("!babelLinks", [
"showCurrent" => 1
])}
</ul>

На выходе получим такой html/

Код на выходе

Если стандартная разметка не подходит то можно, создать свой чанк с оформлением и вызвать бабел с параметром tpl:

{$_modx->runSnippet("!babelLinks", [
"showCurrent" => 1,
"tpl" => "babelLinksTpl"
])}

Где в моем случае чанк babelLinksTpl содержит следующий код:

<li><a href="[[+url]]" class="[[+cultureKey]][[+active:notempty=` [[+active]]`]]" data-language="[[+language]]">
    [[+cultureKey:is=`ru`:then=`<i class="flag flag-ru"></i> Ru`
    :else=`<i class="flag flag-en"></i> En`]]</a></li>

Все параметры BabelLinks можно посмотреть в документации — babel.babellinks.

Изредка бывает, что BabelLinks не выводит связанные страницы, хотя все верно настроено и опубликовано. В данном случае попробуйте переустановить Babel.

Вывод статического содержимого в зависимости от языка

Существует несколько способов вывода различного статического содержания (адреса, заголовки, кнопки, копирайт и пр.) в зависимости от языка:

1. Для текстовых строк, правильнее всего создавать в лексиконах переводы  для каждого языка. И затем вызывать их в нужных местах, а они уже в зависимости от нужной языковой версии будут выводить свои значения.

2. К примеру для чанков можно создать копии с нужным языком, пример: [[$header_ru]], [[$header_en]], а в шаблонах вызывать в виде [[$header_[[++cultureKey]]]] (при генерации страницы MODX подставит нужное значение [[++cultureKey]] и выведет содержание чанка для активного языка).

3. Можно проверять контекст и выводить нужное содержимое (лексиконы и прочее) через фильтры ввода-вывода.

Условие вывода лучше прописывать через [[*context_key]], а, не через [[++cultureKey]] т. к. Ключ контекста заполняется один раз и изменить его нельзя, а настройки же контекста можно менять. Например, условие будет таким:

[[*context_key:is=`web`:then=`Контактная информация`:else=`Contact Information`]]

Если языков больше чем 2, например 4, тогда вам нужно просто указывать по очереди значения вот так:

[[*context_key:is=`web`:then=`Контактная информация`]]
[[*context_key:is=`en`:then=`Contact Information`]]

или так

{if $_modx->context.key == 'web'}
Контактная информация
{else}
Contact Information
{/if}

когда языков много.

{if $_modx->context.key == 'web'} Контактная информация {/if}
{if $_modx->context.key == 'en} Contact Information {/if}

С другой стороны, с использованием [[++cultureKey]], условие будет грамотнее читаться:

[[++cultureKey:is=`ru`:then=`Контактная информация`:else=`Contact Information`]]

В общем, выбор, за вами 🙂

Автоматически определяем id переведенных страниц

Часто в чанках и прочих статических элементах прописаны ссылки на ресурсы обычной версии. Соответственно, нужно прописать и id другой языковой версии сайта. И чтобы не выискивать ID языковой версии, можно воспользоваться сниппетом BabelTranslation — он выводит связанный id переведенной страницы нужного контекста, пример:

[[BabelTranslation? &resourceId=`7` &contextKey=`eng`]]

Выведет в шаблоне связанный id в контексте eng для страницы с id=7 активного контекста (в нашем случае web).

Источники файлов для нескольких контекстов

Если для TV (изображений) настроены источники файлов, то после создания нового контекста не забудьте добавить источники файлов в настройках этих TV к новым контекстам.

Источник: cat-art.ru

pdoTools для разных контекстов

К примеру нам нужно вывести меню при помощи pdoMenu для разных родителей (parents) контекстов. Пусть будет так:
&parents=`5` //русский язык
&parents=`55` //английский язык
Решение: просто указываем оба родителя и указываем параметр context

[[!pdoMenu?
&parents=`5,55`
&context = `[[*context_key]]`
]]

SEO для мультиязычных сайтов

Canonical и hreflang

Используем вариант указания языковой версии в теге head. Этот вариант идеален для сайтов, у которых меньше 10 языков. Если больше, то лучше указать локальные версии в sitemap.xml.

Открываем чанк с кодом секции head и вписываем следующий код:

<link rel="canonical" href="{$_modx->resource.id|url:['scheme' => 'full']}" />
{set $babel = $_modx->resource.id|resource:'babelLanguageLinks'}
{if $babel}
    {set $ctx_explode = $babel|split:';'}
    {foreach $ctx_explode as $ctx_res}
        {set $res_explode = $ctx_res|split:':'}
        {set $resourceId = intval($res_explode.1) }
        {if $res_explode.0 == 'web'}{set $cultureKey = 'ru'}
        {elseif $res_explode.0 == 'en'}{set $cultureKey = 'en'}{/if}
        {if $resourceId}
            {set $arr[$cultureKey] = $resourceId} {* забиваем языки в массив *}
        {/if}
    {/foreach}
{/if}
{* выводим языки перебором *}
{foreach $arr as $key => $value}
{if $key == 'ru'}
{* тут указываем языковую версию по умолчанию *}
<link rel="alternate" hreflang="x-default" href="{$value|url:['scheme' => 'full']}" />
{/if}
<link rel="alternate" hreflang="{$key}" href="{$value|url:['scheme' => 'full']}" />
{/foreach}

Выведет в код следующее:

<link rel="alternate" hreflang="x-default" href="https://alex87.ru/" />
<link rel="alternate" hreflang="ru" href="https://alex87.ru/" />
<link rel="alternate" hreflang="en" href="https://alex87.ru/en/" />

Подробнее о hreflang и sitemap можно прочитать в документации от Google.

Источник bazstudio.

sitemap.xml

Знаю 2 способа создания мультиязычного sitemap.xml:

Первый способ. Установить из основного репозитория пакет «SEO Tab». Создать ресурс sitemap.xml и вывести:

{'!StercSeoSiteMap' | snippet: [
    'contexts' => 'web,en'
]}

И нужно включить системную настройку компонента с ключом stercseo.xmlsitemap.babel.add_alternate_links.

Кому нужен обычный шаблонизатор смотрите документацию: https://github.com/Sterc/SEOTab.

Второй способ. Использовать pdoSitemap.

Описывать его не буду, кому интересно смотрите заметку от iWatchYouFromAfar

Прочие часто задаваемые вопросы (FAQ)

Вопрос 1: У меня 3 языка, переключатель работает, все хорошо, выводит языки в такой последовательности: Рус Енг Укр, а мне хотелось бы: Укр Рус Енг, как поменять последовательность.

Решение:

Делаем копию сниппета BabelLinks, называем его к примеру BabelLinksCustom. Открываем его (редактируем), и на 74 строке добавляем кусок кода:

$contextKeys = array('uk', 'web', 'en');

Меняем в сниппете порядок вывода контекстов

где uk', 'web', 'en' — это ключи контекстов и порядок их выстраивается слева на право)

А далее уже выводим переключалку языков через него.

[[BabelLinksCustom]]

Вопрос 2. Как убрать активный язык (чтобы страница не ссылалась сама на себя).

Ответ: За это отвечает параметр showCurrent:

[[BabelLinks &showCurrent=`0`]]

Вопрос 3. Как по своему назвать языки в переключателе контента

Ответ. Создайте чанк BabelLinksTpl с примерно таким содержанием:

<li><a href="[[+url]]" class="[[+cultureKey]][[+active:notempty=` [[+active]]`]]">[[+cultureKey:is=`ru`:then=`Русский`]][[+cultureKey:is=`uk`:then=`Україньска`]][[+cultureKey:is=`en`:then=`English`]]</a></li>

И затем вызовите его:

[[BabelLinks? &tpl=`BabelLinksTpl`]]

Так же возможно пригодится статья с modx pro: Как настроить Babel, чтобы не было мучительно больно.

Поделиться с друзьями
Алексей

Веб-дизайнер и SEO оптимизатор. Занимаюсь созданием сайтов с 2010 года и их продвижение с 2012 года!

Оцените автора
( 3 оценки, среднее 5 из 5 )
Web-Revenue.ru
Добавить комментарий

  1. Alex

    Привет. Все работает на контексте web, все выводит. Но не работает вывод картинок в контексте EN, как это решить ? Перекопал инет, и вроде решения есть, но на моем сайте они не работают….

    Ответить
    1. Алексей автор

      Надо смотреть в админке, так ничего не скажу

      Ответить
  2. Аноним

    Привет, может подскажите как сделать префикс для основного контекста web? Т.е. хочу, чтобы открывался сайт сразу mysite.com/ru/ например. Я сделал по Вашему примеру все, только изменил base_url и site_url, прописал редиректы с / на /ru/. Но когда открываю корзину minishop2 — она пустая в этом контексте, а в другом заполнена товарами, которые я добавил

    Ответить
    1. Голягин Алексей

      Не подскажу. А зачем к основной версии site.ru добавлять /ru/?

      Ответить