mirror of
https://github.com/sysadminsmedia/homebox.git
synced 2025-12-24 06:28:34 +01:00
* fix: #321 use date-fns for localized datetime formatting * chore: lint fixes for use-formatters * chore: more lint fixes for use-formatters * date and currency localization fixes --------- Co-authored-by: Ádám Kleizer <adkl@boyum-it.com>
This commit is contained in:
@@ -1,5 +1,6 @@
|
||||
import { useI18n } from "vue-i18n";
|
||||
import { type UseTimeAgoMessages, type UseTimeAgoUnitNamesDefault } from "@vueuse/core";
|
||||
import { format, formatDistance } from "date-fns";
|
||||
/* eslint import/namespace: ['error', { allowComputed: true }] */
|
||||
import * as Locales from "date-fns/locale";
|
||||
|
||||
const cache = {
|
||||
currency: "",
|
||||
@@ -20,105 +21,63 @@ export async function useFormatCurrency() {
|
||||
}
|
||||
}
|
||||
|
||||
return (value: number | string) => fmtCurrency(value, cache.currency);
|
||||
return (value: number | string) => fmtCurrency(value, cache.currency, getLocaleCode());
|
||||
}
|
||||
|
||||
export type DateTimeFormat = "relative" | "long" | "short" | "human";
|
||||
export type DateTimeType = "date" | "time" | "datetime";
|
||||
|
||||
function ordinalIndicator(num: number) {
|
||||
if (num > 3 && num < 21) return "th";
|
||||
switch (num % 10) {
|
||||
case 1:
|
||||
return "st";
|
||||
case 2:
|
||||
return "nd";
|
||||
case 3:
|
||||
return "rd";
|
||||
default:
|
||||
return "th";
|
||||
}
|
||||
export function getLocaleCode() {
|
||||
const { $i18nGlobal } = useNuxtApp();
|
||||
return ($i18nGlobal?.locale?.value as string) ?? "en-US";
|
||||
}
|
||||
|
||||
export function useLocaleTimeAgo(date: Date) {
|
||||
const { t } = useI18n();
|
||||
|
||||
const I18N_MESSAGES: UseTimeAgoMessages<UseTimeAgoUnitNamesDefault> = {
|
||||
justNow: t("components.global.date_time.just-now"),
|
||||
past: n => (n.match(/\d/) ? t("components.global.date_time.ago", [n]) : n),
|
||||
future: n => (n.match(/\d/) ? t("components.global.date_time.in", [n]) : n),
|
||||
month: (n, past) =>
|
||||
n === 1
|
||||
? past
|
||||
? t("components.global.date_time.last-month")
|
||||
: t("components.global.date_time.next-month")
|
||||
: `${n} ${t(`components.global.date_time.months`)}`,
|
||||
year: (n, past) =>
|
||||
n === 1
|
||||
? past
|
||||
? t("components.global.date_time.last-year")
|
||||
: t("components.global.date_time.next-year")
|
||||
: `${n} ${t(`components.global.date_time.years`)}`,
|
||||
day: (n, past) =>
|
||||
n === 1
|
||||
? past
|
||||
? t("components.global.date_time.yesterday")
|
||||
: t("components.global.date_time.tomorrow")
|
||||
: `${n} ${t(`components.global.date_time.days`)}`,
|
||||
week: (n, past) =>
|
||||
n === 1
|
||||
? past
|
||||
? t("components.global.date_time.last-week")
|
||||
: t("components.global.date_time.next-week")
|
||||
: `${n} ${t(`components.global.date_time.weeks`)}`,
|
||||
hour: n => `${n} ${n === 1 ? t("components.global.date_time.hour") : t("components.global.date_time.hours")}`,
|
||||
minute: n => `${n} ${n === 1 ? t("components.global.date_time.minute") : t("components.global.date_time.minutes")}`,
|
||||
second: n => `${n} ${n === 1 ? t("components.global.date_time.second") : t("components.global.date_time.seconds")}`,
|
||||
invalid: "",
|
||||
};
|
||||
|
||||
return useTimeAgo(date, {
|
||||
fullDateFormatter: (date: Date) => date.toLocaleDateString(),
|
||||
messages: I18N_MESSAGES,
|
||||
});
|
||||
function getLocaleForDate() {
|
||||
const localeCode = getLocaleCode();
|
||||
const lang = localeCode.length > 1 ? localeCode.substring(0, 2) : localeCode;
|
||||
const region = localeCode.length > 2 ? localeCode.substring(3) : "";
|
||||
return Locales[(lang + region) as keyof typeof Locales] ?? Locales[lang as keyof typeof Locales] ?? Locales.enUS;
|
||||
}
|
||||
|
||||
export function fmtDate(value: string | Date, fmt: DateTimeFormat = "human"): string {
|
||||
const months = [
|
||||
"January",
|
||||
"February",
|
||||
"March",
|
||||
"April",
|
||||
"May",
|
||||
"June",
|
||||
"July",
|
||||
"August",
|
||||
"September",
|
||||
"October",
|
||||
"November",
|
||||
"December",
|
||||
];
|
||||
export function fmtDate(
|
||||
value: string | Date | number,
|
||||
fmt: DateTimeFormat = "human",
|
||||
type: DateTimeType = "date"
|
||||
): string {
|
||||
const dt = typeof value === "string" || typeof value === "number" ? new Date(value) : value;
|
||||
|
||||
const dt = typeof value === "string" ? new Date(value) : value;
|
||||
if (!dt) {
|
||||
if (!dt || !validDate(dt)) {
|
||||
return "";
|
||||
}
|
||||
|
||||
if (!validDate(dt)) {
|
||||
return "";
|
||||
const localeOptions = { locale: getLocaleForDate() };
|
||||
|
||||
if (fmt === "relative") {
|
||||
return `${formatDistance(dt, new Date(), { ...localeOptions, addSuffix: true })} (${fmtDate(dt, "short", "date")})`;
|
||||
}
|
||||
|
||||
if (type === "time") {
|
||||
return format(dt, "p", localeOptions);
|
||||
}
|
||||
|
||||
let formatStr = "";
|
||||
|
||||
switch (fmt) {
|
||||
case "relative":
|
||||
return useLocaleTimeAgo(dt).value + useDateFormat(dt, " (YYYY-MM-DD)").value;
|
||||
case "long":
|
||||
return useDateFormat(dt, "YYYY-MM-DD (dddd)").value;
|
||||
case "short":
|
||||
return useDateFormat(dt, "YYYY-MM-DD").value;
|
||||
case "human":
|
||||
// January 1st, 2021
|
||||
return `${months[dt.getMonth()]} ${dt.getDate()}${ordinalIndicator(dt.getDate())}, ${dt.getFullYear()}`;
|
||||
formatStr = "PPP";
|
||||
break;
|
||||
case "long":
|
||||
formatStr = "PP";
|
||||
break;
|
||||
case "short":
|
||||
formatStr = "P";
|
||||
break;
|
||||
default:
|
||||
return "";
|
||||
}
|
||||
if (type === "datetime") {
|
||||
formatStr += "p";
|
||||
}
|
||||
|
||||
return format(dt, formatStr, localeOptions);
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user