first version
This commit is contained in:
@@ -0,0 +1,78 @@
|
||||
/**
|
||||
* Per-locale formatters used in PDF rendering. We pin these to specific
|
||||
* locales (de-AT for German invoices) so that the output is deterministic
|
||||
* regardless of the runtime's default locale.
|
||||
*/
|
||||
|
||||
const MONEY_FORMATTERS = new Map<string, Intl.NumberFormat>();
|
||||
const QTY_FORMATTERS = new Map<string, Intl.NumberFormat>();
|
||||
const DATE_FORMATTERS = new Map<string, Intl.DateTimeFormat>();
|
||||
|
||||
function localeFor(language: string): string {
|
||||
return language === "en" ? "en-GB" : "de-AT";
|
||||
}
|
||||
|
||||
export function formatMoney(
|
||||
amount: number | string,
|
||||
currency: string,
|
||||
language: string,
|
||||
): string {
|
||||
const num = typeof amount === "string" ? Number(amount) : amount;
|
||||
const key = `${language}|${currency}`;
|
||||
let f = MONEY_FORMATTERS.get(key);
|
||||
if (!f) {
|
||||
f = new Intl.NumberFormat(localeFor(language), {
|
||||
style: "decimal",
|
||||
minimumFractionDigits: 2,
|
||||
maximumFractionDigits: 2,
|
||||
});
|
||||
MONEY_FORMATTERS.set(key, f);
|
||||
}
|
||||
return `${f.format(Number.isFinite(num) ? num : 0)} ${currency}`;
|
||||
}
|
||||
|
||||
export function formatQuantity(qty: number, unit: string, language: string): string {
|
||||
let f = QTY_FORMATTERS.get(language);
|
||||
if (!f) {
|
||||
f = new Intl.NumberFormat(localeFor(language), {
|
||||
minimumFractionDigits: 2,
|
||||
maximumFractionDigits: 2,
|
||||
});
|
||||
QTY_FORMATTERS.set(language, f);
|
||||
}
|
||||
return `${f.format(qty)} ${unit}`;
|
||||
}
|
||||
|
||||
export function formatDate(date: Date | string, language: string): string {
|
||||
const d = typeof date === "string" ? new Date(date) : date;
|
||||
let f = DATE_FORMATTERS.get(language);
|
||||
if (!f) {
|
||||
f = new Intl.DateTimeFormat(localeFor(language), {
|
||||
day: "2-digit",
|
||||
month: "2-digit",
|
||||
year: "numeric",
|
||||
});
|
||||
DATE_FORMATTERS.set(language, f);
|
||||
}
|
||||
return f.format(d);
|
||||
}
|
||||
|
||||
/** Adds days to a date, returning a new Date. */
|
||||
export function addDays(date: Date, days: number): Date {
|
||||
const d = new Date(date);
|
||||
d.setDate(d.getDate() + days);
|
||||
return d;
|
||||
}
|
||||
|
||||
/**
|
||||
* Formats a percentage. Tax rates from Shopify can be either 0.20 or 20 — we
|
||||
* accept both shapes via heuristics.
|
||||
*/
|
||||
export function formatTaxRate(rate: number, language: string): string {
|
||||
const pct = rate <= 1 ? rate * 100 : rate;
|
||||
const f = new Intl.NumberFormat(localeFor(language), {
|
||||
minimumFractionDigits: 0,
|
||||
maximumFractionDigits: 2,
|
||||
});
|
||||
return `${f.format(pct)}%`;
|
||||
}
|
||||
Reference in New Issue
Block a user