Локализованное форматирование

Локализованное форматирование в date-fns основано на концепции передачи локали (locale) в функции форматирования, что позволяет получать строки дат, адаптированные под язык, культурные особенности и правила конкретного региона. В отличие от встроенного Intl, библиотека предоставляет более предсказуемый API, единый стиль работы и возможность тонкой настройки отображения дат через подключаемые локали.


Каждая локаль в date-fns представляет собой набор правил:

  • названия месяцев и дней недели;
  • формы склонения;
  • правила форматирования относительных интервалов;
  • особенности грамматики (падежи, окончания);
  • словари для сокращений.

Локаль передаётся как опция:

import { format } from 'date-fns'
import { ru } from 'date-fns/locale'

format(new Date(2026, 0, 24), 'PPPP', { locale: ru })

Ключевой принцип: локаль не глобальная, а передаётся явно в каждую функцию.


Подключение локалей

Date-fns использует модульную структуру локалей. Каждая локаль импортируется отдельно:

import { enUS, de, fr, ru } from 'date-fns/locale'

Такой подход позволяет:

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

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

import { format } from 'date-fns'
import { enUS, ru } from 'date-fns/locale'

const locales = { en: enUS, ru }

function formatDate(date, lang) {
  return format(date, 'PPPP', { locale: locales[lang] })
}

Локализованное форматирование дат

Функция format поддерживает локализованные токены:

import { format } from 'date-fns'
import { ru } from 'date-fns/locale'

format(new Date(2026, 4, 22), 'EEEE, d MMMM yyyy', { locale: ru })

Результат:

пятница, 22 мая 2026

Основные локализованные токены

  • EEEE — полное название дня недели
  • EEE — сокращённое название дня недели
  • MMMM — полное название месяца
  • MMM — сокращённое название месяца
  • do — порядковый номер дня (с суффиксом в некоторых локалях)

Форматирование относительного времени

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

formatDistance

import { formatDistance } from 'date-fns'
import { ru } from 'date-fns/locale'

formatDistance(
  new Date(2026, 4, 22),
  new Date(2026, 4, 25),
  { locale: ru }
)

Результат:

3 дня

formatDistanceToNow

Используется для выражений типа «2 часа назад»:

import { formatDistanceToNow } from 'date-fns'
import { ru } from 'date-fns/locale'

formatDistanceToNow(new Date(2026, 4, 20), {
  locale: ru,
  addSuffix: true
})

Результат:

2 дня назад

Параметр addSuffix включает грамматическую форму с предлогами.


Локализованное относительное форматирование

Функция formatRelative формирует человекочитаемые строки с учётом контекста даты:

import { formatRelative } from 'date-fns'
import { ru } from 'date-fns/locale'

formatRelative(new Date(2026, 4, 22), new Date(), { locale: ru })

Возможные результаты:

  • «сегодня в 12:00»
  • «вчера в 18:30»
  • «на прошлой неделе в 14:00»

Логика зависит от расстояния между датами и внутренних правил локали.


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

1. Грамматические формы

Некоторые языки требуют изменения слов в зависимости от числа:

  • 1 день
  • 2 дня
  • 5 дней

Date-fns автоматически выбирает правильную форму на основе локали.


2. Контекстные изменения

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

  • английский: MMMM d, yyyy
  • русский: d MMMM yyyy

3. Сокращения и аббревиатуры

Локали содержат отдельные словари для:

  • коротких форм дней недели;
  • сокращённых месяцев;
  • неформальных выражений.

Комбинирование функций с локалями

Локаль можно применять последовательно в разных функциях:

import { format, formatDistance, formatRelative } from 'date-fns'
import { ru } from 'date-fns/locale'

const date = new Date(2026, 4, 22)

format(date, 'PPP', { locale: ru })
formatDistance(date, new Date(), { locale: ru })
formatRelative(date, new Date(), { locale: ru })

Это обеспечивает единообразие представления дат в интерфейсе.


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

Типичный сценарий — мультиязычное приложение:

import { format } from 'date-fns'
import { enUS, ru, de } from 'date-fns/locale'

const localeMap = {
  en: enUS,
  ru,
  de
}

function formatUserDate(date, lang) {
  return format(date, 'PPPP', {
    locale: localeMap[lang] || enUS
  })
}

Такой подход позволяет:

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

Работа с fallback-локалями

Если локаль отсутствует или не поддерживается, используется fallback:

format(date, 'PPPP', { locale: enUS })

Рекомендуется всегда задавать дефолтную локаль для предотвращения неоднородного вывода.


Пользовательские локали

Хотя date-fns не предназначен для создания локалей с нуля в стандартном использовании, локаль представляет собой обычный объект JavaScript, что позволяет модифицировать или расширять её:

import { ru } from 'date-fns/locale'

const customRu = {
  ...ru,
  formatDistance: {
    ...ru.formatDistance,
    lessThanXSeconds: 'мгновенно'
  }
}

Это даёт возможность:

  • адаптировать текст под продукт;
  • изменять стиль формулировок;
  • упрощать или усложнять локализацию.

Использование локали в сложных форматах

Некоторые токены полностью зависят от локали:

format(new Date(), 'P', { locale: ru })
format(new Date(), 'PP', { locale: ru })
format(new Date(), 'PPP', { locale: ru })
format(new Date(), 'PPPP', { locale: ru })

Каждый уровень добавляет детализацию:

  • короткий числовой формат;
  • расширенные текстовые формы;
  • полные локализованные представления.

Производительность локализации

Локали в date-fns оптимизированы:

  • импортируются отдельно;
  • не загружаются автоматически;
  • не влияют на базовый bundle без явного подключения.

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


Частые ошибки при локализации

Отсутствие передачи locale

format(date, 'PPPP') // всегда default enUS

Результат игнорирует нужный язык.


Неправильный импорт локали

import ru from 'date-fns/locale/ru' // некорректный путь в современных версиях

Корректный способ — через именованный экспорт:

import { ru } from 'date-fns/locale'

Смешивание разных локалей в UI

Если разные части интерфейса используют разные локали, возникает:

  • несогласованность форматов;
  • визуальный шум;
  • проблемы UX.

Архитектурный подход к локализации

При проектировании систем с date-fns часто выделяют слой форматирования:

// dateFormatter.js
import { format } from 'date-fns'

export function formatDate(date, locale, pattern = 'PPP') {
  return format(date, pattern, { locale })
}

Такой слой позволяет:

  • централизовать контроль локалей;
  • упростить тестирование;
  • обеспечить единый стиль отображения дат.