Errors and runtime
What the package throws, what it returns as empty, and which runtime capabilities two of its functions need.
@workspace/active-format 1.0.0Developmentunreleased, in development in Foundationbaseline ce081dc3
Three kinds of outcome#
| Situation | Outcome |
|---|---|
| an empty or unreadable value in a human formatter | '': your interface decides what to show |
| a language tag the runtime cannot format | Unsupported |
| a programming or configuration error | a Range (or Error) naming the problem |
The package never falls back silently: there is no English floor and no host default.
Unsupported language tags#
Any BCP 47 tag your runtime's Intl formats is accepted. Every other tag throws an
UnsupportedLocaleError, a RangeError that carries the locale as passed and a reason:
malformed, unsupported, calendar (only the Gregorian calendar is supported) or
numbering-system.
To test a tag before it becomes a presentation, for example a tag from a profile or a request
header, use isSupportedLocale(tag). It gives the same verdict without throwing.
Unsupported language tagsClient
| Tag | isSupportedLocale | formatNumber(1234.5) |
|---|---|---|
| en-GB | true | 1,234.5 |
| nl | true | 1.234,5 |
| pt-BR | true | 1.234,5 |
| zz-ZZ | false | UnsupportedLocaleError (unsupported) |
| en_US | false | UnsupportedLocaleError (malformed) |
| ja-JP-u-ca-japanese | false | UnsupportedLocaleError (calendar) |
// apps/docs/examples/format/locale-errors.tsx'use client';
import { formatNumber, isSupportedLocale, UnsupportedLocaleError,} from '@workspace/active-format';import { Table, TableBody, TableCell, TableHead, TableHeader, TableRow,} from '@workspace/active-ui/components/primitives/table';
// Tags a host might receive from a profile, a header or a setting.const TAGS = ['en-GB', 'nl', 'pt-BR', 'zz-ZZ', 'en_US', 'ja-JP-u-ca-japanese'];
function tryFormat(tag: string): string { try { return formatNumber(1234.5, 'decimal-1', tag); } catch (err) { if (err instanceof UnsupportedLocaleError) { return `UnsupportedLocaleError (${err.reason})`; } throw err; }}
/** * A refused tag throws: there is no silent English or host default. A host * that wants to test a tag first asks `isSupportedLocale`. */export default function LocaleErrors() { return ( <Table> <TableHeader> <TableRow> <TableHead>Tag</TableHead> <TableHead>isSupportedLocale</TableHead> <TableHead>formatNumber(1234.5)</TableHead> </TableRow> </TableHeader> <TableBody> {TAGS.map((tag) => ( <TableRow key={tag}> <TableCell className="font-mono text-xs">{tag}</TableCell> <TableCell className="font-mono text-xs" suppressHydrationWarning> {String(isSupportedLocale(tag))} </TableCell> <TableCell suppressHydrationWarning>{tryFormat(tag)}</TableCell> </TableRow> ))} </TableBody> </Table> );}Configuration errors#
These throw, because they are mistakes in code or configuration, not in data:
- a malformed pattern in
formatDateWithPattern; - a malformed currency code, or an invalid
decimalsorsign; - an unknown unit in
formatUnit; - an inconsistent
NumberSpec, or one out of range; smallestUnitlarger thanlargestUnitinformatElapsedDuration;- an untyped call of
todayIsoDateorcalendarDayOfwithout a zone.
Runtime requirements#
The package installs no polyfill: your application owns its runtime. Two functions need an Intl
capability beyond ES2022, in Node.js and in the browser alike:
| Function | Needs | Without it |
|---|---|---|
format with a Decimal | Intl. reading a string as an exact decimal (ES2023) | silent precision loss: the engine converts the string to a number itself |
format | Intl. (ES2025) | throws on every call |
First versions with both, according to MDN's compatibility data: Chrome and Edge 129, Firefox 136, Safari 16.4, Node.js 23. Decide your supported runtimes from that, or check once at start-up:
const exactDecimal = new Intl.NumberFormat('en', {useGrouping: false}).format( '9007199254740993' as unknown as number, ) === '9007199254740993';const elapsedDuration = typeof (Intl as {DurationFormat?: unknown}).DurationFormat === 'function';Without the exact-decimal capability, keep amounts with more digits than a double carries away from
formatCurrency, or install a polyfill. Without Intl.DurationFormat, do not call
formatElapsedDuration, or install a polyfill before the first call.