first commit
This commit is contained in:
@@ -0,0 +1,82 @@
|
||||
# acceptLanguageDetector
|
||||
|
||||
<!-- begin:auto-docs -->
|
||||
_(no submodules)_
|
||||
<!-- end:auto-docs -->
|
||||
## 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.
|
||||
Reference in New Issue
Block a user