Создание собственной локали позволяет полностью контролировать формат строк, грамматику, стиль обращения и набор используемых единиц времени. Это основной механизм кастомизации в timeago.js.
Локаль — это функция следующей сигнатуры:
function myLocale(number, index) {
return [pastString, futureString];
}
number — количество единиц времени (число, используемое
в %s)index — индекс интервала от 0 до 13import { register, format } from 'timeago.js';
register('simple', (number, index) => {
return [
['только что', 'прямо сейчас'], // 0
['%s сек. назад', 'через %s сек.'], // 1
['%s сек. назад', 'через %s сек.'], // 2
['1 мин. назад', 'через 1 мин.'], // 3
['%s мин. назад', 'через %s мин.'], // 4
['1 ч. назад', 'через 1 ч.'], // 5
['%s ч. назад', 'через %s ч.'], // 6
['1 д. назад', 'через 1 д.'], // 7
['%s д. назад', 'через %s д.'], // 8
['1 нед. назад', 'через 1 нед.'], // 9
['%s нед. назад', 'через %s нед.'], // 10
['1 мес. назад', 'через 1 мес.'], // 11
['%s мес. назад', 'через %s мес.'], // 12
['1 г. назад', 'через 1 г.'], // 13
['%s л. назад', 'через %s л.'], // 14
][index];
});
format(Date.now() - 1000 * 60 * 30, 'simple');
// → "30 мин. назад"
Русский язык имеет три формы:
import { register } from 'timeago.js';
function plural(n, one, few, many) {
const mod100 = Math.abs(n) % 100;
const mod10 = mod100 % 10;
if (mod100 >= 11 && mod100 <= 14) return many;
if (mod10 === 1) return one;
if (mod10 >= 2 && mod10 <= 4) return few;
return many;
}
register('ru_full', (number, index) => {
const ago = 'назад';
const next = 'через';
return [
['только что', 'прямо сейчас'],
[`${number} ${plural(number, 'секунду', 'секунды', 'секунд')} ${ago}`,
`${next} ${number} ${plural(number, 'секунду', 'секунды', 'секунд')}`],
[`${number} ${plural(number, 'секунду', 'секунды', 'секунд')} ${ago}`,
`${next} ${number} ${plural(number, 'секунду', 'секунды', 'секунд')}`],
[`1 минуту ${ago}`, `${next} 1 минуту`],
[`${number} ${plural(number, 'минуту', 'минуты', 'минут')} ${ago}`,
`${next} ${number} ${plural(number, 'минуту', 'минуты', 'минут')}`],
[`1 час ${ago}`, `${next} 1 час`],
[`${number} ${plural(number, 'час', 'часа', 'часов')} ${ago}`,
`${next} ${number} ${plural(number, 'час', 'часа', 'часов')}`],
[`1 день ${ago}`, `${next} 1 день`],
[`${number} ${plural(number, 'день', 'дня', 'дней')} ${ago}`,
`${next} ${number} ${plural(number, 'день', 'дня', 'дней')}`],
[`1 неделю ${ago}`, `${next} 1 неделю`],
[`${number} ${plural(number, 'неделю', 'недели', 'недель')} ${ago}`,
`${next} ${number} ${plural(number, 'неделю', 'недели', 'недель')}`],
[`1 месяц ${ago}`, `${next} 1 месяц`],
[`${number} ${plural(number, 'месяц', 'месяца', 'месяцев')} ${ago}`,
`${next} ${number} ${plural(number, 'месяц', 'месяца', 'месяцев')}`],
[`1 год ${ago}`, `${next} 1 год`],
[`${number} ${plural(number, 'год', 'года', 'лет')} ${ago}`,
`${next} ${number} ${plural(number, 'год', 'года', 'лет')}`],
][index];
});
Современный способ через встроенный API браузера:
import { register } from 'timeago.js';
const rules = new Intl.PluralRules('ru');
const forms = {
second: { one: 'секунду', few: 'секунды', many: 'секунд', other: 'секунды' },
minute: { one: 'минуту', few: 'минуты', many: 'минут', other: 'минуты' },
hour: { one: 'час', few: 'часа', many: 'часов', other: 'часа' },
day: { one: 'день', few: 'дня', many: 'дней', other: 'дня' },
};
function plural(n, unit) {
const rule = rules.select(n);
return forms[unit][rule] || forms[unit].other;
}
register('ru_intl', (number, index) => {
if (index === 0) return ['только что', 'прямо сейчас'];
if (index <= 2) return [`${number} ${plural(number, 'second')} назад`, `через ${number} ${plural(number, 'second')}`];
if (index <= 4) return [`${number} ${plural(number, 'minute')} назад`, `через ${number} ${plural(number, 'minute')}`];
if (index <= 6) return [`${number} ${plural(number, 'hour')} назад`, `через ${number} ${plural(number, 'hour')}`];
if (index <= 8) return [`${number} ${plural(number, 'day')} назад`, `через ${number} ${plural(number, 'day')}`];
return [`${number} ед. назад`, `через ${number} ед.`];
});
register('ru_human', (number, index) => {
return [
['только что', 'скоро'],
['несколько секунд назад', 'через несколько секунд'],
['менее минуты назад', 'менее чем через минуту'],
['около минуты назад', 'примерно через минуту'],
['несколько минут назад', 'через несколько минут'],
['около часа назад', 'примерно через час'],
['несколько часов назад', 'через несколько часов'],
['вчера', 'завтра'],
['несколько дней назад', 'через несколько дней'],
['на прошлой неделе', 'на следующей неделе'],
['несколько недель назад', 'через несколько недель'],
['в прошлом месяце', 'в следующем месяце'],
['несколько месяцев назад', 'через несколько месяцев'],
['в прошлом году', 'в следующем году'],
['давно', 'нескоро'],
][index];
});
Для больших проектов локаль выносится в отдельный файл:
// src/locales/ru.js
function pluralRu(n, one, few, many) {
const m100 = Math.abs(n) % 100;
const m10 = m100 % 10;
if (m100 > 10 && m100 < 20) return many;
if (m10 === 1) return one;
if (m10 > 1 && m10 < 5) return few;
return many;
}
export default function ru(number, index) {
// ... строки
}
// src/main.js
import { register } from 'timeago.js';
import ru from './locales/ru.js';
register('ru', ru);
import { register, format } from 'timeago.js';
import myLocale from './locales/my_locale.js';
register('my', myLocale);
const cases = [
[Date.now() - 1000 * 30, 'только что'],
[Date.now() - 1000 * 60 * 5, '5 мин. назад'],
[Date.now() - 1000 * 3600 * 3, '3 ч. назад'],
[Date.now() + 1000 * 60 * 10, 'через 10 мин.'],
];
cases.forEach(([date, expected]) => {
const result = format(date, 'my');
console.assert(result === expected, `Expected "${expected}", got "${result}"`);
});