Как реализовать мультиязычный словарь интерфейса в 1С без лишних вызовов сервера?

Программист 1С v8.3 (Управляемые формы) IT и автоматизация бизнеса
← На главную

При разработке интернациональных или многоязычных конфигураций на платформе 1С:Предприятие 8 разработчики часто сталкиваются с необходимостью вывода текстовых сообщений, заголовков окон и предупреждений на языке текущего пользователя. Стандартный механизм платформы НСтр() отлично подходит для статических строк, зашитых в код. Однако, если перед нами стоит задача сделать словарь динамическим (с возможностью редактирования фраз в пользовательском режиме без изменения метаданных), стандартных функций становится недостаточно.

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

В чем опасность хранения словаря в справочнике?

На первый взгляд, самое очевидное решение — создать справочник СловарьИнтерфейса с реквизитами для каждого поддерживаемого языка (например, КодСтроки, ТекстRU, ТекстEN) и получать оттуда значения по мере необходимости. Рассмотрим, почему классический подход "запрос к справочнику при каждом выводе сообщения" является крайне неэффективным:

  1. Огромное количество вызовов сервера: Если при открытии формы, заполнении полей или выводе предупреждений система будет каждый раз обращаться к серверу (и тем более к базе данных) для получения текстовой строки, интерфейс начнет заметно "притормаживать" на медленных каналах связи.
  2. Потеря статического анализа кода: Использование конструкции вида ПолучитьСтрокуИзСловаря("ИмяКлюча") лишает разработчика возможности использовать стандартную проверку конфигурации. Если вы случайно удалите ключ или сделаете в нем опечатку, платформа не выдаст ошибку на этапе компиляции — сбой произойдет непосредственно у пользователя в процессе работы.
  3. Сложности при обновлении конфигурации: Если конфигурация является тиражной, перенос измененных текстов интерфейса между базами клиентов превращается в сложную задачу синхронизации данных справочников, в отличие от простого обновления кода конфигурации.

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

---

Решение №1: Глобальное кэширование словаря на клиенте (0 вызовов сервера в работе)

Наиболее производительный вариант — загрузить словарь фраз в оперативную память клиентского приложения один раз при старте системы. Для этого мы задействуем экспортную переменную в модуле управляемого приложения.

Рассмотрим по шагам, как реализовать этот механизм:

Шаг 1. Объявление глобальной переменной

Откроем Модуль управляемого приложения и объявим экспортную переменную, которая будет хранить структуру нашего словаря для текущей локали пользователя:

Перем глСловарьИнтерфейса Экспорт;

Шаг 2. Инициализация словаря при запуске

В этом же модуле в обработчике события ПриНачалеРаботыСистемы вызовем серверную функцию для получения подготовленного словаря. Сервер определит язык сеанса пользователя, соберет нужные строки и вернет на клиент уже готовую структуру:


Процедура ПриНачалеРаботыСистемы()
    
    #Если Клиент Тогда
        // Загружаем словарь фраз один раз при старте
        глСловарьИнтерфейса = ПолучитьСловарьИнтерфейсаНаСервере();
    #КонецЕсли
    
КонецПроцедуры

&НаСервере
Функция ПолучитьСловарьИнтерфейсаНаСервере()
    
    Словарь = Новый Структура;
    ТекущийКодЯзыка = ТекущийЯзыкСистемы(); // Например, "ru" или "en"
    
    // В данном примере мы заполняем словарь программно, 
    // но здесь может быть чтение из Справочника или общего макета JSON
    Если ТекущийКодЯзыка = "ru" Тогда
        Словарь.Вставить("Приветствие", "Добро пожаловать в систему!");
        Словарь.Вставить("ЗапросНомера", "Пожалуйста, введите номер документа:");
        Словарь.Вставить("ОшибкаСохранения", "Не удалось сохранить изменения.");
    Иначе // Английский по умолчанию
        Словарь.Вставить("Приветствие", "Welcome to the system!");
        Словарь.Вставить("ЗапросНомера", "Please enter the document number:");
        Словарь.Вставить("ОшибкаСохранения", "Failed to save changes.");
    КонецЕсли;
    
    Возврат Словарь;
    
КонецФункции

Шаг 3. Использование на клиенте

Теперь в любой клиентской процедуре модуля формы (или общего клиентского модуля) мы можем мгновенно обращаться к нашему словарю без единого серверного вызова:


&НаКлиенте
Процедура ПоказатьДиалогВвода()
    
    Оповещение = Новый ОписаниеОповещения("ПослеВводаДанных", ЭтотОбъект);
    
    // Получаем строку из глобальной переменной на клиенте
    ТекстЗаголовка = глСловарьИнтерфейса.ЗапросНомера; 
    
    ПоказатьВводСтроки(Оповещение, "", ТекстЗаголовка);
    
КонецПроцедуры

---

Решение №2: Использование JSON-макета для хранения фраз

Хранить строки перевода прямо в программном коде — не всегда удобно. Использование макетов табличных документов (MXL), как часто предлагают на форумах, избыточно нагружает память сервера при парсинге ячеек. Современным стандартом является использование формата JSON, хранящегося в текстовом макете конфигурации.

Проанализируем этот подход подробнее:

Шаг 1. Создание макета

Создадим общий макет с типом Текстовый документ и назовем его СловарьИнтерфейсаJSON. Наполним его структурированными данными:


{
  "ru": {
    "Welcome": "Добро пожаловать!",
    "EnterNumber": "Введите номер:",
    "Error": "Произошла ошибка!"
  },
  "en": {
    "Welcome": "Welcome!",
    "EnterNumber": "Enter number:",
    "Error": "An error occurred!"
  }
}

Шаг 2. Чтение и парсинг макета на сервере

Для быстрого разбора JSON воспользуемся встроенными механизмами платформы. Напишем функцию в общем серверном модуле:


Функция ПолучитьЛокализованныйСловарь(КодЯзыка) Экспорт
    
    Макет = ПолучитьОбщийМакет("СловарьИнтерфейсаJSON");
    ТекстJSON = Макет.ПолучитьТекст();
    
    Чтение = Новый ЧтениеJSON;
    Чтение.УстановитьСтроку(ТекстJSON);
    
    // Платформа 1С мгновенно преобразует JSON-строку в соответствие/структуру
    ПолныйСловарь = ПрочитатьJSON(Чтение);
    Чтение.Закрыть();
    
    // Возвращаем только ветку для текущего языка пользователя
    Если ПолныйСловарь.Свойство(КодЯзыка) Тогда
        Возврат ПолныйСловарь[КодЯзыка];
    Иначе
        // Возврат английского по умолчанию, если язык не найден
        Возврат ПолныйСловарь["en"];
    КонецЕсли;
    
КонецФункции

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

---

Решение №3: Общие модули с повторным использованием значений

Если вы не хотите использовать глобальные переменные в модуле управляемого приложения, отличной альтернативой станет механизм модулей повторного использования значений (кэшируемые модули).

Выясним, как настроить этот вариант работы:

  1. Создадим новый Общий модуль с именем СловарьПовтИсп.
  2. В свойствах модуля установите флаги Клиент (управляемое приложение), Сервер и свойство Повторное использование возвращаемых значений в положение На время сеанса.

Напишем внутри модуля функцию формирования словаря:


Функция ПолучитьСловарьДляЛокали(КодЯзыка) Экспорт
    
    Словарь = Новый Соответствие;
    
    // Наполняем структуру словаря
    Если КодЯзыка = "ru" Тогда
        Словарь.Вставить("Btn_Save", "Сохранить");
        Словарь.Вставить("Btn_Cancel", "Отмена");
    Иначе
        Словарь.Вставить("Btn_Save", "Save");
        Словарь.Вставить("Btn_Cancel", "Cancel");
    КонецЕсли;
    
    Возврат Словарь;
    
КонецФункции

Теперь при вызове этой функции из клиентского кода:


&НаКлиенте
Процедура НастройкаКнопок()
    
    КодЯзыка = ТекущийЯзыкСистемы();
    
    // Первый вызов за сеанс выполнит тело функции, 
    // последующие вызовы будут мгновенно возвращать результат из кэша
    Словарь = СловарьПовтИсп.ПолучитьСловарьДляЛокали(КодЯзыка);
    
    Элементы.КнопкаЗаписать.Заголовок = Словарь.Получить("Btn_Save");
    
КонецПроцедуры

Важное преимущество данного подхода: Кэш "на время сеанса" автоматически уничтожается при завершении работы пользователя, не оставляя следов в оперативной памяти устройства, а повторные обращения к функции происходят за доли миллисекунды.

---

Когда стоит использовать типовые механизмы БСП?

Если ваша самописная конфигурация разрабатывается с использованием Библиотеки Стандартных Подсистем (БСП), изобретать собственный велосипед не нужно. В БСП встроена готовая и мощная подсистема «Мультиязычные данные».

Она позволяет:

Для перевода элементов интерфейса самой платформы (заголовков реквизитов, кнопок, стандартных команд) лучше использовать стандартный механизм локализации 1С через синонимы объектов метаданных и файлы локализации, редактируемые в среде разработки 1С:EDT (Enterprise Development Tools) с плагином LangTool.

← На главную