Руководство по безопасному добавлению пользовательских строк локализации в Cotonti
Цель
Научиться выносить собственные языковые строки из стандартных файлов модулей и плагинов Cotonti в отдельные файлы. Это позволит избежать потери ваших переводов при обновлении ядра или расширений.
Для кого
Для начинающих и опытных пользователей Cotonti, которые хотят навести порядок в локализации и защитить свои данные от перезаписи.
Итоговое решение
Мы создадим небольшую функцию cot_langfile_custom, разместим её в файле system/functions.custom.php, а затем будем вызывать в любом языковом файле модуля или плагина. Кастомные строки будут храниться в той же папке lang, что и основные переводы, но в отдельном файле с суффиксом .custom. Такой подход не требует правки системных функций, полностью совместим со штатными механизмами Cotonti и безопасен при обновлениях.
Оглавление
1. Проблема: потеря пользовательских строк при обновлении
Представьте, что вы активно используете модуль Page. Со временем вы добавили в modules/page/lang/page.ru.lang.php около 400 собственных строк: подписи кнопок, описания, сообщения для посетителей. Всё работает отлично. Но при очередном обновлении Cotonti или самого модуля этот файл может быть заменён на новый из дистрибутива — и все ваши строки исчезнут.
Разумное решение — вынести пользовательские строки в отдельный файл, который не будет затрагиваться обновлениями. В идеале этот файл должен подгружаться автоматически вместе с основным языковым пакетом и учитывать текущий язык интерфейса (русский, английский и др.).
Cotonti предоставляет несколько механизмов для кастомизации языковых файлов, но они либо требуют размещения в удалённой директории datas/lang, что может показаться нелогичным (пользовательские строки модуля Page лежат где-то «у чёрта на куличках»), либо не работают для модулей напрямую. Мы пойдём другим путём — создадим простую универсальную функцию, которая подключает файл-спутник прямо из родной папки lang.
2. Архитектура решения
Мы будем использовать специальный файл system/functions.custom.php. Он загружается Cotonti автоматически, если в настройках включена опция «Использовать пользовательские функции» (customfuncs). Это стандартное и безопасное место для добавления собственных функций без правки ядра.
Наша функция cot_langfile_custom():
- Принимает имя расширения (например,
'page') и его тип ('module' или 'plug'). - Формирует путь к кастомному языковому файлу внутри папки
lang этого расширения. - Проверяет существование файла и при необходимости использует английскую версию как fallback.
- Подключает файл, добавляя все определённые в нём строки в глобальный массив
$L.
После этого в любом основном языковом файле (например, page.ru.lang.php) достаточно вставить одну строку вызова, обёрнутую проверкой существования функции. Это гарантирует, что даже если functions.custom.php не загружен (например, опция выключена), ошибки не произойдёт.
3. Подготовка: включаем пользовательские функции
По умолчанию Cotonti загружает system/functions.custom.php при наличии опции customfuncs. Убедитесь, что она включена.
- Зайдите в админ-панель → «Конфигурация» → «Основные настройки».
- Найдите пункт «Использовать пользовательские функции» (customfuncs) и установите значение «Да».
- Сохраните настройки.
Теперь система будет автоматически подключать functions.custom.php на каждом запуске.
4. Пишем функцию cot_langfile_custom
Откройте или создайте файл system/functions.custom.php (он должен находиться в корневой папке system вашего сайта). Добавьте в него следующий код.
/**
* Загружает пользовательский языковой файл для модуля или плагина.
*
* Ищет файл с именем `{name}.custom.{lang}.lang.php` в директории `lang/` расширения.
* Если файл для текущего языка не найден, пытается загрузить файл для языка по умолчанию (обычно 'en').
*
* @param string $name Имя расширения (например, 'page', 'aliaspagepro').
* @param string $type Тип расширения: 'module' или 'plug'. По умолчанию 'plug'.
* @param string $default Код языка по умолчанию, если `$lang` не задан или файл локализации отсутствует. По умолчанию 'en'.
*
* @return bool True, если пользовательский языковой файл был успешно загружен, иначе false.
*/
function cot_langfile_custom($name, $type = 'plug', $default = 'en')
{
// Получаем глобальные переменные конфигурации и текущий язык интерфейса
global $cfg, $lang, $L;
// Определяем код языка: используем текущий язык интерфейса или fallback по умолчанию
$langCode = isset($lang) ? $lang : $default;
// Формируем путь к директории lang расширения
if ($type === 'module') {
$dir = $cfg['modules_dir'] . '/' . $name . '/lang';
} else {
$dir = $cfg['plugins_dir'] . '/' . $name . '/lang';
}
// Основной файл для текущего языка
$file = $dir . '/' . $name . '.custom.' . $langCode . '.lang.php';
// Если файл существует и доступен для чтения, загружаем его
if (is_file($file) && is_readable($file)) {
include $file;
return true;
}
// Если текущий язык не является языком по умолчанию, пробуем загрузить файл языка по умолчанию
if ($langCode !== $default) {
$fallback = $dir . '/' . $name . '.custom.' . $default . '.lang.php';
if (is_file($fallback) && is_readable($fallback)) {
include $fallback;
return true;
}
}
// Пользовательский языковой файл не найден
return false;
}
Пояснения к каждой строке:
global $cfg, $lang; — подключаем глобальные переменные конфигурации и текущего языка.$langCode = isset($lang) ? $lang : $default; — на случай, если переменная $lang не определена (маловероятно, но для надёжности), берём английский по умолчанию.- Формирование пути
$dir — используем стандартные директории модулей или плагинов из конфигурации Cotonti. $file = $dir . '/' . $name . '.custom.' . $langCode . '.lang.php'; — вот шаблон имени кастомного файла: <имя_расширения>.custom.<код_языка>.lang.php. Например: page.custom.ru.lang.php.- Проверка
is_file и is_readable — гарантирует, что файл существует и доступен для чтения перед включением. - Fallback — если файла для нужного языка нет, но есть для английского, загружаем английский.
- Возврат
true или false позволяет понять, был ли загружен файл (может пригодиться для отладки).
Разместите этот код в конце functions.custom.php, если там уже есть что-то, или создайте файл с этим содержимым.
5. Именование и расположение кастомных языковых файлов
Теперь, когда функция готова, нужно правильно назвать и разместить сами файлы с вашими строками.
Для модуля Page (и любого другого модуля) создайте файлы:
modules/page/lang/page.custom.ru.lang.php — русские строки.modules/page/lang/page.custom.en.lang.php — английские строки.
Для плагина Alias Page PRO (имя плагина aliaspagepro):
plugins/aliaspagepro/lang/aliaspagepro.custom.ru.lang.phpplugins/aliaspagepro/lang/aliaspagepro.custom.en.lang.php
Общий шаблон:
<путь_к_расширению>/lang/<имя_расширения>.custom.<код_языка>.lang.php
где <имя_расширения> совпадает с именем папки модуля/плагина (как в первом параметре вызова функции).
Важно:
- Файлы должны начинаться с проверки
defined('COT_CODE') or die('Wrong URL.');. - Внутри определяйте любые строки через
$L['ключ'] = 'значение';. Ключи старайтесь делать уникальными, используя префикс расширения, например: $L['page_custom_login'] = 'Войти';.
6. Подключение кастомных строк в основном языковом файле
Теперь нужно сообщить системе, чтобы она загружала наш кастомный файл при загрузке основного. Для этого открываем языковой файл модуля/плагина, например:
modules/page/lang/page.ru.lang.phpplugins/aliaspagepro/lang/aliaspagepro.ru.lang.php
И в самом конце (или в начале, но лучше в конце, чтобы не мешать основным строкам) добавляем вызов:
if (function_exists('cot_langfile_custom')) {
cot_langfile_custom('page', 'module');
}
Или для плагина:
if (function_exists('cot_langfile_custom')) {
cot_langfile_custom('aliaspagepro', 'plug');
}
Что здесь происходит:
function_exists проверяет, определена ли наша функция. Если functions.custom.php по какой-то причине не загрузился, ошибки не будет — просто кастомные строки не подхватятся.- Затем вызываем функцию, передавая имя расширения и тип (module/plug). Функция сама найдёт кастомный файл для текущего языка и загрузит его.
Для многоязычных сайтов аналогичную строчку нужно добавить в каждый языковой файл, где вы хотите иметь кастомные переводы. Функция автоматически подставит код языка из глобальной переменной $lang.
7. Примеры
7.1. Модуль Page
Файл modules/page/lang/page.ru.lang.php (фрагмент в конце):
// ... стандартные строки модуля ...
// Пользовательские строки
if (function_exists('cot_langfile_custom')) {
cot_langfile_custom('page', 'module');
}
Файл modules/page/lang/page.custom.ru.lang.php:
<?php
defined('COT_CODE') or die('Wrong URL.');
$L['page_custom_contact'] = 'Свяжитесь с нами';
$L['page_custom_agree'] = 'Я принимаю условия';
// ... ещё 400 ваших строк ...
Теперь при загрузке русской версии сайта все эти строки будут доступны в шаблонах через {PHP.L.page_custom_contact} или в коде через $L['page_custom_contact'].
7.2. Плагин Alias Page PRO
Файл plugins/aliaspagepro/lang/aliaspagepro.ru.lang.php (фрагмент):
if (function_exists('cot_langfile_custom')) {
cot_langfile_custom('aliaspagepro', 'plug');
}
Файл plugins/aliaspagepro/lang/aliaspagepro.custom.ru.lang.php:
<?php
defined('COT_CODE') or die('Wrong URL.');
$L['aliaspagepro_custom_label'] = 'Мой кастомный текст';
8. Для английского языка и других языков
Вам нужно повторить действия:
- Создать аналогичные кастомные файлы с английскими строками (например,
page.custom.en.lang.php). - В английском языковом файле (
page.en.lang.php) добавить тот же вызов функции.
Функция cot_langfile_custom использует системный $lang для выбора языка. Если по какой-то причине кастомный файл для языка отсутствует, но включён fallback, то загрузится английская версия (или тот язык, который вы указали третьим параметром при вызове, по умолчанию 'en').
9. Проверка работы
- Создайте кастомный языковой файл с тестовой строкой.
- В основном файле добавьте вызов функции.
- Откройте любую страницу сайта на соответствующем языке.
- Убедитесь, что ошибок нет, и ваша строка отображается (если вы её где-то вывели).
В админке или логах не должно появляться предупреждений.
10. Преимущества данного подхода
- Никакого дублирования кода — один раз написали функцию, используем во всех расширениях.
- Файлы лежат рядом с основными переводами — логично и легко найти.
- Безопасность при обновлениях — ни
functions.custom.php, ни ваши кастомные файлы не перезаписываются стандартными обновлениями Cotonti (если вы не обновляете папку system вручную с заменой, но functions.custom.php специально создан для пользовательского кода). - Универсальность — работает с любыми модулями и плагинами.
- Простота — в основном языковом файле всего одна строка.
- Совместимость с многоязычностью — автоматически выбирается нужный язык.
11. Возможные проблемы и их решение
Проблема 1: Файл functions.custom.php не загружается
Проверьте настройку customfuncs в админке. Она должна быть включена. Также можно проверить наличие файла system/functions.custom.php на сервере.
Если опция выключена, можно включить её через конфигурационный файл datas/config.php:
$cfg['customfuncs'] = true;
Проблема 2: Кастомные строки не видны
- Убедитесь, что вызов
cot_langfile_custom находится в языковом файле модуля, а не в шаблоне. Функция должна отработать до использования строк. - Проверьте правильность имени кастомного файла. Оно должно строго соответствовать шаблону:
<имя_расширения>.custom.<код_языка>.lang.php. - Убедитесь, что файл не пуст и не содержит синтаксических ошибок. Можно временно добавить
echo 'test'; в начало файла и посмотреть, появится ли вывод на странице.
Проблема 3: Конфликт имён строк
Используйте уникальные префиксы для своих ключей, чтобы не переопределить системные строки. Например, page_custom_, myplugin_.
// Жёсткая проверка: если функция не существует, получим фатальную ошибку и увидим это
cot_langfile_custom('market', 'module');
// Дополнительно выводим, какой путь проверялся (если функция выполнилась)
$testDir = Cot::$cfg['modules_dir'] . '/market/lang';
$testFile = $testDir . '/market.custom.' . $GLOBALS['lang'] . '.lang.php';
echo "<!-- DEBUG: Проверяемый файл: $testFile -->";
if (!file_exists($testFile)) {
echo "<!-- DEBUG: ФАЙЛ НЕ НАЙДЕН! -->";
}
12. Дополнительные советы
- Храните кастомные файлы в системе контроля версий (Git), чтобы не потерять их при миграции сервера.
- Если вы обновляете ядро Cotonti вручную, не забывайте, что кастомные файлы не должны быть перезаписаны — они же новые. А вот сам
functions.custom.php может быть заменён, поэтому перед обновлением всегда делайте резервную копию этого файла. - Для автоматического создания языковых файлов можно использовать скрипты-генераторы, но это выходит за рамки руководства.
13. Почему не datas/lang?
Стандартный метод Cotonti с использованием datas/lang требует размещения файлов по пути вроде datas/lang/ru/modules/page.custom.ru.lang.php. Это рабочий вариант, но он разносит файлы модуля в разные ветки файловой системы. Многим пользователям удобнее, когда кастомные строки лежат бок о бок с оригинальными — так проще ориентироваться. Наше решение не противоречит идеологии Cotonti, потому что мы не меняем системные файлы, а добавляем собственные рядом.
14. Заключение
Теперь у вас есть простой и надёжный метод расширения языковых файлов Cotonti без риска потери данных. Вы можете применять его для любых существующих или будущих проектов.
Повторим краткий алгоритм действий:
- Убедитесь, что опция
customfuncs включена. - В
system/functions.custom.php добавьте функцию cot_langfile_custom. - Для каждого расширения, где нужны свои строки, создайте файл
<имя>.custom.<язык>.lang.php в папке lang этого расширения. В основном языковом файле (например, page.ru.lang.php) вставьте строку:
if (function_exists('cot_langfile_custom')) {
cot_langfile_custom('page', 'module');
}
- Наполните кастомный файл своими строками.
Всё готово. Приятной работы с Cotonti!