Интернационализация (i18n)
Добавление новых языков в админ-панель apidcms. JSON-пакеты, функция lang() в Twig, хелпер __t() в JavaScript.
Интернационализация (i18n) в apidcms
apidcms поддерживает мультиязычный интерфейс админ-панели. Система построена на JSON-пакетах, функции lang() в Twig-шаблонах и хелпере __t() в JavaScript.
Как это работает
system_settings.admin_language = "en"
↓
Lang::getInstance('en')
↓
1. Загружает admin/lang/ru.json как базу (fallback)
2. Поверх накладывает admin/lang/en.json (перекрывает совпадающие ключи)
↓
{{ lang('sidebar.home') }} → "Home" (если en.json содержит ключ)
"Главная" (если ключа нет — fallback на ru)
Структура языковых файлов
core_lib/admin/lang/
├── ru.json ← 1200 ключей (обязательный, fallback)
└── en.json ← 1200 ключей (канонические имена)
Формат ключей: section.subsection.element
{
"sidebar.home": "Главная",
"common.save": "Сохранить",
"table.back_to_list": "Назад к списку таблиц",
"settings.maintenance_on": "Включён — посетители видят заглушку"
}
Параметры через {name} плейсхолдеры:
{
"forms.saved": "Форма '{name}' сохранена",
"table.confirm_delete": "Удалить запись #%id%?"
}
Жёсткие правила
- Канонический язык — английский. Ключи только на английском (
sidebar.home, а несайдбар.главная) - Русский всегда полный. Каждый ключ в
en.jsonОБЯЗАН иметь запись вru.json - Fallback на русский. Если ключ отсутствует в выбранной локали, возвращается русский перевод
- Двойные скобки в Twig.
{{ lang('key') }}— двойные. Одинарные{ }Twig выводит как текст $this->lang->t()в контроллерах. НеLang::t()статически —__callStaticне работает в PHP 8
Использование в Twig-шаблонах
{# Простой ключ #}
<h1>{{ lang('sidebar.home') }}</h1>
{# С параметрами #}
<p>{{ lang('table.empty_no_data')|replace({'%table%': tableName}) }}</p>
{# В атрибутах #}
<input placeholder="{{ lang('table.search_placeholder') }}">
{# В JavaScript (через __t) #}
<script>
alert(__t('filemanager.link_copied'));
</script>
Использование в PHP-контроллерах
// Заголовок страницы
$data['title'] = $this->lang->t('settings.page_title');
// Флеш-сообщение с параметрами
$this->setFlash('success', $this->lang->t('forms.form_saved', ['name' => $name]));
// Исключение
throw new Exception($this->lang->t('settings.key_not_specified'));
Использование в JavaScript
// window.__lang содержит все 1200 ключей
// __t(key) — краткий хелпер
showNotification(__t('filemanager.link_copied'), 'success');
// С конкатенацией
alert(__t('filemanager.error_upload') + ': ' + error.message);
Как добавить новый язык
1. Создать JSON-пакет
cp core_lib/admin/lang/en.json core_lib/admin/lang/de.json
2. Перевести значения
Отредактировать de.json — заменить английские значения на целевой язык. Ключи не трогать.
{
"sidebar.home": "Startseite",
"common.save": "Speichern",
...
}
Не обязательно переводить все 1200 ключей сразу. Отсутствующие ключи автоматически вернут русский перевод (fallback).
3. Добавить язык в настройки
В admin/app/views/settings/index.html.twig найти выпадашку языка:
<select name="settings[admin_language]" ...>
<option value="ru">Русский</option>
<option value="en">English</option>
<option value="de">Deutsch</option> ← добавить
</select>
4. Применить
sync-core all
# Сбросить кэши на всех сайтах
После этого новый язык появится в выпадашке Настройки → Основные → Язык интерфейса.
Аудит переводов
Для проверки полноты перевода используйте поиск:
# Найти все вызовы lang() в шаблонах
grep -roh "lang('[^']*'" admin/app/views/ | sort -u
# Проверить наличие в JSON (Python)
python3 -c "
import json, re, os
with open('admin/lang/en.json') as f:
keys = set(json.load(f).keys())
# Найти ключи из шаблонов, которых нет в JSON
for path in ...:
...
"
Класс Lang
namespace Admin\Core;
class Lang {
public static function getInstance(string $locale = 'ru'): self;
public static function reload(string $locale): self; // смена языка
public function t(string $key, array $params = [], ?string $default = null): string;
public function getLocale(): string;
public function all(): array; // все переводы для window.__lang
}
Текущее состояние
| Язык | Ключей | Статус |
|---|---|---|
| Русский (ru) | 1200 | Полный ✅ |
| Английский (en) | 1200 | Полный ✅ |