Концепция локалей в Day.js

Day.js использует модель локалей как фундаментальный слой форматирования дат, парсинга и отображения временных значений. Локали определяют правила представления дат в различных языках и регионах: названия месяцев и дней недели, форматы относительного времени, порядок компонентов даты, особенности сокращений и грамматические формы.

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

Локаль в Day.js представляет собой объект конфигурации, включающий:

  • массивы названий месяцев и дней недели
  • форматы отображения времени
  • правила относительного времени (ago/in)
  • настройки первого дня недели
  • правила ординальных числительных
  • функции кастомного форматирования

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

Базовая локаль и поведение по умолчанию

По умолчанию используется английская локаль en. Это означает:

  • месяцы и дни недели отображаются на английском
  • относительное время: a few seconds ago, in 3 hours
  • стандартный порядок форматов
import dayjs from 'dayjs'

dayjs().format('MMMM D, YYYY')
// March 10, 2026

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

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

Локали в Day.js подключаются модульно. Каждая локаль представляет собой отдельный файл.

import dayjs from 'dayjs'
import 'dayjs/locale/ru'

dayjs.locale('ru')

dayjs().format('D MMMM YYYY')
// 10 марта 2026

Подключение происходит в два этапа:

  1. Импорт локали
  2. Установка активной локали через dayjs.locale()

При этом локаль применяется глобально для всех последующих операций форматирования.

Структура объекта локали

Каждая локаль представляет собой структурированный объект с предсказуемыми полями:

{
  name: 'ru',
  weekdays: ['воскресенье', 'понедельник', ...],
  months: ['январь', 'февраль', ...],
  formats: {
    LT: 'HH:mm',
    LTS: 'HH:mm:ss',
    L: 'DD.MM.YYYY',
    LL: 'D MMMM YYYY',
    LLL: 'D MMMM YYYY HH:mm',
    LLLL: 'dddd, D MMMM YYYY HH:mm'
  },
  relativeTime: {
    future: 'через %s',
    past: '%s назад',
    s: 'несколько секунд',
    m: 'минута',
    mm: '%d минут',
    h: 'час',
    hh: '%d часов',
    d: 'день',
    dd: '%d дней',
    M: 'месяц',
    MM: '%d месяцев',
    y: 'год',
    yy: '%d лет'
  },
  ordinal: n => `${n}-й`,
  week: {
    dow: 1
  }
}

Каждое поле отвечает за отдельный аспект локализации.

Форматы дат в локалях

Поле formats задаёт стандартизированные шаблоны отображения. Эти форматы используются внутри метода format() при передаче предустановленных токенов.

Основные уровни:

  • LT — время
  • L — короткая дата
  • LL — расширенная дата
  • LLL — дата и время
  • LLLL — полное текстовое представление

Пример различий между локалями:

dayjs.locale('en')
dayjs().format('LL')
// March 10, 2026

dayjs.locale('ru')
dayjs().format('LL')
// 10 марта 2026

Локаль изменяет не только слова, но и синтаксис представления даты.

Относительное время и его локализация

Функциональность относительного времени активируется через плагин relativeTime, который тесно связан с локалями.

import relativeTime from 'dayjs/plugin/relativeTime'
dayjs.extend(relativeTime)

После этого локаль начинает управлять формированием строк:

dayjs.locale('ru')

dayjs().subtract(5, 'minute').fromNow()
// 5 минут назад

dayjs().add(2, 'hour').fromNow()
// через 2 часа

Локаль определяет:

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

Ординальные числа

Поле ordinal отвечает за форматирование порядковых числительных:

ordinal: n => `${n}-й`

Используется в форматах, где присутствует позиционная нумерация:

dayjs('2026-03-10').format('DDo')
// 10-й

В разных локалях реализация ординалов может значительно отличаться:

  • английский: 1st, 2nd, 3rd
  • русский: 1-й, 2-й, 3-й
  • французский: 1er, 2e

Неделя и первый день недели

Локаль определяет начало недели через поле week.dow:

  • 0 — воскресенье
  • 1 — понедельник
week: {
  dow: 1
}

Это влияет на:

  • вычисление начала недели
  • форматирование недельных диапазонов
  • работу календарных UI-компонентов

Пример:

dayjs.locale('ru')
// неделя начинается с понедельника

Переключение локалей во время выполнения

Day.js позволяет динамически изменять локаль без пересоздания объектов дат.

dayjs.locale('en')
const d = dayjs()

dayjs.locale('ru')

d.format('LL')
// формат изменится на русском

Важно, что объект даты не содержит локаль внутри себя — локаль применяется при каждом вызове форматирования.

Локаль по умолчанию для экземпляров

Существует возможность задавать локаль для конкретного экземпляра:

dayjs().locale('ru').format('LL')

Это позволяет комбинировать разные локали в одном приложении без глобального переключения.

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

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

import dayjs from 'dayjs'

dayjs.locale({
  name: 'custom',
  months: ['M1', 'M2', 'M3'],
  weekdays: ['D0', 'D1', 'D2', 'D3', 'D4', 'D5', 'D6'],
  relativeTime: {
    future: '+%s',
    past: '-%s',
    s: 'now',
    m: '1m',
    mm: '%dm',
    h: '1h',
    hh: '%dh',
    d: '1d',
    dd: '%dd',
    M: '1mo',
    MM: '%dmo',
    y: '1y',
    yy: '%dy'
  }
}, null, true)

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

  • внутренних форматов приложений
  • компактных UI
  • нестандартных доменных языков

Влияние локалей на парсинг

Хотя основная роль локалей — форматирование, некоторые плагины используют их для парсинга.

Особенно это важно для:

  • customParseFormat
  • localizedFormat

Пример:

import customParseFormat from 'dayjs/plugin/customParseFormat'
dayjs.extend(customParseFormat)

dayjs('10 марта 2026', 'D MMMM YYYY', 'ru')

Здесь локаль критична для интерпретации текстовых месяцев.

Tree-shaking и оптимизация локалей

Модель подключаемых локалей в Day.js ориентирована на минимизацию размера сборки:

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

Пример оптимизированного импорта:

import 'dayjs/locale/ru'
import 'dayjs/locale/de'

Это позволяет ограничить итоговый bundle только нужными локалями.

Конфликты локалей и порядок подключения

Если подключено несколько локалей, активной считается последняя установленная:

dayjs.locale('en')
dayjs.locale('ru')

Форматирование будет использовать русскую локаль.

Для предотвращения конфликтов в крупных приложениях применяется явное управление контекстом локали через .locale() на уровне экземпляра.

Использование локалей в многоязычных интерфейсах

В интерфейсах с динамическим языковым переключением локали используются как реактивный слой:

  • язык пользователя → локаль Day.js
  • переключение языка → смена глобальной локали
  • отдельные компоненты → локаль на уровне экземпляра

Это обеспечивает согласованность отображения дат с остальным интерфейсом.

Ограничения модели локалей

Несмотря на гибкость, модель имеет ограничения:

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

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

Практическая роль локалей в архитектуре приложений

В архитектуре приложений локали в Day.js выступают как слой представления данных:

  • модель данных: timestamp
  • бизнес-логика: вычисления дат
  • слой представления: локализация

Такое разделение упрощает:

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