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

Перевод временных отрезков — задача, которая выходит за рамки простой замены слов. Разные языки имеют разные грамматические конструкции, падежные формы, порядок слов и уровни вежливости. Грамотная реализация локали учитывает все эти факторы.


Архитектура индексов

timeago.js использует 15 индексов (0–14), каждый из которых соответствует диапазону разницы во времени:

0  → только что (< 45 сек)
1  → секунды (45–90 сек, единственное число)
2  → секунды (90 сек – 45 мин, множественное число)
3  → минуты (1 минута)
4  → минуты (несколько минут)
5  → часы (1 час)
6  → часы (несколько часов)
7  → дни (1 день)
8  → дни (несколько дней)
9  → недели (1 неделя)
10 → недели (несколько недель)
11 → месяцы (1 месяц)
12 → месяцы (несколько месяцев)
13 → годы (1 год)
14 → годы (несколько лет)

“Только что” — нулевой интервал

Индекс 0 особенный: number здесь не несёт смысловой нагрузки. Оба варианта строки (прошлое и будущее) обычно игнорируют число:

[0] → ['только что', 'прямо сейчас']

В некоторых локалях будущий вариант этого индекса также использует “только что”:

[0] → ['just now', 'just now']

Разрыв между индексами 1 и 2

Индекс 1 — секунды в единственном числе (~1 секунда), индекс 2 — секунды в множественном. Это сделано для языков, где “1 секунда назад” и “2 секунды назад” грамматически различаются.

Для языков без этого различия оба индекса возвращают одинаковую форму:

[1] → ['%s seconds ago', 'in %s seconds']
[2] → ['%s seconds ago', 'in %s seconds']

Падежи в русском языке

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

Прошедшее время:

1 минуту назад    ← винительный
2 минуты назад    ← родительный (ед.ч.)
5 минут назад     ← родительный (мн.ч.)

Будущее время:

через 1 минуту    ← винительный
через 2 минуты    ← родительный (ед.ч.)
через 5 минут     ← родительный (мн.ч.)

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

const minuteForms = {
  past:   { one: 'минуту',  few: 'минуты',  many: 'минут' },
  future: { one: 'минуту',  few: 'минуты',  many: 'минут' },
};

“1 час назад” vs “%s часов назад”

Для единственного числа (индексы 3, 5, 7, 9, 11, 13) число в строке жёстко задано:

[3] → ['1 минуту назад', 'через 1 минуту']
[5] → ['1 час назад',    'через 1 час']

Для множественного (индексы 2, 4, 6, 8, 10, 12, 14) используется %s:

[4] → ['%s минут назад', 'через %s минут']

Языки с постпозицией глаголов

В японском и корейском время ставится в конец фразы:

// Японский
[3] → ['1分前', '1分後']   // "1 минута перед", "1 минута после"
[4] → ['%s分前', '%s分後']

Порядок слов: число + единица + суффикс.


Арабский: шесть форм числа

В арабском языке шесть категорий: zero, one, two, few, many, other.

const arRules = new Intl.PluralRules('ar');

function arForm(n, forms) {
  return forms[arRules.select(n)];
}

Турецкий: суффиксная агглютинация

В турецком временны́е суффиксы присоединяются к слову:

// "несколько минут назад"
'%s dakika önce'  // dakika önce — минута перед

Особенность в том, что суффиксы гармонируют по гласным (vowel harmony), что нельзя реализовать через простые строки.


Финский: падежные окончания

Финские существительные изменяются по падежам, что влияет на перевод:

// "5 минут назад"
'%s minuuttia sitten'  // -a — партитив множественного числа

Особенности перевода “недавно”

Некоторые языки не различают “1 секунду назад” и “только что”. Для таких случаев:

[0] → ['недавно', 'скоро']
[1] → ['недавно', 'скоро']
[2] → ['%s секунд назад', 'через %s секунд']

Перевод будущего времени

Не все языки используют симметричные конструкции для прошлого и будущего. Например:

// Прошлое: "Χ минут назад"
// Будущее: "через Х минут"

Vs. асимметричный вариант:

// Прошлое: "Χ минут тому"
// Будущее: "через Х минут (в будущем)"

Тонкости перевода “год”

Форма “лет” (5 лет назад) отличается от “год” и “года”. Это супплетивная форма — совершенно другое слово:

function yearForm(n) {
  return pluralRu(n, 'год', 'года', 'лет');
}

yearForm(1);  // "год"
yearForm(2);  // "года"
yearForm(5);  // "лет"
yearForm(11); // "лет"
yearForm(21); // "год"

Недели в русском

“Неделя” имеет особенности склонения при предлоге “через”:

1 неделю назад    ← "неделю" (вин. пад.)
через 1 неделю    ← "неделю" (вин. пад.)
2 недели назад    ← "недели" (род. ед.)
через 2 недели    ← "недели" (род. ед.)
5 недель назад    ← "недель" (род. мн.)
через 5 недель    ← "недель" (род. мн.)

Сводная таблица сложностей перевода по языкам

Язык Особенности
Русский 3 формы, падежи, супплетив (“год/лет”)
Арабский 6 форм, восточноарабские цифры, RTL
Польский 4 формы, исключения
Финский Падежные суффиксы, партитив
Японский Счётные слова, постпозиция времени
Иврит Сопряжённые формы, RTL
Турецкий Гармония гласных, суффиксы
Китайский Нет склонения, счётные слова