Простейшая настройка мультиязычности

Во время работы над modx-test.com (который потом вырос в https://modhost.pro) придумал и реализовал прикольную мультиязычность.

Никаких копирований файлов, поддоменов и прочих заморочек. 1 простой плагин, который делает всю работу.

Нам нужно 2 контекста, по умолчанию в основном контексте ставим русский язык. В настройках контекстов указаны следующие параметры:

web- cultureKey - ru

  • site_start - 1
  • error_page - 1

en- cultureKey - en

  • site_start - 3
  • error_page - 3

В системных настройках отключаем проверку дупликатов url во всех контекстах. Url соответствующих страниц должны быть одинаковыми - так гораздо проще. Иначе, надо будет наворачивать сниппет, выдающий ссылку на другую языковую версию.

А вот и сам плагин, реагирует на событие OnHandleRequest:

<?php
if ($modx->event->name != "OnHandleRequest" || $modx->context->key == 'mgr') {return;}

if (isset($_GET['lang']) && $_GET['lang'] != $_SESSION['lang']) {
    if ($_GET['lang'] == 'en') {
        $_SESSION['lang'] = 'en';
    }
    else {
        $_SESSION['lang'] = 'ru';
    }
}

if ($_SESSION['lang'] == 'en') {
    $modx->switchContext('en');
}

То есть, при указании параметра ?lang=en или ?lang=ru любой ссылке - контекст сайта переключается, а вместе с ним и язык - и это запоминается в сессию, то есть ссылка больше не нужна.

Прощай геморрой с настройками!

Бонус в виде сниппета для вывода ссылки на переключение:

<?php
$link = $modx->makeUrl($modx->resource->id, '', '', 'full');

if ($modx->getOption('cultureKey') == 'en') {
    return "<a href=\"$link?lang=ru\">Русский</a>";
}
else {
    return "<a href=\"$link?lang=en\">English</a>";
}

Поисковики такой сайт индексируют нормально - ведь на каждой странице есть ссылка на другую языковую версию, и урл отличается. То есть в индексе страницы с разным ?lang=(en|ru) и с разным содержимым.

← Предыдущая заметка
Форматирование дат
Следующая заметка →
Редирект на ресурс сразу после его создания
Комментарии (69)
shadowВладимир
03.12.2012 17:30

Всем доброго дня!

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

В настоящий момент делаю сайт с мультиязычностю Finnish, English, Russian, French, Spanish, Arabic, соответственно, двусимвольные сокращения fi,web,ru,fr,es,ar как для cultureKey так и для настроек плагина babel. Планируется добавления языков которые в babel отсутствуют, и что бы их добавить туда нужно знать общепринятое сокращение. (например один из таких языков иврит)

Константин Хетагуров
12.12.2012 20:19

Добрый день.

Делаю всё как тут написано. Отображается ссылочка на английскую версию сайта, при нажатии на неё в адрес, добавляется ?lang=en и ничего не происходит. Подскажите в чем проблема, пожалуйста. Я так понимаю, что просто не переключаются контексты, правильно?

Ivan Moshkov
08.01.2013 03:46

Всем доброго времени суток!

В данной реализации, на нерусской версии сайта даты будут выводиться на русском языке. Поэтому в последнее условие необходимо добавить принудительную установку локали:

if ($_SESSION['lang'] == 'en') {
    $modx->switchContext('en');
    setlocale(LC_TIME, 'en_US.UTF8');
}

В зависимости от языка или кодировки строчку setlocale(LC_TIME, 'en_US.UTF8'); надо изменить. Точно так же можно написать и для нескольких языков.

bezumkinВасилий Наумкин
08.01.2013 09:10

Да, верно.

Еще можно выводить даты через сниппет dateAgo - он берёт названия месяцев из лексикона.

Bond Nataly
08.01.2013 17:16

Здравствуйте! Подскажите пожалуйста, как переделать ваше решение мультиязычности без контекстов? Т.е.: Создаются ТВ для каждого языка, и у каждого документа прописываются названия, контент и тд на каждом языке. Пробовала ваш вариант плагина, только вместо $modx->switchContext('en'); пробовала $modx->setPlaceholder('cultureKey','en'); и $modx->setOption('cultureKey', 'en'); не помогло.

Я даже просто пробовала показать $_SESSION['lang'], переходя по ссылкам http://shop.test1.ru/?lang=en и http://shop.test1.ru/?lang=ru - ничего не выводит, т.е. даже сессию не устанавливает.

Bond Nataly
08.01.2013 17:27

Включила кеширование настроек контекстов (до этого было отключено), сессия устанавливается. Теперь пробую выводить нужные ТВ в зависимости от сессии, работает через раз - при каждом обновлении страницы, меняются с русских на англ. и наоборот) Видимо дело в кешировании! Подскажите, кто сталкивался, как с этим бороться? Спасибо.

Bond Nataly
08.01.2013 17:30

Нет) Простите за флуд, Я так понимаю сессия устанавливается при первом заходе, и уже выводятся нужные ТВ при следующем обновлении страницы. Наверное я туплю, пошла разбираться)

Bond Nataly
08.01.2013 17:33

Все получилось, всем спасибо!)

bezumkinВасилий Наумкин
08.01.2013 17:56

На здоровье! =)

Alexander Legan
23.12.2013 06:06

Привет. Bond Nataly, как я понял, Вы пытались создать отдельные TV под каждый язык для каждого ресурса, и в итоге все получилось? Буду благодарен если у Вас будет возможность расписать решение поподробнее.

Bond Nataly
23.12.2013 15:32

Ох, это ж было аж год назад, почти ничего не помню уже) Ну приблизительно могу описать так: При переключении языка у меня в сессию записывался язык (ru,en,ua). И потом исходя из этого, у меня подставлялись нужные TV, которые были названы с префиксом своего языка. Например, en_pagetitle, ua_pagetitle и тд. И сниппет для вызова нужной тв, например так pagetitle вызывала:

[[!cK?id=`1`&tv=`pagetitle`&field=`Главная страница`]]

И сам сниппет cK:

$cK = (isset($lang)) ? $lang : $_SESSION['lang'];
if($cK != '' && $cK != 'ru') {
  $tv_name = $cK.'_'.$tv;
  $tvv = $modx->getObject('modTemplateVar', array('name' =>$tv_name));
  $out = $tvv->getValue($id);
  echo trim($out)!='' ? $out : $field;
} else {
  echo $field;
}
Alexander Legan
23.12.2013 16:20

Спасибо. Уже ближе к полуночи сам к такому решению пришёл, а теперь убедился в правильности хода мыслей. Данное решение позволяет избавиться от дублирования ресурсов, что в некоторых случаях (сайтах) очень даже правильно, и это мне подходит. ) Спасибо за оперативность.

Bond Nataly
23.12.2013 16:41

Пожалуйста )

Мордынский Николай
08.01.2013 23:33

Ты однако круче чем Чак Норис. Помог человек силой мысли)) во как!!! ))

bezumkinВасилий Наумкин
09.01.2013 00:06

Не поминай имя Чака всуе, а то - накажет!

Kondakov DmitriyKondakov Dmitriy
09.01.2013 15:18

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

Kondakov DmitriyKondakov Dmitriy
09.01.2013 16:37

Разобрался, правда незнаю насколько это правильно. Воспользовался elseif: код плагина

<?php
if ($modx->event->name != "OnHandleRequest" || $modx->context->key == 'mgr') {return;}

if (isset($_GET['lang']) && $_GET['lang'] != $_SESSION['lang']) {
    if ($_GET['lang'] == 'en') {
        $_SESSION['lang'] = 'en';
    }
    elseif ($_GET['lang'] == 'kz') {
        $_SESSION['lang'] = 'kz';
    }
    else {
        $_SESSION['lang'] = 'ru';
    }
}

if ($_SESSION['lang'] == 'en') {
    $modx->switchContext('en');
}
if ($_SESSION['lang'] == 'kz') {
    $modx->switchContext('kz');
}
bezumkinВасилий Наумкин
09.01.2013 16:46

Все верно.

Только в последнем блоке вместо 2х if лучше тоже else if.

Kondakov DmitriyKondakov Dmitriy
09.01.2013 17:12

Точно, поторопился что-то. еще пришлось сделать небольшой сниппет для вывода своего меню в каждом контексте, чтобы не делать несколько шаблонов. Если надо кому выложу

Андрей Минаков
24.05.2013 19:17

Было бы здорово.

Константин Баранов
08.02.2013 15:36

делаю для заказчика и важен только сайт, а не гугловская выдача, но интересно, как гугл на такие сессионные вещи реагирует, спасибо за простое и красивое решение.

bezumkinВасилий Наумкин
08.02.2013 17:29

Пока не было проблем.

Константин Баранов
09.02.2013 21:48

Как думаете Василий, лучше делать копии шаблонов, например для английских ресурсов или проверку контекста/сессии для вывода соответствующих чанков/сниппетов в общих шаблонах?

bezumkinВасилий Наумкин
09.02.2013 22:02

Проверка удобнее, а шаблоны быстрее.

Ну а выбирает каждый сам, зависит от размера сайта и личных предпочтений.

Богдан
16.02.2013 19:17

А зачем делать копии чанков или шаблонов? Для каждой фразы создается свой ключ в настройках контекста, а в шаблоне подставляется [[++ключ_фразы]]. Параметры в сниппеты тоже можно передавать таким образом, например [[getresources? &parents=\[\[++ID\_родителя\_для\_текущего\_языка\]\]]]. После завершения основной версии, делается копия контекста и в настройках копии просто переводим фразы на соответствующий язык. По такой схеме, пока не приходилось использовать копии чанков и шаблонов.

bezumkinВасилий Наумкин
16.02.2013 21:35

Зачем использовать системные параметры, если есть лексиконы?

Тег [[%name]] специально для этого. Вот дока.

Богдан
16.02.2013 21:44

Спасибо, Василий, так еще лучше, почему-то не обращал раньше внимания на управление словарями.

Богдан
13.02.2013 06:22

Самое удобное решение из тех, что встречал, но не без недостатка - url каждой страницы на разных языках должны быть одинаковыми, столкнулся с необходимостью вручную устанавливать урлы во всех контекстах для большого количества ресурсов, что очень неудобно.

Богдан
12.03.2013 22:21

Поправил немного сниппет для вывода ссылки на переключение языка:

<?php
if ($modx->getOption('cultureKey') == 'en') {
    $translateLink = $modx->runSnippet('BabelTranslation',array('contextKey' => 'web'));
    $link = $modx->makeUrl($translateLink,'',array('lang' => 'ru'));
    return "<a href=\"$link\">Русский</a>";
}
else {
    $translateLink = $modx->runSnippet('BabelTranslation',array('contextKey' => 'en'));
    $link = $modx->makeUrl($translateLink,'',array('lang' => 'en'));
    return "<a href=\"$link\">English</a>";
}

Теперь нет необходимости указания одинаковых url для соответствующих страниц. Естественно, все соответствующие страницы должны быть связаны через Babel.

Артур КостюнинАртур Костюнин
31.03.2013 20:20

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

503 Error Page not found The page you requested was not found. Спасибо.

Андрей Минаков
24.05.2013 04:01

Та же ересь. Никак не найду почему. :(

Мордынский Николай
24.05.2013 04:40

а страничка в английском контексте у тебя стем же урл что и в русском? должны быть одинаковые

Андрей Минаков
24.05.2013 16:04

Абсолютно идентичные и урл и алиасы - на болванке сайта тестирую, по странице в каждом контексте. Более того - такую же ошибку выдает в недефолтном (en) контексте при простом просмотре страницы. Предположений много, но дело, кажется, в каких-то настройках - сам скрипт потестить пока не выходит. Есть идеи?

Андрей Минаков
24.05.2013 18:06

Повторил по инструкции на тестовом сайте: заработало! Причин отказа так и не понял. Предполагаемое решение см. чуть ниже.

Андрей Минаков
24.05.2013 18:08

Решение: Предположительно, надо быть внимательным к адресу контекста в плагине:

$modx->switchContext('адрес_контекста');

Результат: http://s2955.modx-test.com

Gabaraev Akhsar
23.04.2013 18:45

Здравствуйте! А как можно при входе на сайт автоматический выбирать язык в зависимости от страны?

Мордынский Николай
23.04.2013 21:40

http://workinweb.com.ua/content/php-opredelenie-yazyka-brauzera-i-perenapravlenie-na-relevantnuyu-yazykovuyu-stranicu

Узнаешь язык клиента и инициализируешь соответсвующий контекст в сесси

Gabaraev Akhsar
23.04.2013 22:55

Да, я видел эту страницу. Просто думал по ip как-то надежнее, а тут http://mitasych.com/kak-opredelit-geograficheskoe-polozhenie-po-ip-i-svyazat-ego-s-google-maps не нашел где качать файлы geoip.inc, geoipcity.inc, geoipregionvars.php.

Мордынский Николай
24.04.2013 00:49

а если человек с ноутом заходит на твой сайт из макдональда в Англии и хочет русский а получает en

Gabaraev Akhsar
24.04.2013 00:54

То он переключит язык на русский, и выбранный язык хранится в сессии. Какой вариант лучше - однозначного мнения нет, как я понял :)

Мордынский Николай
24.04.2013 01:10

ну вот видишь сам ответ дал)

Дмитрий Нижник
13.06.2013 19:29

Подскажите пожалуйста, в чём может быть проблема!

Всё прекрасно работало, но в один момент ошибка стала вылетать 404ая, копал и накопал вот что когда отключаешь событие OnHandleRequest в плагине:

<?php
if ($modx->event->name != "OnHandleRequest" || $modx->context->key == 'mgr') {return;}

if (isset($_GET['lang']) && $_GET['lang'] != $_SESSION['lang']) {
    if ($_GET['lang'] == 'en') {
        $_SESSION['lang'] = 'en';
    }
    else {
        $_SESSION['lang'] = 'ru';
    }
}

if ($_SESSION['lang'] == 'en') {
    $modx->switchContext('en');
}

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

Помогите пожалуйста, 2 дня уже убил, кэш чистил, переустанавливал систему, ничего не помогает :(

Андрей Минаков
13.06.2013 22:08

Фазы луны, вероятно. Тоже лечил, но была 503-я: здесьУ меня все работает с настройками, приведенными в топике. Проверьте имена контекстов в коде (второй контекст точно зовется en?) и их настройки.

Дмитрий Нижник
14.06.2013 12:06

Всё работало, я только установил Quip и что то пошло не так, естественно я удалил Quip... Точно фаза луны, блин..

Дмитрий Нижник
18.06.2013 14:44

Удалил [[!Loginza?action=getProfile]] всё заработало, фаза луны пришла в норму, что думаете по этому поводу?

Андрей Минаков
20.06.2013 16:48

Увы, у меня нет версий. Я не очень в php шарю. :( Может Логинза что-то в запросе свое дописывала, что скрипт мультиязычности понять не мог?

sergantСергей Шлоков
20.06.2013 00:04

Василий, если есть время, кивни правильно или нет. Воюю с контекстами. Есть домен site.ru и поддомен sub.site.ru. Делаю согласно официальному руководству и твоим комментам на habre Как я воевал с контекстами. Не работает через http_host, хоть ты тресни (в контекстах прописал все настройки согласно твоей картинке из коммента). Вот плагин на OnHandleRequest

<?php
/* don't execute if in the Manager */
if ($modx->event->name != "OnHandleRequest" || $modx->context->key == 'mgr') {return;}
 
switch ($modx->getOption('http_host')) {
    case 'sub.site.ru':
        // if the http_host is of a specific domain, switch the context
        $modx->switchContext('sub');
        break;
    default:
        // by default, don't do anything
        break;
}

Если заменить $modx->getOption('http_host') на $_SERVER['HTTP_HOST'], то все работает, но хотелось бы узнать мнение грамотных специалистов - правильно так?

bezumkinВасилий Наумкин
20.06.2013 00:06

Если работает - это правильно.

sergantСергей Шлоков
20.06.2013 02:20

Спасибо. Успокоил.

Дмитрий Нижник
28.06.2013 13:59

При переключении языков Wayfinderы частично отключаются т.е. главное меню работает а доп.меню слева не работает, а в английской версии и главное пропадает, после обновления страницы всё появляется

З.Ы точно так же форма ввода пароля не отображается, только после повторного обновления страницы. Пакет Login. Помогите пожалуйста кто чем может?!

Мордынский Николай
28.06.2013 14:38

С таким не сталкивался. Все работало как надо.

Я делал для каждого языка категорию и в нее копировал чанки снипеты и шаблоны отдельно копия каждого элемента для каждого языка нудно зато потом путаницы нет что где менять и скешированием тоже нету проблемм.

Дмитрий Нижник
28.06.2013 14:43

Заметил что контекст (а именно [[*context_key]]) срабатывает правильно, а вот айди из словаря подставляет от другого контекста. Что за магия, не могу понять

Дмитрий Нижник
28.06.2013 15:22

С cultureKey проблемы, хотя в контекстах настроено правильно

Дмитрий Нижник
28.06.2013 18:50

Help!!!

Дмитрий Нижник
28.06.2013 21:01

Заманался, cultureKey путается при переключении на другие языки.. короче спасибо за помощь

bezumkinВасилий Наумкин
28.06.2013 21:02

На здоровье!

Homchenko Kostya
03.07.2013 23:12

Установил чистый MODx 2.2.8 сделал все по пунктам, не работает ни русская версия ни английская (((( Че за БРЕД ?!?!?!

Homchenko Kostya
03.07.2013 23:51

Все, разобрался. Оказывается в этой части

if ($_SESSION['lang'] == 'en') {
    $modx->switchContext('en');
}

там где

switchContext('en');

надо вместо "en" явно указать имя своего контекста для англоязычных материалов.

Maxim M
13.08.2013 18:44

На демосайте в Firefox 22 под Mac OS после достаточно быстрой смены языков 3-4 раза на странице каталога(да и вообще любой кроме товара) туда-сюда возникает такое при открытии конкретного товараостаются часть чанков случайным образом от прошлого языка. решается сменой языка туда-обратно на странице товара. на скрине, например, от текущего русского есть только цвет. наверное, такое в реальности не произойдет, но все же баг

bezumkinВасилий Наумкин
13.08.2013 18:48

На этом сайте вообще один контекст и все тексты переключаются через лексиконы, динамически. То есть, это одна и таже страница, и некоторые плейсхолдеры на ней кэшируются.

Если же делать 2 контекста, как расписано в заметке, то такой проблемы быть не может.

Maxim M
13.08.2013 19:52

Я тоже собирался через лексиконы делать, потому что получается наполнение на всех языках одно, нужно только подписывать в зависимости от языка. Судя по всему, возникает проблема только при быстром переключении подряд, если же это рабочий режим и все делается достаточно медленно, то все ок.

LEONesoПавел Левин
06.09.2013 20:37

Я вот делал мультиязычность вида your.domain/en/ и т.п. скок душе угодно по этой инструкции.

Правда никаких сессий там не используют и соответственно $_GET параметров.

Николай
13.09.2013 04:53

Я уже которые сутки пытаюсь догуглиться до истины. Для этого плагина нужен же этот сниппет? На http://minishop2.com/ Я его не видел, там так же не переводятся товары. Можно настроить это все так чтобы весь сайт был полностью на англ \ рус языке? Я так понял babel создает во втором контексте копию документа, который меняется контентом, шаблонами, и на сайте потом подменяется исходный ресурс на копию. Верно? А как же cart.html, он на сайте должен же быть один.

bezumkinВасилий Наумкин
13.09.2013 10:03

На minishop2.com это сделано довольно коряво.

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

TiamorphisИлья Никитин
14.02.2014 16:36

Подскажите, кто в курсе. Я всё насчёт поисковиков и индексации. Может вместо использования clean-param, который прикажет игнорировать все ?lang= лучше использовать Disallow /*?lang=ru? Иначе как поисковики попадут на страницы переводов, если будут шарить по страницам без параметров? С другой стороны, тогда останутся дубли у иностранных страниц...

Чикин Артур
14.02.2014 17:09

Robots.txt вам в помощь.

bezumkinВасилий Наумкин
14.02.2014 17:13

Эта заметка устарела, лучше делать вот так - http://bezumkin.ru/sections/tips\_and\_tricks/2439/

TiamorphisИлья Никитин
15.02.2014 20:45

О, спасибо. Может стоит это указать в начале заметки? А то в гугле эту первым делом выдаёт.

bezumkinВасилий Наумкин
15.02.2014 22:13

Лучше я просто редирект сделаю.

http://bezumkin.ru/sections/tips\_and\_tricks/2439/

born2slip
pishnaa istntome
22.11.2022 14:06
огромное спасибо! )
inetlover
Александр Наумов
14.11.2022 10:19
посмотри документацию. Спасибо, что-то она мне не нагуглилась. Это просто функции объединения для о...
bezumkin
Василий Наумкин
10.11.2022 05:46
Спасибо за поздравления!
inetlover
Александр Наумов
09.11.2022 17:08
Посмотрел в ДевТулсе свойство overscroll-behavior: none; присутствует, проверил в Chrome и Chromium ...
bezumkin
Василий Наумкин
03.11.2022 20:57
Поискать в исходниках ссылки на её адрес и поменять - скорее всего только nuxt.config.js. А зачем эт...
ni.kolokol@mail.ru
Николай Каленников
03.11.2022 19:43
Спасибо. Попробую тоже с нуля переставить
inetlover
Александр Наумов
03.11.2022 19:24
Спасибо!!! Все заработало!
bezumkin
Василий Наумкин
28.10.2022 05:23
В тексте есть подсказка // Контроллер требует новое разрешение protected $scope = &#x27;ord...
bezumkin
Василий Наумкин
27.10.2022 13:25
Понял, спасибо!
inetlover
Александр Наумов
23.10.2022 13:33
Понял, спасибо!