UNPKG

@schukai/monster

Version:

Monster is a simple library for creating fast, robust and lightweight websites.

1,388 lines (1,345 loc) 25.1 kB
/** * 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", }, }, }, };