Локализация экстраполей в Cotonti (пример: статус товара)
Локализация экстраполей в Cotonti: подробная инструкция на конкретном примере для начинающих разработчиков
Введение (обзор проблемы и цели инструкции)
Возьмём конкретный пример: экстраполе с именем "product_status" (статус товара) для модуля "pages" (страницы, но представим, что это страницы товаров в вашем сайте-магазине). Это поле типа "select" (выпадающий список) с вариантами значений: "available" (в наличии), "out_of_stock" (нет в наличии), "running_low" (заканчивается), "on_order" (под заказ).
Почему именно "pages"? Потому что в Cotonti это одна из базовых сущностей, и пример из исходного кода был оттуда. Если у вас другой модуль (например, "market" или кастомный), принципы идентичны — просто замените 'pages' на имя вашей таблицы (например, 'market').
Что мы сделаем в этой инструкции:
- Добавим экстраполе в базу данных.
- Создадим локализацию для заголовка поля и для каждого значения варианта.
- Покажем, как использовать в PHP-коде модуля.
- Покажем вывод в шаблонах (TPL).
- Обработаем типичные ошибки.
- Дадим полный цикл тестирования.
- Всё с копируемыми примерами кода.
Теперь по шагам.
Шаг 1: Подготовка расширения и языкового файла
1.1. Создайте структуру плагина
Если у вас нет плагина — создайте папку plugins/my_shop/. Внутри:
- my_shop.php (основной файл плагина).
- my_shop.setup.php (для установки, включая добавление экстраполей).
- Папка lang/ с my_shop.ru.lang.php.
Почему плагин? Экстраполи можно добавлять в плагине или модуле — для новичков плагин проще, так как не требует полной структуры модуля.
1.2. Создайте языковой файл
Файл: plugins/my_shop/lang/my_shop.ru.lang.php
Содержимое (копируйте целиком):
<?php
// Защита от прямого доступа — обязательно, иначе хакеры могут вызвать файл напрямую.
defined('COT_CODE') or die('Wrong URL.');
// ── Заголовок поля: префикс 'page_' + имя поля 'product_status' + '_title' ──
// Это для функции cot_extrafield_title(). Без префикса может быть конфликт с другими полями.
$L['page_product_status_title'] = 'Статус товара';
// ── Локализация значений вариантов: имя поля 'product_status' + '_' + значение ──
// Значения — это ключи из вариантов в cot_extrafield_add() (см. шаг 2).
// Без префикса 'page_', потому что cot_build_extrafields_data() ищет именно так: $L['field_name' . '_' . $value].
// Если добавить 'page_' — локализация не сработает, выведет сырое значение (например, 'available' вместо 'В наличии').
$L['product_status_available'] = 'В наличии';
$L['product_status_out_of_stock'] = 'Нет в наличии';
$L['product_status_running_low'] = 'Заканчивается';
$L['product_status_on_order'] = 'Под заказ';
// ── Опционально: подсказка или хинт для админки/формы. Используйте в коде вручную.
$L['page_product_status_hint'] = 'Выберите статус товара: в наличии, нет и т.д.';
// ── Если нужно склонения (для чисел, но здесь не нужно) — используйте $Ls, но для статуса не актуально.Пояснение по именам:
- Заголовок: 'page_product_status_title' — префикс 'page_' обязателен, чтобы функция cot_extrafield_title() нашла его по приоритету (см. исходный код функции: сначала с префиксом, потом с location, потом без).
- Значения: 'product_status_available' — без 'page_', потому что в функции cot_build_extrafields_data() для типов select/radio/checklistbox код такой: (!empty($L[$extrafield['field_name'] . '_' . $value])) ? $L[$extrafield['field_name'] . '_' . $value] : $value;. То есть, field_name = 'product_status', value = 'available' → ищет 'product_status_available'.
- Если вы ошибётесь и напишете 'page_product_status_available' — функция не найдёт, и выведет 'available' (сырое значение из БД).
- Значения должны быть на латинице в ключах (available, out_of_stock), потому что в БД хранятся ключи, а не переводы. Переводы — только для вывода.
Типичная ошибка: Забыть defined('COT_CODE') — файл уязвим. Или использовать кириллицу в ключах — Cotonti не поймёт.
1.3. Установите плагин в админке
Зайдите в админ-панель Cotonti: /admin/extensions → Установить 'my_shop'. Это подключит lang-файл автоматически.
Шаг 2: Добавление экстраполя в setup-файл
Файл: plugins/my_shop/my_shop.setup.php
Содержимое (копируйте):
<?php
// Защита
defined('COT_CODE') or die('Wrong URL.');
// Добавляем экстраполе только если его нет (проверяется внутри функции).
// Параметры: location = 'pages' (таблица cot_pages), name = 'product_status' (имя колонки в БД: page_product_status).
// Тип 'select' — для выпадающего списка.
// Варианты: строка с ключами через запятую — 'available,out_of_stock,running_low,on_order'.
// Эти ключи будут храниться в БД (короткие, латиница, без пробелов).
// Default = 'available' — по умолчанию "в наличии".
cot_extrafield_add(
'pages', // Локация: таблица без 'cot_' (pages → cot_pages).
'product_status', // Имя поля: только a-z0-9_ (без '-', пробелов, кириллицы).
'select', // Тип: select для списка.
'', // HTML: оставьте пустым, Cotonti сам сгенерирует <select>.
'available,out_of_stock,running_low,on_order', // Варианты: ключи, которые будут в value опций.
'available', // Default: один из вариантов.
false, // Required: false — не обязательно.
'HTML', // Parse: HTML — парсинг как HTML (не актуально для select).
'Статус товара для страниц-магазина', // Description: для админки, видно в /admin/extrafields.
'', // Params: для select — пусто.
1, // Enabled: 1 — включено.
false, // Noalter: false — ALTER таблицу, добавит колонку page_product_status VARCHAR(255).
'' // Customtype: пусто, по умолчанию VARCHAR для select.
);
// Если нужно обновить позже — используйте cot_extrafield_update(), но для нового — add.Пояснение:
- Функция добавит запись в cot_extra_fields и ALTER'ит cot_pages, добавив колонку 'page_product_status' типа VARCHAR(255) DEFAULT ''.
- Варианты: 'available,out_of_stock...' — это ключи. В форме админки Cotonti покажет их как опции, но если есть локализация — в выводе (не в форме!) покажет переводы.
- В форме добавления страницы (админка) опции будут сырыми: "available", "out_of_stock" — потому что формы не локализуют варианты автоматически. Чтобы локализовать опции в форме, нужно кастомизировать форму (не в этой инструкции, но возможно через хуки).
- Почему VARCHAR? Смотрите исходный код cot_extrafield_add(): для select — "VARCHAR(255) DEFAULT ''".
- Ошибка: Если имя не alphanumeric — функция вернёт false (проверяет cot_import($name, 'D', 'ALP')).
- После выполнения: Очистите кэш в админке (/admin/cache) или кодом Cot::$cache->db->remove('cot_extrafields', 'system');.
Что если ошибка: Если "field already exists" — удалите вручную из cot_extra_fields и ALTER DROP COLUMN page_product_status.
Шаг 3: Использование в PHP-коде модуля (обработка данных)
Предполагаем, вы модифицируете модуль "pages" (или свой). В файле modules/pages/inc/pages.main.php (или в вашем плагине через хук 'pages.page.loop') добавьте цикл для экстраполей.
Код (добавьте в место, где формируется $temp_array для шаблона):
// Проверяем, есть ли экстраполи для pages.
if (!empty(Cot::$extrafields[Cot::$db->pages])) {
// Цикл по всем экстраполям (Cot::$extrafields['cot_pages'] — глобальный кэш полей).
foreach (Cot::$extrafields[Cot::$db->pages] as $exfld) {
// Тег для шаблона: uppercase имени поля (PRODUCT_STATUS).
$tag = mb_strtoupper($exfld['field_name']); // 'PRODUCT_STATUS'
// Префикс для заголовка — 'page_' (соответствует location).
$prefix = 'page_';
// Локализованный заголовок: cot_extrafield_title() ищет $L['page_product_status_title'].
// Если не найдёт — fallback на description или имя поля.
$exfld_title = cot_extrafield_title($exfld, $prefix);
$temp_array[$tag . '_TITLE'] = $exfld_title; // PAGE_PRODUCT_STATUS_TITLE = 'Статус товара'
// Значение из данных страницы: $page_data — массив из БД (предполагаем, он есть).
// Ключ в БД: 'page_product_status'.
$temp_value = isset($page_data['page_' . $exfld['field_name']]) ? $page_data['page_' . $exfld['field_name']] : null; // Например, 'running_low'
// Локализованное значение: cot_build_extrafields_data() для select ищет $L['product_status_running_low'] = 'Заканчивается'.
// Если не найдёт — вернёт 'running_low'.
// 'page' — имя сущности (не таблица), $page_data['page_parser'] — парсер страницы (обычно 'HTML').
$temp_array[$tag] = cot_build_extrafields_data('page', $exfld, $temp_value, $page_data['page_parser']);
// Сырое значение (опционально, для условий в шаблоне).
$temp_array[$tag . '_VALUE'] = $temp_value; // 'running_low'
}
}
// Присваиваем в шаблон (предполагаем, $t — объект шаблонизатора).
$t->assign($temp_array);Пояснение:
- Cot::$extrafields[Cot::$db->pages] — массив всех экстраполей для pages (кэшируется).
- cot_extrafield_title($exfld, 'page_') — приоритет: $L['page_product_status_title'].
- cot_build_extrafields_data('page', ...): 'page' — это код сущности (в функциях Cotonti для pages — 'page', для users — 'user').
- Для select: если value = 'available' → ищет $L['product_status_available'] → 'В наличии'.
- Ошибка: Если префикс не 'page_' — может не найти заголовок.
- В реальном коде: Добавьте это в цикл по страницам (если список) или в single-страницу.
Шаг 4: Вывод в шаблонах (TPL)
Файл: themes/ваша_тема/page.tpl (или кастомный).
Добавьте
<!-- Блок статуса товара -->
<div class="product-status">
<strong>{PAGE_PRODUCT_STATUS_TITLE}:</strong> {PAGE_PRODUCT_STATUS}
<!-- Вывод: Статус товара: Заканчивается -->
<!-- Если сырое: {PAGE_PRODUCT_STATUS_VALUE} = running_low (для CSS-классов, например class="status-{PAGE_PRODUCT_STATUS_VALUE}") -->
</div>
<!-- Если в списке страниц (pages.list.tpl) -->
{PHP.L.page_product_status_title}: {LIST_ROW_PRODUCT_STATUS}Пояснение:
- Теги uppercase: {PAGE_PRODUCT_STATUS_TITLE} — из $temp_array.
- В админке: При редактировании страницы (/pages/edit/ид) поле появится автоматически с заголовком 'Статус товара' (из $L), опции — сырые ключи.
- Чтобы локализовать опции в форме: Нужно переопределить форму через хук 'pages.edit.tags', но это продвинутый уровень.
Шаг 5: Локализация в административной панели и формах
- В админке (/admin/extrafields?type=pages): Поле видно с description 'Статус товара для страниц-магазина'.
- В форме добавления/редактирования страницы: Заголовок — из cot_extrafield_title(), то есть 'Статус товара'.
- Опции: Cotonti генерирует <select> с value="available" и текстом "available" (сырым). Чтобы перевести опции в форме:
- В lang.php добавьте $L['product_status_available_option'] = 'В наличии'; (кастом ключ).
- В хуке pages.edit.tags модифицируйте HTML поля: используйте cot_default_html_construction('select') и замените тексты на $L['product_status_xxx_option'].
- Но для базовой инструкции — оставим сырые, так как фокус на выводе.
Шаг 6: Полный цикл тестирования
- Установите плагин: /admin/extensions → my_shop → Установить.
- Проверьте БД: В phpmyadmin посмотрите cot_pages — есть колонка page_product_status.
- Добавьте страницу: /pages/add → Заполните поле 'Статус товара' — выберите 'running_low'.
- Посмотрите страницу: /pages/ид — должно быть 'Статус товара: Заканчивается'.
- Если 'running_low' вместо перевода — проверьте ключ в lang: $L['product_status_running_low'].
- Смените язык на en (если есть en.lang.php) — создайте аналогичный файл с английскими переводами.
- Очистите кэш после изменений.
Типичные проблемы и решения:
- Нет поля в форме: Не очистили кэш.
- Сырое значение: Ошибка в ключе $L (проверьте опечатку, например 'product_status_runnig_low' вместо 'running_low').
- Конфликт ключей: Если другой плагин имеет $L['product_status_available'] — добавьте уникальный префикс, но для значений это редко.
- ALTER не сработал: Проверьте права БД, или установите noalter=true и добавьте колонку вручную SQL: ALTER TABLE cot_pages ADD page_product_status VARCHAR(255) DEFAULT ''.
Шаг 7: Расширенные советы (для полноты)
- Для checklistbox: Тип 'checklistbox', варианты те же, но значение в БД — 'available,out_of_stock' (через запятую). В выводе: cot_build_extrafields_data() локализует каждый и соединит через $extrafield['field_params'] (по умолчанию ', ').
- Обновление: cot_extrafield_update('pages', 'old_name', 'product_status', ... ) — изменит имя колонки в БД.
- Удаление: Нет встроенной, вручную: DELETE FROM cot_extra_fields WHERE field_name='product_status' AND field_location='pages'; ALTER TABLE cot_pages DROP page_product_status;
- Многоязычность: Создайте my_shop.en.lang.php с $L['page_product_status_title'] = 'Product Status';
- Интеграция с поиском: В запросах SQL используйте page_product_status для фильтров.
- Если для structure: location='structure', prefix='structure_', tag='CAT_PRODUCT_STATUS'.
Comments (0)
Content author
Offline
Sodium Carbonate
Last logged: 2026-07-20 04:22
- Page published: 2026-03-01 08:36
- Last update: 2026-04-24 06:19