Локализация интерфейса

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

Основные элементы, подлежащие локализации:

  • текстовые подсказки и плейсхолдеры
  • ARIA-метки и сообщения для скринридеров
  • формат отображаемых элементов списка
  • поведение фильтрации и сортировки, зависящее от языка
  • направление текста (LTR/RTL)

Базовая модель текстовых интерфейсов Awesomplete

Awesomplete не содержит централизованного i18n-слоя. Все строки формируются либо:

  • браузером (placeholder, value)
  • разработчиком (рендер списка)
  • через ARIA-атрибуты
  • через кастомные DOM-узлы

Типовая инициализация:

const input = document.querySelector("#city");

new Awesomplete(input, {
    list: ["London", "Paris", "Berlin"]
});

Локализация в такой модели начинается с внешнего управления текстовыми ресурсами:

const i18n = {
    ru: {
        placeholder: "Введите город",
        empty: "Ничего не найдено",
        help: "Используйте стрелки для навигации"
    },
    en: {
        placeholder: "Enter city",
        empty: "No results found",
        help: "Use arrow keys to navigate"
    }
};

Локализация placeholder и базового текста поля

Placeholder задаётся напрямую на input-элементе, поэтому перевод управляется вне Awesomplete:

function applyLocale(input, lang) {
    input.setAttribute("placeholder", i18n[lang].placeholder);
}

Такой подход важен из-за отсутствия абстракции в библиотеке: Awesomplete не перехватывает и не управляет значением placeholder.


ARIA-локализация и доступность

Awesomplete активно использует ARIA-атрибуты:

  • role=“listbox”
  • aria-expanded
  • aria-activedescendant
  • aria-label

Именно ARIA-слой является ключевым объектом локализации для скринридеров.

Пример переопределения ARIA-меток:

input.setAttribute("aria-label", i18n[lang].placeholder);

Для списка результатов можно расширять контейнер:

const awesomplete = new Awesomplete(input, {
    list: data
});

awesomplete.ul.setAttribute("aria-label", i18n[lang].help);

Локализация сообщений отсутствия результатов

Awesomplete не предоставляет встроенного текста «нет результатов». Этот сценарий реализуется через кастомный рендер или обработку события.

Подход через расширение item и filter:

new Awesomplete(input, {
    list: data,

    filter: function(text, input) {
        return text.toLowerCase().includes(input.toLowerCase());
    },

    item: function(text, input) {
        const li = document.createElement("li");
        li.textContent = text;
        return li;
    }
});

Добавление сообщения «ничего не найдено» выполняется вручную:

function renderEmpty(ul, lang) {
    const li = document.createElement("li");
    li.textContent = i18n[lang].empty;
    li.className = "awesomplete-empty";
    ul.appendChild(li);
}

Локализация списка данных (data layer)

Мультиязычность часто реализуется не через интерфейс, а через источники данных.

Структура локализованных данных:

const cities = {
    ru: ["Москва", "Санкт-Петербург", "Казань"],
    en: ["Moscow", "Saint Petersburg", "Kazan"]
};

Инициализация:

function setLanguage(input, lang) {
    input.awesomplete.list = cities[lang];
}

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


Локализация рендеринга элементов (item template)

Awesomplete позволяет полностью контролировать HTML элементов списка через item.

Это основной механизм адаптации под язык, включая:

  • порядок слов
  • форматирование
  • добавление переводов категорий

Пример:

new Awesomplete(input, {
    list: data,

    item: function(text, input) {
        const li = document.createElement("li");

        const label = document.createElement("span");
        label.textContent = text.name;

        const meta = document.createElement("small");
        meta.textContent = text.country;

        li.appendChild(label);
        li.appendChild(meta);

        return li;
    }
});

Для локализации достаточно подменять поля name, country в зависимости от языка.


Сортировка с учётом языковой специфики

Стандартная фильтрация Awesomplete не учитывает локализацию. При необходимости подключается Intl.Collator.

const collator = new Intl.Collator("ru");

new Awesomplete(input, {
    list: data,

    sort: function(a, b) {
        return collator.compare(a, b);
    }
});

Для разных языков:

const collator = new Intl.Collator(lang);

Это критично для языков с диакритикой и различными алфавитами.


RTL (Right-to-Left) поддержка

Awesomplete не имеет встроенной логики RTL, поэтому направление текста задаётся CSS и атрибутами DOM.

input.setAttribute("dir", "rtl");

И для контейнера:

awesomplete.ul.setAttribute("dir", "rtl");

CSS адаптация:

.awesomplete {
    direction: rtl;
    text-align: right;
}

Особое внимание требуется при:

  • позиционировании выпадающего списка
  • выравнивании иконок
  • обработке курсора навигации

Локализация клавиатурной навигации

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

Пример добавления динамического описания:

input.setAttribute(
    "aria-describedby",
    "awesomplete-help"
);

document.getElementById("awesomplete-help").textContent =
    i18n[lang].help;

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

Механизм смены локали строится поверх пересоздания или обновления конфигурации Awesomplete.

function updateLocale(input, lang) {
    input.setAttribute("placeholder", i18n[lang].placeholder);
    input.setAttribute("aria-label", i18n[lang].placeholder);

    input.awesomplete.list = cities[lang];
}

При сложных интерфейсах часто применяется полная переинициализация:

function rebuildAwesomplete(input, lang) {
    if (input.awesomplete) {
        input.awesomplete.destroy();
    }

    new Awesomplete(input, {
        list: cities[lang]
    });
}

Локализация через data-атрибуты

Иногда используется декларативный подход:

<input
    id="city"
    data-lang-ru-placeholder="Введите город"
    data-lang-en-placeholder="Enter city"
/>

И обработка:

function applyDataLocale(input, lang) {
    input.setAttribute(
        "placeholder",
        input.dataset[`lang${lang.toUpperCase()}Placeholder`]
    );
}

Такой способ удобен при статических страницах без i18n-библиотек.


Форматы отображения и региональные различия

Хотя Awesomplete не связан напрямую с числами и датами, часто автодополнение используется для:

  • дат
  • валют
  • адресов

Локализация в этих случаях строится через Intl:

const formatter = new Intl.DateTimeFormat(lang);

const item = {
    label: formatter.format(new Date())
};

И передача в список:

new Awesomplete(input, {
    list: items.map(i => i.label)
});

Обработка смешанных алфавитов и Unicode

Для корректной локализации критично учитывать Unicode-особенности:

  • нормализация строк (NFC/NFD)
  • регистронезависимое сравнение
  • игнорирование диакритики

Пример фильтрации:

function normalize(str) {
    return str.normalize("NFD").replace(/\p{Diacritic}/gu, "");
}

new Awesomplete(input, {
    filter: function(text, input) {
        return normalize(text.toLowerCase())
            .includes(normalize(input.toLowerCase()));
    }
});

Разделение языковых контекстов в одном приложении

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

const dataset = [
    { lang: "ru", value: "Москва" },
    { lang: "en", value: "Moscow" }
];

Фильтрация по активной локали:

new Awesomplete(input, {
    list: dataset.filter(i => i.lang === lang)
});

Локализация поведения ввода

Поведение автодополнения может отличаться по регионам:

  • акцент на префиксный поиск
  • разрешение суффиксов
  • чувствительность к регистру

Переопределение фильтра:

new Awesomplete(input, {
    filter: function(text, input) {
        return text.toLowerCase().startsWith(input.toLowerCase());
    }
});

Для некоторых языков (например, с иероглифическими системами) применяется более мягкий поиск через includes.


Изоляция языковой логики от UI слоя

На практике локализация Awesomplete строится по трёхслойной модели:

  • слой данных (переведённые списки)
  • слой логики (filter/sort/collator)
  • слой интерфейса (ARIA, item, placeholder)

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