Переопределение сообщений

В связке с react-hook-form и Yup резолвер выполняет функцию промежуточного слоя между схемой валидации и формой. Именно на этом этапе происходит формирование структуры ошибок, их нормализация и передача в UI. Переопределение сообщений в этом контексте затрагивает сразу несколько уровней: сообщения внутри самой схемы Yup, глобальные локали, трансформацию ошибок в резолвере и постобработку результата перед возвратом в форму.

Источники сообщений в Yup

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

Сообщения по умолчанию

Каждое правило валидации Yup содержит дефолтный текст ошибки:

Yup.string().required()
// "this field is a required field"

Эти сообщения используются, если не задано явное переопределение.

Переопределение на уровне схемы

Наиболее прямой способ управления текстом ошибки — передача строки в метод валидации:

Yup.string().required('Поле обязательно для заполнения')

или с параметрами:

Yup.string().min(3, 'Минимум ${min} символа')

В этом случае Yup выполняет интерполяцию переменных (${min}, ${max}, ${path}), формируя итоговое сообщение.

Использование объекта конфигурации

Некоторые методы поддерживают объектный синтаксис:

Yup.string().matches(/^[a-z]+$/, {
  message: 'Допустимы только латинские буквы',
  excludeEmptyString: true
})

Это расширяет контроль над условиями генерации ошибки.

Глобальное переопределение через setLocale

Yup предоставляет механизм глобальной локализации сообщений через setLocale. Этот уровень влияет на все схемы, если не задано локальное переопределение.

import * as Yup from 'yup'

Yup.setLocale({
  mixed: {
    required: 'Обязательное поле',
    default: 'Некорректное значение'
  },
  string: {
    min: 'Минимальная длина ${min} символа',
    max: 'Максимальная длина ${max} символов'
  },
  number: {
    min: 'Значение должно быть не меньше ${min}',
    max: 'Значение должно быть не больше ${max}'
  }
})

Особенности приоритетов

Приоритет сообщений строится следующим образом:

  1. Явно заданное сообщение в методе (required('...'))
  2. Локаль, заданная через setLocale
  3. Встроенные сообщения Yup

Роль YupResolver в формировании сообщений

YupResolver не генерирует сообщения самостоятельно. Его задача — преобразовать ошибки Yup в структуру, совместимую с react-hook-form.

import { yupResolver } from '@hookform/resolvers/yup'

Процесс выглядит следующим образом:

  1. Выполняется валидация схемы Yup
  2. Yup возвращает ValidationError
  3. Резолвер извлекает inner массив ошибок
  4. Формируется объект вида:
{
  fieldName: {
    type: 'validation_type',
    message: 'текст ошибки'
  }
}

Переопределение сообщений через трансформацию в резолвере

Хотя YupResolver не предоставляет встроенного API для изменения сообщений, возможна постобработка результата.

Базовая трансформация ошибок

const customResolver = async (schema, values, context, options) => {
  const result = await yupResolver(schema)(values, context, options)

  const transformedErrors = Object.fromEntries(
    Object.entries(result.errors || {}).map(([key, error]) => {
      return [
        key,
        {
          ...error,
          message: `[FORM ERROR] ${error.message}`
        }
      ]
    })
  )

  return {
    ...result,
    errors: transformedErrors
  }
}

Такой подход используется для:

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

Условное переопределение сообщений

В ряде случаев требуется динамическое изменение текста в зависимости от контекста формы.

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

Yup поддерживает context, который передаётся из резолвера:

Yup.string().required('${label} обязательно')

Передача контекста:

yupResolver(schema, undefined, {
  context: {
    label: 'Имя пользователя'
  }
})

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

Кастомные тесты с динамическими сообщениями

Yup.string().test(
  'custom-check',
  function (value) {
    const { path, createError } = this

    if (!value || value.length < 5) {
      return createError({
        path,
        message: `Поле ${path} должно содержать минимум 5 символов`
      })
    }

    return true
  }
)

Переопределение сообщений на уровне полей формы

В архитектуре react-hook-form сообщения можно модифицировать после получения результата резолвера.

Перехват ошибок через setError

setError('username', {
  type: 'manual',
  message: 'Пользовательское сообщение'
})

Этот механизм не связан напрямую с Yup, но часто используется для замещения сообщений, пришедших из резолвера.

Нормализация сообщений

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

Пример нормализации

const normalizeError = (error) => {
  if (!error) return error

  return {
    ...error,
    message: error.message?.trim().replace(/\.$/, '')
  }
}

Используется для:

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

Локализация сообщений

Переопределение сообщений часто связано с интернационализацией.

Статическая локализация через setLocale

Yup.setLocale({
  string: {
    required: 'Требуется заполнение поля'
  }
})

Динамическая локализация

Интеграция с i18n системами:

Yup.string().required(t('validation.required'))

или через фабрику схем:

const createSchema = (t) =>
  Yup.object({
    email: Yup.string().required(t('email_required'))
  })

Переопределение сообщений для вложенных объектов

При работе с вложенными схемами ошибки могут иметь путь вида user.email.

Модификация структуры ошибок

const flattenErrors = (errors) => {
  return Object.keys(errors).reduce((acc, key) => {
    acc[key.replace(/\./g, '_')] = errors[key]
    return acc
  }, {})
}

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

Приоритеты переопределения сообщений в комплексных схемах

В сложных схемах с вложенными объектами и массивами действует многоуровневая система приоритетов:

  • локальное сообщение поля
  • сообщение внутри test
  • сообщение из setLocale
  • дефолт Yup
  • постобработка резолвера
  • UI-переопределение через setError

Интеграционные сценарии с YupResolver

При использовании yupResolver в больших формах часто вводится слой адаптеров сообщений.

Пример адаптера сообщений

const messageAdapter = (error) => {
  const dictionary = {
    'this field is required': 'Обязательное поле',
    'must be a valid email': 'Некорректный email'
  }

  return {
    ...error,
    message: dictionary[error.message] || error.message
  }
}

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

Контроль стабильности сообщений

При масштабировании схем важным становится предотвращение расхождений в текстах.

Используются:

  • централизованные словари
  • фабрики схем
  • обёртки над yupResolver
  • единые трансформеры ошибок

Каждый из этих уровней может перехватывать и переопределять сообщения, формируя финальный текст, отображаемый в интерфейсе.