-
-
- {title}
- {date}
-
+
+
+
+
{title}
+
+ {$displayRange(range.start, range.end)} • {$displayMonthDuration(
+ range.start,
+ range.end
+ )}
+
+ {#if body}
+
+ {/if}
-
- {#if body}
-
- {/if}
diff --git a/svelte-app/src/languages/en.json b/svelte-app/src/languages/en.json
index 9beaab911..32bcb7210 100644
--- a/svelte-app/src/languages/en.json
+++ b/svelte-app/src/languages/en.json
@@ -57,6 +57,10 @@
"present": "present",
"refresh the page": "refresh the page",
"{length} min read": "{length} min read",
+ "{months} months": "{months} months",
+ "{month} month": "{month} month",
"{stars} stars": "{stars} stars",
- "{views} views": "{views} views"
+ "{views} views": "{views} views",
+ "{years} years": "{years} years",
+ "{year} year": "{year} year"
}
\ No newline at end of file
diff --git a/svelte-app/src/languages/fr.json b/svelte-app/src/languages/fr.json
index 49d914387..3a6bbbb08 100644
--- a/svelte-app/src/languages/fr.json
+++ b/svelte-app/src/languages/fr.json
@@ -57,6 +57,10 @@
"present": "présent",
"refresh the page": "rafraîchir la page",
"{length} min read": "{length} minute de lecture",
+ "{month} month": "{month} mois",
+ "{month} months": "{month} mois",
"{stars} stars": "{stars} étoiles",
- "{views} views": "{views} vues"
+ "{views} views": "{views} vues",
+ "{year} year": "{year} an",
+ "{year} years": "{year} ans"
}
\ No newline at end of file
diff --git a/svelte-app/src/lib/date.ts b/svelte-app/src/lib/date.ts
new file mode 100644
index 000000000..0c333e8f0
--- /dev/null
+++ b/svelte-app/src/lib/date.ts
@@ -0,0 +1,83 @@
+/* eslint-disable func-call-spacing */
+import { derived } from 'svelte/store';
+
+import { currentLang, t } from '$i18n';
+
+export const displayRange = derived([currentLang, t], ([currentLang, t]) => {
+ return (start: string, end: string | undefined) => {
+ try {
+ const startDate = new Date(start),
+ endDate = end ? new Date(end) : undefined;
+
+ if (!endDate) {
+ return `${new Intl.DateTimeFormat(currentLang, {
+ month: 'short',
+ year: 'numeric'
+ }).format(startDate)} - ${t('present')}`;
+ }
+
+ return `${new Intl.DateTimeFormat(currentLang, {
+ month: 'short',
+ year: 'numeric'
+ }).format(startDate)} - ${new Intl.DateTimeFormat(currentLang, {
+ month: 'short',
+ year: 'numeric'
+ }).format(endDate)}`;
+ } catch (_) {
+ return t('Invalid date');
+ }
+ };
+});
+
+export const displayMonthDuration = derived<
+ typeof t,
+ (startDate?: string | Date, endDate?: string | Date) => string
+>(t, (t) => {
+ return (startDate?: string | Date, endDate?: string | Date) => {
+ if (!startDate) {
+ return t('{month} month', { month: 1 });
+ }
+
+ const start = new Date(startDate),
+ end = endDate ? new Date(endDate) : new Date();
+
+ let years = end.getFullYear() - start.getFullYear();
+ let months = end.getMonth() - start.getMonth();
+
+ // Adjust for cases where the end month is earlier in the year than the start month
+ if (months < 0) {
+ years--;
+ months += 12; // Add the months that have passed in the current year
+ }
+
+ // Consolidate total duration into years and months
+ years += Math.floor(months / 12);
+ months %= 12;
+
+ let yearString = '',
+ monthString = '';
+
+ if (years > 0) {
+ if (years === 1) {
+ yearString = t('{year} year', { year: years });
+ } else {
+ yearString = t('{year} years', { year: years });
+ }
+ }
+
+ if (months > 0) {
+ if (months === 1) {
+ monthString = t('{month} month', { month: months });
+ } else {
+ monthString = t('{month} months', { month: months });
+ }
+ }
+
+ // Handle the case where the difference is less than one month
+ if (years > 0 && months > 0) {
+ monthString = t('{month} month', { month: 1 });
+ }
+
+ return `${yearString}${yearString && monthString ? ' ' : ''}${monthString}`;
+ };
+});