mirror of
https://github.com/lux-tel/session-desktop.git
synced 2026-10-30 20:33:24 +00:00
172 lines
5.2 KiB
TypeScript
172 lines
5.2 KiB
TypeScript
import {
|
|
FormatDistanceStrictOptions,
|
|
FormatDistanceToNowStrictOptions,
|
|
format,
|
|
formatDistanceStrict,
|
|
formatDistanceToNowStrict,
|
|
formatDuration,
|
|
formatRelative,
|
|
} from 'date-fns';
|
|
import { omit, upperFirst } from 'lodash';
|
|
import { getBrowserLocale, getTimeLocaleDictionary } from '../shared';
|
|
import { getForcedEnglishTimeLocale, timeLocaleMap } from '../timeLocaleMap';
|
|
import type { CrowdinLocale } from '../../../localization';
|
|
|
|
/**
|
|
* Formats a duration in milliseconds into a localized human-readable string.
|
|
*
|
|
* @param durationMs - The duration in milliseconds.
|
|
* @param options - An optional object containing formatting options.
|
|
* @returns A formatted string representing the duration.
|
|
*/
|
|
export const formatTimeDurationMs = (
|
|
durationMs: number,
|
|
options?: Omit<FormatDistanceStrictOptions, 'locale'>
|
|
) => {
|
|
return formatDistanceStrict(new Date(durationMs), new Date(0), {
|
|
locale: getTimeLocaleDictionary(),
|
|
...options,
|
|
});
|
|
};
|
|
|
|
export const formatToTimeWithLocale = (date: Date) => {
|
|
return new Intl.DateTimeFormat(getBrowserLocale(), {
|
|
hour: 'numeric',
|
|
minute: 'numeric',
|
|
hour12: undefined, // am/pm depending on the locale
|
|
}).format(date);
|
|
};
|
|
|
|
export const formatDateWithLocale = ({ date, formatStr }: { date: Date; formatStr: string }) => {
|
|
return format(date, formatStr, { locale: getTimeLocaleDictionary() });
|
|
};
|
|
|
|
export const formatDateOnlyInEnglish = ({ date, formatStr }: { date: Date; formatStr: string }) => {
|
|
return format(date, formatStr, { locale: timeLocaleMap.en });
|
|
};
|
|
|
|
/**
|
|
* Returns a formatted date like `Wednesday, Jun 12, 2024, 4:29 PM`
|
|
*/
|
|
export const formatFullDate = (date: Date) => {
|
|
return upperFirst(
|
|
date.toLocaleString(getBrowserLocale(), {
|
|
year: 'numeric',
|
|
month: 'short',
|
|
weekday: 'long',
|
|
day: 'numeric',
|
|
hour: 'numeric',
|
|
minute: 'numeric',
|
|
})
|
|
);
|
|
};
|
|
|
|
/**
|
|
* @param timestampMs The timestamp in ms to display with a relative string
|
|
* @returns a localized string like "last thursday", "yesterday at 10:28am", ...
|
|
*/
|
|
export const formatRelativeTimestampWithLocale = (timestampMs: number) => {
|
|
return upperFirst(formatRelative(timestampMs, Date.now(), { locale: getTimeLocaleDictionary() }));
|
|
};
|
|
|
|
/**
|
|
* Returns a forced in english string to describe - in relative terms - durationSeconds.
|
|
*
|
|
*/
|
|
export const formatTimeDistanceToNow = (
|
|
durationSeconds: number,
|
|
options?: Omit<FormatDistanceToNowStrictOptions, 'locale'>
|
|
) => {
|
|
return formatDistanceToNowStrict(durationSeconds * 1000, {
|
|
locale: getForcedEnglishTimeLocale(),
|
|
...options,
|
|
});
|
|
};
|
|
|
|
type CurrencyCode = 'USD';
|
|
|
|
type FormatNumberOptionsType = Intl.NumberFormatOptions & {
|
|
locale?: CrowdinLocale;
|
|
currency?: CurrencyCode;
|
|
};
|
|
|
|
/**
|
|
* Formats a number as a string using the browser's locale.
|
|
* If the value is not a finite number, it returns the value as a string.
|
|
*
|
|
* @param value - The number to format.
|
|
* @param options - An optional object containing formatting options
|
|
*/
|
|
export const formatNumber = (value: number, options?: FormatNumberOptionsType): string => {
|
|
if (!Number.isFinite(value)) {
|
|
return value.toString();
|
|
}
|
|
|
|
const locale = options?.locale || getBrowserLocale();
|
|
return new Intl.NumberFormat(locale, omit(options, 'locale')).format(value);
|
|
};
|
|
|
|
/**
|
|
* Returns an English formatted date like `12 June 2024`
|
|
*/
|
|
export const formatToDateOnlyInEnglish = (date: Date) => {
|
|
return new Intl.DateTimeFormat('en-GB', {
|
|
day: 'numeric',
|
|
month: 'long',
|
|
year: 'numeric',
|
|
}).format(date);
|
|
};
|
|
|
|
/**
|
|
* Returns an English formatted time like `2:29 PM`
|
|
*/
|
|
export const formatToTimeOnlyInEnglish = (date: Date) => {
|
|
return new Intl.DateTimeFormat('en-GB', {
|
|
hour: 'numeric',
|
|
minute: 'numeric',
|
|
hour12: true,
|
|
}).format(date);
|
|
};
|
|
|
|
/**
|
|
* Formats a duration to a rounded up localized duration string.
|
|
*
|
|
* Rules:
|
|
* - Days: when more than 1 full day remains (rounds up)
|
|
* - Hours: when less than 1 full day but more than 1 full hour remains (rounds up)
|
|
* - Minutes: when less than 1 full hour remains (rounds up, minimum 1 minute)
|
|
*
|
|
* @param durationsMs - Duration in milliseconds
|
|
* @returns A formatted string like "25 days", "24 hours", or "33 minutes"
|
|
*/
|
|
export function formatRoundedUpDuration(durationMs: number): string {
|
|
const locale = getTimeLocaleDictionary();
|
|
const daysRemaining = durationMs / (1000 * 60 * 60 * 24);
|
|
if (daysRemaining >= 1) {
|
|
const displayDays = Math.ceil(daysRemaining);
|
|
const duration = { days: displayDays };
|
|
return formatDuration(duration, { locale });
|
|
}
|
|
|
|
const hoursRemaining = durationMs / (1000 * 60 * 60);
|
|
if (hoursRemaining >= 1) {
|
|
const displayHours = Math.ceil(hoursRemaining);
|
|
const duration = { hours: displayHours };
|
|
return formatDuration(duration, { locale });
|
|
}
|
|
|
|
const minutesRemaining = durationMs / (1000 * 60);
|
|
const displayMinutes = Math.max(1, Math.ceil(minutesRemaining));
|
|
const duration = { minutes: displayMinutes };
|
|
return formatDuration(duration, { locale });
|
|
}
|
|
|
|
/**
|
|
* Formats the time remaining until a unix timestamp with localized duration strings.
|
|
* @see {@link formatRoundedUpDuration}
|
|
*/
|
|
export function formatRoundedUpTimeUntilTimestamp(unixTsMs: number): string {
|
|
const msRemaining = unixTsMs - Date.now();
|
|
return formatRoundedUpDuration(msRemaining);
|
|
}
|