Переключение языков динамически

Динамическое переключение языков актуально для многоязычных приложений, где пользователь может сменить интерфейсный язык в runtime. timeago.js поддерживает это нативно — функция format принимает локаль аргументом, а render позволяет пересоздать обновляемые элементы с новой локалью.


Базовый принцип переключения

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

import { format } from 'timeago.js';

format(date, 'ru');     // русский
format(date, 'en_US'); // английский
format(date, 'de');     // немецкий

Переключение в vanilla JS

import { cancel, render } from 'timeago.js';

let currentLocale = 'ru';

function setLocale(locale) {
  currentLocale = locale;

  const nodes = document.querySelectorAll('[data-timeago]');
  cancel(nodes);
  render(nodes, locale);
}

// Пользователь нажимает кнопку смены языка
document.getElementById('btn-en').addEventListener('click', () => setLocale('en_US'));
document.getElementById('btn-ru').addEventListener('click', () => setLocale('ru'));
document.getElementById('btn-de').addEventListener('click', () => setLocale('de'));

Хранение текущей локали

import { cancel, render, format } from 'timeago.js';

const state = {
  locale: localStorage.getItem('locale') || 'ru',
};

function setLocale(locale) {
  state.locale = locale;
  localStorage.setItem('locale', locale);

  const nodes = document.querySelectorAll('[data-timeago]');
  cancel(nodes);
  render(nodes, locale);
}

function getLocale() {
  return state.locale;
}

Переключение в React

import { useState, useCallback } from 'react';
import { format } from 'timeago.js';

type Locale = 'ru' | 'en_US' | 'de';

function useTimeAgoLocale(initialLocale: Locale = 'ru') {
  const [locale, setLocale] = useState<Locale>(initialLocale);

  const formatDate = useCallback(
    (date: Date | string | number) => format(date, locale),
    [locale]
  );

  return { locale, setLocale, formatDate };
}

function App() {
  const { locale, setLocale, formatDate } = useTimeAgoLocale();

  return (
    <div>
      <button onCl ick={() => setLocale('ru')}>RU</button>
      <button onCl ick={() => setLocale('en_US')}>EN</button>

      <time>{formatDate('2025-05-26T08:00:00Z')}</time>
    </div>
  );
}

Переключение в Vue 3

<script setup>
import { ref, computed } from 'vue';
import { format } from 'timeago.js';

const locale = ref('ru');

function changeLocale(newLocale) {
  locale.value = newLocale;
}

function timeAgo(date) {
  return format(date, locale.value);
}
</script>

<template>
  <div>
    <button @click="changeLocale('ru')">RU</button>
    <button @click="changeLocale('en_US')">EN</button>

    <time>{{ timeAgo('2025-05-26T08:00:00Z') }}</time>
  </div>
</template>

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

При использовании vue-i18n или react-i18next локаль timeago.js синхронизируется с глобальным состоянием:

// Vue i18n
import { useI18n } from 'vue-i18n';
import { format } from 'timeago.js';

const { locale } = useI18n();

function timeAgo(date) {
  return format(date, locale.value);
}
// React i18next
import { useTranslation } from 'react-i18next';
import { format } from 'timeago.js';

function useTimeAgo() {
  const { i18n } = useTranslation();
  return (date) => format(date, i18n.language);
}

Маппинг локалей i18n → timeago

Имена локалей в i18n-библиотеках и timeago.js могут отличаться:

const LOCALE_MAP = {
  'ru':    'ru',
  'en':    'en_US',
  'en-US': 'en_US',
  'de':    'de',
  'zh':    'zh_CN',
  'zh-CN': 'zh_CN',
  'zh-TW': 'zh_TW',
};

function mapLocale(i18nLocale) {
  return LOCALE_MAP[i18nLocale] || 'en_US';
}

format(date, mapLocale(i18n.language));

Предзагрузка всех нужных локалей

import { register } from 'timeago.js';
import ru from 'timeago.js/esm/lang/ru';
import en from 'timeago.js/esm/lang/en_US';
import de from 'timeago.js/esm/lang/de';
import fr from 'timeago.js/esm/lang/fr';

const locales = { ru, en_US: en, de, fr };

Object.entries(locales).forEach(([key, fn]) => register(key, fn));

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


Ленивая загрузка локалей

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

import { register, format } from 'timeago.js';

const loaded = new Set(['en_US']);

async function loadAndFormat(date, locale) {
  if (!loaded.has(locale)) {
    const module = await import(`timeago.js/esm/lang/${locale}.js`);
    register(locale, module.default);
    loaded.add(locale);
  }
  return format(date, locale);
}

Обновление DOM после смены языка

При использовании render:

import { cancel, render } from 'timeago.js';

function onLocaleChange(newLocale) {
  const nodes = document.querySelectorAll('[data-timeago]');

  // Обязательно отменить старые таймеры
  cancel(nodes);

  // Запустить с новой локалью
  render(nodes, newLocale);
}

Без cancel старые и новые таймеры будут работать одновременно.