@schukai/monster
Version:
Monster is a simple library for creating fast, robust and lightweight websites.
1,388 lines (1,345 loc) • 25.1 kB
JavaScript
/**
* Copyright © schukai GmbH and all contributing authors, {{copyRightYear}}. All rights reserved.
* Node module: @schukai/monster
*
* This source code is licensed under the GNU Affero General Public License version 3 (AGPLv3).
* The full text of the license can be found at: https://www.gnu.org/licenses/agpl-3.0.en.html
*
* For those who do not wish to adhere to the AGPLv3, a commercial license is available.
* Acquiring a commercial license allows you to use this software without complying with the AGPLv3 terms.
* For more information about purchasing a commercial license, please contact schukai GmbH.
*
* SPDX-License-Identifier: AGPL-3.0
*/
export { formatTimeAgo };
/**
* Format a date as a relative time string with multiple units.
*
* @param date
* @param locale
* @returns {string}
*/
function formatTimeAgo(date, locale) {
const now = new Date(Math.floor(new Date().getTime() / 1000) * 1000);
const roundedDate = new Date(Math.floor(date.getTime() / 1000) * 1000);
const diffInSeconds = Math.floor((roundedDate - now) / 1000);
const absDiff = Math.abs(diffInSeconds);
const translation = translations[normalizeLocale(locale)];
if (absDiff === 0) {
return translation.template.justNow();
}
if (absDiff > 31536000) {
return translation.template.on(
new Intl.DateTimeFormat(locale, {
dateStyle: "full",
timeStyle: "short",
}).format(date),
);
}
const units = [
{ name: "year", length: 31536000 }, // Hinzugefügt für Konsistenz, auch wenn nicht genutzt in dieser spezifischen Logik
{ name: "day", length: 86400 },
{ name: "hour", length: 3600 },
{ name: "minute", length: 60 },
{ name: "second", length: 1 },
];
let remainder = absDiff;
const parts = [];
for (const unit of units) {
if (remainder >= unit.length) {
const count = Math.floor(remainder / unit.length);
remainder %= unit.length;
const formatted = formatUnitCount(count, unit.name, locale);
parts.push(formatted);
}
}
if (parts.length === 0) {
return translation.template.justNow();
}
const joined = new Intl.ListFormat(locale, {
style: "long",
type: "conjunction",
}).format(parts);
if (diffInSeconds > 0) {
return translation.template.future(joined);
} else {
return translation.template.past(joined);
}
}
function formatUnitCount(count, unit, locale) {
const lang = normalizeLocale(locale);
const fallback = translations[lang] || translations["en"];
const dictForUnit = fallback.units[unit];
const pr = new Intl.PluralRules(lang);
const category = pr.select(count);
const phrase = dictForUnit[category] || dictForUnit.other;
return `${count} ${phrase}`;
}
function normalizeLocale(locale) {
return locale.split("-")[0].toLowerCase();
}
/**
* @private
*/
const translations = {
en: {
template: {
on: (value) => `on ${value}`,
past: (value) => `${value} ago`,
future: (value) => `in ${value}`,
justNow: () => `just now`,
},
units: {
day: {
zero: "days",
one: "day",
two: "days",
few: "days",
many: "days",
other: "days",
},
hour: {
zero: "hours",
one: "hour",
two: "hours",
few: "hours",
many: "hours",
other: "hours",
},
minute: {
zero: "minutes",
one: "minute",
two: "minutes",
few: "minutes",
many: "minutes",
other: "minutes",
},
second: {
zero: "seconds",
one: "second",
two: "seconds",
few: "seconds",
many: "seconds",
other: "seconds",
},
},
},
zh: {
template: {
on: (value) => `在${value}`,
past: (value) => `${value}前`,
future: (value) => `${value}后`,
justNow: () => `刚刚`,
},
units: {
day: {
zero: "天",
one: "天",
two: "天",
few: "天",
many: "天",
other: "天",
},
hour: {
zero: "小时",
one: "小时",
two: "小时",
few: "小时",
many: "小时",
other: "小时",
},
minute: {
zero: "分钟",
one: "分钟",
two: "分钟",
few: "分钟",
many: "分钟",
other: "分钟",
},
second: {
zero: "秒",
one: "秒",
two: "秒",
few: "秒",
many: "秒",
other: "秒",
},
},
},
es: {
template: {
on: (value) => `el ${value}`,
past: (value) => `hace ${value}`,
future: (value) => `en ${value}`,
justNow: () => `justo ahora`,
},
units: {
day: {
zero: "días",
one: "día",
two: "días",
few: "días",
many: "días",
other: "días",
},
hour: {
zero: "horas",
one: "hora",
two: "horas",
few: "horas",
many: "horas",
other: "horas",
},
minute: {
zero: "minutos",
one: "minuto",
two: "minutos",
few: "minutos",
many: "minutos",
other: "minutos",
},
second: {
zero: "segundos",
one: "segundo",
two: "segundos",
few: "segundos",
many: "segundos",
other: "segundos",
},
},
},
de: {
template: {
on: (value) => `am ${value}`,
past: (value) => `vor ${value}`,
future: (value) => `in ${value}`,
justNow: () => `gerade eben`,
},
units: {
day: {
zero: "Tagen",
one: "Tag",
two: "Tagen",
few: "Tagen",
many: "Tagen",
other: "Tagen",
},
hour: {
zero: "Stunden",
one: "Stunde",
two: "Stunden",
few: "Stunden",
many: "Stunden",
other: "Stunden",
},
minute: {
zero: "Minuten",
one: "Minute",
two: "Minuten",
few: "Minuten",
many: "Minuten",
other: "Minuten",
},
second: {
zero: "Sekunden",
one: "Sekunde",
two: "Sekunden",
few: "Sekunden",
many: "Sekunden",
other: "Sekunden",
},
},
},
fr: {
template: {
on: (value) => `le ${value}`,
past: (value) => `il y a ${value}`,
future: (value) => `dans ${value}`,
justNow: () => `à l'instant`,
},
units: {
day: {
zero: "jours",
one: "jour",
two: "jours",
few: "jours",
many: "jours",
other: "jours",
},
hour: {
zero: "heures",
one: "heure",
two: "heures",
few: "heures",
many: "heures",
other: "heures",
},
minute: {
zero: "minutes",
one: "minute",
two: "minutes",
few: "minutes",
many: "minutes",
other: "minutes",
},
second: {
zero: "secondes",
one: "seconde",
two: "secondes",
few: "secondes",
many: "secondes",
other: "secondes",
},
},
},
ru: {
template: {
on: (value) => `на ${value}`,
past: (value) => `${value} назад`,
future: (value) => `через ${value}`,
justNow: () => `только что`,
},
units: {
day: {
zero: "дней",
one: "день",
two: "дня",
few: "дня",
many: "дней",
other: "дней",
},
hour: {
zero: "часов",
one: "час",
two: "часа",
few: "часа",
many: "часов",
other: "часов",
},
minute: {
zero: "минут",
one: "минута",
two: "минуты",
few: "минуты",
many: "минут",
other: "минут",
},
second: {
zero: "секунд",
one: "секунда",
two: "секунды",
few: "секунды",
many: "секунд",
other: "секунд",
},
},
},
ar: {
template: {
on: (value) => `في ${value}`,
past: (value) => `منذ ${value}`,
future: (value) => `بعد ${value}`,
justNow: () => `الآن`,
},
units: {
day: {
zero: "أيام",
one: "يوم",
two: "يومين",
few: "أيام",
many: "أيام",
other: "أيام",
},
hour: {
zero: "ساعات",
one: "ساعة",
two: "ساعتين",
few: "ساعات",
many: "ساعات",
other: "ساعات",
},
minute: {
zero: "دقائق",
one: "دقيقة",
two: "دقيقتين",
few: "دقائق",
many: "دقائق",
other: "دقائق",
},
second: {
zero: "ثواني",
one: "ثانية",
two: "ثانيتين",
few: "ثواني",
many: "ثواني",
other: "ثواني",
},
},
},
hi: {
template: {
on: (value) => `${value} को`,
past: (value) => `${value} पहले`,
future: (value) => `${value} में`,
justNow: () => `अभी`,
},
units: {
day: {
zero: "दिन",
one: "दिन",
two: "दिन",
few: "दिन",
many: "दिन",
other: "दिन",
},
hour: {
zero: "घंटे",
one: "घंटा",
two: "घंटे",
few: "घंटे",
many: "घंटे",
other: "घंटे",
},
minute: {
zero: "मिनट",
one: "मिनट",
two: "मिनट",
few: "मिनट",
many: "मिनट",
other: "मिनट",
},
second: {
zero: "सेकंड",
one: "सेकंड",
two: "सेकंड",
few: "सेकंड",
many: "सेकंड",
other: "सेकंड",
},
},
},
pt: {
template: {
on: (value) => `em ${value}`,
past: (value) => `há ${value}`,
future: (value) => `em ${value}`,
justNow: () => `agora mesmo`,
},
units: {
day: {
zero: "dias",
one: "dia",
two: "dias",
few: "dias",
many: "dias",
other: "dias",
},
hour: {
zero: "horas",
one: "hora",
two: "horas",
few: "horas",
many: "horas",
other: "horas",
},
minute: {
zero: "minutos",
one: "minuto",
two: "minutos",
few: "minutos",
many: "minutos",
other: "minutos",
},
second: {
zero: "segundos",
one: "segundo",
two: "segundos",
few: "segundos",
many: "segundos",
other: "segundos",
},
},
},
ja: {
template: {
on: (value) => `${value}に`,
past: (value) => `${value}前`,
future: (value) => `${value}後`,
justNow: () => `たった今`,
},
units: {
day: {
zero: "日",
one: "日",
two: "日",
few: "日",
many: "日",
other: "日",
},
hour: {
zero: "時間",
one: "時間",
two: "時間",
few: "時間",
many: "時間",
other: "時間",
},
minute: {
zero: "分",
one: "分",
two: "分",
few: "分",
many: "分",
other: "分",
},
second: {
zero: "秒",
one: "秒",
two: "秒",
few: "秒",
many: "秒",
other: "秒",
},
},
},
it: {
template: {
on: (value) => `il ${value}`,
past: (value) => `${value} fa`,
future: (value) => `in ${value}`,
justNow: () => `proprio ora`,
},
units: {
day: {
zero: "giorni",
one: "giorno",
two: "giorni",
few: "giorni",
many: "giorni",
other: "giorni",
},
hour: {
zero: "ore",
one: "ora",
two: "ore",
few: "ore",
many: "ore",
other: "ore",
},
minute: {
zero: "minuti",
one: "minuto",
two: "minuti",
few: "minuti",
many: "minuti",
other: "minuti",
},
second: {
zero: "secondi",
one: "secondo",
two: "secondi",
few: "secondi",
many: "secondi",
other: "secondi",
},
},
},
ko: {
template: {
on: (value) => `${value}에`,
past: (value) => `${value} 전`,
future: (value) => `${value} 후`,
justNow: () => `방금`,
},
units: {
day: {
zero: "일",
one: "일",
two: "일",
few: "일",
many: "일",
other: "일",
},
hour: {
zero: "시간",
one: "시간",
two: "시간",
few: "시간",
many: "시간",
other: "시간",
},
minute: {
zero: "분",
one: "분",
two: "분",
few: "분",
many: "분",
other: "분",
},
second: {
zero: "초",
one: "초",
two: "초",
few: "초",
many: "초",
other: "초",
},
},
},
sw: {
template: {
on: (value) => `kwa ${value}`,
past: (value) => `${value} iliyopita`,
future: (value) => `katika ${value}`,
justNow: () => `hivi punde`,
},
units: {
day: {
zero: "siku",
one: "siku",
two: "siku",
few: "siku",
many: "siku",
other: "siku",
},
hour: {
zero: "masaa",
one: "saa",
two: "masaa",
few: "masaa",
many: "masaa",
other: "masaa",
},
minute: {
zero: "dakika",
one: "dakika",
two: "dakika",
few: "dakika",
many: "dakika",
other: "dakika",
},
second: {
zero: "sekunde",
one: "sekunde",
two: "sekunde",
few: "sekunde",
many: "sekunde",
other: "sekunde",
},
},
},
nl: {
template: {
on: (value) => `op ${value}`,
past: (value) => `${value} geleden`,
future: (value) => `over ${value}`,
justNow: () => `net`,
},
units: {
day: {
zero: "dagen",
one: "dag",
two: "dagen",
few: "dagen",
many: "dagen",
other: "dagen",
},
hour: {
zero: "uren",
one: "uur",
two: "uren",
few: "uren",
many: "uren",
other: "uren",
},
minute: {
zero: "minuten",
one: "minuut",
two: "minuten",
few: "minuten",
many: "minuten",
other: "minuten",
},
second: {
zero: "seconden",
one: "seconde",
two: "seconden",
few: "seconden",
many: "seconden",
other: "seconden",
},
},
},
ms: {
template: {
on: (value) => `pada ${value}`,
past: (value) => `${value} yang lalu`,
future: (value) => `${value} lagi`,
justNow: () => `tadi`,
},
units: {
day: {
zero: "hari",
one: "hari",
two: "hari",
few: "hari",
many: "hari",
other: "hari",
},
hour: {
zero: "jam",
one: "jam",
two: "jam",
few: "jam",
many: "jam",
other: "jam",
},
minute: {
zero: "minit",
one: "minit",
two: "minit",
few: "minit",
many: "minit",
other: "minit",
},
second: {
zero: "saat",
one: "saat",
two: "saat",
few: "saat",
many: "saat",
other: "saat",
},
},
},
id: {
template: {
on: (value) => `pada ${value}`,
past: (value) => `${value} yang lalu`,
future: (value) => `dalam ${value}`,
justNow: () => `tadi`,
},
units: {
day: {
zero: "hari",
one: "hari",
two: "hari",
few: "hari",
many: "hari",
other: "hari",
},
hour: {
zero: "jam",
one: "jam",
two: "jam",
few: "jam",
many: "jam",
other: "jam",
},
minute: {
zero: "menit",
one: "menit",
two: "menit",
few: "menit",
many: "menit",
other: "menit",
},
second: {
zero: "detik",
one: "detik",
two: "detik",
few: "detik",
many: "detik",
other: "detik",
},
},
},
tr: {
template: {
on: (value) => `${value} tarihinde`,
past: (value) => `${value} önce`,
future: (value) => `${value} sonra`,
justNow: () => `az önce`,
},
units: {
day: {
zero: "günler",
one: "gün",
two: "gün",
few: "gün",
many: "gün",
other: "gün",
},
hour: {
zero: "saatler",
one: "saat",
two: "saat",
few: "saat",
many: "saat",
other: "saat",
},
minute: {
zero: "dakikalar",
one: "dakika",
two: "dakika",
few: "dakika",
many: "dakika",
other: "dakika",
},
second: {
zero: "saniyeler",
one: "saniye",
two: "saniye",
few: "saniye",
many: "saniye",
other: "saniye",
},
},
},
pl: {
template: {
on: (value) => `w dniu ${value}`,
past: (value) => `${value} temu`,
future: (value) => `za ${value}`,
justNow: () => `przed chwilą`,
},
units: {
day: {
zero: "dni",
one: "dzień",
two: "dni",
few: "dni",
many: "dni",
other: "dni",
},
hour: {
zero: "godzin",
one: "godzina",
two: "godziny",
few: "godziny",
many: "godzin",
other: "godzin",
},
minute: {
zero: "minut",
one: "minuta",
two: "minuty",
few: "minuty",
many: "minut",
other: "minut",
},
second: {
zero: "sekund",
one: "sekunda",
two: "sekundy",
few: "sekundy",
many: "sekund",
other: "sekund",
},
},
},
sv: {
template: {
on: (value) => `den ${value}`,
past: (value) => `för ${value} sedan`,
future: (value) => `om ${value}`,
justNow: () => `nyss`,
},
units: {
day: {
zero: "dagar",
one: "dag",
two: "dagar",
few: "dagar",
many: "dagar",
other: "dagar",
},
hour: {
zero: "timmar",
one: "timme",
two: "timmar",
few: "timmar",
many: "timmar",
other: "timmar",
},
minute: {
zero: "minuter",
one: "minut",
two: "minuter",
few: "minuter",
many: "minuter",
other: "minuter",
},
second: {
zero: "sekunder",
one: "sekund",
two: "sekunder",
few: "sekunder",
many: "sekunder",
other: "sekunder",
},
},
},
ro: {
template: {
on: (value) => `pe ${value}`,
past: (value) => `acum ${value}`,
future: (value) => `peste ${value}`,
justNow: () => `chiar acum`,
},
units: {
day: {
zero: "zile",
one: "zi",
two: "zile",
few: "zile",
many: "zile",
other: "zile",
},
hour: {
zero: "ore",
one: "oră",
two: "ore",
few: "ore",
many: "ore",
other: "ore",
},
minute: {
zero: "minute",
one: "minut",
two: "minute",
few: "minute",
many: "minute",
other: "minute",
},
second: {
zero: "secunde",
one: "secundă",
two: "secunde",
few: "secunde",
many: "secunde",
other: "secunde",
},
},
},
bg: {
template: {
on: (value) => `на ${value}`,
past: (value) => `преди ${value}`,
future: (value) => `след ${value}`,
justNow: () => `току-що`,
},
units: {
day: {
zero: "дни",
one: "ден",
two: "дни",
few: "дни",
many: "дни",
other: "дни",
},
hour: {
zero: "часа",
one: "час",
two: "часа",
few: "часа",
many: "часа",
other: "часа",
},
minute: {
zero: "минути",
one: "минута",
two: "минути",
few: "минути",
many: "минути",
other: "минути",
},
second: {
zero: "секунди",
one: "секунда",
two: "секунди",
few: "секунди",
many: "секунди",
other: "секунди",
},
},
},
da: {
template: {
on: (value) => `den ${value}`,
past: (value) => `for ${value} siden`,
future: (value) => `om ${value}`,
justNow: () => `lige nu`,
},
units: {
day: {
zero: "dage",
one: "dag",
two: "dage",
few: "dage",
many: "dage",
other: "dage",
},
hour: {
zero: "timer",
one: "time",
two: "timer",
few: "timer",
many: "timer",
other: "timer",
},
minute: {
zero: "minutter",
one: "minut",
two: "minutter",
few: "minutter",
many: "minutter",
other: "minutter",
},
second: {
zero: "sekunder",
one: "sekund",
two: "sekunder",
few: "sekunder",
many: "sekunder",
other: "sekunder",
},
},
},
fi: {
template: {
on: (value) => `päivänä ${value}`,
past: (value) => `${value} sitten`,
future: (value) => `${value} kuluttua`,
justNow: () => `juuri nyt`,
},
units: {
day: {
zero: "päivää",
one: "päivä",
two: "päivää",
few: "päivää",
many: "päivää",
other: "päivää",
},
hour: {
zero: "tuntia",
one: "tunti",
two: "tuntia",
few: "tuntia",
many: "tuntia",
other: "tuntia",
},
minute: {
zero: "minuuttia",
one: "minuutti",
two: "minuuttia",
few: "minuuttia",
many: "minuuttia",
other: "minuuttia",
},
second: {
zero: "sekuntia",
one: "sekunti",
two: "sekuntia",
few: "sekuntia",
many: "sekuntia",
other: "sekuntia",
},
},
},
cs: {
template: {
on: (value) => `dne ${value}`,
past: (value) => `před ${value}`,
future: (value) => `za ${value}`,
justNow: () => `právě teď`,
},
units: {
day: {
zero: "dny",
one: "den",
two: "dny",
few: "dny",
many: "dnů",
other: "dny",
},
hour: {
zero: "hodin",
one: "hodina",
two: "hodiny",
few: "hodiny",
many: "hodin",
other: "hodin",
},
minute: {
zero: "minut",
one: "minuta",
two: "minuty",
few: "minuty",
many: "minut",
other: "minut",
},
second: {
zero: "sekund",
one: "sekunda",
two: "sekundy",
few: "sekundy",
many: "sekund",
other: "sekund",
},
},
},
el: {
template: {
on: (value) => `στις ${value}`,
past: (value) => `πριν ${value}`,
future: (value) => `σε ${value}`,
justNow: () => `μόλις τώρα`,
},
units: {
day: {
zero: "ημέρες",
one: "ημέρα",
two: "ημέρες",
few: "ημέρες",
many: "ημέρες",
other: "ημέρες",
},
hour: {
zero: "ώρες",
one: "ώρα",
two: "ώρες",
few: "ώρες",
many: "ώρες",
other: "ώρες",
},
minute: {
zero: "λεπτά",
one: "λεπτό",
two: "λεπτά",
few: "λεπτά",
many: "λεπτά",
other: "λεπτά",
},
second: {
zero: "δευτερόλεπτα",
one: "δευτερόλεπτο",
two: "δευτερόλεπτα",
few: "δευτερόλεπτα",
many: "δευτερόλεπτα",
other: "δευτερόλεπτα",
},
},
},
hr: {
template: {
on: (value) => `na ${value}`,
past: (value) => `prije ${value}`,
future: (value) => `za ${value}`,
justNow: () => `prije trenutka`,
},
units: {
day: {
zero: "dana",
one: "dan",
two: "dana",
few: "dana",
many: "dana",
other: "dana",
},
hour: {
zero: "sati",
one: "sat",
two: "sata",
few: "sata",
many: "sati",
other: "sati",
},
minute: {
zero: "minuta",
one: "minuta",
two: "minute",
few: "minute",
many: "minuta",
other: "minuta",
},
second: {
zero: "sekundi",
one: "sekunda",
two: "sekunde",
few: "sekunde",
many: "sekundi",
other: "sekundi",
},
},
},
sk: {
template: {
on: (value) => `v deň ${value}`,
past: (value) => `pred ${value}`,
future: (value) => `za ${value}`,
justNow: () => `práve teraz`,
},
units: {
day: {
zero: "dni",
one: "deň",
two: "dni",
few: "dni",
many: "dní",
other: "dni",
},
hour: {
zero: "hodiny",
one: "hodina",
two: "hodiny",
few: "hodiny",
many: "hodín",
other: "hodiny",
},
minute: {
zero: "minúty",
one: "minúta",
two: "minúty",
few: "minúty",
many: "minút",
other: "minúty",
},
second: {
zero: "sekundy",
one: "sekunda",
two: "sekundy",
few: "sekundy",
many: "sekúnd",
other: "sekundy",
},
},
},
no: {
template: {
on: (value) => `på ${value}`,
past: (value) => `${value} siden`,
future: (value) => `om ${value}`,
justNow: () => `nettopp`,
},
units: {
day: {
zero: "dager",
one: "dag",
two: "dager",
few: "dager",
many: "dager",
other: "dager",
},
hour: {
zero: "timer",
one: "time",
two: "timer",
few: "timer",
many: "timer",
other: "timer",
},
minute: {
zero: "minutter",
one: "minutt",
two: "minutter",
few: "minutter",
many: "minutter",
other: "minutter",
},
second: {
zero: "sekunder",
one: "sekund",
two: "sekunder",
few: "sekunder",
many: "sekunder",
other: "sekunder",
},
},
},
sl: {
template: {
on: (value) => `na ${value}`,
past: (value) => `pred ${value}`,
future: (value) => `čez ${value}`,
justNow: () => `ravno zdaj`,
},
units: {
day: {
zero: "dni",
one: "dan",
two: "dni",
few: "dni",
many: "dni",
other: "dni",
},
hour: {
zero: "ure",
one: "ura",
two: "ure",
few: "ure",
many: "ure",
other: "ure",
},
minute: {
zero: "minute",
one: "minuta",
two: "minute",
few: "minute",
many: "minute",
other: "minute",
},
second: {
zero: "sekunde",
one: "sekunda",
two: "sekunde",
few: "sekunde",
many: "sekund",
other: "sekund",
},
},
},
vi: {
template: {
on: (value) => `vào ${value}`,
past: (value) => `${value} trước`,
future: (value) => `${value} sau`,
justNow: () => `vừa mới`,
},
units: {
day: {
zero: "ngày",
one: "ngày",
two: "ngày",
few: "ngày",
many: "ngày",
other: "ngày",
},
hour: {
zero: "giờ",
one: "giờ",
two: "giờ",
few: "giờ",
many: "giờ",
other: "giờ",
},
minute: {
zero: "phút",
one: "phút",
two: "phút",
few: "phút",
many: "phút",
other: "phút",
},
second: {
zero: "giây",
one: "giây",
two: "giây",
few: "giây",
many: "giây",
other: "giây",
},
},
},
};