first commit
This commit is contained in:
109
docs/localization/i18n/i18n-shared/src/errors/error-codes.md
Normal file
109
docs/localization/i18n/i18n-shared/src/errors/error-codes.md
Normal file
@@ -0,0 +1,109 @@
|
||||
# `I18N_CODES` and `I18nErrorCode` — i18n error code registry
|
||||
|
||||
## Purpose
|
||||
|
||||
`I18N_CODES` is the single, frozen registry of every fully-qualified
|
||||
error code that any package in the `@suaveplan/i18n*` family is
|
||||
permitted to throw. Keeping all 18 codes in one runtime constant has
|
||||
two non-negotiable benefits: (1) `instanceof I18nError` plus a
|
||||
`switch (err.code)` discrimination is exhaustive at the type level
|
||||
without importing every leaf, and (2) OTel span events, log sinks,
|
||||
and dashboards see one stable `"I18N."` prefix rather than 13
|
||||
separate per-leaf prefixes. `I18nErrorCode` is the discriminant
|
||||
union derived from the registry — use it as the `TCode` parameter
|
||||
when extending `SuaveplanError`.
|
||||
|
||||
## Features
|
||||
|
||||
- 18 codes covering parser, interpolation, pluralization, backends,
|
||||
formatters, detector, and plugin failures
|
||||
- Every code is namespaced under `"I18N."` (e.g. `"I18N.MISSING_KEY"`)
|
||||
- Frozen registry — `I18N_CODES.MISSING_KEY = "x"` throws at runtime
|
||||
- Type-level discriminant union (`I18nErrorCode`) is exhaustive
|
||||
- Back-compat alias `I18nCode` for pre-split call-sites
|
||||
|
||||
## Usage: Basic Example
|
||||
|
||||
```ts
|
||||
import { I18N_CODES, I18nError } from "@suaveplan/i18n-shared";
|
||||
|
||||
throw new I18nError(I18N_CODES.MISSING_KEY, "i18n.missing", {
|
||||
context: { key: "checkout.button" },
|
||||
});
|
||||
```
|
||||
|
||||
## Usage: Advanced Example
|
||||
|
||||
```ts
|
||||
import {
|
||||
I18N_CODES,
|
||||
I18nError,
|
||||
type I18nErrorCode,
|
||||
} from "@suaveplan/i18n-shared/errors";
|
||||
|
||||
function categorise(err: I18nError): "user" | "config" | "system" {
|
||||
const code: I18nErrorCode = err.code;
|
||||
switch (code) {
|
||||
case I18N_CODES.MISSING_KEY:
|
||||
case I18N_CODES.INVALID_LOCALE:
|
||||
return "user";
|
||||
case I18N_CODES.INVALID_OPTIONS:
|
||||
case I18N_CODES.INVALID_FORMATTER_OPTIONS:
|
||||
case I18N_CODES.UNSUPPORTED_LOCALE:
|
||||
case I18N_CODES.PLUGIN_ALREADY_INSTALLED:
|
||||
return "config";
|
||||
default:
|
||||
return "system";
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
## API Reference
|
||||
|
||||
### `I18N_CODES`
|
||||
|
||||
Frozen `Record` of code-name → `"I18N.<code>"` literal. The 18 codes:
|
||||
|
||||
| Cluster | Code | Failure |
|
||||
|---|---|---|
|
||||
| Parser | `MISSING_KEY` | Lookup found no value |
|
||||
| Parser | `INVALID_LOCALE` | Locale tag is not BCP-47 parseable |
|
||||
| Parser | `INVALID_OPTIONS` | Catalog/parser options failed validation |
|
||||
| Parser | `LOADER_FAILED` | Async catalog loader rejected |
|
||||
| Parser | `INTERPOLATION_ERROR` | Placeholder render threw |
|
||||
| Parser | `PLURAL_RULE_NOT_FOUND` | No plural rule for the locale |
|
||||
| Parser | `NESTING_DEPTH_EXCEEDED` | Recursion exceeded `maxDepth` |
|
||||
| Backend | `BACKEND_READ_FAILED` | Read raised |
|
||||
| Backend | `BACKEND_WRITE_FAILED` | Write raised |
|
||||
| Backend | `BACKEND_NOT_REGISTERED` | Lookup against unknown backend |
|
||||
| Backend | `BACKEND_LOCALE_NOT_AVAILABLE` | Locale missing from backend |
|
||||
| Backend | `BACKEND_TIMEOUT` | Backend exceeded its deadline |
|
||||
| Backend | `CHAINED_BACKEND_ALL_FAILED` | Every chain candidate raised |
|
||||
| Formatter | `INVALID_FORMATTER_OPTIONS` | Formatter opts rejected |
|
||||
| Formatter | `UNSUPPORTED_LOCALE` | Locale not in supported set |
|
||||
| Formatter | `FORMATTER_CACHE_OVERFLOW` | LRU cap exceeded |
|
||||
| Detector | `DETECTOR_CHAIN_EXHAUSTED` | No detector returned a locale |
|
||||
| Plugin | `PLUGIN_ALREADY_INSTALLED` | Duplicate plugin registration |
|
||||
|
||||
### `I18nErrorCode`
|
||||
|
||||
`type I18nErrorCode = (typeof I18N_CODES)[keyof typeof I18N_CODES]` —
|
||||
discriminant union over all 18 fully-qualified strings.
|
||||
|
||||
### `I18nCode`
|
||||
|
||||
Back-compat alias for `I18nErrorCode`. New code SHOULD prefer
|
||||
`I18nErrorCode`.
|
||||
|
||||
## Implementation Notes
|
||||
|
||||
- The registry is constructed via `defineCodes("I18N", [...] as const)`
|
||||
from `@suaveplan/error`, which freezes the result with
|
||||
`Object.freeze` and infers the literal-typed `Record`.
|
||||
- The four "new" codes (`BACKEND_TIMEOUT`,
|
||||
`CHAINED_BACKEND_ALL_FAILED`, `DETECTOR_CHAIN_EXHAUSTED`,
|
||||
`FORMATTER_CACHE_OVERFLOW`) model failure modes the per-package
|
||||
split surfaces — they were latent in the monolith but never
|
||||
formally typed.
|
||||
- Cardinality 18 is asserted at type level via `expectTypeOf` in the
|
||||
unit test so future drift is caught at typecheck time.
|
||||
Reference in New Issue
Block a user