# acceptLanguageDetector _(no submodules)_ ## Purpose `acceptLanguageDetector` is a server-only `LocaleDetector` that parses the inbound `Accept-Language` header per RFC 9110 §5.3.5 and returns the highest-priority entry. It is the canonical fallback when nothing else (querystring, user preference, cookie, geo lookup) has produced a match — every browser submits an `Accept-Language` header so this detector almost always returns _something_ on a real request. The detector returns the _raw_ highest-q entry; supported-locale negotiation is the chain runner's responsibility (it calls `LocaleResolver.negotiate(raw, supported)` to perform BCP-47 fallback). ## Features - Full RFC 9110 q-value parsing (default 1.0, range `[0, 1]`) - Stable sort: ties keep insertion order - Wildcard `*` skipped (no useful locale information) - Malformed entries silently skipped - `environment: "server"` ## Usage: Basic Example ```ts import { acceptLanguageDetector } from "@suaveplan/react-i18n/detector/accept-language/accept-language"; import { createDetectorChain } from "@suaveplan/i18n/detector"; const chain = createDetectorChain([acceptLanguageDetector()]); ``` ## Usage: Advanced Example ```ts import { parseAcceptLanguage } from "@suaveplan/react-i18n/detector/accept-language/accept-language"; // Build a custom detector that biases language groups using the // canonical RFC 9110 parser exposed by this module. const groups = parseAcceptLanguage("fr-FR;q=0.5, de-DE;q=0.9, en;q=0.8"); // → [{ locale: "de-DE", q: 0.9 }, { locale: "en", q: 0.8 }, ...] ``` ## API Reference ### `acceptLanguageDetector(): LocaleDetector` Returns a `LocaleDetector` with `name: "acceptLanguage"` and `environment: "server"`. Only `detect(ctx)` is implemented. ### `parseAcceptLanguage(header: string): AcceptLanguageEntry[]` Parses an `Accept-Language` header into a sorted descending-by-q array of `{ locale, q }` entries. Exposed for tests and as a building block for advanced consumers building custom detectors. ### `AcceptLanguageEntry` ```ts interface AcceptLanguageEntry { readonly locale: string; readonly q: number; } ``` ## Implementation Notes - The parser uses `Array.prototype.sort` with a tie-breaking insertion-index because the JavaScript spec only guarantees a stable sort in modern engines; the explicit index keeps the behaviour deterministic across older runtimes too. - Wildcards are skipped at parse time — they never appear in the returned array. The chain runner still has the option of consulting `ctx.fallbackLocale` once every detector returns null. - An entry whose q-value is unparseable, negative, or > 1 is treated as a malformed entry per RFC 9110 ("the recipient SHOULD discard") rather than coerced to the documented default — this keeps the parser strict at the field level while staying liberal at the header level.