Несколько мультиязычных сайтов в одной админке
        Вот как реализовать переключение контекстов на нескольких доменах, но когда языки находятся в папках.
Вот пример:
Я поднял этот вопрос, в результате которого мы нашли решение. Думаю это решение пригодится многим.
Вместе с Сергеем (спасибо ему большое за идеи) у нас получилось найти работающее решение (возможно есть вариант и изящнее).
Остальные настройки можно взять из статьи Василия bezumkin.ru/sections/tips_and_tricks/2439/
2. Проверки на несуществующие языки типа /de/ решаются просто — достаточно во всех контекстах сайта прописать настройку страницы 404 [error_page] для каждого контекста отдельно, даже для web. Тогда если человек пройдёт по несущесвующей ссылке site2.ru/de/, то он попадёт на 404-ю страницу, которая указана сайту site2.ru
2. Удобство управления, особенно когда есть 5 связанных между собой сайтов с 3-мя языками каждый. Очень скоро именно на таком проекте я испытаю этот плагин!
3. Если грамотно настроить права, то разные группы пользователей (менеджеров) смогут заходить в одну и ту же админку не подозревая, что на ней крутятся ещё много других сайтов. К тому же заходят они в админку на своём домене, например site1.ru/manager и site2.ru/manager
P.S.
Если вы знаете как решить эту задачу красивее — можете предложить в комментариях!
    
    
                                                                                
            Вот пример:
- site1.ru/ru
 - site1.ru/en
 - site2.ru/ru
 - site2.ru/en
 
Я поднял этот вопрос, в результате которого мы нашли решение. Думаю это решение пригодится многим.
Вместе с Сергеем (спасибо ему большое за идеи) у нас получилось найти работающее решение (возможно есть вариант и изящнее).
Плагин
Плагин на OnHandleRequest:<?php
// Работаем только на фронтенде
if ($modx->event->name != 'OnHandleRequest' || $modx->context->key == 'mgr') {return;}
$alias = $modx->getOption('request_param_alias', null, 'alias', true);
$request = &$_REQUEST[$alias];
// Определяем язык папки из URL
preg_match('|/(.*)/|', $_SERVER['REQUEST_URI'], $m);
$lang = trim($m[1]);
// Выбираем все существующие на сайте языки
$q = $modx->newQuery('modContextSetting');
$q->select('value');
$q->where(array('key' => 'cultureKey'));
$q->prepare();
$q->stmt->execute();
$langs = $q->stmt->fetchAll(PDO::FETCH_ASSOC);
$lang_arr = array();
foreach ($langs as $l) {
    array_push($lang_arr, $l['value']);
}
// Если папка пуста, указываем русский язык
if (!in_array($lang,$lang_arr)) $lang = 'ru';
// Формируем нужный host_language
$host_language = $_SERVER['HTTP_HOST'].'_'.$lang;   
// Выбираем контекст с настройкой host_language
$q = $modx->newQuery('modContextSetting', array('key' => 'host_language', 'value' => $host_language));
$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);
			$request = preg_replace('/^'.$lang.'\//', '', $request);
		}
	}
}Контексты
В настройки контекстов добавляем ключ host_language со значением site.ru_en, где «en» = cultureKey.Остальные настройки можно взять из статьи Василия bezumkin.ru/sections/tips_and_tricks/2439/
Проблема
1. Плагин не работает почему-то с ресурсами-контейнерами, поэтому пришлось обойти костылём и убрать«Суффикс контейнера» в настройках системы [container_suffix].2. Проверки на несуществующие языки типа /de/ решаются просто — достаточно во всех контекстах сайта прописать настройку страницы 404 [error_page] для каждого контекста отдельно, даже для web. Тогда если человек пройдёт по несущесвующей ссылке site2.ru/de/, то он попадёт на 404-ю страницу, которая указана сайту site2.ru
Возможные варианты применения решения:
1. Экономия места на хостинге, не нужно переплачивать за лишний хостинг.2. Удобство управления, особенно когда есть 5 связанных между собой сайтов с 3-мя языками каждый. Очень скоро именно на таком проекте я испытаю этот плагин!
3. Если грамотно настроить права, то разные группы пользователей (менеджеров) смогут заходить в одну и ту же админку не подозревая, что на ней крутятся ещё много других сайтов. К тому же заходят они в админку на своём домене, например site1.ru/manager и site2.ru/manager
P.S.
Если вы знаете как решить эту задачу красивее — можете предложить в комментариях!
Комментарии: 38
                1)Выполнять не в цикле:
3)нет проверки на язык отсутствующий у домена
например есть набор контекстов:
P.S. я бы предложил выбрать сначала все контексты с текущим доменом, а потом уже среди них выбрать тот что с языком
                    $lang_arr = array_unique($lang_arr);2)не обязательно проверяя «in_array» уникализировать значения3)нет проверки на язык отсутствующий у домена
например есть набор контекстов:
test1.com_ru
test1.com_en
test1.com_de
test2.com_ru
test2.com_enесли мы запросим для test2.com/de что получится?P.S. я бы предложил выбрать сначала все контексты с текущим доменом, а потом уже среди них выбрать тот что с языком
                1) Точно, не заметил. Исправил.
2) Убрал. Логично.
3) Добавил проверку с редиректом на 404-ю страницу текущего контекста
P.S. Я пробовал так, но что-то у меня не завелось…
                    2) Убрал. Логично.
3) Добавил проверку с редиректом на 404-ю страницу текущего контекста
P.S. Я пробовал так, но что-то у меня не завелось…
                Только что-то сомневаюсь, что моя проверка и редирект правильно работают… 
Буду пробовать.
                    Буду пробовать.
                текущий контекст это какой? разумнее сделать именно выборку домена а потом уже дефолтного контекста в рамках домена, это при условии что отсечение по домену идет по DNS, т.е. невозможно запросить домен которого нет, хотя на этот случай тоже можно сделать проверку и выдавать домен заглушку или домен по-умолчанию            
                    
                Ок, давай попробуем и ваш вариант (у меня он с первого раза не завёлся)…            
                    
                Хочешь чтобы я написал решение или сам?
План такой:
1)берем контексты по домену, если их нет показываем что-то по умолчанию(web например)
2)если контексты нашли проверяем язык внутри них, если наш язык не найден — берем первый контекст или контекст по-умолчанию и выбираем его
3)если найден контекст с нужным языком — берем его
            
                    План такой:
1)берем контексты по домену, если их нет показываем что-то по умолчанию(web например)
2)если контексты нашли проверяем язык внутри них, если наш язык не найден — берем первый контекст или контекст по-умолчанию и выбираем его
3)если найден контекст с нужным языком — берем его
                Доработаю вначале проверку для первого плагина, потом возьмусь за твой план.
Если хочешь, можешь попробовать написать!!!
                    Если хочешь, можешь попробовать написать!!!
                А не подскажете как выводить в wayfinder меню?
Что бы в версии en выводился чанк $enmenu а в русскоязычной $menu
Слышал, что можно методом else, them а как не знаю…
конструкции вида:
                    Что бы в версии en выводился чанк $enmenu а в русскоязычной $menu
Слышал, что можно методом else, them а как не знаю…
конструкции вида:
&parents=`[[*context_key:is=`web`:then=`1`:else=`[[*context_key:is=`de`:then=`5`:else=`4`]]`]]`Спасибо            
                Изучай Феном, чтобы сайт из-за подобных конструкций не превратился в «неповоротливую корову».            
                    
                Спасибо! а родными методами как организовать..?
Есть же стандартный метод вывода?
Как модиксу проверить если контекст en, то выводить чанк в wayfinder [[$enmenu]]
Если контекст web то выводить [[$menu]]
Спасибо
                    Есть же стандартный метод вывода?
Как модиксу проверить если контекст en, то выводить чанк в wayfinder [[$enmenu]]
Если контекст web то выводить [[$menu]]
Спасибо
                Извини, конечно, но меня давно не возбуждают эти стандартные методы и вдаваться в подробности этих ужасов снова нет никакого желания.
Либо проверить контексты:
Либо твой пример:
Присмотрись в сторону Fenom, уверяю тебя, ни грамма не пожалеешь об этом.
                    {if $_modx->config.cultureKey == 'ru'}
    культурКей Ru
{elseif $_modx->config.cultureKey == 'en'}
    культурКей En
{/if}Либо проверить контексты:
{if $_modx->context.key == 'web'}
    контекст web
{elseif $_modx->context.key == 'en'}
    контекст en
{/if}Либо твой пример:
{if $_modx->context.key == 'web'}
    {include 'menu'}
{elseif $_modx->context.key == 'en'}
    {include 'enmenu'}
{/if}Присмотрись в сторону Fenom, уверяю тебя, ни грамма не пожалеешь об этом.
                Спасибо, Вы даже написали мою конструкцию, вроде выглядет красиво код.
Но не отображается, потому что пакет не поставлен..? fenom
Я просто почему стандартными средствами., потому что сам не люблю добавления ставить. кажется, что каждое дополнение будет тормозить работу скриптов в целом, ошибался.
                    {if $_modx->context.key == 'web'}
    {include 'menu'}
{elseif $_modx->context.key == 'en'}
    {include 'enmenu'}
{/if}prntscr.com/8zlelhНо не отображается, потому что пакет не поставлен..? fenom
Я просто почему стандартными средствами., потому что сам не люблю добавления ставить. кажется, что каждое дополнение будет тормозить работу скриптов в целом, ошибался.
                pdoTools надо ставить для работы с Феномом.
В работе с Феном много тонкостей. Например, скорей всего на твоём сайте, если ты поставишь pdoTools с включённым Феном, у тебя повываливаются ошибки и страница не отобразится, как надо. Это связано с тем, что Феном любой код (даже JS, даже JSON в параметрах сниппетов стандартным выводом) с фигурной скобой {, если после неё идёт какой-либо текст, а не пробел, таб или перенос строки, будет считать «за своего» и пытаться обработать. Естественно синтаксис его не устроит и он вывалит ошибку. Приведу пример:
Мы на странице вызываем код fancybox вот так:
Или есть у нас сниппет вызываемый стандартными средствами MODX с параметром, в котором указана JSON строка вот так:
И так со всем кодом на странице. Когда все подобные моменты на странице будут исправлены — Феном будет радовать нас своими возможностями и скоростью работы.
                    В работе с Феном много тонкостей. Например, скорей всего на твоём сайте, если ты поставишь pdoTools с включённым Феном, у тебя повываливаются ошибки и страница не отобразится, как надо. Это связано с тем, что Феном любой код (даже JS, даже JSON в параметрах сниппетов стандартным выводом) с фигурной скобой {, если после неё идёт какой-либо текст, а не пробел, таб или перенос строки, будет считать «за своего» и пытаться обработать. Естественно синтаксис его не устроит и он вывалит ошибку. Приведу пример:
Мы на странице вызываем код fancybox вот так:
$("a[rel='ajaxModal']").fancybox({'type':'iframe', 'arrows':false});Феном видит это безобразие и в логе ошибок в бекенде сообщает нам, что он не понимает синтаксис, который мы указали для него на странице. Что нам надо сделать, чтобы удовлетворить потребность Фенома в корректном синтаксисе? Да просто после фигурной скобы поставить пробел, вот так:$("a[rel='ajaxModal']").fancybox({ 'type':'iframe', 'arrows':false});Или есть у нас сниппет вызываемый стандартными средствами MODX с параметром, в котором указана JSON строка вот так:
[[!pdoResources? &sortby=`{"id":"DESC"}`]]Феном не устроит подобное отношение и он, как и в прошлом примере скажет нам, что синтаксис не уместен. Что мы делаем? Правильно! Просто ставим пробел после скобы:[[!pdoResources? &sortby=`{ "id":"DESC"}`]]И так со всем кодом на странице. Когда все подобные моменты на странице будут исправлены — Феном будет радовать нас своими возможностями и скоростью работы.
                Меня это не пугает, буду изучать fenom) pdotools поставил, но всеравно конструкция в шаблоне не отображает меню. 
а сейчас решил наплодить темплейты — в Главной [[$menu]] в копия главной [[$enmenu]] ппц как топор))
                    а сейчас решил наплодить темплейты — в Главной [[$menu]] в копия главной [[$enmenu]] ппц как топор))
                Думаю есть какой то код типа ignore, что бы fenom не обрабатывал не корректный для него синтаксис            
                    
                Есть, но он не работает… — modx.pro/help/6326/            
                    
                А что мешает переименовать чанки в соответствии с языком и его подставлять?
Например чанки [[$enmenu]] и [[$rumenu]], а потом просто подставлять системный параметр:
                    Например чанки [[$enmenu]] и [[$rumenu]], а потом просто подставлять системный параметр:
[[$[[++cultureKey]]menu]]Можно и по другим параметрам, но принцип ясен.            
                Да, спасибо! я так сделал: 
а чанки menu_ru и menu_en
                    [[$menu_[[++cultureKey]]]] а чанки menu_ru и menu_en
                дополнительная проверка по контексту интересна, но наверное надо сделать что-то одно чтобы управлять было удобнее и прозрачнее
                    $context=$host.'-'.$lang;
if ($modx->getCount('modContext', $context)) {
    $modx->switchContext($context);
    $request = preg_replace('/^'.$lang.'\//', '', $request);
}            
                Выкинул лишние проверки, спасибо! Теперь код стал чище и прозрачнее.
Но проверку для несуществующего языка (/de/) ещё не дописал…
                    Но проверку для несуществующего языка (/de/) ещё не дописал…
                Ну, справедливости ради, хотел бы заметить, что я предлагал другое решение, попроще и с минимальным количеством запросов к БД.
Создаем контексты для все языков с ключами host-language — site1-ru (для site1.ru), site1-en (для site1.ru/en/), site2-ru (для site2.ru), site2-en (для site2.ru/en/). Контекст web не рабочий. В нем одна страница 404.
Вот плагин.
                    Создаем контексты для все языков с ключами host-language — site1-ru (для site1.ru), site1-en (для site1.ru/en/), site2-ru (для site2.ru), site2-en (для site2.ru/en/). Контекст web не рабочий. В нем одна страница 404.
Вот плагин.
<?php
// Работаем только на фронтенде
if ($modx->event->name != 'OnHandleRequest' || $modx->context->key == 'mgr') {return;}
$alias = $modx->getOption('request_param_alias', null, 'alias', true);
$request = &$_REQUEST[$alias];
// Определяем язык папки из URL
preg_match('|/(.*)/|', $_SERVER['REQUEST_URI'], $m);
$lang = trim($m[1]);
//Сравниваем с языками из массива. Языки указывает админз, он знает какие, незачем делать запрос к БД
if (! in_array($lang,array('en','de','sp'))) $lang = 'ru';
// Определяем домен
preg_match('/(.+)(\.com|ru)/', $_SERVER['HTTP_HOST'], $m);
$host = trim($m[1]);
//Формируем ключ контекста
$context = $host.'-'.$lang;
//Проверяем наличие контекста, если есть, переключаем
if ($modx->getCount('modContext', $context)) {
    $modx->switchContext($context);
    $request = preg_replace('/^'.$lang.'\//', '', $request);
}
//Если контекст не найден, то остаемся в контексте web, у которого страница 404 (заглушка).            
                если будет 2 домена site1.ru и site1.eu к примеру, надо будет немного подправить вариант ;)            
                    
                Ну не пользователи же добавляют домены и языки. Это работа админа :)            
                    //Прописываем языки в массиве. Админ знает какие, незачем делать запрос к БД
if (! in_array($lang,array('en','de','sp'))) $lang = 'ru';Да, я решил добавить запрос в БД, чтобы решение было универсальнее.// Определяем домен
preg_match('/(.+)(\.com|ru)/', $_SERVER['HTTP_HOST'], $m);А если все домены в разных доменных зонах? И новые домены будут добавляться непонятно каких зон? Как автоматизировать этот момент?//Если контекст не найден, то остаемся в контексте web, у которого страница 404 (заглушка).Не стал развивать этот момент, т.к. тогда пришлось бы переносить весь контекст web в другой контекст, а потом настраивать всё это. К тому же синхронизация ресурсов в Babel-е может слететь. Особенно неудобно это будет, если в контексте web настроенный рабочий магазин с тысячами товаров.            А если все домены в разных доменных зонах? И новые домены будут добавляться непонятно каких зон? Как автоматизировать этот момент?Админ для начала должен будет создать контекст со всеми настройками и это никак не автоматизируешь. А уж добавить за 2 секунды еще одну зону я думаю он будет в состоянии.
В конце концов можно регулярку сделать более универсальной — убрать зоны.
                Как-то Василий вспомнил одну интересную поговорку «лучше день потерять потом за пять минут долететь». Я тоже уже кучу времени потерял с этим решением в ущерб работе с мыслю о инвестиции в будущую экономию времени на настройку — гораздо проще раз поставить плагин и забыть о нём.
В моём варианте я тоже вначале срезал у регулярки зоны, правда не знаю как она себя поведёт в ситуации с поддоменами типа sub.site.ru — я не силён в регулярках. Поэтому я не использую её для определения хоста, а запрашиваю контекст из БД через $host_language, который у меня указан вместе с доменной зоной (site.ru_en)
                    В моём варианте я тоже вначале срезал у регулярки зоны, правда не знаю как она себя поведёт в ситуации с поддоменами типа sub.site.ru — я не силён в регулярках. Поэтому я не использую её для определения хоста, а запрашиваю контекст из БД через $host_language, который у меня указан вместе с доменной зоной (site.ru_en)
                Да я без претензий, поэтому и написал «справедливости ради».            
                    
                Я тебя упомянул в статье, потому что без твоих идей я бы не справился, спасибо тебе!            
                    
                Проверки на несуществующие языки типа /de/ оказывается и не нужно было писать в плагине. Достаточно было во всех контекстах сайта прописать настройку страницы 404 [error_page] для каждого контекста отдельно, даже для web.
Все мои задачи уже решены!
                    Все мои задачи уже решены!
                ну если по одному домену выдается информация с другого — странно это выглядит как минимум
                    2. Проверки на несуществующие языки типа /de/ решаются просто — достаточно во всех контекстах сайта прописать настройку страницы 404 [error_page] для каждого контекста отдельно, даже для web. Тогда если человек пройдёт по несущесвующей ссылке site2.ru/de/, то он попадёт на 404-ю страницу, которая указана сайту site2.ruсудя по твоему коду, будет не найден ключ вида host_language и по умолчанию показан контекст web
                Не понял что ты имеешь ввиду? У меня задача была чтобы языки были не на отдельных доменах, а в подпапках определённого домена. И если указывается несуществующая подпапка языка, то соответственно это несуществующая ошибка главного языка, и это нормально.            
                    
                переключение контекста в какой момент идет? и по каким критериям? и по каким критериям он может не переключится, а лучше конечно взять да протестировать на домене который не в контексте web 
Если считаешь что правильно все, то ладно)
                    Если считаешь что правильно все, то ладно)
                Уже тестировал на сайтах:
Оба этих сайта в одной админке. У первого языки ru (web) и en, а у второго ru, en, ro. Можешь погонять, пока они ещё в тестовом режиме.
                    Оба этих сайта в одной админке. У первого языки ru (web) и en, а у второго ru, en, ro. Можешь погонять, пока они ещё в тестовом режиме.
                домен на контексте web какой?            
                    
                bazstudio.com/ — web
bazstudio.com/en/ — en
macinatorul.com/ — macinatorul-ru
macinatorul.com/en/ — macinatorul-en
macinatorul.com/ro/ — macinatorul-ro
                    bazstudio.com/en/ — en
macinatorul.com/ — macinatorul-ru
macinatorul.com/en/ — macinatorul-en
macinatorul.com/ro/ — macinatorul-ro
                надо чтобы на первом домене где web было больше языков чем на втором, пример
bazstudio.com/ — web
bazstudio.com/en/ — en
bazstudio.com/ro/ — ro
macinatorul.com/ — macinatorul-ru
macinatorul.com/en/ — macinatorul-en
при обращении к macinatorul.com/ro/
будет показываться 404 с bazstudio.com, а не с macinatorul.com
                    bazstudio.com/ — web
bazstudio.com/en/ — en
bazstudio.com/ro/ — ro
macinatorul.com/ — macinatorul-ru
macinatorul.com/en/ — macinatorul-en
при обращении к macinatorul.com/ro/
будет показываться 404 с bazstudio.com, а не с macinatorul.com
                По ссылке:
macinatorul.com/bg/
Выдает:
host_language: bazstudio.com_ru
а должен macinatorul-ru
особенно если разные дизайны будут и наполнение это сильно будет влиять
хотя чего я доказываю, если устраивает как работает, пожалуйста ;)
                    macinatorul.com/bg/
Выдает:
host_language: bazstudio.com_ru
а должен macinatorul-ru
особенно если разные дизайны будут и наполнение это сильно будет влиять
хотя чего я доказываю, если устраивает как работает, пожалуйста ;)
                            Авторизуйтесь или зарегистрируйтесь, чтобы оставлять комментарии.