Мультиязычные сайты

Как создать сайт на нескольких языках: настройки, URL-префиксы, _t объект, класс Core\I18n.

Мультиязычные сайты

apidcms поддерживает создание сайтов на нескольких языках через систему URL-префиксов, кук и объект перевода _t.

Как включить

В админке перейдите в Настройки (/admin/settings). Найдите две опции:

Настройка Описание Пример
site_language Базовый язык сайта ru
site_languages Дополнительные языки (JSON-массив) ["en", "de"]

После сохранения на фронтенде появится переключатель языков, а все страницы будут доступны с языковым префиксом в URL.

Важно: система opt-in — пока site_languages не заполнен, мультиязычность не активна.

Как это работает

URL-префиксы

Каждый дополнительный язык получает префикс в URL:

Базовый язык (ru) Английский (en)
/changelog /en/changelog
/docs/install /en/docs/install
/plugins /en/plugins

Базовый язык (site_language) не получает префикс — его URL остаются «голыми». Это позволяет сохранить обратную совместимость со старыми ссылками.

Кука site_lang

При посещении страницы с языковым префиксом система устанавливает куку site_lang на 1 год. Если пользователь переходит по ссылке без префикса, система проверяет куку и показывает сохранённый язык.

Переключение на базовый язык происходит через query-параметр ?lang=ru — он сбрасывает куку и возвращает базовую локаль.

Объект _t в шаблонах

Все переводы хранятся прямо в шаблоне base.html.twig в виде объекта _t:

{% set _t = {
  ru: {
    home: "Главная",
    docs: "Документация",
    changelog: "CHANGELOG"
  },
  en: {
    home: "Home",
    docs: "Documentation",
    changelog: "Changelog"
  }
} %}

Использование в любом шаблоне:

<h1>{{ _t[site_lang].changelog_heading }}</h1>
<a href="{{ url('/docs') }}">{{ _t[site_lang].docs }}</a>

Переменная site_lang автоматически передаётся во все шаблоны — она содержит текущий язык (ru или en).

Функция url()

Все внутренние ссылки должны использовать url(), а не жёсткие пути:

{# Правильно — префикс добавится автоматически #}
<a href="{{ url('/changelog') }}">Чейнджлог</a>

{# Неправильно — ссылка всегда ведёт на базовый язык #}
<a href="/changelog">Чейнджлог</a>

url() проверяет текущую локаль и, если она отличается от базовой, добавляет префикс:

  • При site_lang = en: url('/changelog') → /en/changelog
  • При site_lang = ru: url('/changelog') → /changelog

Служебные пути (/admin, /storage, /static) не получают префикс.

Переключатель языков

Минимальный переключатель в base.html.twig:

{% if get_setting('site_languages')|default('') is not empty %}
<div class="lang-switch">
    <a href="/{{ current_path }}?lang=ru"
       class="{% if site_lang == 'ru' %}active{% endif %}">RU</a>
    <a href="/en/{{ current_path }}"
       class="{% if site_lang == 'en' %}active{% endif %}">EN</a>
</div>
{% endif %}
  • Базовый язык (RU): /{current_path}?lang=ru — query-параметр сигнализирует о явном переключении
  • Дополнительный язык (EN): /en/{current_path} — URL-префикс

Переменная current_path содержит текущий путь без языкового префикса.

current_path

Переменная current_path автоматически очищается от префикса локали:

URL страницы site_lang current_path
/changelog ru changelog
/en/changelog en changelog
/en/changelog/v2-1-1 en changelog/v2-1-1

Это позволяет переключателю языков всегда формировать правильные ссылки.

Класс Core\I18n

Для продвинутой работы с переводами в PHP-коде используется класс Core\I18n.

resolve()

Извлекает значение для текущей локали из i18n-объекта:

use Core\I18n;

$title = I18n::resolve($item['title'], 'ru');  // {"ru":"Привет","en":"Hello"} → "Привет"
$title = I18n::resolve($item['title'], 'en');  // → "Hello"

resolveArray()

Рекурсивно обходит массив и разрешает все i18n-поля:

$items = I18n::resolveArray($items, 'en');
// Все поля вида {"ru":"...","en":"..."} будут заменены на англ. значение

Используется в FrontController::resolveI18nData() для автоматического перевода данных перед рендером.

searchExpr()

Экранирует поисковый запрос для разных локалей:

$expr = I18n::searchExpr($query, 'ru');

Полезно при реализации поиска на мультиязычных сайтах.

encode()

Кодирует значение с учётом локали:

$encoded = I18n::encode($value, 'ru');

Внешние страницы и contenturl{locale}

Для внешних страниц (changelog, плагины) можно указать разные URL контента для разных языков.

Вместо одного поля content_url используйте:

Поле Назначение
content_url URL по умолчанию (базовый язык)
content_url_ru URL для русской версии
content_url_en URL для английской версии

Если поле content_url_{locale} не задано, используется content_url.

Настройка <html lang>

Шаблон base.html.twig должен использовать site_lang для атрибута lang:

<html lang="{{ site_lang }}">

Это важно для SEO и доступности (screen readers).

Известные ограничения

  • Нет авто-редиректа. Система не перенаправляет с голого URL на префиксный. Если у пользователя установлена кука site_lang=en, а он заходит на /changelog, страница отобразится на английском, но URL останется без префикса.
  • Только префиксный метод. Нет поддержки поддоменов (en.example.com) или параметров (?lang=en для постоянного использования).
  • Переводы в шаблонах. Все строки _t хранятся в base.html.twig. Для больших проектов это может стать громоздким — рассмотрите вынос в отдельный Twig-файл через include.
  • Нет перевода контента. Система переводит только интерфейс (навигацию, кнопки, заголовки). Контент страниц (тексты, статьи) требует ручного дублирования для каждой локали.