Поддержка локалей

Архитектура интернационализации и роль локалей

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

Локализация в данном контексте не является встроенным механизмом ядра библиотеки, а реализуется через внешние слои — обёртки, словари сообщений и интеграцию с системами i18n. Это делает Validator.js гибким инструментом, который может адаптироваться под любые языковые среды без изменения исходного кода валидации.

Ключевая идея заключается в том, что каждая функция валидации возвращает либо true, либо false, либо строку-идентификатор ошибки, которая затем интерпретируется системой локализации.


Базовый принцип разделения логики и текста ошибок

Validator.js не навязывает формат сообщений об ошибках. В простейшем виде результат проверки выглядит так:

  • true — значение корректно
  • false — значение не прошло проверку
  • строка или код ошибки — идентификатор типа ошибки

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

const messages = {
  en: {
    required: "This field is required",
    email: "Invalid email format"
  },
  ru: {
    required: "Поле обязательно для заполнения",
    email: "Некорректный формат email"
  }
};

Валидационная функция при этом возвращает ключ:

function validateEmail(value) {
  return /\S+@\S+\.\S+/.test(value) ? true : "email";
}

Подключение локалей через обёртки

На практике Validator.js часто используется вместе с функциями-обёртками, которые сопоставляют результаты проверки с конкретной локалью.

Пример базового механизма:

function localizeValidator(validator, locale = "en") {
  return function(value) {
    const result = validator(value);

    if (result === true) return true;

    return messages[locale][result] || "Unknown error";
  };
}

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


Управление наборами локалей

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

Структура локалей обычно организуется следующим образом:

locales/
  en.json
  ru.json
  kz.json

Каждый файл содержит плоскую или иерархическую структуру сообщений:

{
  "required": "Поле обязательно",
  "email": "Некорректный email",
  "minLength": "Слишком короткое значение"
}

Validator.js в таком случае выступает только как генератор кодов ошибок, а не как источник текстов.


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

Одним из ключевых аспектов локализации является возможность изменения языка в рантайме. Это особенно важно для SPA-приложений.

Пример реализации:

let currentLocale = "en";

function setLocale(locale) {
  currentLocale = locale;
}

function translate(key) {
  return messages[currentLocale][key] || key;
}

В связке с Validator.js это позволяет мгновенно переключать язык интерфейса без повторной инициализации валидаторов.


Локализация встроенных правил валидации

Некоторые расширенные версии Validator.js или его обёртки включают предопределённые правила: email, URL, IP-адрес, длина строки и другие. Для них также требуется локализация.

Пример типовой структуры:

const validators = {
  email: (value) => /\S+@\S+\.\S+/.test(value) || "email",
  required: (value) => value !== undefined && value !== null && value !== "" || "required",
  minLength: (value, len) => value.length >= len || "minLength"
};

Далее слой локализации интерпретирует ключи:

const messages = {
  ru: {
    minLength: "Минимальная длина не соблюдена"
  }
};

Параметризованные сообщения

Сложные правила требуют передачи параметров в сообщения. Validator.js не ограничивает формат, поэтому часто используются шаблоны.

Пример:

const messages = {
  ru: {
    minLength: (len) => `Минимальная длина: ${len} символов`
  }
};

Использование:

function validateMinLength(value, len) {
  return value.length >= len ? true : { key: "minLength", params: { len } };
}

Обработчик локализации:

function resolveError(error) {
  if (typeof error === "string") {
    return translate(error);
  }

  if (typeof error === "object") {
    return messages[currentLocale][error.key](error.params.len);
  }
}

Интеграция с i18n-библиотеками

Validator.js часто используется совместно с системами интернационализации уровня приложения:

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

В таких случаях Validator.js полностью делегирует работу с текстами внешнему слою.

Типовая интеграция:

import i18n from "i18next";

function validateRequired(value) {
  return value ? true : "required";
}

function translateError(key) {
  return i18n.t(`validation.${key}`);
}

Кэширование локализованных сообщений

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

const cache = new Map();

function translateCached(key, locale) {
  const cacheKey = `${locale}:${key}`;

  if (cache.has(cacheKey)) {
    return cache.get(cacheKey);
  }

  const result = messages[locale][key];
  cache.set(cacheKey, result);

  return result;
}

Обработка множественных ошибок в разных локалях

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

function validatePassword(value) {
  const errors = [];

  if (value.length < 8) errors.push("minLength");
  if (!/[A-Z]/.test(value)) errors.push("uppercase");

  return errors.length ? errors : true;
}

Локализация:

function translateErrors(errors) {
  return errors.map(e => translate(e));
}

Стратегии расширения локалей

При росте приложения возникает необходимость поддержки дополнительных языков без изменения логики валидаторов. Используются следующие подходы:

  • подключение новых JSON-файлов локалей
  • динамическая загрузка переводов
  • lazy-loading языковых пакетов
  • разделение доменных переводов (forms, auth, profile)

Такая архитектура позволяет масштабировать Validator.js без модификации ядра.


Особенности работы с RTL-языками

При поддержке языков с направлением письма справа налево локализация затрагивает не только текст ошибок, но и представление форм. Validator.js не занимается UI, но передаёт корректные данные для адаптации интерфейса:

  • порядок сообщений
  • структура ошибок
  • кодировка текста

Это позволяет интеграционному слою корректно перестраивать визуальное отображение.


Расширенные сценарии локализации

В корпоративных системах Validator.js часто используется в связке с доменными правилами, где локализация выходит за рамки простого перевода:

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

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

const messages = {
  ru: {
    phone: "Неверный формат номера телефона РФ"
  },
  en: {
    phone: "Invalid phone number format"
  }
};