Система локализации в Tom Select строится вокруг набора текстовых строк, которые используются внутри компонента для отображения пользовательских сообщений: состояния загрузки, отсутствия результатов, подсказок поиска, ошибок и служебных уведомлений. Эти строки не являются частью бизнес-логики, но напрямую влияют на восприятие интерфейса, особенно в многоязычных приложениях и системах с динамически изменяемым языком.
Внутренние тексты компонента сгруппированы в объект конфигурации
render/plugins/settings, но
ключевой механизм локализации реализован через объект
render и переопределяемые строки конфигурации. В
стандартной поставке используется набор значений по умолчанию:
Каждое из этих сообщений может быть заменено на пользовательское значение через конфигурацию при инициализации.
Основной механизм переопределения системных сообщений заключается в передаче текстов через параметры инициализации:
new TomSelect("#select", {
render: {
no_results: function(data, escape) {
return `Ничего не найдено для "${escape(data.input)}"`;
},
loading: function(data, escape) {
return "Загрузка данных...";
}
}
});
Здесь каждая функция возвращает строку, которая будет отображена в соответствующем состоянии интерфейса. Использование функции вместо статической строки позволяет учитывать контекст ввода пользователя.
Функции рендера получают объект состояния компонента. Наиболее часто используемые поля:
input — текущий текст в поле поискаoptions — доступные элементыitems — выбранные элементыЭто позволяет формировать динамические сообщения, адаптирующиеся к действиям пользователя.
Некоторые сообщения задаются не через render, а через
отдельные параметры конфигурации. Это касается текстов, связанных с
удалением элементов и подсказками.
Пример изменения текста удаления выбранного элемента:
new TomSelect("#select", {
plugins: ["remove_button"],
render: {
item_remove: function(data, escape) {
return `<div class="remove-hint">Удалить</div>`;
}
}
});
Хотя в большинстве случаев используется плагин
remove_button, текст кнопки может быть стилизован или
заменён через кастомный рендер.
Наиболее важной частью системы является обработка сообщений поиска.
При отсутствии совпадений отображается сообщение
no_results. Его поведение критично для UX, особенно в
больших списках.
Типичный вариант локализации:
new TomSelect("#select", {
render: {
no_results: function(data, escape) {
if (!data.input.length) {
return "Введите запрос для поиска";
}
return `По запросу "${escape(data.input)}" ничего не найдено`;
}
}
});
Здесь реализована логика двух состояний:
Такой подход позволяет снизить когнитивную нагрузку и направить пользователя.
Для масштабных приложений строки выносятся в отдельные словари:
const i18n = {
ru: {
no_results: "Ничего не найдено",
loading: "Загрузка...",
create: (input) => `Создать "${input}"`
},
en: {
no_results: "No results found",
loading: "Loading...",
create: (input) => `Create "${input}"`
}
};
Инициализация компонента с выбором языка:
const lang = "ru";
new TomSelect("#select", {
render: {
no_results: () => i18n[lang].no_results,
loading: () => i18n[lang].loading,
option_create: (data, escape) => i18n[lang].create(escape(data.input))
}
});
Такой подход позволяет отделить UI-слой от логики локализации и упростить поддержку нескольких языков.
В ряде сценариев требуется смена языка без полной реинициализации
селекта. Для этого обновляются функции render и вызывается
принудительное обновление списка.
function updateLanguage(ts, lang) {
ts.settings.render.no_results = function(data, escape) {
return i18n[lang].no_results;
};
ts.settings.render.loading = function() {
return i18n[lang].loading;
};
ts.refreshOptions(false);
}
Метод refreshOptions используется для перерисовки
выпадающего списка без потери текущего состояния ввода.
В режиме create компонент позволяет добавлять новые
элементы, если они отсутствуют в списке. Соответствующее сообщение также
подлежит локализации.
new TomSelect("#select", {
create: true,
render: {
option_create: function(data, escape) {
return `
<div class="create-option">
Добавить: <strong>${escape(data.input)}</strong>
</div>
`;
}
}
});
Важно учитывать, что пользовательский ввод должен быть экранирован для предотвращения XSS.
Функция escape передаётся во все рендер-функции и
предназначена для безопасного вывода пользовательских данных. Она
обязательна при включении input в строки сообщений.
Типичная ошибка — прямое использование data.input без
экранирования:
// небезопасно
return `Ничего не найдено для ${data.input}`;
Корректный вариант:
return `Ничего не найдено для "${escape(data.input)}"`;
Это критично в системах, где ввод пользователя не ограничен.
Некоторые сообщения формируются внутри плагинов и требуют отдельной переопределяемой логики. Например, плагин множественного выбора может добавлять собственные подсказки.
new TomSelect("#select", {
plugins: ["remove_button"],
render: {
item: function(data, escape) {
return `<div class="item">${escape(data.text)}</div>`;
},
item_remove: function() {
return "×";
}
}
});
Здесь даже минимальные символы интерфейса могут быть локализованы или заменены в зависимости от языка или дизайна системы.
При сложной архитектуре приложения целесообразно формировать единый слой сообщений:
function createTomSelectI18n(lang) {
return {
no_results: (data, escape) => i18n[lang].no_results,
loading: () => i18n[lang].loading,
create: (input) => i18n[lang].create(input),
placeholder: i18n[lang].placeholder
};
}
Инициализация:
new TomSelect("#select", {
render: createTomSelectI18n("ru")
});
Такой подход упрощает масштабирование интерфейса и снижает дублирование логики.
При использовании remote data источников сообщения становятся частью UX обработки сети. В частности:
loading отображается при каждом запросеno_results появляется после завершения поискаnew TomSelect("#select", {
load: function(query, callback) {
fetch(`/api/search?q=${query}`)
.then(res => res.json())
.then(data => callback(data))
.catch(() => callback());
},
render: {
loading: () => "Поиск...",
no_results: () => "Результаты отсутствуют"
}
});
Здесь текстовые сообщения становятся частью асинхронного взаимодействия и должны учитывать задержки сети и ошибки API.
Продвинутые реализации используют контекст приложения для изменения сообщений. Например, в зависимости от роли пользователя или режима работы:
render: {
no_results: function(data, escape) {
return user.isAdmin
? "Элементы не найдены в базе данных"
: "Ничего не найдено";
}
}
Такой подход позволяет адаптировать интерфейс без изменения логики компонента, сохраняя единый механизм локализации.