• avatar paic
  • 0
Спасибо за отзыв.
Я в курсе, как работает evoBabel и другие, начиная с e-KAO и YAMS ))
Но задача не стояла сделать еще один evoBabel.

Задача стояла показать как максимально просто сделать мультиязычный сайт, не прибегая к специальным компонентам, с кучей плагинов, сниппетов, дополнительными таблицами в базе. Это один момент.

А второй заключается в том, что в таком варианте ничем не скрыта физика работы подобного сайта — имеется ввиду, что если под кнопкой переключателя языка ссылка, то ссылка и пишется, а не плейсхолдер или еще что-то.
Тому кто делает мультиязычный сайт впервые это в любом случае полезно знать, вне зависимости на чем он будет делать.

Касательно разрастания сайта — для этого и сделал плагин miniLang — клепайте на здоровье хоть 1000, хоть сколько захотите страниц и категорий, все сопряжения устанавливаются автоматически:
— сопряжение страниц
— сопряжение родителей
— сопряжение шаблонов

А со временем может и добавлю лексиконы и уберу дублирующие шаблоны, подумаю. Но добавлять дополнительные таблицы в базу пока не хочется, пока смотрю в сторону ClientSettings.
Дублировать шаблоны только ради того, чтобы вписать в них другие идентификаторы ресурсов для вызовов DlMenu, DlCrumbs и прочих сниппетов, и другие названия чанков — это очень избыточно.

Тут как минимум следующие решения напрашиваются:

1 — Аналогично тому, как это сделано в evoBabel, можно задавать свои плейсхолдеры вида [+menu_parent_id+]. Заполнить которые можно хоть в сниппете, хоть в плагине.
И вызывать уже

[[DLMenu?
&parents=`[+menu_parent_id+]`
&outerTpl=`[+menu_outer_tpl+]`
&maxDepth=`2`

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

2. Можно в prepare-сниппетах в зависимости от языковой версии подменять tpl и ownerTPL на соответствующий чанк.
Но это уже какие-то мега-костели.

Мне доводилось забирать сайты на modx, которые были вроде и маленькими, но там было наделано по 40-50 шаблонов на все случаи жизни. После «прореживания» и удаления дублирующего кода удавалось уменьшить их на 5-10 штук ;)

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

В целом, установка и настройка evoBabel даже на последних версиях Evo и PHP (у меня — работает) не выглядит такой уж сложной по сравнению с дублированием шаблонов, чанков и всего подобного.
  • avatar paic
  • 0
Про дублирование я сразу написал, что это минус. В дальнейшем можно будет подумать на этот счет.
Зато эта штука точно запустится сразу и будет работать без всяких-яких, и не поломается ни при каких обстоятельствах — там ломаться нечему.
И сделать можно за один вечер. У меня на писанину больше ушло ((
Про лучше и изящнее — просто не успел, ниже выложил, там тоже найдется что покритиковать, но все же))
  • avatar paic
  • 0
11. Плагин miniLang

Сразу код
/**
 * miniLang
 * 
 * Мультиязычность - создание альтернативных страниц
 * 
 * @category    plugin
 * @version     1.0.0
 * @internal    @events OnDocFormSave
**/

switch ($modx->Event->name) {
    case 'OnDocFormSave': {
    	if ($mode == "new") {
        	include_once(MODX_BASE_PATH.'assets/lib/MODxAPI/modResource.php');
        	$doc = new modResource($modx);
        	$doc->edit($id);
        	$template = $doc->get('template');
			$pagetitle = $doc->get('pagetitle');
			$image = $doc->get('image');
			
			// Определение родителя альтернативной версии
			$parent = $doc->get('parent');
			if ($parent != 0) {
				$value = $doc->get('parent');
				$tmplvarid = '9';
				$out = $modx->db->getValue('Select contentid from '.$modx->getFullTableName('site_tmplvar_contentvalues').' where value="'.$value.'" and tmplvarid="'.$tmplvarid.'"');
			}else{ 
				$out = '11';
			}
			$newparent = $out;
			
			// Определение шаблона альтернативной версии
			$table1 = $modx->getFullTableName( 'site_templates' );
			$res = $modx->db->select("description", $table1, "id='".$template."'");
			while ($row=$modx->db->getRow($res)) {
				$description = $row['description'];
			}
			$category = '2';
			$newtemplate = $modx->db->getValue('Select id from '.$table1.' where description="'.$description.'" and category="'.$category.'"');
			
			// Создание страницы альтернативной версии
        	        if ($template != $newtemplate) {
				$doc->create(array(
    				'pagetitle' => $pagetitle,
    				'template' => $newtemplate,
    				'parent' => $newparent,
					'published' => 0,
					'altRu' => $id,
					'image' => $image
				));
				
		// Запись id созданной альтернативной страницы в ТВ основной страницы
		    $newid = $doc->save(true, false);
		    $table = $modx->getFullTableName('site_tmplvar_contentvalues');
		    $fields = array(
                    	'value' => $newid,  
                    	'contentid'  => $id,  
                    	'tmplvarid' => 10
                    );   
    		    $modx->db->insert( $fields, $table);  
		}
			
    	    }
	}
}

Плагин составлялся исходя из того, что основной язык сайта русский, и добавления страниц на сайт так же будет сначала на русском языке, а потом на альтернативном (английском).
Что делает плагин:
1. При создании страницы на русском языке в любой категории или в корне сайта, при ее сохранении дополнительно создается страница в англоязычной версии в такой же категории или тоже в ее корне.
2. Альтернативная страница создается не опубликованной (в плагине можно изменить).
3. На альтернативную страницу передается заголовок (для последующей идентификации) и изображение (чтобы меньше работы было, но можно и поменять).
4. Выполняется двухстороннее сопряжения — в оба ТВ altEn и altRu вписываются нужные id страниц, т.е. вручную их больше прописывать не надо.

Основная страница



Альтернативная страница



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

Комментарии по коду прописаны, что еще осталось пояснить:
tmplvarid = 9 — это altRu
tmplvarid = 10 — это altEn
category = 2 — категория, в которой находятся шаблоны англоязычной версии
description — это описание шаблона, в данном случае оно пошло «в дело», с помощью него сделано сопряжение шаблонов, чтобы шаблон создаваемой альтернативной страницы использовал аналогичный шаблон, какой выбран у основной страницы.
Поэтому, если посмотрите скриншот, он одинаков для каждой пары шаблонов, например у шаблонов и Блог, и Блог En — blog.



12. TV параметры altEn и altRu

Они теперь вроде как и не у дел, можно даже скрыть, чтобы «не путались под ногами».
А можно и оставить на случай форс-мажора.

Я оставил, но «приукрасил». В качестве украшательства рассматривались несколько вариантов, в итоге остановился на ddTree (DropDown Tree) (да, он еще живой, на v 7.3 полет нормальный).
Выглядит теперь так



Это все, что я хотел написать в рамках этого топика. Дополнения и критика, как всегда приветствуется.
Еще раз хочу подчеркнуть, что это для простых сайтов, когда проще и быстрее продублировать несколько шаблонов, чем ставить и настраивать какой-то сложный и объемный компонент.
Эту задачу было бы интереснее решить в 3.x, ну или через EvoTwig (заодно можно было бы написать расширение для твига для лексиконов).
Если я берусь за задачу, которую уже решали до меня, то мне хочется решить ее лучше, чем предшественники. Ну или хотя бы изящнее (: Здесь, увы, я этого не наблюдаю — одно дублирование шаблонов чего стоит. Нужно признать очевидное — из коробки ево не способна ни в мультиязычность, ни в мультисайтовость.

За старания, конечно, плюс.
  • avatar paic
  • 0
  • avatar paic
  • 0
14. Контроллеры в EvoTwig, исправления и дополнения к п.13.

Заключительный алгоритм при работе с контроллерами, начиная с установки:

1. Создаем в папке assets файл composer.json, внутри файла помещаем
{
	"require":{
		"pathologic/evo-twig-lib": "*"
	}
}

2. Запускаем Composer и переходим в папку assets (вариант для Open Server)
cd domains/site.ru/assets
где site.ru — это ваш домен.

3. Запускаем команду и ждем ее выполнения
composer require pathologic/evo-twig-lib

4. Устанавливаем плагин EvoTwig2 из Extras (или вручную), включаем его в админке (по умолчанию он выключен.

5. Создаем нужные шаблоны в папке tpl и подключаем их в админке к нужным шаблонам Evo. Проверяем работоспособность.

6. Для работы с контроллерами создаем свои контроллеры (глобальный и дочерние для шаблонов) и помещаем их в отдельную папку вне папки Vendor. Я их разместил в папке по адресу assets/plugins/evotwig/addons/controllers/

Глобальный контроллер — расширяет базовый контроллер, а дочерние контроллеры для шаблонов должны расширять глобальный контроллер. Т.е. получается такая цепочка: базовый контроллер — глобальный контроллер — дочерний контроллер.
Дочерний контроллер подключается к шаблону, например @FILE:service@ServiceController, где service — название шаблона, а ServiceController — дочерний контроллер.
Котроллер GlobalController никуда подключать не надо.

В конфигурации плагина EvoTwig в поле Base controller class вместо прописанного там по умолчанию Pathologic\EvoTwig\BaseController указываем класс своего контроллера. У меня это Controllers\GlobalController

Пример Глобального контроллера, который расширяет штатный Базовый контроллер EvoTwig
<?php

namespace Controllers;

use Pathologic\EvoTwig\BaseController;

class GlobalController extends BaseController 
{
    public function __construct(\DocumentParser $modx, array $params = [])
    {
        parent::__construct($modx, $params);
	$this->docid = $this->modx->documentIdentifier;
        $this->setTemplateData([
            'mymenu' => json_decode($this->modx->runSnippet('DLMenu', ['parents' => 0, 'maxDepth' => 2, 'api' => 1]), true)[0]
	    // здесь можно добавлять и другие переменные, через запятую
        ]);
    } 
}

Пример дочерних контроллеров, которые расширяют Глобальный контроллер
<?php

namespace Controllers;

class ServiceController extends GlobalController
{
    public function __construct(\DocumentParser $modx, array $params = [])
    {
        parent::__construct($modx, $params);
        $this->setTemplateData([
	    'service' => json_decode($this->modx->runSnippet('DocLister', ['tvPrefix' => '', 'parents' => $this->docid, 'depth' => 0, 'tvList' => 'image', 'api' => 1]), true)
	    // здесь можно добавлять и другие переменные, через запятую
        ]);
    }
}


Как вариант, можно и так:
Глобальный контроллер
<?php

namespace Controllers;

use Pathologic\EvoTwig\BaseController;

class GlobalController extends BaseController 
{
    public function __construct(\DocumentParser $modx, array $params = [])
    {
        parent::__construct($modx, $params);
	$this->docid = $this->modx->documentIdentifier;
	$this->setGlobalData();
        $this->setPageData();
    } 
    public function setGlobalData()
    {
        $this->data['mymenu'] = json_decode($this->modx->runSnippet('DLMenu', ['parents' => 0, 'maxDepth' => 2, 'api' => 1]), true)[0];
        // сюда же добавляются и другие глобальные переменные
    }

    protected function setPageData()
    {
        // оставлять пустым, используется для дочерних контроллеров
    }
}

Дочерний контроллер
<?php

namespace Controllers;

class ServiceController extends GlobalController
{
    protected function setPageData()
    {
        $this->data['service'] = json_decode($this->modx->runSnippet('DocLister', ['tvPrefix' => '', 'parents' => $this->docid, 'depth' => 0, 'tvList' => 'image', 'api' => 1]), true);
	// сюда же добавляются и другие дочерние переменные
    }
}

7. В файл composer.json помещаем код автозагрузки для созданных контроллеров
{
	"require":{
		"pathologic/evo-twig-lib": "*"
	},
	"autoload":{
		"psr-4": {
            "Controllers\\": "plugins/evotwig/addons/controllers/"
        }
    }
}


8. В Composer запускаем команду
composer update

9. Подключаем дочерние контроллеры к нужным шаблонам и проверяем работоспособность сайта.

10. Обновление
Все что выше в п.1-9 — это для текущей версии EvoTwig 2.2.0, которая вышла 31.03.21.
В предыдущей версии все то же самое, за исключением п.6 в части конфигурации плагина EvoTwig.
Ранее в конфигурации не было поля Base controller class и нужно было в поле Controllers namespace прописывать namespace своего глобального контроллера, у меня это Controllers.

Теперь порядок обновления:
— Обновляем плагин EvoTwig2.
— В конфигурации плагина удаляем из поля Controllers namespace неймспейс своего контроллера. А в поле Base controller class вместо прописанного там по умолчанию Pathologic\EvoTwig\BaseController прописываем класс своего контроллера, например, у меня это Controllers\GlobalController.
— выполняем пункты 7 и 8, при этом обновятся и evo-twig-lib — иначе обновления плагина не вступят в силу, и автогазрузка своего контроллера.

Это все, что планировал написать в этом топике. Любые дополнения приветствуются.

Автору спасибо и за помощь, и за EvoTwig2.
я пока с Дитто работаю, версию ПХП понизил))
В таком случае умываю руки
НЕ ПОМОГЛО!(((((
Ну, как бы на эту же версию я такой же сайт подымал, и ничего. А тут вдруг такое(((
Скорее не к автору сниппета а к изменчивости php. От версии к версии очень многие вещи становятся неактуальными, выпиливаются старые функции, или меняется еще что нибудь, на обратную совместимость можно вообще не надеяться.
Блин, так это ведь тогда больше вопрос к автору сниппета))
Точно не вспомню, но на 7.3 и предыдущих версиях константы определяются по разному, это легко гуглится, у меня так отвалился ajax submit, переопределял константы в соответствии с новой версией.
А подробнее? У меня 7.3, вроде как везде.
Была похожая проблема, ругалось на константы, на разных версиях php они по разному объявляются, смотрел код и менял объявление констант в соответствии со своей версие php, мне помогло
  • avatar dcm999
  • 0
Я может чего не понимаю, подскажите пожалуйста. Как на странице «Избранные товары» вывести весь список товаров, которые попали в «избранное»? Если на странице размещен плейсхолдер [+eFavoriteDocs+], то просто выводятся id ресурсов через запятую. Если я этот плейсхолдер подставляю в параметр &documents=`[+eFavoriteDocs+]` DocLister`а, то ничего не происходит.
Причём, если смотреть разметку, то при выводе id`шников добавляются множество пробелов и переносов строк. Производил манипуляции со сниппетом, посредством удаления строк и переносов у переменной eFavoriteDocs, но безрезультатно. Приведите пожалуйста примеры, как правильно выводить список через DocLister? Заранее благодарен.
  • avatar gk71
  • 0
ddTypograph не подходит?
  • avatar fc3000
  • 0
Можно написать простой плагин на событие сохранения документа OnDocFormSave, который и будет менять.
К сожалению, не владею такими знаниями.

А еще можете почитать про настройки (валидные элементы и тому подобное) TinyMce, возможно прямо там это можно сделать, но не уверен на 100%.
Даже если так, но ведь названия страниц и пр не будут меняться…