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

Во время работы над 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 13:30

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

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

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

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

Добрый день.

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

Ivan Moshkov
07.01.2013 23:46

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

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

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

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

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

Да, верно.

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

Bond Nataly
08.01.2013 13: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 13:27

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

Bond Nataly
08.01.2013 13:30

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

Bond Nataly
08.01.2013 13:33

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

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

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

Alexander Legan
23.12.2013 02:06

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

Bond Nataly
23.12.2013 11: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 12:20

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

Bond Nataly
23.12.2013 12:41

Пожалуйста )

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

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

bezumkinВасилий Наумкин
08.01.2013 20:06

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

Kondakov DmitriyKondakov Dmitriy
09.01.2013 11:18

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

Kondakov DmitriyKondakov Dmitriy
09.01.2013 12: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 12:46

Все верно.

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

Kondakov DmitriyKondakov Dmitriy
09.01.2013 13:12

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

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

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

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

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

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

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

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

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

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

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

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

Богдан
16.02.2013 15:17

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

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

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

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

Богдан
16.02.2013 17:44

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

Богдан
13.02.2013 02:22

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

Богдан
12.03.2013 18: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 16:20

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

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

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

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

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

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

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

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

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

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

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

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

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

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

Gabaraev Akhsar
23.04.2013 14:45

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

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

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

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

Gabaraev Akhsar
23.04.2013 18:55

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

Мордынский Николай
23.04.2013 20:49

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

Gabaraev Akhsar
23.04.2013 20:54

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

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

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

Дмитрий Нижник
13.06.2013 15: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 18:08

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

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

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

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

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

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

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

sergantСергей Шлоков
19.06.2013 20: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Василий Наумкин
19.06.2013 20:06

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

sergantСергей Шлоков
19.06.2013 22:20

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

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

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

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

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

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

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

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

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

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

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

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

Help!!!

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

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

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

На здоровье!

Homchenko Kostya
03.07.2013 19:12

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

Homchenko Kostya
03.07.2013 19:51

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

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

там где

switchContext('en');

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

Maxim M
13.08.2013 14:44

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

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

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

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

Maxim M
13.08.2013 15:52

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

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

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

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

Николай
13.09.2013 00:53

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

bezumkin
Василий Наумкин
13.08.2022 11:41
неужели, все глобальное, так просто можно взять и сделать Да, именно так. Мелкие затыки, конечно ж...
bezumkin
Василий Наумкин
13.08.2022 08:18
Killed говорит, что сервер прибивает задачу, скорее всего у провайдера есть какие-то лимиты по нагру...
bezumkin
Василий Наумкин
11.08.2022 15:46
Класс!! Рад, что тебе нравится! нужно добавить @click=&quot;showCart = true&quot; в: Спасибо, попра...
bezumkin
Василий Наумкин
09.08.2022 11:27
На здоровье!
inetlover
Александр Наумов
30.07.2022 19:58
Василий, спасибо большое! Первый вариант помог, не было вот этой настройки: php_value[sys_temp_dir].
bezumkin
Василий Наумкин
12.07.2022 20:40
Всё как обычно, в самом начале файла конфига import axios from &#x27;axios&#x27;
bezumkin
Василий Наумкин
06.07.2022 14:06
Базовый Vue, базовый ES 6: импорт-экспорт модулей, вот это всё. Если что-то будет непонятно - просто...
bezumkin
Василий Наумкин
06.07.2022 11:19
Спасибо, что читаешь!
bezumkin
Василий Наумкин
05.07.2022 11:40
На здоровье!
inetlover
Александр Наумов
03.07.2022 23:36
Василий, спасибо! Все понятно!