Библиотека Validator.js предоставляет набор функций для проверки
строковых значений (email, URL, числа, длина строки и др.), однако не
содержит встроенного механизма интернационализации. Все функции
возвращают либо true, либо false, не формируя
текстовые сообщения об ошибках. Это означает, что локализация
реализуется на уровне приложения, а не внутри библиотеки.
Ключевая особенность архитектуры Validator.js заключается в том, что она отделяет проверку данных от формирования пользовательских сообщений. Такой подход даёт полный контроль над тем, как и на каком языке будут отображаться ошибки.
Локализация валидационных сообщений строится вокруг трёх компонентов:
Validator.js используется только как слой проверки:
import validator from 'validator';
validator.isEmail('test@example.com'); // true
validator.isEmail('invalid-email'); // false
Сообщения формируются отдельно:
const messages = {
ru: {
email: 'Некорректный email адрес',
},
en: {
email: 'Invalid email address',
}
};
На практике создаётся слой абстракции, который связывает результат проверки с текстом ошибки.
import validator from 'validator';
const locale = 'ru';
const dictionary = {
ru: {
email: 'Некорректный email адрес',
required: 'Поле обязательно для заполнения'
},
en: {
email: 'Invalid email address',
required: 'This field is required'
}
};
function validateEmail(value) {
if (!value) {
return dictionary[locale].required;
}
if (!validator.isEmail(value)) {
return dictionary[locale].email;
}
return null;
}
Такой подход масштабируется на любое количество правил.
При увеличении количества полей ручное описание функций становится неудобным. Используется универсальный валидатор с конфигурацией правил:
import validator from 'validator';
const locale = 'ru';
const messages = {
ru: {
required: 'Поле обязательно',
email: 'Некорректный email',
minLength: (n) => `Минимальная длина: ${n}`
}
};
const rules = {
email: (value) => validator.isEmail(value),
required: (value) => value && value.trim().length > 0,
minLength: (value, n) => value.length >= n
};
function validate(value, ruleName, param) {
const rule = rules[ruleName];
const isValid = rule(value, param);
if (isValid) return null;
const message = messages[locale][ruleName];
return typeof message === 'function' ? message(param) : message;
}
Часто требуется динамическая подстановка значений (например, минимальная длина строки). Для этого используются функции или шаблоны.
minLength: (n) => `Минимальная длина ${n} символов`
function interpolate(template, params) {
return template.replace(/\{(\w+)\}/g, (_, key) => params[key]);
}
const messages = {
ru: {
minLength: 'Минимальная длина {n} символов'
}
};
interpolate(messages.ru.minLength, { n: 8 });
При работе с формами удобнее использовать единый механизм проверки набора полей.
import validator from 'validator';
const locale = 'ru';
const messages = {
ru: {
email: 'Некорректный email',
required: 'Поле обязательно',
minLength: 'Минимум {n} символов'
}
};
function validateField(value, rules) {
for (const rule of rules) {
if (rule.type === 'required' && !value) {
return messages[locale].required;
}
if (rule.type === 'email' && !validator.isEmail(value)) {
return messages[locale].email;
}
if (rule.type === 'minLength' && value.length < rule.value) {
return messages[locale].minLength.replace('{n}', rule.value);
}
}
return null;
}
В реальных приложениях локализация часто делегируется специализированным библиотекам, например i18next. Validator.js при этом остаётся только механизмом проверки.
import validator from 'validator';
import i18next from 'i18next';
function validateEmail(value) {
if (!validator.isEmail(value)) {
return i18next.t('validation.email');
}
return null;
}
Структура переводов:
{
"validation": {
"email": "Некорректный email",
"required": "Обязательное поле"
}
}
Такой подход позволяет:
Одним из ключевых архитектурных принципов является изоляция логики проверки от текста ошибок.
if (!validator.isEmail(value)) {
return 'Invalid email';
}
const isValid = validator.isEmail(value);
if (!isValid) {
return getMessage('email');
}
При масштабировании проекта используется многоуровневая структура:
const messages = {
ru: {
validation: {
email: 'Некорректный email',
password: {
minLength: 'Пароль слишком короткий',
weak: 'Слишком простой пароль'
}
}
},
en: {
validation: {
email: 'Invalid email',
password: {
minLength: 'Password too short',
weak: 'Password is too weak'
}
}
}
};
Доступ к сообщениям реализуется через вспомогательную функцию:
function t(path) {
return path.split('.').reduce((acc, key) => acc?.[key], messages[locale]);
}
Некоторые правила требуют контекста (например, сравнение дат или диапазонов чисел).
import validator from 'validator';
function validateAge(value, min, max) {
if (!validator.isInt(value + '')) {
return 'Возраст должен быть числом';
}
const age = parseInt(value, 10);
if (age < min || age > max) {
return `Возраст должен быть от ${min} до ${max}`;
}
return null;
}
При локализации такие строки также выносятся в словарь с параметризацией.
Переключение языка обычно реализуется через глобальный контекст:
let currentLocale = 'ru';
function setLocale(locale) {
currentLocale = locale;
}
function getLocale() {
return currentLocale;
}
Использование:
function getMessage(key) {
return messages[getLocale()][key];
}
В больших системах применяется модульная схема:
Пример структуры:
/validation
rules.js
validator.js
messages/
ru.js
en.js
index.js
Такое разделение упрощает:
Единый формат сообщений позволяет стандартизировать ошибки:
const error = {
field: 'email',
rule: 'email',
message: 'Некорректный email'
};
Это упрощает интеграцию с фронтенд-фреймворками и API.
При валидации формы часто требуется возвращать несколько ошибок одновременно:
function validateForm(data) {
const errors = {};
if (!validator.isEmail(data.email || '')) {
errors.email = messages.ru.email;
}
if (!data.password || data.password.length < 8) {
errors.password = 'Слишком короткий пароль';
}
return errors;
}
Отсутствие встроенной локализации в Validator.js является архитектурным преимуществом: библиотека остаётся минималистичной и независимой от UI-логики. Это позволяет строить любую систему локализации поверх неё — от простых словарей до сложных многоязычных платформ с динамическими правилами и контекстными сообщениями.