Перейти к содержимому

Языковые файлы - сообщения, подстановки, второй язык

Выносим тексты из кода в языковые файлы: чтобы правка формулировки не была правкой логики, а второй язык не был переписыванием модуля.

Решение

Раскладываем файлы рядом с кодом:

/local/modules/vendor.shop/lib/sync.php
/local/modules/vendor.shop/lang/ru/lib/sync.php - тексты того же файла
/local/modules/vendor.shop/lang/en/lib/sync.php - и его же на втором языке
// путь после lang/<язык>/ повторяет путь к файлу с кодом

Языковой файл находят по пути, а не по имени модуля. Он повторяет путь к файлу с кодом, и файл, положенный не туда, платформа просто не увидит.

Подключаем сообщения и читаем их:

use Bitrix\Main\Localization\Loc;
Loc::loadMessages(__FILE__); // подключаем тексты этого файла
echo Loc::getMessage('VENDOR_SHOP_SYNC_START');
// в языковом файле: $MESS['VENDOR_SHOP_SYNC_START'] = 'Обмен запущен';
// вызов загрузки ставят один раз, в самом начале файла с кодом

Ключи начинают с имени модуля, потому что они общие для всего проекта. Ключ вида TITLE рано или поздно встретится в чужом файле, и один из двух текстов проиграет.

Подставляем значения в текст:

echo Loc::getMessage('VENDOR_SHOP_SYNC_DONE', ['#COUNT#' => $count, '#TIME#' => $sec]);
// в языковом файле: 'Обработано #COUNT# товаров за #TIME# секунд'
// склейка строк вместо замен ломает перевод: порядок слов в языках разный
// имена фраз начинают с имени модуля: так они не сталкиваются с чужими

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

Отдельно кладём тексты компонента:

components/vendor/cart/lang/ru/class.php - тексты кода компонента
components/vendor/cart/lang/ru/.parameters.php - названия параметров
components/vendor/cart/templates/.default/lang/ru/template.php - тексты шаблона

У компонента своя раскладка языковых файлов: отдельно код, отдельно параметры, отдельно шаблон. Текст шаблона в файле кода не найдётся, и наоборот.

Тексты для сотрудников и тексты для покупателей стоит разводить по ключам сразу. Формулировка в административной части живёт годами, а витринную правят к каждой акции, и общий ключ делает эту правку опасной.

Языковой файл читают целиком при первом обращении к нему. Складывать в один файл тексты всего модуля дешевле, чем дробить его на десятки маленьких, каждый со своим обращением к диску.

Второй язык добавляют копированием каталога и переводом значений. Ключи при этом не трогают: расхождение в ключах даёт пропавший текст ровно на том языке, на котором его никто не проверяет.

Типичные проблемы

Вместо текста выводится имя ключа.

Сообщения именно этого файла не подключены вызовом загрузки в самом его начале. Строку загрузки сообщений ставят до первого обращения к любому из этих текстов.

Текст не меняется после правки файла.

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

В тексте видны решётки вместо чисел.

Замены не переданы вторым аргументом при чтении сообщения. Подстановки в тексте сообщения работают только через этот второй аргумент вызова чтения.

На втором языке текст остался русским.

Для этого языка нет файла с таким ключом. Платформа в такой ситуации берёт язык по умолчанию.

Тексты шаблона компонента не подхватились.

Они лежат в языковом файле кода, а не шаблона. У шаблона компонента свой собственный каталог языковых файлов рядом с его разметкой.

Частые вопросы

Нужны ли языковые файлы, если сайт один и русский?

Полезны: правка формулировок перестаёт быть правкой кода. Это дешевле, чем кажется на старте.

Как назвать ключ сообщения?

Именем модуля с приставкой и смыслом текста. Ключи общие для всего проекта, и короткие имена конфликтуют.

Где взять список языков сайта?

В настройках сайта: язык задаётся там же, где и остальные его параметры. Код читает текущий язык из окружения.

Можно ли хранить тексты в базе?

Можно, но тогда их правка требует интерфейса и переноса между стендами. Файлы едут вместе с кодом.

Смежное

Первоисточник