<small>Предыдущие статьи:

- ➡️ [Раздел 23. Выбор js-оболочки](/docs/23-js)
- ➡️ [Раздел 24. Динамическая подпись](/docs/24-security-sign)
- ➡️ [Раздел 25. Защита доступа](/docs/25-security-access)
</small>
# SLOT-H: Принцип локализации

В системе локализация разделена на три типа в зависимости от источника текста и способа его перевода. Все они работают по единому принципу: при наличии перевода на текущий язык пользователя показывается перевод, при отсутствии - исходный текст.

---

## 1. Текст в коде

Тексты, которые жёстко зашиты в PHP-файлах, передаются через статический метод `\Config\CC::locale('....')`.

**Пример:**

```php
echo CC::locale('Добро пожаловать');
```
Для таких текстов существует сборщик, который сканирует код, находит все вызовы CC::locale() и актуализирует список строк для перевода. Эти строки сохраняются в таблицу tkeys.

В полной версии предусмотрен механизм автоматического перевода через API внешних сервисов. Он формирует первичный пул переводов в таблице tvalues. Первичный - потому что машинный перевод требует ручной корректировки, так как качество автоматического перевода недостаточно для production-использования.

Переводы выполняются на все языки, включённые в проекте (таблица project_languages).

Если перевод отсутствует, система возвращает исходный текст, переданный как аргумент в CC::locale().

## 2. Полноценные тексты
Это тексты, которые хранятся в таблице texts и управляются через административный интерфейс. Для них используется связанная таблица переводов t_texts.

Для таких текстов автоматизированный перевод не применяется. Большие объёмы текста при машинном переводе дают результат, неприемлемый с точки зрения носителей языка. Переводы выполняются вручную через интерфейс администратора.

Структура:

texts - основная таблица с исходными текстами

t_texts - таблица переводов, связанная с texts через поле parent

## 3. Переводные тексты в хранилище данных
Для таблиц, которые должны поддерживать переводы, в классе DbTable устанавливается свойство:

```php
public static $_translate = true;
```
Для работы с переводами необходимо:

Создать таблицу переводов с именем t_<имя основной таблицы>

В этой таблице обязательно должны быть поля:

language_id - идентификатор языка

parent - идентификатор записи из основной таблицы

Добавить поля, соответствующие переводимым полям основной таблицы (1:1 по именам и типам)

Программисту не нужно думать о JOIN-ах и данных. Его задача - работать с исходной моделью, без использования модели с префиксом t_. ORM автоматически формирует один запрос, получающий исходные данные таблицы и JSON, содержащий полный набор переводов.

Пример для демонстрации принципа:

В административной части вызывается:

```php
$links = \Modules\Base\Models\DbTables\Alias::getAll();
```
ORM генерирует следующий SQL-запрос:

```sql
SELECT 
  aliases.*,
  CONCAT(
    "{",
    GROUP_CONCAT(
      CONCAT(
        '"',
        dev.t_aliases.language_id,
        '":{"alias_name":"',
        REPLACE(
          REPLACE(
            REPLACE(
              IFNULL(dev.t_aliases.alias_name,''),
              '"',
              '\\"'
            ),
            '\n',
            '<br>'
          ),
          '\r',
          ''
        ),
        '"}'
      )
    ),
    "}"
  ) AS tblock
FROM 
  `dev`.`aliases` AS aliases
LEFT JOIN dev.t_aliases ON dev.t_aliases.parent = dev.aliases.alias_id
WHERE dev.aliases.alias_id IS NOT NULL
AND aliases.project_id = "1"
GROUP BY dev.aliases.alias_id
```
Все переводы собираются в JSON-поле tblock, которое затем парсится моделью. При вызове геттера модель проверяет наличие перевода на текущий язык и возвращает его, если он доступен.

## Единый принцип
Во всех трёх случаях действует одно правило:

Если перевод на текущий язык пользователя существует - показывается он. Если нет - показывается исходный текст.

Исходный текст для кода - это аргумент метода CC::locale(). Для данных - это значение в исходной таблице.

Программист работает только с исходными сущностями. Один раз создав таблицу с префиксом t_ и переопределив в классе признак переводной сущности, программист может забыть про переводы. Всё, что связано с JOIN-ами, группировкой и подстановкой переводов, берёт на себя ORM. Это делает систему устойчивой к отсутствию переводов: пользователь всегда видит текст, пусть и не на своём языке.

---

## Что дальше?

- ➡️ [Раздел 27. Запуск сервера очередей](/docs/27-queue-start)
- ➡️ [Раздел 28. Задачи сервера очередей](/docs/28-queue-tasks)
- ➡️ [Раздел 29. Хелперы](/docs/29-utils-helpers)
