From 017be69511d1d3638fa834ffb1300fbbb9a187b7 Mon Sep 17 00:00:00 2001 From: "(quasar) nebula" Date: Wed, 29 Nov 2023 21:41:16 -0400 Subject: data: language: formatDateDuration, formatRelativeDate Also related counting functions. --- src/data/things/language.js | 108 ++++++++++++++++++++++++++++++++++++++++++++ src/strings-default.yaml | 48 ++++++++++++++++++++ 2 files changed, 156 insertions(+) (limited to 'src') diff --git a/src/data/things/language.js b/src/data/things/language.js index d8af9620..fa529a8e 100644 --- a/src/data/things/language.js +++ b/src/data/things/language.js @@ -1,3 +1,5 @@ +import { Temporal, toTemporalInstant } from '@js-temporal/polyfill'; + import {isLanguageCode} from '#validators'; import {Tag} from '#html'; @@ -284,6 +286,108 @@ export class Language extends Thing { return this.intl_date.formatRange(startDate, endDate); } + formatDateDuration({ + years: numYears = 0, + months: numMonths = 0, + days: numDays = 0, + approximate = false, + }) { + let basis; + + const years = this.countYears(numYears, {unit: true}); + const months = this.countMonths(numMonths, {unit: true}); + const days = this.countDays(numDays, {unit: true}); + + if (numYears && numMonths && numDays) + basis = this.formatString('count.dateDuration.yearsMonthsDays', {years, months, days}); + else if (numYears && numMonths) + basis = this.formatString('count.dateDuration.yearsMonths', {years, months}); + else if (numYears && numDays) + basis = this.formatString('count.dateDuration.yearsDays', {years, days}); + else if (numYears) + basis = this.formatString('count.dateDuration.years', {years}); + else if (numMonths && numDays) + basis = this.formatString('count.dateDuration.monthsDays', {months, days}); + else if (numMonths) + basis = this.formatzString('count.dateDuration.months', {months}); + else if (numDays) + basis = this.formatString('count.dateDuration.days', {days}); + else + return this.formatString('count.dateDuration.zero'); + + if (approximate) { + return this.formatString('count.dateDuration.approximate', { + duration: basis, + }); + } else { + return basis; + } + } + + formatRelativeDate(currentDate, referenceDate, { + considerRoundingDays = false, + approximate = true, + absolute = true, + } = {}) { + const currentInstant = toTemporalInstant.apply(currentDate); + const referenceInstant = toTemporalInstant.apply(referenceDate); + + const comparison = + Temporal.Instant.compare(currentInstant, referenceInstant); + + if (comparison === 0) { + return this.formatString('count.dateDuration.same'); + } + + const currentTDZ = currentInstant.toZonedDateTimeISO('Etc/UTC'); + const referenceTDZ = referenceInstant.toZonedDateTimeISO('Etc/UTC'); + + const earlierTDZ = (comparison === -1 ? currentTDZ : referenceTDZ); + const laterTDZ = (comparison === 1 ? currentTDZ : referenceTDZ); + + const {years, months, days} = + laterTDZ.since(earlierTDZ, { + largestUnit: 'year', + smallestUnit: + (considerRoundingDays + ? (laterTDZ.since(earlierTDZ, { + largestUnit: 'year', + smallestUnit: 'day', + }).years + ? 'month' + : 'day') + : 'day'), + roundingMode: 'halfCeil', + }); + + const duration = + this.formatDateDuration({ + years, months, days, + approximate: false, + }); + + const relative = + this.formatString( + 'count.dateDuration', + (approximate + ? (comparison === -1 + ? 'approximateEarlier' + : 'approximateLater') + : (comparison === -1 + ? 'earlier' + : 'later')), + {duration}); + + if (absolute) { + return this.formatString('count.dateDuration.relativeAbsolute', { + relative, + absolute: this.formatDate(currentDate), + }); + } else { + return relative; + } + } + formatDuration(secTotal, {approximate = false, unit = false} = {}) { if (secTotal === 0) { return this.formatString('count.duration.missing'); @@ -442,7 +546,11 @@ Object.assign(Language.prototype, { countCommentaryEntries: countHelper('commentaryEntries', 'entries'), countContributions: countHelper('contributions'), countCoverArts: countHelper('coverArts'), + countDays: countHelper('days'), + countMonths: countHelper('months'), countTimesReferenced: countHelper('timesReferenced'), countTimesUsed: countHelper('timesUsed'), countTracks: countHelper('tracks'), + countWeeks: countHelper('weeks'), + countYears: countHelper('years'), }); diff --git a/src/strings-default.yaml b/src/strings-default.yaml index af2ddc42..30b04141 100644 --- a/src/strings-default.yaml +++ b/src/strings-default.yaml @@ -129,6 +129,16 @@ count: many: "" other: "{DAYS} days" + months: + _: "{MONTHS}" + withUnit: + zero: "" + one: "{MONTHS} month" + two: "" + few: "" + many: "" + other: "{MONTHS} months" + timesReferenced: _: "{TIMES_REFERENCED}" withUnit: @@ -149,6 +159,16 @@ count: many: "" other: "used {TIMES_USED} times" + weeks: + _: "{WEEKS}" + withUnit: + zero: "" + one: "{WEEKS} week" + two: "" + few: "" + many: "" + other: "{WEEKS} weeks" + words: _: "{WORDS}" thousand: "{WORDS}k" @@ -160,6 +180,16 @@ count: many: "" other: "{WORDS} words" + years: + _: "{YEARS}" + withUnit: + zero: "" + one: "{YEARS} year" + two: "" + few: "" + many: "" + other: "{YEARS} years" + # Numerical things that aren't exactly counting, per se duration: @@ -172,6 +202,24 @@ count: _: "{MINUTES}:{SECONDS}" withUnit: "{MINUTES}:{SECONDS} minutes" + dateDuration: + earlier: "{DURATION} earlier" + later: "{DURATION} later" + same: "on the same date" + zero: "no days apart" + approximate: "about {DURATION}" + approximateEarlier: "about {DURATION} earlier" + approximateLater: "about {DURATION} later" + relativeAbsolute: "{ABSOLUTE}; {RELATIVE}" + + years: "{YEARS}" + months: "{MONTHS}" + days: "{DAYS}" + yearsMonthsDays: "{YEARS}, {MONTHS}, {DAYS}" + yearsMonths: "{YEARS}, {MONTHS}" + yearsDays: "{YEARS}, {DAYS}" + monthsDays: "{MONTHS}, {DAYS}" + fileSize: terabytes: "{TERABYTES} TB" gigabytes: "{GIGABYTES} GB" -- cgit 1.3.0-6-gf8a5