Суть проблемы
Если на сайте Cotonti установлен плагин i18n (многоязычность) и включены Handy URLs (ЧПУ) с префиксами языка, то при попытке сменить язык интерфейса внутри административной панели генерируются неправильные ссылки. Вместо корректного URL вида:
https://cotonti.local/admin/page
формируется ошибочный адрес:
https://cotonti.local/en/page?m=page
вместо нужного
https://cotonti.local/en/admin/page
В результате браузер переходит на несуществующую страницу, и пользователь видит ошибку 404 – Страница не найдена.
Почему так происходит
Плагин i18n в файле i18n.header.tags.php при построении ссылок для языкового селектора использует универсальную функцию cot_url(), передавая ей в качестве первого аргумента значение $i18n_ext. Для админ-панели эта переменная получает значение 'admin', но вызов cot_url('admin', $params) с сырыми GET-параметрами (например, m=other&p=extentionname) не даёт правильного пути с учётом настроек ЧПУ. Роутер строит URL так, будто это обычная фронтовая страница, что приводит к неверной структуре ссылки.
Решение
Необходимо явно обрабатывать случай админ-панели и принудительно формировать ссылку через cot_url('admin', $params), сохраняя все актуальные GET-параметры текущего запроса. При этом для фронтенда логика остаётся прежней.
Файл, который нужно изменить:/plugins/i18n/i18n.header.tags.php
Инструкция по исправлению:
- Откройте файл
/plugins/i18n/i18n.header.tags.phpв текстовом редакторе. - Найдите в цикле
foreach ($i18n_locales as $lc => $lc_title)блок, где формируется переменная$i18n_extи удаляетсяrwr. - Добавьте перед присвоением значения в шаблон проверку на
COT_ADMINи сохраните результат в переменную$url. - Замените строку
'I18N_LANG_ROW_URL' => cot_url($i18n_ext, $i18n_urlparams, '', false, true)на'I18N_LANG_ROW_URL' => $url.
Готовый исправленный фрагмент файла:
<?php
/* ====================
[BEGIN_COT_EXT]
Hooks=header.tags
Tags=header.tpl:{I18N_LANG_ROW_URL},{I18N_LANG_ROW_CODE},{I18N_LANG_ROW_TITLE},{I18N_LANG_ROW_CLASS},{I18N_LANG_ROW_SELECTED}
[END_COT_EXT]
==================== */
/**
* Renders language selector
*
* @package I18n
* @copyright (c) Cotonti Team
* @license https://github.com/Cotonti/Cotonti/blob/master/License.txt
*/
defined('COT_CODE') or die('Wrong URL');
if (count($i18n_locales) > 0) {
foreach ($i18n_locales as $lc => $lc_title) {
if ($lc === $i18n_locale) {
$lc_class = 'selected';
$lc_selected = 'selected="selected"';
} else {
$lc_class = '';
$lc_selected = '';
}
$i18n_urlparams = $_GET;
// Управление параметром языка в URL
if ($cfg['plugin']['i18n']['omitmain']
&& $lc === $i18n_fallback
&& (!$cfg['plugin']['i18n']['cookie'] || !cot_import('i18n_locale', 'COOKIE', 'ALP'))
) {
unset($i18n_urlparams['l']);
} else {
$i18n_urlparams['l'] = $lc;
}
// Определение расширения для роутинга
if (defined('COT_PLUG')) {
$i18n_ext = 'plug';
} else {
$i18n_ext = $env['ext'];
unset($i18n_urlparams['e']);
}
if (isset($i18n_urlparams['rwr'])) {
unset($i18n_urlparams['rwr']);
}
// === ИСПРАВЛЕНИЕ ДЛЯ АДМИН-ПАНЕЛИ ===
// При смене языка в админ-панели строим URL с префиксом /admin/
// Пример: https://cotonti.local/en/admin/page вместо ошибочного https://cotonti.local/en/page?m=page
if (defined('COT_ADMIN') && COT_ADMIN) {
$url = cot_url('admin', $i18n_urlparams, '', false, true);
} else {
// старый I18N_LANG_ROW_URL из $t->assign переносим сюда в else самого условия if (defined('COT_ADMIN') && COT_ADMIN) {
// 'I18N_LANG_ROW_URL' => cot_url($i18n_ext, $i18n_urlparams, '', false, true),
$url = cot_url($i18n_ext, $i18n_urlparams, '', false, true);
}
$t->assign([
'I18N_LANG_ROW_URL' => $url,
'I18N_LANG_ROW_CODE' => $lc,
'I18N_LANG_ROW_FLAG' => $lc === 'en' ? 'gb' : $lc,
'I18N_LANG_ROW_TITLE' => htmlspecialchars($lc_title),
'I18N_LANG_ROW_CLASS' => $lc_class,
'I18N_LANG_ROW_SELECTED' => $lc_selected,
]);
$t->parse('HEADER.I18N_LANG.I18N_LANG_ROW');
}
$t->parse('HEADER.I18N_LANG');
}
ВАЖНОЕ Примечание!!!!!!!!!
Данное исправление не затрагивает работу языкового селектора на пользовательской части сайта. Ветка else сохраняет оригинальное поведение для фронтенда. Проблема возникает исключительно в административной области из-за особенностей роутинга.
Если у вас используется другая версия плагина i18n или индивидуальная тема с кастомным языковым переключателем, принцип решения аналогичен: нужно обеспечить правильную генерацию URL для административного раздела через проверку COT_ADMIN.
Совместимость: Cotonti Siena 0.9.26 и выше, плагин i18n (стандартный).
Дата: 2026-Apr-19
после обновления всё слетит! я не в команде разработчиков Cotonti, - пишите им, если хотите чтоб записали рефакторинг под капот в ядро!