8.3 KiB
Capability Spec: i18n-formatter-display-name (i18n-formatter-display-name)
Package: @suaveplan/i18n-formatter-display-name
Status: ACTIVE
Every requirement below carries a
**Verified by:**line at authoring time. (Seeopenspec/AGENTS.mdSection 13.)
Requirements
Requirement: DisplayNameFormatter class wrapping Intl.DisplayNames
The package SHALL export a DisplayNameFormatter class that wraps Intl.DisplayNames with construction-time Zod validation of options and a format(code: string, locale: string): string method. Construction with malformed options SHALL throw I18nError(I18N.INVALID_FORMATTER_OPTIONS). The type option is required.
Scenario: format with type: language
- GIVEN
const f = new DisplayNameFormatter({ type: "language" }) - WHEN
f.format("fr", "en-GB")is called - THEN the result equals
"French"
Scenario: missing type throws INVALID_FORMATTER_OPTIONS
- WHEN
new DisplayNameFormatter({} as never)is called - THEN the call throws
I18nErrorwith code"I18N.INVALID_FORMATTER_OPTIONS"
Verified by: packages/i18n/i18n-formatter-display-name/src/formatter.test.ts::"DisplayNameFormatter formats language" AND packages/i18n/i18n-formatter-display-name/src/formatter.test.ts::"DisplayNameFormatter rejects missing type with INVALID_FORMATTER_OPTIONS"
Requirement: formatDisplayName standalone helper
The package SHALL export a formatDisplayName(code, locale, options) standalone helper that delivers the same behaviour as DisplayNameFormatter.format without requiring class construction. Defaults: style: "long", fallback: "code".
Scenario: standalone helper formats region
- WHEN
formatDisplayName("GB", "en-GB", { type: "region" })is called - THEN the result equals
"United Kingdom"
Scenario: standalone helper twins class output
- WHEN both
formatDisplayName(code, l, opts)andnew DisplayNameFormatter(opts).format(code, l)are called for the same(code, l, opts) - THEN the results are identical
Verified by: packages/i18n/i18n-formatter-display-name/src/formatter.test.ts::"formatDisplayName formats region" AND packages/i18n/i18n-formatter-display-name/src/formatter.test.ts::"formatDisplayName output twins DisplayNameFormatter.format output"
Requirement: Intl.DisplayNames RangeError maps to UNSUPPORTED_LOCALE
The package SHALL catch every RangeError thrown by the Intl.DisplayNames constructor and re-throw it as I18nError(I18N.UNSUPPORTED_LOCALE) with the original error attached as cause and the locale string in context.
Scenario: bogus locale throws UNSUPPORTED_LOCALE
- WHEN
formatDisplayName("fr", "xx-bogus-tag-!!!", { type: "language" })is called - THEN the call throws
I18nErrorwith code"I18N.UNSUPPORTED_LOCALE"AND the error'scauseis the originalRangeError
Verified by: packages/i18n/i18n-formatter-display-name/src/formatter.test.ts::"unsupported locale throws UNSUPPORTED_LOCALE with cause"
Requirement: Per-(locale, type, style, fallback) cache
The package SHALL maintain an internal Map<string, Intl.DisplayNames> keyed by ${locale}|${type}|${style}|${fallback}. Repeated calls with identical key SHALL reuse the same Intl.DisplayNames instance. The package SHALL export a clearDisplayNameCache() test-only helper.
Scenario: identical key reuses the same Intl.DisplayNames
- GIVEN the cache is empty
- WHEN
formatDisplayName("fr", "en-GB", { type: "language" })is called twice in sequence - THEN only one
Intl.DisplayNamesconstructor invocation occurs
Scenario: distinct type creates distinct cache entries
- WHEN
formatDisplayName("fr", "en-GB", { type: "language" })andformatDisplayName("fr", "en-GB", { type: "region" })are called - THEN two distinct
Intl.DisplayNamesinstances are created and cached
Verified by: packages/i18n/i18n-formatter-display-name/src/formatter.test.ts::"identical key reuses cached Intl.DisplayNames" AND packages/i18n/i18n-formatter-display-name/src/formatter.test.ts::"distinct type creates distinct cache entries"
Requirement: OTel histogram i18n.format.display_name.duration_ms
The package SHALL emit an OTel histogram named exactly i18n.format.display_name.duration_ms (unit ms) on every successful formatDisplayName call, tagged with locale, type, and style.
Scenario: histogram emitted on every call
- GIVEN an OTel test exporter capturing histogram observations
- WHEN
formatDisplayName("fr", "en-GB", { type: "language", style: "long" })is called - THEN exactly one observation appears under
i18n.format.display_name.duration_mswithlocale,type, andstyleattributes
Verified by: packages/i18n/i18n-formatter-display-name/src/observability.test.ts::"emits i18n.format.display_name.duration_ms histogram on every call"
Requirement: OTel cache-hit counter i18n.format.cache_hit
The package SHALL emit an OTel counter i18n.format.cache_hit tagged with formatter: "display_name" on every cache hit. The counter SHALL NOT increment on the first (cache-miss) call.
Scenario: cache-hit counter increments only on second call
- GIVEN an OTel test exporter capturing counter observations and an empty cache
- WHEN
formatDisplayName("fr", "en-GB", { type: "language" })is called twice in sequence - THEN the counter
i18n.format.cache_hit{formatter="display_name"}shows exactly one increment
Verified by: packages/i18n/i18n-formatter-display-name/src/observability.test.ts::"cache-hit counter increments only on second call with same options"
Requirement: Ergonomic helpers — language, region, currency, script, calendar
The package SHALL export formatLanguageName, formatRegionName, formatCurrencyName, formatScriptName, and formatCalendarName ergonomic shortcuts pre-binding formatDisplayName with the corresponding type.
Scenario: formatLanguageName renders French
- WHEN
formatLanguageName("fr", "en-GB")is called - THEN the result equals
"French"
Scenario: formatRegionName renders United Kingdom
- WHEN
formatRegionName("GB", "en-GB")is called - THEN the result equals
"United Kingdom"
Scenario: formatCurrencyName renders US Dollar
- WHEN
formatCurrencyName("USD", "en-GB")is called - THEN the result equals
"US Dollar"
Scenario: formatScriptName renders Latin
- WHEN
formatScriptName("Latn", "en-GB")is called - THEN the result equals
"Latin"
Scenario: formatCalendarName renders gregorian
- WHEN
formatCalendarName("gregory", "en-GB")is called - THEN the result is the locale-correct gregorian display name (non-empty)
Verified by: packages/i18n/i18n-formatter-display-name/src/helpers.test.ts::"formatLanguageName renders French" AND packages/i18n/i18n-formatter-display-name/src/helpers.test.ts::"formatRegionName renders United Kingdom" AND packages/i18n/i18n-formatter-display-name/src/helpers.test.ts::"formatCurrencyName renders US Dollar" AND packages/i18n/i18n-formatter-display-name/src/helpers.test.ts::"formatScriptName renders Latin" AND packages/i18n/i18n-formatter-display-name/src/helpers.test.ts::"formatCalendarName renders gregorian display name"
Requirement: Subpath exports
The package SHALL declare subpath exports in package.json:
@suaveplan/i18n-formatter-display-name— root barrel@suaveplan/i18n-formatter-display-name/formatter—DisplayNameFormatterclass +formatDisplayName+ types + schema only@suaveplan/i18n-formatter-display-name/helpers— five ergonomic helpers only
Scenario: every documented subpath resolves
- WHEN every documented subpath is imported in a consumer test fixture
- THEN every import resolves with no
Module not founderrors
Verified by: packages/i18n/i18n-formatter-display-name/src/index.test.ts::"every documented subpath export resolves"
Requirement: Side-effect-free package
The package SHALL declare "sideEffects": false in package.json.
Scenario: package.json declares sideEffects false
- WHEN
package.jsonis parsed - THEN the
sideEffectsfield equalsfalse
Verified by: packages/i18n/i18n-formatter-display-name/src/index.test.ts::"package.json declares sideEffects false"