Статья: Модификация плагина i18n для Cotonti – корректная работа селектора языка при добавлении и редактировании переводов
1. Введение (Часть 1 общее)
Плагин i18n (интернационализация) является стандартным инструментом Cotonti для управления переводами страниц. Он позволяет создавать локализованные версии страниц на разных языках. Однако в процессе эксплуатации были выявлены серьёзные недостатки, связанные с определением языка при добавлении и редактировании переводов, что приводило к путанице и ошибкам. В данной статье описан процесс диагностики, внесённые изменения и итоговый функционал модифицированной версии плагина.
2. Исходная проблема
При работе с плагином наблюдались следующие проблемы:
- При добавлении перевода язык определялся не из селектора в форме, а из глобальной локали (определяемой по URL, кукам или настройкам пользователя). В результате, даже если пользователь выбирал в форме другой язык, перевод сохранялся для текущего языка сайта (например, при выборе польского – сохранялось в английский).
- Форма добавления могла не отображаться, если для текущей глобальной локали уже существовал перевод – плагин считал, что перевод уже есть, и перенаправлял на редактирование.
- При редактировании перевода отсутствовала возможность сменить язык: локаль была жёстко привязана к той, с которой открыли форму. Если требовалось изменить язык перевода, приходилось удалять старый и создавать новый.
- В шаблоне присутствовали два одинаковых поля
name="locale" (одно для десктопа, другое для мобильных). При отправке браузер передавал оба значения, и PHP использовал последнее (мобильное), которое часто оставалось со значением по умолчанию. - При ошибках валидации (например, пустой заголовок) происходил редирект на ту же форму, но все введённые данные терялись, что было неудобно.
Таким образом, плагин в оригинале не позволял полноценно управлять переводами: селектор языка был декоративным, а реальная локаль бралась извне.
3. Поставленные задачи
На основе выявленных проблем были сформулированы следующие задачи:
- При добавлении перевода локаль должна браться исключительно из POST-поля
locale (выбор пользователя), игнорируя все остальные источники. - Гарантировать отображение формы добавления всегда, независимо от наличия перевода для глобальной локали.
- Добавить проверку на уникальность – не позволять создавать дубликаты для одного языка.
- Включить возможность смены языка при редактировании перевода, с соответствующей проверкой на существование целевой локали.
- Устранить дублирование селектора в шаблоне, оставив один элемент
select с именем locale. - Сохранять введённые данные при ошибках валидации, не сбрасывая поля формы.
- После успешного сохранения редиректить на страницу с той локалью, которую выбрал пользователь.
4. Реализованные изменения
4.1. Изоляция логики добавления (файл i18n.page.php)
В оригинале перед отображением формы всегда выполнялся запрос к таблице переводов с глобальной локалью. Мы изменили это:
if($a=='add'){
$pag_i18n=[];
}else{
$stmt=Cot::$db->query(...);// для edit/delete
}
Теперь при a=add массив $pag_i18n пуст, что гарантирует показ формы, даже если для текущей глобальной локали уже есть перевод.
4.2. Обработка POST при добавлении
- Локаль получаем через
cot_import('locale', 'P', 'ALP') – только из POST. - Добавлена проверка на существование перевода для выбранной локали (чтобы избежать дубля).
- При ошибках (неверная локаль, пустой заголовок) редирект не выполняется – просто продолжаем выполнение, и форма отображается снова с заполненными данными (массив
$pag_i18n хранит введённые значения). - При успехе – вставка записи в БД и редирект на страницу с выбранной локалью.
4.3. Обработка POST при редактировании
- Добавлена обработка поля
locale из POST: $new_locale = cot_import('locale', 'P', 'ALP');. - Проверка допустимости новой локали.
- Если локаль изменилась, выполняется проверка на существование перевода для
$new_locale. - Обновление записи в БД с условием по старой локали (
$i18n_locale), а в массив данных включается новое значение ipage_locale. - При ошибках – форма отображается с заполненными полями (значения из POST), селектор сохраняет выбранное.
- При успехе – редирект на страницу с новой локалью.
-
4.4. Формирование списка локалей для редактирования
$lc_list=$i18n_locales;
unset($lc_list[Cot::$cfg['defaultlang']]);// исключаем язык оригинала
$existing=cot_i18n_list_page_locales($id);
foreach($existingas$lc){
if($lc!=$i18n_locale){
unset($lc_list[$lc]);// убираем занятые, кроме текущей
}
}
Это позволяет выбрать любую свободную локаль, а текущая остаётся доступной (чтобы можно было не менять язык).
4.5. Шаблон i18n.page.tpl
- Удалён мобильный дубликат селектора (тот, что внутри правой колонки).
- В верхнем блоке (где раньше был селектор только для десктопа) убраны классы
d-none d-md-block, теперь он видим на всех устройствах. - В результате остался один элемент
<select name="locale">, что исключает путаницу при отправке формы. - Добавлена подпись для селектора с использованием языковой константы
{PHP.L.i18n_locale_selection} (при необходимости её можно добавить в языковые файлы).
4.6. Обработка ошибок без потери данных
При ошибках валидации редиректы заменены на повторное отображение формы. Для этого:
- В блоке добавления: массив
$pag_i18n заполняется из POST. - В блоке редактирования: значения полей берутся из POST через
cot_import() внутри отрисовки. - Селектор сохраняет выбранное значение через переменные
$selected_in_selector (для добавления) и $selected_in_selector = ($_SERVER['REQUEST_METHOD'] == 'POST' && isset($new_locale)) ? $new_locale : $i18n_locale; (для редактирования).
5. Итоговый функционал
После внесённых изменений плагин работает следующим образом:
- Добавление перевода:
- Форма отображается всегда, независимо от наличия перевода для текущего языка.
- Язык перевода выбирается строго через селектор.
- Проверка на уникальность предотвращает создание дубликатов.
- При ошибках все введённые данные сохраняются.
- После успешного добавления пользователь переходит на страницу с выбранным языком.
- Редактирование перевода:
- В форме присутствует селектор языка, где отображаются все доступные для выбора локали (исключая уже занятые, кроме текущей).
- Можно изменить язык перевода – запись будет обновлена для новой локали (с проверкой на уникальность).
- При ошибках данные не теряются.
- После успешного обновления – переход на страницу с новой локалью.
- Удаление перевода: без изменений.
- Обработка ошибок: все сообщения об ошибках выводятся через стандартный механизм
cot_display_messages(), поля формы заполнены ранее введёнными значениями. - Совместимость: все хуки сохранены, плагин остаётся расширяемым.
6. Инструкция по обновлению
- Скопируйте модифицированные файлы:
plugins/i18n/inc/i18n.page.phpthemes/ваша_тема/i18n.page.tpl (или plugins/i18n/i18n.page.tpl, если используется стандартный шаблон)
- Очистите кэш Cotonti:
- Удалите содержимое папки
datas/cache/. - Или через админ-панель: Администрирование → Очистка кэша.
При необходимости добавьте языковые константы (в файлы lang/ru/lang.php, lang/en/lang.php и т.д.):
$L['i18n_locale_selection']='Выберите язык';
$L['i18n_translation_exists']='Перевод для этого языка уже существует';
- Проверьте работу согласно сценариям тестирования (см. раздел 7).
7. Тестирование изменений
Рекомендуется проверить следующие сценарии:
- Добавление перевода:
- Перейти на страницу добавления для страницы без переводов. Выбрать язык, заполнить поля, отправить – перевод создаётся для выбранного языка.
- Попытаться добавить перевод для языка, который уже есть – должна появиться ошибка.
- Отправить форму с пустым заголовком – поля не сбрасываются, ошибка отображается.
- После успешного добавления проверить URL – он должен содержать выбранный язык (
?l=xx).
- Редактирование перевода:
- Открыть существующий перевод на редактирование. В селекторе должен быть выбран текущий язык.
- Изменить текст и выбрать другой язык (если он свободен) – после сохранения перевод должен отображаться для нового языка, старый исчезнуть.
- Попытаться изменить язык на уже занятый – ошибка.
- Отправить форму с ошибкой (пустой заголовок) – поля заполнены введённым текстом, селектор сохраняет выбранное значение.
- После успешного редактирования редирект на страницу с новым языком.
- Удаление перевода: проверить, что удаление работает корректно.
8. Заключение
Модифицированная версия плагина i18n полностью решает описанные проблемы. Теперь селектор языка выполняет свою прямую функцию – определяет локаль перевода при добавлении и позволяет изменять её при редактировании. Все внешние источники локали игнорируются, что исключает ошибки и неоднозначности. Улучшена также обработка ошибок – пользователь не теряет данные при неудачной отправке формы.
Данные изменения могут быть внедрены в любой проект на Cotonti, использующий стандартный плагин i18n, без потери совместимости с другими расширениями.