2.7 KiB
2.7 KiB
bcp47-negotiate.ts — default BCP-47 negotiator
Purpose
bcp47Negotiate(raw, supported, fallback) is the default negotiator
wired into createDetectorChain when no options.negotiate is
supplied. It maps a detector's raw locale output onto a value the
application actually supports without forcing the configured
fallback prematurely. Returning null on miss is intentional — the
chain advances to the next detector instead of committing to the
fallback before every detector has been consulted.
The implementation handles the three cases the upstream
LocaleResolver.resolve() happy path covered: exact match,
short-code expansion via LOCALE_BCP47_MAP from
@suaveplan/i18n-shared, and language-subtag fallback.
Features
- Exact-match short-circuit: returns the raw input unchanged when it
appears in
supported. - Short-code expansion via
LOCALE_BCP47_MAP("en"→"en-GB"). - Language-subtag matching falls back to the first supported entry whose primary language matches the raw input's primary language.
- Strict null on miss — the negotiator never invents a value.
- Pure function, no internal state, safe to call from any context.
Usage: Basic Example
import { bcp47Negotiate } from "@suaveplan/i18n-detector/chain";
bcp47Negotiate("fr-FR", ["en-GB", "fr-FR"], "en-GB"); // "fr-FR"
bcp47Negotiate("en", ["en-GB", "fr-FR"], "en-GB"); // "en-GB"
bcp47Negotiate("zh-Hant-TW", ["zh-CN", "en-GB"], "en-GB"); // "zh-CN"
bcp47Negotiate("xx-XX", ["en-GB"], "en-GB"); // null
Usage: Advanced Example
import {
bcp47Negotiate,
createDetectorChain,
type NegotiateFn,
} from "@suaveplan/i18n-detector";
// Wrap the default with a per-request override map.
const negotiate: NegotiateFn = (raw, supported, fallback) => {
if (raw === "zh-Hans") return "zh-CN";
return bcp47Negotiate(raw, supported, fallback);
};
const chain = createDetectorChain(detectors, { negotiate });
API Reference
bcp47Negotiate: NegotiateFn— pure function;(raw: string, supported: readonly string[], fallback: string) => string | null.- Returns
nullwhen input is empty, non-string, or no supported match exists. - The
fallbackargument is accepted for parity with theNegotiateFnsignature but is intentionally unused — the chain decides the fallback policy.
Implementation Notes
- Lookup order: exact → lower-cased short-code expansion → original short-code expansion → language-subtag scan.
LOCALE_BCP47_MAPis consulted twice (loweredfirst, raw form as a fallback) so mixed-case inputs like"En-GB"resolve via the same lookup path as"en".- Whitespace-only and empty inputs return
nullbefore any lookup runs.