Категории форума

Проблема: Некорректная работа переключателя языка в админ-панели Cotonti при использовании плагина i18n и ЧПУ

Сайт на Cotonti, если установлен плагин i18n (многоязычность) и включены Handy URLs (ЧПУ) с префиксами языка, то при попытке сменить язык интерфейса внутри административной панели генерируются неправильные ссылки и получаем ошибку 404.


webitproff
webitproff • 19.04.2026 18:32 #1

Суть проблемы 

Если на сайте 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

Инструкция по исправлению:

  1. Откройте файл /plugins/i18n/i18n.header.tags.php в текстовом редакторе.
  2. Найдите в цикле foreach ($i18n_locales as $lc => $lc_title) блок, где формируется переменная $i18n_ext и удаляется rwr.
  3. Добавьте перед присвоением значения в шаблон проверку на COT_ADMIN и сохраните результат в переменную $url.
  4. Замените строку '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, - пишите им, если хотите чтоб записали рефакторинг под капот в ядро!

Отредактировано: webitproff (20.04.2026 14:42, 3 месяца назад)
2/2/0

🗿

🧙‍♂️ Радуйся, странниче добрый и честный! Не понапрасну привела тя стезя в земли сии. Зде бо мужи мудры и искусники дела писменнаго и численнаго, что куют словеса и плетут узоры кода, тайны разгадывают и знанием делятся, летописи множа и ремесло цифровое творя.
⬅️ Аще налево пойдеши — обрящеши грамоты древния, писания старинныя и свитки учения. ⬆️ Аще прямо — слово мудрое и совет от мужей разумеющих, что в деле кодописном искусны, получиши. ➡️ Аще направо — сам в писцы и летописцы внидеши, и в ремесло цифровое, где строки и знаки в дело живое обращаются, слово свое в память веков вложиши.
📝 Не медли же — нареки имя свое, и вниди в чин наш, и стань с нами в братстве, где код есть магия, а строки — заклятия живыя, числом и буквою слово едины суть.
🏰 Не тайно есть собрание сие, и не инициации в нем, но многое сокрыто от пришлых и ступалого, понеже не всякому открывается знание, но токмо ищущим и пребывающим в деле сем.

Рекомендуемые товары в этой теме

CotCP - шаблон админки, панели управления для Cotonti v.0.9.26

Минималистичная тема для панели управления CMF Cotonti Siena v.0.9.26, созданная на основе Bootstrap Темы и шаблоны для Cotonti

Украинская локализация для Cotonti

Данный пакет предназначен для внедрения полноценного украинского интерфейса в стандартной поставке Cotonti CMF

Установка, интеграция и адаптация плагинов под Cotonti CMF

профессиональные услуги по установке, глубокой интеграции и адаптации плагинов под Cotonti CMF, с Поддержка и услуги по Cotonti