Динамическая смена языка

Механизм локализации интерфейса в компонентах выбора строится на разделении текстовых ресурсов и логики отображения. В случае Tom Select текстовые строки, используемые в подсказках, плейсхолдерах, сообщениях об отсутствии результатов и состояниях загрузки, выносятся в отдельный слой конфигурации и могут быть переопределены в рантайме без пересоздания всей структуры приложения.

Локализация в Tom Select опирается на набор ключей, соответствующих элементам интерфейса. Эти ключи группируются в объект, который передаётся через конфигурацию i18n. Каждый язык представляет собой независимый словарь.

const i18n_en = {
  no_results: 'No results found',
  loading: 'Loading...',
  add_item: 'Add',
  max_items: 'Maximum items reached',
  remove_item: 'Remove'
};

const i18n_ru = {
  no_results: 'Совпадений не найдено',
  loading: 'Загрузка...',
  add_item: 'Добавить',
  max_items: 'Достигнут лимит элементов',
  remove_item: 'Удалить'
};

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

Инициализация с поддержкой языка

При создании экземпляра Tom Select словарь передаётся через параметр i18n. Это фиксирует язык на этапе инициализации компонента.

const tom = new TomSelect('#select', {
  options: [
    { value: '1', text: 'Option 1' },
    { value: '2', text: 'Option 2' }
  ],
  i18n: i18n_en,
  placeholder: 'Select item'
});

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

Структура внутренних текстов Tom Select

Внутренние строки интерфейса распределены по нескольким зонам:

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

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

Динамическая смена словаря без пересоздания

Смена языка в рантайме возможна через обновление конфигурации экземпляра. Tom Select хранит ссылку на объект i18n, поэтому его можно заменить напрямую.

tom.settings.i18n = i18n_ru;
tom.refreshOptions(false);

Метод refreshOptions используется для обновления визуального состояния без полной перерисовки компонента. Однако не все строки обновляются автоматически, поскольку часть текста кэшируется при первичной отрисовке.

Для полного обновления интерфейса применяется принудительная перерисовка:

tom.clear();
tom.sync();
tom.refreshItems();

В зависимости от версии библиотеки может потребоваться дополнительное обновление placeholder:

tom.control_input.setAttribute('placeholder', tom.settings.placeholder);

Переключение языка через пересоздание экземпляра

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

tom.destroy();

tom = new TomSelect('#select', {
  options: [
    { value: '1', text: 'Option 1' },
    { value: '2', text: 'Option 2' }
  ],
  i18n: i18n_ru,
  placeholder: 'Выберите элемент'
});

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

Хранение и централизованное управление языками

При масштабных интерфейсах словари выносятся в отдельный модуль. Это позволяет управлять локализацией централизованно.

export const languages = {
  en: {
    no_results: 'No results found',
    loading: 'Loading...'
  },
  ru: {
    no_results: 'Совпадений не найдено',
    loading: 'Загрузка...'
  },
  kz: {
    no_results: 'Нәтиже табылмады',
    loading: 'Жүктелуде...'
  }
};

Далее используется индексный доступ к нужному языку:

function setLanguage(tom, lang) {
  tom.settings.i18n = languages[lang];
  tom.refreshOptions(false);
}

Синхронизация языка с внешним состоянием приложения

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

let currentLanguage = 'en';

function updateLanguage(lang) {
  currentLanguage = lang;
  tom.settings.i18n = languages[lang];
  tom.refreshOptions(false);
}

При этом важно учитывать, что некоторые элементы DOM могут сохранять старые строки, если они были сгенерированы до смены словаря.

Обновление динамических сообщений

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

tom.on('type', function() {
  tom.dropdown_content.innerHTML = tom.settings.i18n.loading;
});

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

Работа с placeholder и подсказками

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

function updatePlaceholder(tom, text) {
  tom.settings.placeholder = text;
  tom.control_input.setAttribute('placeholder', text);
}

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

Локализация пользовательских шаблонов

Tom Select позволяет переопределять рендеринг элементов через render. При динамической смене языка такие шаблоны также должны учитывать текущий словарь.

tom.settings.render.option = function(data, escape) {
  return `
    <div>
      <span>${escape(data.text)}</span>
      <small>${tom.settings.i18n.add_item}</small>
    </div>
  `;
};

После смены языка требуется повторное применение render-логики:

tom.refreshOptions(false);

Изоляция языковых зависимостей

Для предотвращения утечек состояния язык не должен храниться внутри отдельных элементов DOM. Все текстовые значения должны вычисляться на основе текущего состояния settings.i18n.

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

Поведение при асинхронной загрузке данных

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

tom.load(function(callback) {
  fetch('/api/items')
    .then(res => res.json())
    .then(data => {
      callback(data);
    });
});

В таких сценариях важно, чтобы текстовые сообщения не были зафиксированы до завершения запроса.

Обновление состояния без потери выбора

При динамической смене языка важно сохранять выбранные значения. Tom Select хранит их отдельно от текстовых меток, поэтому обновление словаря не должно затрагивать value.

const selected = tom.getValue();

tom.settings.i18n = i18n_ru;
tom.refreshOptions(false);

tom.setValue(selected);

Такое разделение обеспечивает независимость данных и представления.

Управление множественными экземплярами

При наличии нескольких селектов с разными языками необходимо избегать глобального изменения словаря. Каждый экземпляр должен иметь собственный i18n объект.

const tom1 = new TomSelect('#select1', {
  i18n: i18n_en
});

const tom2 = new TomSelect('#select2', {
  i18n: i18n_ru
});

Общие ссылки на один объект словаря приводят к одновременному изменению всех компонентов.

Обновление интерфейса после смены языка

После изменения языка требуется синхронизация следующих частей интерфейса:

  • список выбранных элементов
  • выпадающий список
  • placeholder
  • сообщения состояния
  • пользовательские render-шаблоны
function applyLanguage(tom, lang) {
  tom.settings.i18n = languages[lang];

  tom.refreshOptions(false);
  tom.refreshItems();
  tom.control_input.setAttribute('placeholder', tom.settings.placeholder);
}

Комплексное обновление исключает частичное отображение старых текстов.

Ограничения динамической локализации

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

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