/** * Texts with named blanks, such as "{name} on a phone". The page texts are plain * data in two languages, so a sentence with a variable part keeps a blank for it. */ export type TemplateValues = Readonly>; const BLANK = /\{(\w+)\}/g; export function fill(template: string, values: TemplateValues): string { return template.replace(BLANK, (blank, name: string) => Object.hasOwn(values, name) ? String(values[name]) : blank, ); }