first commit
This commit is contained in:
182
docs/localization/i18n/i18n-icu-parser/README.md
Normal file
182
docs/localization/i18n/i18n-icu-parser/README.md
Normal file
@@ -0,0 +1,182 @@
|
||||
# @suaveplan/i18n-icu-parser - ICU MessageFormat parser, {{var}} interpolation engine, and 9-language CLDR pluralization for the @suaveplan/i18n family. Universal leaf package — no formatter, backend, or core dependencies. Renders ICU placeholders through a FormatBridge DI seam so the package stays free of Intl wrappers.
|
||||
|
||||
## Summary
|
||||
|
||||
ICU MessageFormat parser, `{{var}}` interpolation engine, and
|
||||
9-language CLDR pluralization for the `@suaveplan/i18n` family.
|
||||
Universal leaf package — depends only on
|
||||
`@suaveplan/i18n-shared`, `@suaveplan/error`, `@suaveplan/types`,
|
||||
and the OTel API. No formatter, backend, detector, or core
|
||||
dependencies.
|
||||
|
||||
<!-- begin:auto-docs -->
|
||||
## Documentation tree
|
||||
|
||||
- [interpolation](./src/interpolation/interpolation.md) — <!-- begin:auto-docs --> _(no submodules)_ <!-- end:auto-docs -->
|
||||
- [escape-html](./src/interpolation/escape-html.md) — `escapeHtmlChars` converts the five HTML special characters (`&`, `<`, `>`, `"`, `'`) to their numeric / named entity e…
|
||||
- [escape-regex](./src/interpolation/escape-regex.md) — `escapeRegex` escapes every regular-expression metacharacter in a string so the string can be embedded literally inside…
|
||||
- [interpolation](./src/interpolation/interpolation.md) — <!-- begin:auto-docs --> _(no submodules)_ <!-- end:auto-docs -->
|
||||
- [observability](./src/observability/metrics.md) — <!-- begin:auto-docs --> _(no submodules)_ <!-- end:auto-docs -->
|
||||
- [metrics](./src/observability/metrics.md) — <!-- begin:auto-docs --> _(no submodules)_ <!-- end:auto-docs -->
|
||||
- [format-bridge](./src/parser/format-bridge.md) — `FormatBridge` is the dependency-injection seam that lets `@suaveplan/i18n-icu-parser` render ICU format placeholders (…
|
||||
- [message-render](./src/parser/message-render.md) — `message-render` provides two standalone utility functions for `@suaveplan/i18n`: `extractVariables`, which collects al…
|
||||
- [message](./src/parser/message.md) — `MessageParser` converts ICU-like message strings into a typed AST (Abstract Syntax Tree), and provides utilities to re…
|
||||
- [pluralization](./src/pluralization/pluralization.md) — <!-- begin:auto-docs --> _(no submodules)_ <!-- end:auto-docs -->
|
||||
- [pluralization](./src/pluralization/pluralization.md) — <!-- begin:auto-docs --> _(no submodules)_ <!-- end:auto-docs -->
|
||||
<!-- end:auto-docs --> - [escape-html](./src/interpolation/escape-html.md) — `escapeHtmlChars` converts the five HTML special characters (`&`, `<`, `>`, `"`, `'`) to their numeric / named entity e…
|
||||
- [escape-regex](./src/interpolation/escape-regex.md) — `escapeRegex` escapes every regular-expression metacharacter in a string so the string can be embedded literally inside…
|
||||
- [interpolation](./src/interpolation/interpolation.md) — <!-- begin:auto-docs --> _(no submodules)_- [observability](./src/observability/metrics.md) — <!-- begin:auto-docs --> _(no submodules)_- [metrics](./src/observability/metrics.md) — <!-- begin:auto-docs --> _(no submodules)_- [format-bridge](./src/parser/format-bridge.md) — `FormatBridge` is the dependency-injection seam that lets `@suaveplan/i18n-icu-parser` render ICU format placeholders (…
|
||||
- [message-render](./src/parser/message-render.md) — `message-render` provides two standalone utility functions for `@suaveplan/i18n`: `extractVariables`, which collects al…
|
||||
- [message](./src/parser/message.md) — `MessageParser` converts ICU-like message strings into a typed AST (Abstract Syntax Tree), and provides utilities to re…
|
||||
- [pluralization](./src/pluralization/pluralization.md) — <!-- begin:auto-docs --> _(no submodules)_- [pluralization](./src/pluralization/pluralization.md) — <!-- begin:auto-docs --> _(no submodules)_- [escape-html](./src/interpolation/escape-html.md) — `escapeHtmlChars` converts the five HTML special characters (`&`, `<`, `>`, `"`, `'`) to their numeric / named entity e…
|
||||
- [escape-regex](./src/interpolation/escape-regex.md) — `escapeRegex` escapes every regular-expression metacharacter in a string so the string can be embedded literally inside…
|
||||
- [interpolation](./src/interpolation/interpolation.md) — <!-- begin:auto-docs --> _(no submodules)_- [observability](./src/observability/metrics.md) — <!-- begin:auto-docs --> _(no submodules)_- [metrics](./src/observability/metrics.md) — <!-- begin:auto-docs --> _(no submodules)_- [format-bridge](./src/parser/format-bridge.md) — `FormatBridge` is the dependency-injection seam that lets `@suaveplan/i18n-icu-parser` render ICU format placeholders (…
|
||||
- [message-render](./src/parser/message-render.md) — `message-render` provides two standalone utility functions for `@suaveplan/i18n`: `extractVariables`, which collects al…
|
||||
- [message](./src/parser/message.md) — `MessageParser` converts ICU-like message strings into a typed AST (Abstract Syntax Tree), and provides utilities to re…
|
||||
- [pluralization](./src/pluralization/pluralization.md) — <!-- begin:auto-docs --> _(no submodules)_- [pluralization](./src/pluralization/pluralization.md) — <!-- begin:auto-docs --> _(no submodules)_- [escape-html](./src/interpolation/escape-html.md) — `escapeHtmlChars` converts the five HTML special characters (`&`, `<`, `>`, `"`, `'`) to their numeric / named entity e…
|
||||
- [escape-regex](./src/interpolation/escape-regex.md) — `escapeRegex` escapes every regular-expression metacharacter in a string so the string can be embedded literally inside…
|
||||
- [interpolation](./src/interpolation/interpolation.md) — <!-- begin:auto-docs --> _(no submodules)_- [observability](./src/observability/metrics.md) — <!-- begin:auto-docs --> _(no submodules)_- [metrics](./src/observability/metrics.md) — <!-- begin:auto-docs --> _(no submodules)_- [format-bridge](./src/parser/format-bridge.md) — `FormatBridge` is the dependency-injection seam that lets `@suaveplan/i18n-icu-parser` render ICU format placeholders (…
|
||||
- [message-render](./src/parser/message-render.md) — `message-render` provides two standalone utility functions for `@suaveplan/i18n`: `extractVariables`, which collects al…
|
||||
- [message](./src/parser/message.md) — `MessageParser` converts ICU-like message strings into a typed AST (Abstract Syntax Tree), and provides utilities to re…
|
||||
- [pluralization](./src/pluralization/pluralization.md) — <!-- begin:auto-docs --> _(no submodules)_- [pluralization](./src/pluralization/pluralization.md) — <!-- begin:auto-docs --> _(no submodules)_- [escape-html](./src/interpolation/escape-html.md) — `escapeHtmlChars` converts the five HTML special characters (`&`, `<`, `>`, `"`, `'`) to their numeric / named entity e…
|
||||
- [escape-regex](./src/interpolation/escape-regex.md) — `escapeRegex` escapes every regular-expression metacharacter in a string so the string can be embedded literally inside…
|
||||
- [interpolation](./src/interpolation/interpolation.md) — <!-- begin:auto-docs --> _(no submodules)_- [observability](./src/observability/metrics.md) — <!-- begin:auto-docs --> _(no submodules)_ - [metrics](./src/observability/metrics.md) — <!-- begin:auto-docs --> _(no submodules)_- [format-bridge](./src/parser/format-bridge.md) — `FormatBridge` is the dependency-injection seam that lets `@suaveplan/i18n-icu-parser` render ICU format placeholders (…
|
||||
- [message-render](./src/parser/message-render.md) — `message-render` provides two standalone utility functions for `@suaveplan/i18n`: `extractVariables`, which collects al…
|
||||
- [message](./src/parser/message.md) — `MessageParser` converts ICU-like message strings into a typed AST (Abstract Syntax Tree), and provides utilities to re…
|
||||
- [pluralization](./src/pluralization/pluralization.md) — <!-- begin:auto-docs --> _(no submodules)_ - [pluralization](./src/pluralization/pluralization.md) — <!-- begin:auto-docs --> _(no submodules)_
|
||||
## Why this exists
|
||||
|
||||
The 14-package i18n modular split needs one home for the three
|
||||
pure-text-processing concerns that share the `MessageNode` AST,
|
||||
the `INTERPOLATION_ERROR` / `PLURAL_RULE_NOT_FOUND` /
|
||||
`NESTING_DEPTH_EXCEEDED` error codes, and the same renderer
|
||||
contract: ICU parsing, `{{var}}` interpolation, and CLDR
|
||||
pluralization. Splitting them further would fragment the seam
|
||||
without benefit; bundling them as `@suaveplan/i18n-icu-parser`
|
||||
keeps the AST internal and exposes a clean public surface
|
||||
(`MessageParser`, `InterpolationEngine`, `PluralizationEngine`,
|
||||
`renderNodes`) for the slim core to compose.
|
||||
|
||||
## The FormatBridge seam
|
||||
|
||||
ICU format placeholders (`{value, number}`, `{amount, number,
|
||||
currency=USD}`, `{date, date, short}`, `{ts, time, long}`,
|
||||
`{delta, relativeTime}`) need locale-aware output. To stay free
|
||||
of the per-formatter packages, the renderer accepts a
|
||||
`FormatBridge` via `RenderOptions.formatBridge`. When the bridge
|
||||
(or a specific method on it) is undefined, the renderer falls
|
||||
back to `String(value)` and never throws — the parser remains
|
||||
fully usable in isolation, with no `Intl.*` runtime cost.
|
||||
|
||||
The slim `@suaveplan/i18n` core (Wave 6) constructs a default
|
||||
bridge by importing the formatter packages and threads it through
|
||||
`createI18n({ ... })` so consumers who use the high-level façade
|
||||
get full ICU output with zero wiring.
|
||||
|
||||
```typescript
|
||||
import {
|
||||
MessageParser,
|
||||
type FormatBridge,
|
||||
} from "@suaveplan/i18n-icu-parser";
|
||||
|
||||
const bridge: FormatBridge = {
|
||||
number: (v, locale) => new Intl.NumberFormat(locale).format(v),
|
||||
currency: (v, currency, locale) =>
|
||||
new Intl.NumberFormat(locale, { style: "currency", currency }).format(v),
|
||||
};
|
||||
|
||||
const parser = new MessageParser();
|
||||
parser.format(
|
||||
"{amount, number, currency/USD} on {when, date, short}",
|
||||
{ amount: 1234.5, when: new Date() },
|
||||
{ locale: "en-US", formatBridge: bridge }
|
||||
);
|
||||
```
|
||||
|
||||
## Install
|
||||
|
||||
```bash
|
||||
bun add @suaveplan/i18n-icu-parser
|
||||
```
|
||||
|
||||
## Quick Start
|
||||
|
||||
```typescript
|
||||
import {
|
||||
InterpolationEngine,
|
||||
MessageParser,
|
||||
PluralizationEngine,
|
||||
} from "@suaveplan/i18n-icu-parser";
|
||||
|
||||
const parser = new MessageParser();
|
||||
parser.format("{count, plural, one {1 item} other {# items}}", { count: 3 });
|
||||
// "3 items"
|
||||
|
||||
const engine = new InterpolationEngine({ escapeHtml: true });
|
||||
engine.render("hello {{ name }}", { name: "Ada" });
|
||||
// { text: "hello Ada", missingVariables: [] }
|
||||
|
||||
const plural = new PluralizationEngine();
|
||||
plural.resolve(0, { zero: "none", one: "one", other: "many" }, { locale: "ar" });
|
||||
// { category: "zero", message: "none", count: 0 }
|
||||
```
|
||||
|
||||
## Modules
|
||||
|
||||
| Subpath | Description |
|
||||
|---|---|
|
||||
| `@suaveplan/i18n-icu-parser` | Root barrel — every public symbol |
|
||||
| `@suaveplan/i18n-icu-parser/parser` | `MessageParser`, `renderNodes`, `extractVariables`, `FormatBridge`, `noopFormatBridge`, AST types |
|
||||
| `@suaveplan/i18n-icu-parser/parser/format-bridge` | `FormatBridge` interface + `noopFormatBridge` ONLY (single-file import for slim-core wiring) |
|
||||
| `@suaveplan/i18n-icu-parser/interpolation` | `InterpolationEngine`, `escapeHtmlChars`, `escapeRegex`, `InterpolationConfigSchema`, types |
|
||||
| `@suaveplan/i18n-icu-parser/pluralization` | `PluralizationEngine`, the 9 plural-rule functions, `defaultPluralRule`, `normalizeLocale`, `getBaseLocale`, types |
|
||||
|
||||
## Modules Documentation
|
||||
|
||||
- [parser/format-bridge.md](src/parser/format-bridge.md) — DI seam between this package and the formatter packages
|
||||
- [parser/message.md](src/parser/message.md) — `MessageParser` class
|
||||
- [parser/message-render.md](src/parser/message-render.md) — `renderNodes` / `extractVariables` standalone helpers
|
||||
- [interpolation/interpolation.md](src/interpolation/interpolation.md) — `InterpolationEngine`
|
||||
- [interpolation/escape-html.md](src/interpolation/escape-html.md) — `escapeHtmlChars` standalone helper
|
||||
- [interpolation/escape-regex.md](src/interpolation/escape-regex.md) — `escapeRegex` standalone helper
|
||||
- [pluralization/pluralization.md](src/pluralization/pluralization.md) — `PluralizationEngine` + 9 plural-rule fns
|
||||
- [observability/metrics.md](src/observability/metrics.md) — OTel histogram recorders
|
||||
|
||||
## Public Surface (snapshot)
|
||||
|
||||
| Export | Kind | Origin |
|
||||
|---|---|---|
|
||||
| `MessageParser` | class | `parser/message.ts` |
|
||||
| `extractVariables` | function | `parser/message-render.ts` |
|
||||
| `renderNodes` | function | `parser/message-render.ts` |
|
||||
| `renderToChunks` | function | `parser/message-render.ts` |
|
||||
| `preprocessIcuApostrophes` | function | `parser/message.ts` |
|
||||
| `findUnknownArgTypes` | function | `parser/message.ts` |
|
||||
| `FormatBridge` | type | `parser/format-bridge.ts` |
|
||||
| `noopFormatBridge` | const | `parser/format-bridge.ts` |
|
||||
| `MessageNode`, `ParsedMessage`, `ParserOptions`, `RenderOptions`, `RenderContext`, `ValidationIssue`, `ValidationResult` | types | `parser/*.types.ts` |
|
||||
| `InterpolationEngine` | class | `interpolation/interpolation.ts` |
|
||||
| `escapeHtmlChars` | function | `interpolation/escape-html.ts` |
|
||||
| `escapeRegex` | function | `interpolation/escape-regex.ts` |
|
||||
| `InterpolationConfigSchema` | const | `interpolation/interpolation.schemas.ts` |
|
||||
| `PluralizationEngine` | class | `pluralization/pluralization.ts` |
|
||||
| `arabicPlural` / `chinesePlural` / `englishPlural` / `frenchPlural` / `germanPlural` / `japanesePlural` / `polishPlural` / `russianPlural` / `welshPlural` / `spanishPlural` / `defaultPluralRule` | functions | `pluralization/pluralization.ts` |
|
||||
| `recordParseDuration` / `recordInterpolationDuration` / `recordPluralDuration` | functions | `observability/metrics.ts` |
|
||||
|
||||
## Versioning
|
||||
|
||||
Part of the i18n modular-split rollout. Stays at `0.1.0` until
|
||||
the slim core (Wave 6) cuts the family `1.0.0` release. Test
|
||||
titles in `parser/message.test.ts`, `interpolation/interpolation.test.ts`,
|
||||
and `pluralization/pluralization.test.ts` mirror the pre-split
|
||||
monolith one-for-one so the core's conformance suite re-runs
|
||||
unchanged against the bridged surface.
|
||||
|
||||
## Wave 2 Scope
|
||||
|
||||
Pure addition. `packages/i18n/i18n/src/` retains its copies of
|
||||
the parser, interpolation engine, and pluralization sources; both
|
||||
copies coexist during Waves 2–5 and the monolith remains green.
|
||||
The slim core (Wave 6) deletes the monolith copies and re-exports
|
||||
from this package.
|
||||
|
||||
Reference in New Issue
Block a user