timeago.js не имеет публичного метода setLocale. Это
осознанное архитектурное решение: вместо глобальной “текущей локали”
библиотека требует явного указания локали в каждом вызове
format и render. Тем не менее поведение
setLocale можно реализовать самостоятельно через
обёртки.
Библиотека придерживается принципа явности: каждый вызов
format(date, locale) однозначно указывает, какой язык
использовать. Глобальное изменение состояния через
setLocale могло бы привести к неожиданному поведению в
многокомпонентных приложениях, где разные части интерфейса могут
использовать разные локали.
// src/timeago-locale.js
import { format, render, cancel } from 'timeago.js';
let currentLocale = 'ru';
export function setLocale(locale) {
currentLocale = locale;
}
export function getLocale() {
return currentLocale;
}
export function timeAgo(date) {
return format(date, currentLocale);
}
export function renderTime(nodes) {
cancel(nodes);
render(nodes, currentLocale);
}
Использование:
import { setLocale, timeAgo, renderTime } from './timeago-locale.js';
setLocale('ru');
console.log(timeAgo(Date.now() - 3600000));
// → "1 час назад"
setLocale('de');
console.log(timeAgo(Date.now() - 3600000));
// → "vor 1 Stunde"
import { createContext, useContext, useState, ReactNode } from 'react';
import { format } from 'timeago.js';
type Locale = 'ru' | 'en_US' | 'de';
interface TimeagoContextValue {
locale: Locale;
setLocale: (l: Locale) => void;
timeAgo: (date: Date | string | number) => string;
}
const TimeagoContext = createContext<TimeagoContextValue>({
locale: 'ru',
setLocale: () => {},
timeAgo: (d) => format(d, 'ru'),
});
export function TimeagoProvider({ children }: { children: ReactNode }) {
const [locale, setLocale] = useState<Locale>('ru');
return (
<TimeagoContext.Provider value={{
locale,
setLocale,
timeAgo: (d) => format(d, locale),
}}>
{children}
</TimeagoContext.Provider>
);
}
export function useTimeago() {
return useContext(TimeagoContext);
}
Использование:
function PostTime({ date }: { date: string }) {
const { timeAgo } = useTimeago();
return <time>{timeAgo(date)}</time>;
}
// composables/useTimeago.ts
import { inject, provide, ref } from 'vue';
import { format } from 'timeago.js';
const LOCALE_KEY = Symbol('timeago-locale');
export function provideTimeago(initialLocale = 'ru') {
const locale = ref(initialLocale);
provide(LOCALE_KEY, {
locale,
setLocale: (l: string) => { locale.value = l; },
timeAgo: (d: Date | string | number) => format(d, locale.value),
});
}
export function useTimeago() {
return inject(LOCALE_KEY) as {
locale: Ref<string>;
setLocale: (l: string) => void;
timeAgo: (d: Date | string | number) => string;
};
}
При использовании i18next:
import i18n from 'i18next';
import { setLocale } from './timeago-locale.js';
const LOCALE_MAP = {
ru: 'ru',
en: 'en_US',
de: 'de',
};
i18n.on('languageChanged', (lang) => {
setLocale(LOCALE_MAP[lang] || 'en_US');
// Обновить все временные метки на странице
const nodes = document.querySelectorAll('[data-timeago]');
renderTime(nodes);
});
import { format } from 'timeago.js';
const LOCALE_KEY = 'app-timeago-locale';
let currentLocale = localStorage.getItem(LOCALE_KEY) || 'ru';
function setLocale(locale) {
currentLocale = locale;
localStorage.setItem(LOCALE_KEY, locale);
}
function timeAgo(date) {
return format(date, currentLocale);
}
navigator.language.format.