Директории
Плагин для ситуации, когда домен один, а языковые версии отличаются префиксом в адресе: mysite.com/ru/page.html и mysite.com/en/page.html.То есть, условия такие:
- Все контексты на одном домене, и у них отличается base_url
- Используются friendly urls
- base_url может не совпадать с именем контекста
Итак, у нас два контекста: web и en c такими настройками:
Создаём новый плагин, добавляем для него событие OnHandleRequest и копируем этот код:
<?php // Работаем только на фронтенде и только с friendly urls if ($modx->event->name != 'OnHandleRequest' || $modx->context->key == 'mgr' || !$modx->getOption('friendly_urls')) {return;} // Получаем запрашиваемый url $alias = $modx->getOption('request_param_alias', null, 'alias', true); $request = &$_REQUEST[$alias]; // Выбираем контексты с настройкой base_url $q = $modx->newQuery('modContextSetting', array('key' => 'base_url', 'value:!=' => '')); $q->select('context_key,value'); $contexts = array(); $tstart = microtime(true); if ($q->prepare() && $q->stmt->execute()) { // Учитываем наш запрос в БД $modx->queryTime += microtime(true) - $tstart; $modx->executedQueries++; // Разбираем результаты while ($row = $q->stmt->fetch(PDO::FETCH_ASSOC)) { $base_url = trim($row['value'], '/'); $context = $row['context_key']; // Если запрос начинается с base_url какого-то контекста if (preg_match('/^('.$base_url.')\//i', $request)) { // То переключаемся на этот контекст // Web инициализируется в index.php - на него переключаться не нужно if ($context != 'web') { $modx->switchContext($context); } // Вырезаем base_url из запроса, чтобы MODX нашел ресурс по uri $request = preg_replace('/^'.$base_url.'\//', '', $request); // Дело сделано - выходим из цикла break; } } }Кстати говоря, еще можно у основного контекста web убрать base_url, чтобы он открывался без /ru/, а второй контекст был по-прежнему с /en/.
Например, вот сайт документации — русская версия и английская.
Поддомены, или разные домены
При конфигурации поддоменами адреса у нас будут такие: ru.mysite.com/page.html и en.mysite.com/page.html.Этот случай проще, так как нужно только сравнить запрашиваемый хост со значениями в БД и получить соответствующий контекст. Здесь не нужно менять запрос и результат выборки может быть только один.
Настройки контекстов такие:
Точно также создаём плагин, и отмечаем событие OnHandleRequest.
<?php // Работаем только на фронтенде if ($modx->event->name != 'OnHandleRequest' || $modx->context->key == 'mgr') {return;} // Определяем запрашиваемый хост $host = $_SERVER['HTTP_HOST']; // Выбираем контекст с настройкой base_url $q = $modx->newQuery('modContextSetting', array('key' => 'http_host', 'value' => $host)); $q->select('context_key'); $tstart = microtime(true); if ($q->prepare() && $q->stmt->execute()) { // Учитываем наш запрос в БД $modx->queryTime += microtime(true) - $tstart; $modx->executedQueries++; // Получаем ключ контекста if ($context = $q->stmt->fetch(PDO::FETCH_COLUMN)) { // Web инициализируется в index.php - на него переключаться не нужно if ($context != 'web') { $modx->switchContext($context); } } }Как вы понимаете, в настройках контекстов должны быть уникальные http_host.
Заключение
Вот так несложно мы полностью автоматизировали переключение языков на мультиязычных сайтах. Можно добавлять сколько угодно контекстов — плагин менять не придётся.Обновлено 03.11.2014г.
Пример сниппета для вывода ссылок на документ в другом контексте для первого случая — директорий.<?php $tplRu = '<a href="[[+link]]">ru</a>'; $tplEn = '<a href="[[+link]]">en</a>'; $tplRuActive = '<span>ru</span>'; $tplEnActive = '<span>en</span>'; $output = ''; if ($modx->context->key == 'web') { $output .= $tplRuActive . ' | ' . $tplEn; $link = 'en/'; if ($modx->getOption('site_start') != $modx->resource->id && $modx->getCount('modResource', array('uri' => $modx->resource->uri, 'context_key' => 'en'))) { $link .= $modx->resource->uri; } } else { $output .= $tplRu . ' | ' . $tplEnActive; $link = '/'; if ($modx->getOption('site_start') != $modx->resource->id && $modx->getCount('modResource', array('uri' => $modx->resource->uri, 'context_key' => 'web'))) { $link .= $modx->resource->uri; } } return str_replace('[[+link]]', $link, $output);Здесь web — русский контекст, а en — английский. Обязательное условие — одинаковые uri ресурсов в разных контекстах. Если нет соответствия, то ссылка будет в корень контекста.
← Следующая заметка
Модификации товара. Учет остатков. Галерея.
Модификации товара. Учет остатков. Галерея.
Предыдущая заметка →
Очистка старых сессий в MODX
Очистка старых сессий в MODX
Настройки контекстов:
base_url: / * base_url: /ru/
cultureKey: en * cultureKey: ru
site_start: 1 * site_start: 4
site_url: mysite.com/ * site_url: mysite.com/ru/
В логе ошибка: [2014-01-11 13:19:01] (ERROR @ /index.php) Could not load context: ru
p.s. влияют ли как-то на это настройки кэширования?
Но ошибка в логе осталась
Также в основной версии (web — английский) сниппет babel постоянно слетает и не показывает русский язык
Чанк [[%babel.language_[[+cultureKey]]? &topic=`default` &namespace=`babel`]]
Т.е. получается, что контекст ru каким-то образом не распознается
preg_match режет и сравнивает полученный запрос с именем контекста. Получается что контекст должен называться ru для нормальной работы а не RUSSIAN меняй preg_match под свои нужды.
Сравнивается base_url, а не key контекста. base_url может не совпадать с именем контекста — в заметке так и написано.
Там скорее всего что-то в .htaccess — у меня его нет.
Контексты: Web — ru, en.
Я удалил base_url у контекста web
.htaccess
Как решить ситуацию с Babel?
Также bezumkin подсказал, что Babel плохо дружит с AjaxManager. Пришлось выключить второй, в угоду первому)
В файле paypal.php следущий код:
$success = $cancel = $modx->getOption('site_url');
if ($id = $modx->getOption('ms2_payment_paypal_success_id', null, 0)) {
$success = $modx->makeUrl($id, $context, $params, 'full');
}
if ($id = $modx->getOption('ms2_payment_paypal_cancel_id', null, 0)) {
$cancel = $modx->makeUrl($id, $context, $params, 'full');
}
$redirect = !empty($_GET['action']) && $_GET['action'] == 'success'? $success: $cancel;
$modx->sendRedirect($redirect);
что тут нужно поменять?
А вопрос скорее по модыксу и бабелю. Решил, как обычно, идти по пути наименьшего сопротивления и заюзать BabelTranslation для составления ссылок на соответствующие иноязычные страницы дабы не быть привязанным к одинаковым урлам. До этого урлы составлялись с помощью выражения типа и оное стабильно выдавало то, что нужно. Однако заменив на я получил вместо относительного адреса полный, что разумеется не входило в мои планы, ибо оный идёт без виртуальной подпапки en/, зато с http и прочими причиндалами. Отчего так проиходит и чего с этим можно поделать? Ежели оставить без то оба выводять нужные номера страниц. Почему же линк от текущего айди получается относительный, а от бабелевского полный?..
Это я всё к тому, что стоит дописать для не слишком продвинутых граждан вроде меня, что для нормальной работы всё-таки желательно site_url прописать, да добавить в .htaccess нечто типа:
И всё работает.
Если по делу, то я прописываю site_url, а все скрипты и стили — через base_url. И тогда нет никаких проблем на любых серверах.
Перенаправлять через .htaccess, когда можно сразу правильно прописать ссылку — не стоит.
Спасибо за науку «по делу».
Шаблон документа можено менять при загрузке страницы, плагином на события OnLoadWebPageCache и OnLoadWebDocument.
Ну и проследить, чтобы галерея выдавала относительные ссылки — тогда всё должно работать.
Честно говоря, я не очень помню, как работает Gallery, потому что пользуюсь ms2Gallery.
Правда есть одна небольшая проблема. Может я конечно, что-то не так настроил, но почему то на контексте web, modx правильно генерирует url, если задать его в виде site.com/?id=2, а в другом контексте (en) modx ссылку не генерирует из site.com/en/?id=2, а оставляет её как есть, соответственно перехода не происходит. ЧЯДНТ? .htaccess стандартный.
UPD: get параметр page работает на обоих контекстах правильно, а вот с id беда(
Он был уже в комментах.
Это нужно Babel ставить еще?
Вариант рабочий, но больше нравится реализация как на docs.modx.pro/
сниппет
но на истину не претендую
Прям скопипастил как есть с docs.modx.pro. Если у документов в разных контекстах одинаковый uri, то будет очень хорошо переключаться.
shop.plugingrid.com/ — Это основной контекст web. Тут все работает и работало как часики.
plugingrid.com/ а вот это уже контекст plugingrid.com, на главной странице есть сниппет слайдера, он работает. И это единственный сниппет, что работает на этом контексте. plugingrid.com/blog/ Тут у меня вызов pdoPage который выводит записи в блоге, но ничего не выводит. Да более того, на любой информационной страничке есть:
plugingrid.com/blog/ Но по факту это самое echo 'WORK!!'; не работает… И die; тоже.
У меня для nsk страницы должны быть индентичны для web
Есть страница site.ru/index.php?id=1 она должна так же открываться на поддомене nsk.site.ru/index.php?id=1
Сейчас ошибка:
503 Error
Page not found
У каждой страницы свой контекст. Если нужно открывать одну страницу по разным адресам — то это решается настройкой веб-сервера, а не контекстами.
На сайте два контекста
web и deb
и два домена соответственно
web.by и dev.by
Проблема с ссылками вида [[~1]]
В контексте web выводится как web.by/1
а в контексте dev как dev.by/1
Как заставить ссылку выводить правильный адрес?
Благодарю
Переключаются как надо, но cultureKey для 2 и 3 почему-то игнорируется и используется системный.
Есть идеи?
Очепятка?
Больше идей нет.
Банально удалил директорию кеша)
Спасибо.
У нас там, вообще-то, техподдержка есть. Пиши, разберемся.
Вопрос: Можно ли сделать так, чтобы при переключении версии открывалась страница, соответствующая той, на которой находился пользователь? Например, он был на странице контактов русской версии (www.mysite.ru/contacts), а при переключении языка его перебрасывает снова на главную но только уже английской версии (www.mysite.ru/en/), хотя должно на www.mysite.ru/en/contacts.
Походи по docs.modx.pro, посмотри на адреса. Например
docs.modx.pro/components/pdotools/
и
docs.modx.pro/en/components/pdotools/
Проверять на дублирование URI во всех контекстах (global_duplicate_uri_check) — ставим «нет».
В этом случае проверка уникальности касается только текущего контекста.
UPD: Единственный момент — если пощелкать туда-сюда, в итоге все равно перекидывает на главную. Но это уже мелочи.
при входе на поддомен пишет следующее:
Fatal error: Call to a member function checkPolicy() on a non-object in /var/www/p93747/data/www/***.com/core/model/modx/modx.class.php on line 1876
Насколько понимаю проблема с настройками политик доступа, никак не могу разобраться
В контексте en выскакивает:
503 Error
Page not found
The page you requested was not found.
Спасибо!!!