Formats ICU Message strings with number, date, plural, and select placeholders to create localized messages.
—
Pending
Does it follow best practices?
Impact
Pending
No eval scenarios have been run
Pending
The risk profile of this skill
Formatting utilities and type definitions for number, date, time, and custom formatters with extensible configuration.
Defines the formatter functions used for number, date/time, and plural formatting.
/**
* Interface for formatter function providers
*/
interface Formatters {
/**
* Get a number formatter instance
* @param locals - Locale(s) for formatting
* @param opts - Number formatting options
* @returns Intl.NumberFormat instance
*/
getNumberFormat(
locals?: string | string[],
opts?: NumberFormatOptions
): Intl.NumberFormat;
/**
* Get a date/time formatter instance
* @param args - Arguments for Intl.DateTimeFormat constructor
* @returns Intl.DateTimeFormat instance
*/
getDateTimeFormat(
...args: ConstructorParameters<typeof Intl.DateTimeFormat>
): Intl.DateTimeFormat;
/**
* Get a plural rules instance
* @param args - Arguments for Intl.PluralRules constructor
* @returns Intl.PluralRules instance
*/
getPluralRules(
...args: ConstructorParameters<typeof Intl.PluralRules>
): Intl.PluralRules;
}Usage Examples:
import IntlMessageFormat from "intl-messageformat";
// Custom formatters with caching
const customFormatters = {
getNumberFormat: (locales, opts) => {
// Custom number formatter with additional logic
return new Intl.NumberFormat(locales, {
...opts,
notation: 'compact' // Always use compact notation
});
},
getDateTimeFormat: (...args) => new Intl.DateTimeFormat(...args),
getPluralRules: (...args) => new Intl.PluralRules(...args)
};
const msg = new IntlMessageFormat(
'You have {count, number} notifications',
'en-US',
undefined,
{ formatters: customFormatters }
);Configuration object for defining number, date, and time format styles.
/**
* Format configuration for different formatting types
*/
interface Formats {
/** Number format configurations */
number: Record<string, NumberFormatOptions>;
/** Date format configurations */
date: Record<string, Intl.DateTimeFormatOptions>;
/** Time format configurations */
time: Record<string, Intl.DateTimeFormatOptions>;
}Default Formats:
// Built-in format configurations
const defaultFormats: Formats = {
number: {
integer: { maximumFractionDigits: 0 },
currency: { style: 'currency' },
percent: { style: 'percent' }
},
date: {
short: { month: 'numeric', day: 'numeric', year: '2-digit' },
medium: { month: 'short', day: 'numeric', year: 'numeric' },
long: { month: 'long', day: 'numeric', year: 'numeric' },
full: { weekday: 'long', month: 'long', day: 'numeric', year: 'numeric' }
},
time: {
short: { hour: 'numeric', minute: 'numeric' },
medium: { hour: 'numeric', minute: 'numeric', second: 'numeric' },
long: { hour: 'numeric', minute: 'numeric', second: 'numeric', timeZoneName: 'short' },
full: { hour: 'numeric', minute: 'numeric', second: 'numeric', timeZoneName: 'short' }
}
};Usage Examples:
// Custom format configurations
const customFormats = {
number: {
currency: { style: 'currency', currency: 'EUR' },
compact: { notation: 'compact', compactDisplay: 'short' }
},
date: {
monthYear: { month: 'long', year: 'numeric' },
dayMonth: { day: '2-digit', month: '2-digit' }
},
time: {
hourMinute: { hour: '2-digit', minute: '2-digit', hour12: false }
}
};
const msg = new IntlMessageFormat(
'Price: {price, number, currency}, Last updated: {date, date, monthYear}',
'en-US',
customFormats
);Cache structure for storing formatter instances to improve performance.
/**
* Cache structure for formatter instances
*/
interface FormatterCache {
/** Cache for number formatters */
number: Record<string, NumberFormatOptions>;
/** Cache for date/time formatters */
dateTime: Record<string, Intl.DateTimeFormat>;
/** Cache for plural rules */
pluralRules: Record<string, Intl.PluralRules>;
}Core formatting function that converts parsed message elements to formatted parts.
/**
* Format message elements to structured parts
* @param els - Array of parsed message format elements
* @param locales - Locale(s) for formatting
* @param formatters - Formatter function providers
* @param formats - Format configurations
* @param values - Values for placeholder substitution
* @param currentPluralValue - Current plural value for nested contexts
* @param originalMessage - Original message for error reporting
* @returns Array of formatted message parts
*/
function formatToParts<T>(
els: MessageFormatElement[],
locales: string | string[],
formatters: Formatters,
formats: Formats,
values?: Record<string, PrimitiveType | T | FormatXMLElementFn<T>>,
currentPluralValue?: number,
originalMessage?: string
): MessageFormatPart<T>[];Type guard function to check if a value is a formatter function for XML elements.
/**
* Type guard to check if a value is an XML element formatter function
* @param el - Value to check
* @returns True if the value is a formatter function
*/
function isFormatXMLElementFn<T>(
el: PrimitiveType | T | FormatXMLElementFn<T>
): el is FormatXMLElementFn<T>;Usage Examples:
const values = {
name: 'Alice',
link: (chunks) => `<a href="/profile">${chunks.join('')}</a>`
};
if (isFormatXMLElementFn(values.link)) {
// TypeScript now knows this is a formatter function
const result = values.link(['Click here']);
}Defines the types of parts that can be returned by formatting operations.
/**
* Types for message format parts
*/
enum PART_TYPE {
/** Literal text part */
literal = 0,
/** Object/variable part */
object = 1
}Structures for representing different types of formatted parts.
/**
* Literal text part
*/
interface LiteralPart {
type: PART_TYPE.literal;
value: string;
}
/**
* Object value part
*/
interface ObjectPart<T = any> {
type: PART_TYPE.object;
value: T;
}
/**
* Union type for all message format parts
*/
type MessageFormatPart<T> = LiteralPart | ObjectPart<T>;Basic primitive types that can be used as message values.
/**
* Basic primitive types for message values
*/
type PrimitiveType = string | number | boolean | null | undefined | Date;Function type for formatting XML/HTML elements in messages.
/**
* Function type for XML element formatting
* @param parts - Array of child content (strings or objects)
* @returns Formatted result (string, object, or array)
*/
type FormatXMLElementFn<T, R = string | T | (string | T)[]> = (
parts: Array<string | T>
) => R;Usage Examples:
// Simple string formatter
const boldFormatter: FormatXMLElementFn<never> = (parts) =>
`<strong>${parts.join('')}</strong>`;
// React component formatter
const LinkFormatter: FormatXMLElementFn<JSX.Element> = (parts) =>
<a href="/link">{parts.join('')}</a>;
// Custom object formatter
const CustomFormatter: FormatXMLElementFn<{type: string, content: string}> = (parts) => ({
type: 'custom',
content: parts.join('')
});// Create a formatter for file sizes
const fileSizeFormatter = {
getNumberFormat: (locales, opts) => {
return new Intl.NumberFormat(locales, {
...opts,
notation: 'compact',
unit: 'byte',
unitDisplay: 'short'
});
},
getDateTimeFormat: (...args) => new Intl.DateTimeFormat(...args),
getPluralRules: (...args) => new Intl.PluralRules(...args)
};
const msg = new IntlMessageFormat(
'File size: {size, number} bytes',
'en-US',
undefined,
{ formatters: fileSizeFormatter }
);// European-style number and date formatting
const europeanFormats = {
number: {
currency: { style: 'currency', currency: 'EUR' },
decimal: { minimumFractionDigits: 2, maximumFractionDigits: 2 }
},
date: {
standard: { day: '2-digit', month: '2-digit', year: 'numeric' }
},
time: {
standard: { hour: '2-digit', minute: '2-digit', hour12: false }
}
};
const europeanMsg = new IntlMessageFormat(
'Price: {price, number, currency} on {date, date, standard}',
'de-DE',
europeanFormats
);// Shared cache across multiple message instances
const sharedCache: FormatterCache = {
number: {},
dateTime: {},
pluralRules: {}
};
const createOptimizedFormatters = (cache: FormatterCache): Formatters => ({
getNumberFormat: memoize(
(...args) => new Intl.NumberFormat(...args),
{ cache: cache.number }
),
getDateTimeFormat: memoize(
(...args) => new Intl.DateTimeFormat(...args),
{ cache: cache.dateTime }
),
getPluralRules: memoize(
(...args) => new Intl.PluralRules(...args),
{ cache: cache.pluralRules }
)
});
const optimizedFormatters = createOptimizedFormatters(sharedCache);
// Use the same formatters across multiple messages
const msg1 = new IntlMessageFormat('Hello {name}!', 'en-US', undefined, {
formatters: optimizedFormatters
});
const msg2 = new IntlMessageFormat('Goodbye {name}!', 'en-US', undefined, {
formatters: optimizedFormatters
});