- Настройки контекстов
- Настройка .htaccess
- Пишем плагин-обработчик
- Корректируем настройки Babel
- Создание мультиязычного контента
- Вывод статического содержимого в зависимости от языка
- Автоматически определяем id переведенных страниц
- Источники файлов для нескольких контекстов
- pdoTools для разных контекстов
- SEO для мультиязычных сайтов
- Canonical и hreflang
- sitemap.xml
- Прочие часто задаваемые вопросы (FAQ)
Перед тем как начать рекомендую сделать полный бэкап сайта (если ваш хостинг не делает их автоматически).
В рамках данного урока будем использовать компонент Babel — установите его с основного репозитория. Опции установки оставляем по умолчанию.
Настройки контекстов
Реализовывать мультиязычность будем на примере английского языка. Т.е. есть русский сайт site.ru с контентом, добавим в него английский язык который будет открываться по адресу site.ru/en/. Сейчас у нас получается есть контент WEB на нем русский язык — отредактируем его и дадим ему имя “Русский”.
Переходим в «Системные настройки» (шестеренка в правом верхнем углу) и выбираем «Контексты». Щелкаем по контексу WEB правой кнопкой мыши и выбираем «Редактировать контекст».
Правим название и сохраняем.
Теперь создадим контекст с ключом EN, а имя ему дадим “Английский”.
Теперь необходимо настроить данные контексты. Для этого кликаем по контексту в дереве ресурсов правой кнопкой мыши и выбираем “редактировать”. В открывшемся окне переключаемся на вкладку “Настройки контекста” и добавляем глобальные настройки системы — которые мы получается будем переопределять.
Для удобства я приведу все заполненные мной настройки контекстов в одной таблице.
Ключ | Название | Значение для 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 страницы |
site_start и error_page для контекста 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]
А лучше комментируем их — добавив перед ними знак #.
И ниже добавляем следующие правила.
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']);
?>
И вешаем его на Системное событие «onHandleRequest» и Сохраняем.
Корректируем настройки Babel
Идем в системные настройки — babel и добавляем в настройку Context Keys, после web, через запятую созданные ранее контексты.
Создание мультиязычного контента
Как добавлять страницы сайта на других языках?
В панели управления сайта, во вкладке «Ресурсы», мы видим контексты (их имена, которые вы заполнили при создании/редактировании контекста). Ресурсы каждого из контекстов отвечают за ресурсы языковых версий сайта.
Теперь нам нужно создать переводы для уже созданных страниц (или связать перевод) — в этом поможет 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, чтобы не было мучительно больно.
Привет. Все работает на контексте web, все выводит. Но не работает вывод картинок в контексте EN, как это решить ? Перекопал инет, и вроде решения есть, но на моем сайте они не работают….
Надо смотреть в админке, так ничего не скажу
Привет, может подскажите как сделать префикс для основного контекста web? Т.е. хочу, чтобы открывался сайт сразу mysite.com/ru/ например. Я сделал по Вашему примеру все, только изменил base_url и site_url, прописал редиректы с / на /ru/. Но когда открываю корзину minishop2 — она пустая в этом контексте, а в другом заполнена товарами, которые я добавил
Не подскажу. А зачем к основной версии site.ru добавлять /ru/?