Мультиязычность динамического контента в MODX

Александр и снова здравствуйте:) Не получается сообразить, как переводить динамический контент на сайте. Со статическим всё более понятно, если коротко, создать компонент лексиконов, прописать там метод вывода, создать пространство имён, создать плагин и повесить его на определённое событие, прописать вывод в шаблоне, тут всё понятно, но а как быть к примеру с полями extendresource и вообще с динамическим контентом фильтра, тв, и т.д, если возможно расскажите пожалуйста, как это лучше и правильней делать? Не много дополню и уточню вопрос к примеру будет два разных домена на одном modx, site.ru и site.com у второго будут разные языковые версии сайта site.com/di/, site.com/by/ и так далее, фильтр mfilter2 фильтрует по своим полям, компонента extendresource, как в данном случае сделать переводы всех значений, дублировать компонент и таблицы в базе с переводами всех значений для разных версий сайта или как то по другому? Александр как правильно в данном случае это можно реализовать?

Комментарии: 21

Александр
Александр
Александр, огромное спасибо за решение, если возможно, хотел бы уточнить некоторые моменты а точнее, всё ли я понял правильно:

1) Для каждой языковой версии сайта, свой шаблон, со своими тв, то есть в каждый контекст, нужно продублировать все ресурсы и создать для них шаблоны в которых указаны тв в зависимости от языка?

2) По поводу extendresource, если я правильно понимаю, нужно продублировать все поля в таблице, добавив к ним свои приставки типа by, перевести все значения, добавив их там же, далее указать их в custom.class.php. В нужных шаблонах языковых версий, разместить вызов mFilter2 у которого в select прописаны название полей с переводами?

3) Если так и прикинуть что полей в таблице к примеру 10 и значений у этих полей 200 а языковых версий сайта 20, получается дополнительно в одной таблице 190 полей и 3800 значений и это наверно очень сильно повлияет на скорость фильтрации если да, то каким обрам этого можно избежать?
Александр Мальцев
Александр Мальцев
А у вас как организована мультиязычность? Через контексты?
Самый простой вариант — это продублировать. Ресурсы и так у вас будут в каждом контексте свои.

В extendresource можно просто создать дополнительное поле, в котором сохранять контекст. Тут не нужно ничего дублировать. В результате будет столько же записей сколько ресурсов.
Александр
Александр
Предполагаю что буду использовать компонент Babel, а это как я понимаю контексты, по поводу ресурсов мне более всё понятно, но по поводу extendresource не могу не как сообразить, к примеру есть поле strana в нём значения Россия, Англия и т.д это поле храниться в таблице компонента extendresource все значения там на русском языке, в фильтре они выводятся тоже на русском, мне не понятно следующее, где хранить значения, которые будут на любом другом языке, как будут они переводиться, если не создаёшь копии полей и значений в таблице extendresource на нужном языке?

Александр, как Вы считайте, если опираться на скорость, что лучше использовать для мультиязычности, Babel где контексты или к примеру MultiLingual, Localizator?
Александр Мальцев
Александр Мальцев
Вам решать, я бы выбрал Babel.
Тут просто добавить дополнительное поле в таблицу (ну и соответсвенно обновить компонент):
id  resource   strana  context
 1         1   Россия       ru
 2         2   Russian      en
Затем его использовать в запросах, и следовательно, выбирать только те записи, которые относятся к этому контексту.
Александр
Александр
Огромное Спасибо! Александр, если возможно, приведите пожалуйста пример, как после этого в mFilter2 выбирать эти значения и какие изменения нужно сделать в файле custom.class.php?
Александр Мальцев
Александр Мальцев
Нужно просто добавить к запросу where:
$q->where(array('context' => 'ru'));
Александр
Александр
Оказывается всё на много проще, чем я думал. Спасибо Вам!
Александр Мальцев
Александр Мальцев
Привет!
Самый простой вариант — это создать разные шаблоны для разных языковых версий сайтов. К одним шаблонам привязать одни TV, например, оканчивающиеся на di, а к другим, другие TV, например, оканчивающиеся на by. После этого в шаблонах и чанках соответственно добавить эти окончания.
Этот вариант основан на дублировании шаблонов, чанков и т.д. Т.е. для каждой языковой версии сайта создавать свой набор MODX элементов.

В extendresource это можно попробовать реализовать просто добавив к нему дополнительное поле для хранения контекста. Далее в запросе можно дополнительно указывать контекст и следовательно выбирать только те данные, которые к нему принадлежат.
Александр
Александр
Александр, здравствуйте! Пришлось оставить это дело на потом а сейчас оторвался от другого и появилась возможность всё сделать а именно вариант с добавлением дополнительного поля в extendresource для хранения контекста, добавил поле «context» в фильтре выбираю данные в зависимости от контекста, всё работает но не могу точно понять и определится подходит ли мне этот вариант, в моём случае на сайте более десяти контекстов (разных языковых версий сайта) в каждом контексте переведённые каталог и ресурсы, у каталога с фильтром во всех контекстах один шаблон, теперь возникает такая проблема, если прикинуть что в одном поле 200 значений в моём случае это поле стран, при таком варианте добавляются ещё 200 значений на английском, 200 на немецком и т.д, теперь в админке редактируя ресурс не зависимо от контекста в котором находишься, для выбора значений поля стран, будут выводится все значения стран которые есть в таблице на русском, английском и всех остальных, скажите пожалуйста возможно ли как-то исключать вывод значений поля в админке, те значения которые не соответствуют контексту в котором редактируешь ресурс?
Александр Мальцев
Александр Мальцев
Здравствуйте! Нужно пробовать, а потом уже решать подойдёт вам этот вариант или нет.
Александр, отображение дополнительных полей в админке у вас реализовано через плагин ExtendedResource, представленный в этой статье? Если так, то в этом случае нужно просто получить контекст ресурса. Это можно сделать так:
$contextKey = $resource->get('context_key');
Далее полученный контекст вам нужно использовать в условиях для выборки соответствующих данных из базы данных и в других местах кода при необходимости.
Александр
Александр
Здравствуйте! Нет, плагин у меня дублирует значения обычных tv в свою таблицу компонента extendresource, реализовано вот таким образом: itchief.ru/questions/591, Александр как я понимаю при таком раскладе значения tv в админке не получится разделять по контексту, не трогая исходники Modx? И самый оптимальный и лучший вариант в данном случае это вывести в админку свои поля?

Александр Мальцев
Александр Мальцев
Привет! В этом случае только если организовать через свои поля.
Александр
Александр
Спасибо!
Александр
Александр
Здравствуйте! Сейчас всё реализовано через плагин «ExtendedResource», спасибо. Александр, не могли бы Вы подробней, если возможно конечно, рассказать что нужно изменить в плагине «ExtendedResource» чтобы в админке выводились значения полей в зависимости от контекста? Я смог только дойти до того, что разместил этот код:
$contextKey = $resource->get('context_key');
в if блок плагина
            if (is_object($extendResource)) {
                $contextKey = $resource->get('context_key');
                $myhobbies = $extendResource->get('myhobbies');
            }
теперь как я понимаю, тут нужно добавить варианты значений для разных контекстов или этот код просто нужно дублировать?
MODx.combo.extendresourceMyhobbies = function(config) {
config = config || {};
Ext.applyIf(config,{
     xtype:'superboxselect'
    ,triggerAction: 'all'
    ,mode: 'local'
    ,store: new Ext.data.ArrayStore({
        id: 0
        ,autoLoad: true
        ,fields: ['hobbies']
        ,data: [
            ['бег'],['дайвинг'],['плавание'],['лыжи'],['боулинг']
        ]
    })
    ,mode: 'local'
    ,displayField: 'hobbies'
    ,valueField: 'hobbies'
    ,forceSelection: true
    ,triggerAction: 'all'
    ,extraItemCls: 'x-tag'
    ,expandBtnCls: 'x-form-trigger'
    ,clearBtnCls: 'x-form-trigger'
});
MODx.combo.extendresourceMyhobbies.superclass.constructor.call(this,config);
};
Ext.extend(MODx.combo.extendresourceMyhobbies,Ext.ux.form.SuperBoxSelect);
Ext.reg('extendresource-myhobbies',MODx.combo.extendresourceMyhobbies);
возможно я вообще не правильно делаю?
Александр Мальцев
Александр Мальцев
Привет!
Добавить варианты значений можно так:
$contextKey = $resource->get('context_key');
if ($contextKey === 'web') {
  $hobbiesData = "[['бег'],['дайвинг'],['плавание'],['лыжи'],['боулинг']]";
} else {
  $hobbiesData = "[['running'], ['diving'], ['swimming'], ['skiing'], ['bowling']]";    
}
...
$modx->controller->addHtml(<<<HTML
...
Ext.applyIf(config,{
  xtype:'superboxselect'
  ,triggerAction: 'all'
  ,mode: 'local'
  ,store: new Ext.data.ArrayStore({
    id: 0
    ,autoLoad: true
    ,fields: ['hobbies']
    ,data: {$hobbiesData}
  })
  ...
Дополнительно, если нужно, можно добавить в таблицу «site_content_extend» поле «context_key» также как это сделано в таблице «site_content». После этого добавить его в схему «extendresource.mysql.schema.xml» и сгенерировать новую модель.
Затем добавить в плагин следующую строку:
$extendResource->set('context_key', $resource->get('context_key'));
Александр
Александр
Александр, доброго вечера Вам! Огромное спасибо за решение, но как обычно у меня не совсем всё гладко получается реализовать, как только вношу в плагин эти изменения, во всех контекстах кроме контекста «web», поля перестают отображаться, код добавляю в блок if плагина, после этой строки:
if (is_object($extendResource)) {
вторым заменяю параметры поля:
Ext.applyIf(config,{
    xtype:'superboxselect'
    ,triggerAction: 'all'
    ,mode: 'local'
    ,store: new Ext.data.ArrayStore({
        id: 0
        ,autoLoad: true
        ,fields: ['hobbies']
        ,data: [
            [['бег'],['дайвинг'],['плавание'],['лыжи'],['боулинг']]
        ]
    })
подскажите пожалуйста с чем это может быть связано?

И если я правильно понимаю, при таком условие в админке должны выводится значения так, если контекст «web» выводим одно, если другой любой контекст, выводим другое, а как можно добавить свои значения поля не только для контекста «web» а к примеру для контекста «deg» и некоторых других, как правильно нужно прописывать условие, подскажите пожалуйста?
Александр
Александр
Александр, здравствуйте! Как обычно я накосячил и не туда код вставил, поэтому были проблемы и не отображались поля в других контекстах, спасибо за отличное решение. Сейчас не понятен один момент, чтобы к примеру добавить свои значения к контексту «deg» делаю так:
$contextKey = $resource->get('context_key');               
if ($contextKey === 'web') {
  $hobbiesData = "[['бег'], [''], ['плавание'], ['лыжи'], ['боулинг']]";
} 
if ($contextKey === 'deg') {
  $hobbiesData = "[['laufen'], ['tauchen'], ['schwimmen'], ['ski'], ['bowling']]";
} 
else {
  $hobbiesData = "[['running'], ['diving'], ['swimming'], ['skiing'], ['bowling']]";    
}
всё работает, но на сколько это правильно? Можно ли для этого как-то одним if блоком обойтись?
Александр Мальцев
Александр Мальцев
Здравствуйте! Рад что получилось.
Сделайте через ассоциативный массив:
$contextKey = $resource->get('context_key');
$hobbiesDataArr = [
  "web" => "[['бег'],['дайвинг'],['плавание'],['лыжи'],['боулинг']]",
  "en" => "[['running'], ['diving'], ['swimming'], ['skiing'], ['bowling']]",
  "deg" => "[['laufen'], ['tauchen'], ['schwimmen'], ['ski'], ['bowling']]"
];
$hobbiesData = $hobbiesDataArr[$contextKey];
Александр
Александр
Александр, доброго вечера Вам! Спасибо, за отличный вариант. Скажите пожалуйста а в массиве можно, как-то определить, если не указано, то используем «en» то-есть сделать то-же самое как в «if» блоке с параметром «else»?
Александр Мальцев
Александр Мальцев
Привет!
Для этого можно проверить наличие ключа в массиве. Если его нет, то используем какой-то по дефолту (например, en):
$contextKey = $resource->get('context_key');
$hobbiesDataArr = [
  "web" => "[['бег'],['дайвинг'],['плавание'],['лыжи'],['боулинг']]",
  "en" => "[['running'], ['diving'], ['swimming'], ['skiing'], ['bowling']]",
  "deg" => "[['laufen'], ['tauchen'], ['schwimmen'], ['ski'], ['bowling']]"
];
if (array_key_exists($contextKey, $hobbiesDataArr)) {
  $hobbiesData = $hobbiesDataArr[$contextKey];
} else {
  // если ключ $contextKey не найден в массиве 
  $hobbiesData = $hobbiesDataArr["en"];    
}
Александр
Александр
Александр, огромное спасибо!