{"_id":"@molecule/api-i18n","_rev":"4-29b95f3af464b73f782b530a3566fa4e","name":"@molecule/api-i18n","dist-tags":{"latest":"1.0.3"},"versions":{"1.0.0":{"name":"@molecule/api-i18n","version":"1.0.0","keywords":["molecule","i18n","internationalization","translations","localization"],"license":"Apache-2.0","_id":"@molecule/api-i18n@1.0.0","maintainers":[{"name":"vialoh","email":"npm@vialoh.me"}],"homepage":"https://github.com/molecule-dev/molecule/tree/main/packages/api/core/i18n","bugs":{"url":"https://github.com/molecule-dev/molecule/issues"},"dist":{"shasum":"41c9ef3b38204df7097a89092530179863cdc5d7","tarball":"https://registry.npmjs.org/@molecule/api-i18n/-/api-i18n-1.0.0.tgz","fileCount":30,"integrity":"sha512-o+ymvVMDPZeCUc3NnSrAF7PlLi3n9VI0zUl+W1fkHmb312TqVMAOkROM16YY8L9vXzdR+died1CADaSWEm4u+w==","signatures":[{"sig":"MEQCIA+AaBeWdrTNWmAyEuU6L0W/UT297Ip0a0RruGZ8IYrBAiBS7lrwqZMrNQovo1rQ8OAV/6YrxErGW2sJAku4gG4D4A==","keyid":"SHA256:DhQ8wR5APBvFHLF/+Tc+AYvPOdTpcIDqOhxsBHRwC7U"}],"unpackedSize":62506},"main":"dist/index.js","type":"module","types":"dist/index.d.ts","exports":{".":{"types":"./dist/index.d.ts","import":"./dist/index.js"}},"gitHead":"92623e72a527ca467963169420f4cf07533e4699","scripts":{"test":"vitest run","build":"tsc","test:watch":"vitest"},"_npmUser":{"name":"vialoh","email":"npm@vialoh.me"},"repository":{"url":"git+https://github.com/molecule-dev/molecule.git","type":"git","directory":"packages/api/core/i18n"},"_npmVersion":"11.12.1","description":"Internationalization interface for molecule.dev API","directories":{},"_nodeVersion":"25.9.0","publishConfig":{"access":"public"},"_hasShrinkwrap":false,"devDependencies":{"vitest":"4.1.10","typescript":"6.0.3","@types/node":"26.1.2","@molecule/api-bond":"1.0.0"},"peerDependencies":{"@molecule/api-bond":"^1.0.0"},"_npmOperationalInternal":{"tmp":"tmp/api-i18n_1.0.0_1785796037864_0.022661484124888887","host":"s3://npm-registry-packages-npm-production"}},"1.0.1":{"name":"@molecule/api-i18n","version":"1.0.1","keywords":["molecule","i18n","internationalization","translations","localization"],"license":"Apache-2.0","_id":"@molecule/api-i18n@1.0.1","maintainers":[{"name":"vialoh","email":"npm@vialoh.me"}],"homepage":"https://github.com/molecule-dev/molecule/tree/main/packages/api/core/i18n","bugs":{"url":"https://github.com/molecule-dev/molecule/issues"},"dist":{"shasum":"a53ba13f9e07f002dd8bb0c227eebd9000afa17e","tarball":"https://registry.npmjs.org/@molecule/api-i18n/-/api-i18n-1.0.1.tgz","fileCount":31,"integrity":"sha512-aOBOdGrGGlyo+vpxqKtCGgzi4o7Y7XY8kgOKtaoQMSMuzGsQ5Z7Smn1q55pvoFtkahuZpctNLS/ooM0AEvq7IQ==","signatures":[{"sig":"MEYCIQDFaAi/d2RLo5kdPqzB1VlYogq5X7LgTr9aFUoBckgtqQIhAJJ8+nUbWzT6ak9HNuWgMhDdvtfDtoLCCmzZKMfMYfJD","keyid":"SHA256:DhQ8wR5APBvFHLF/+Tc+AYvPOdTpcIDqOhxsBHRwC7U"}],"attestations":{"url":"https://registry.npmjs.org/-/npm/v1/attestations/@molecule%2fapi-i18n@1.0.1","provenance":{"predicateType":"https://slsa.dev/provenance/v1"}},"unpackedSize":78495},"main":"dist/index.js","type":"module","types":"dist/index.d.ts","exports":{".":{"types":"./dist/index.d.ts","import":"./dist/index.js"}},"gitHead":"8621216fd4c8c9abe863e4e4f41efd2bc866fb09","scripts":{"test":"vitest run","build":"tsc","test:watch":"vitest"},"_npmUser":{"name":"vialoh","email":"npm@vialoh.me"},"repository":{"url":"git+https://github.com/molecule-dev/molecule.git","type":"git","directory":"packages/api/core/i18n"},"_npmVersion":"12.0.2","description":"Internationalization interface for molecule.dev API","directories":{},"_nodeVersion":"22.23.1","publishConfig":{"access":"public"},"_hasShrinkwrap":false,"devDependencies":{"vitest":"4.1.10","typescript":"6.0.3","@types/node":"26.1.2","@molecule/api-bond":"1.0.1"},"peerDependencies":{"@molecule/api-bond":"^1.0.1"},"_npmOperationalInternal":{"tmp":"tmp/api-i18n_1.0.1_1785811957501_0.5795872292332152","host":"s3://npm-registry-packages-npm-production"}},"1.0.2":{"name":"@molecule/api-i18n","version":"1.0.2","keywords":["molecule","i18n","internationalization","translations","localization"],"license":"Apache-2.0","_id":"@molecule/api-i18n@1.0.2","maintainers":[{"name":"vialoh","email":"npm@vialoh.me"}],"homepage":"https://github.com/molecule-dev/molecule/tree/main/packages/api/core/i18n","bugs":{"url":"https://github.com/molecule-dev/molecule/issues"},"dist":{"shasum":"1114c38c7bd3b857f6a65e13d97d61d7a0d24293","tarball":"https://registry.npmjs.org/@molecule/api-i18n/-/api-i18n-1.0.2.tgz","fileCount":31,"integrity":"sha512-OoJ5Krm5T+rSszscJOAexEXiuhdFXOLc4ymRDfGSiOpYD5XcMJQnefM+6YNqW2bmRazPI7SWM32I0tccrp9LeQ==","signatures":[{"sig":"MEQCH2hF7oTWLlWlf07MWnEY+6ieEnvyfoMTwXeYMde163ACIQCbLXs55MDLX/x3wM0T8NP88LVyiFKIy8fuYnATEHSm8g==","keyid":"SHA256:DhQ8wR5APBvFHLF/+Tc+AYvPOdTpcIDqOhxsBHRwC7U"},{"sig":"MEQCIEdju1twrD8Cpx3v88hhp4w1TsQWerjRs06T4nrNW/7kAiBfjtE/L8J1iv6FI2KoncQUSHQEq496Gmt84Ivo4YUacg==","keyid":"SHA256:DhQ8wR5APBvFHLF/+Tc+AYvPOdTpcIDqOhxsBHRwC7U"}],"attestations":{"url":"https://registry.npmjs.org/-/npm/v1/attestations/@molecule%2fapi-i18n@1.0.2","provenance":{"predicateType":"https://slsa.dev/provenance/v1"}},"unpackedSize":79324},"main":"dist/index.js","type":"module","types":"dist/index.d.ts","exports":{".":{"types":"./dist/index.d.ts","import":"./dist/index.js"}},"gitHead":"a7bc0adbe7010d415e7b9245df3dcc5b25e39aae","scripts":{"test":"vitest run","build":"tsc","test:watch":"vitest"},"_npmUser":{"name":"GitHub Actions","email":"npm-oidc-no-reply@github.com","trustedPublisher":{"id":"github","oidcConfigId":"oidc:86a739ad-89da-4f56-94b8-aaa7893293fd"}},"repository":{"url":"git+https://github.com/molecule-dev/molecule.git","type":"git","directory":"packages/api/core/i18n"},"_npmVersion":"12.0.2","description":"Internationalization interface for molecule.dev API","directories":{},"_nodeVersion":"22.23.2","publishConfig":{"access":"public"},"_hasShrinkwrap":false,"devDependencies":{"vitest":"4.1.11","typescript":"6.0.3","@types/node":"26.1.2","@molecule/api-bond":"1.0.1"},"peerDependencies":{"@molecule/api-bond":"^1.0.1"},"_npmOperationalInternal":{"tmp":"tmp/api-i18n_1.0.2_1789739044876_0.7642093914954433","host":"s3://npm-registry-packages-npm-production"}},"1.0.3":{"_id":"@molecule/api-i18n@1.0.3","bugs":{"url":"https://github.com/molecule-dev/molecule/issues"},"dist":{"shasum":"a71d9e0d10f742ab8a47892a045b9bc918396676","tarball":"https://registry.npmjs.org/@molecule/api-i18n/-/api-i18n-1.0.3.tgz","fileCount":31,"integrity":"sha512-kGpbnA2blePwfmKe+uzsppvsLncgNqN3dXnHarzG0lSMwbSwyqUweWFNlWVtwIDFUBUq0wUL5Zd6vnmUXxnJww==","signatures":[{"sig":"MEUCIQD/2cEymo90R9uRunrlA0Kpqo802BPae+9dfhX5E6DwkwIgdiYB8HcuDY0i9pANrEzDaKotwDVlpLyitbBDpH+mjso=","keyid":"SHA256:DhQ8wR5APBvFHLF/+Tc+AYvPOdTpcIDqOhxsBHRwC7U"},{"keyid":"SHA256:DhQ8wR5APBvFHLF/+Tc+AYvPOdTpcIDqOhxsBHRwC7U","sig":"MEQCIHzlcJOF57v/jSQgIkE2e8XLOt5jQyGI2MCqX0qPqLTkAiAkzQ2NbbcGfGbUCQ6V9mKd2RJeehXLh6ro73h1IioAbg=="}],"attestations":{"url":"https://registry.npmjs.org/-/npm/v1/attestations/@molecule%2fapi-i18n@1.0.3","provenance":{"predicateType":"https://slsa.dev/provenance/v1"}},"unpackedSize":79293},"main":"dist/index.js","name":"@molecule/api-i18n","type":"module","types":"dist/index.d.ts","exports":{".":{"types":"./dist/index.d.ts","import":"./dist/index.js"}},"gitHead":"41bbb7d6c46b04d052a6b333e1b18e76ed007d23","license":"Apache-2.0","scripts":{"test":"vitest run","build":"tsc","test:watch":"vitest"},"version":"1.0.3","_npmUser":{"name":"GitHub Actions","email":"npm-oidc-no-reply@github.com","trustedPublisher":{"id":"github","oidcConfigId":"oidc:86a739ad-89da-4f56-94b8-aaa7893293fd"}},"homepage":"https://www.molecule.dev/packages/api-i18n","keywords":["molecule","i18n","internationalization","translations","localization"],"repository":{"url":"git+https://github.com/molecule-dev/molecule.git","type":"git","directory":"packages/api/core/i18n"},"_npmVersion":"12.0.2","description":"Internationalization interface for molecule.dev API","directories":{},"maintainers":[{"name":"vialoh","email":"npm@vialoh.me"}],"_nodeVersion":"22.23.2","publishConfig":{"access":"public"},"_hasShrinkwrap":false,"devDependencies":{"vitest":"4.1.11","typescript":"6.0.3","@types/node":"26.1.2","@molecule/api-bond":"1.0.2"},"peerDependencies":{"@molecule/api-bond":"^1.0.1"},"_npmOperationalInternal":{"host":"s3://npm-registry-packages-npm-production","tmp":"tmp/api-i18n_1.0.3_1789899041813_0.44616088132684606"}}},"time":{"created":"2026-08-03T22:27:17.726Z","modified":"2026-09-20T10:10:42.256Z","1.0.0":"2026-08-03T22:27:18.007Z","1.0.1":"2026-08-04T02:52:37.669Z","1.0.2":"2026-09-18T13:44:04.992Z","1.0.3":"2026-09-20T10:10:41.918Z"},"bugs":{"url":"https://github.com/molecule-dev/molecule/issues"},"license":"Apache-2.0","homepage":"https://www.molecule.dev/packages/api-i18n","keywords":["molecule","i18n","internationalization","translations","localization"],"repository":{"url":"git+https://github.com/molecule-dev/molecule.git","type":"git","directory":"packages/api/core/i18n"},"description":"Internationalization interface for molecule.dev API","maintainers":[{"name":"vialoh","email":"npm@vialoh.me"}],"readme":"<!--\nAUTO-GENERATED — DO NOT EDIT THIS FILE.\nGenerated by `mlcl sync-docs` from the package's src/index.ts JSDoc + mlcl/registry.json.\nEdits here are overwritten on the next commit (molecule's pre-commit hook regenerates).\nTo change this document, edit the module-level JSDoc in src/index.ts.\nGenerated: 2026-08-04T01:48:20.163Z\n-->\n\n# @molecule/api-i18n\n\n> **Auto-generated, AI-first package reference** for the [molecule.dev](https://molecule.dev) ecosystem.\n> It is written to be read by coding agents as much as by people, and is generated from this\n> package's source — edit `src/index.ts` JSDoc, not this file.\n\nInternationalization (i18n) interface for molecule.dev API.\n\nMirrors `@molecule/app-i18n` for the server side: `t()` translations with\n`{{variable}}` interpolation, locale bond registration, and number/date\nformatting. Works with ZERO wiring — if no provider is bonded, a simple\nin-memory provider ('en' default) is auto-created on first use, and `t()`\nfalls back to `defaultValue` (or the key itself), so untranslated strings\nnever crash a request.\n\n## Quick Start\n\n```typescript\nimport { registerLocaleModule, t } from '@molecule/api-i18n'\nimport * as locales from '@molecule/api-locales-user'\n\n// Startup: register a companion locale bond (all 79 locales in one call)\nregisterLocaleModule(locales)\n\n// Error responses — default locale\nt('user.error.notFound', undefined, { defaultValue: 'User not found.' })\n\n// Per-user content (emails, notifications) — per-request locale OPTION\nt(\n  'user.email.resetSubject',\n  { appName },\n  { locale: user.locale, defaultValue: '{{appName}} password reset' },\n)\n```\n\n## Type\n\n`core`\n\n## Installation\n\n```bash\nnpm install @molecule/api-i18n @molecule/api-bond\n```\n\n## API\n\n### Interfaces\n\n#### `DateFormatOptions`\n\nDate format options.\n\n```typescript\ninterface DateFormatOptions {\n  /**\n   * Date style.\n   */\n  dateStyle?: 'full' | 'long' | 'medium' | 'short'\n\n  /**\n   * Time style.\n   */\n  timeStyle?: 'full' | 'long' | 'medium' | 'short'\n\n  /**\n   * Custom format string (implementation-specific).\n   */\n  format?: string\n\n  /**\n   * Relative time.\n   */\n  relative?: boolean\n}\n```\n\n#### `I18nProvider`\n\ni18n provider interface.\n\nAll i18n providers must implement this interface.\n\n```typescript\ninterface I18nProvider {\n  /**\n   * Gets the current locale.\n   */\n  getLocale(): string\n\n  /**\n   * Sets the current locale.\n   */\n  setLocale(locale: string): void\n\n  /**\n   * Gets all available locales.\n   */\n  getLocales(): LocaleConfig[]\n\n  /**\n   * Adds a locale.\n   */\n  addLocale(config: LocaleConfig): void\n\n  /**\n   * Adds translations to a locale. Auto-creates the locale if it doesn't exist.\n   */\n  addTranslations(locale: string, translations: Translations, namespace?: string): void\n\n  /**\n   * Translates a key.\n   */\n  t(\n    key: string,\n    values?: InterpolationValues,\n    options?: { defaultValue?: string; count?: number; locale?: string },\n  ): string\n\n  /**\n   * Checks if a translation exists.\n   */\n  exists(key: string): boolean\n\n  /**\n   * Formats a number.\n   */\n  formatNumber(value: number, options?: NumberFormatOptions): string\n\n  /**\n   * Formats a date.\n   */\n  formatDate(value: Date | number | string, options?: DateFormatOptions): string\n\n  /**\n   * Formats a relative time (e.g., \"2 hours ago\").\n   */\n  formatRelativeTime(value: Date | number, options?: { unit?: Intl.RelativeTimeFormatUnit }): string\n\n  /**\n   * Formats a list (e.g., \"A, B, and C\").\n   */\n  formatList(values: string[], options?: { type?: 'conjunction' | 'disjunction' | 'unit' }): string\n\n  /**\n   * Gets the text direction for the current locale.\n   */\n  getDirection(): 'ltr' | 'rtl'\n}\n```\n\n#### `LocaleConfig`\n\nServer-side locale configuration (code, display name, text direction, translations or loader).\n\n```typescript\ninterface LocaleConfig {\n  /**\n   * Locale code (e.g., 'en', 'fr', 'zh-TW').\n   */\n  code: string\n\n  /**\n   * Display name (e.g., 'English', 'Francais').\n   */\n  name: string\n\n  /**\n   * Native display name.\n   */\n  nativeName?: string\n\n  /**\n   * Text direction.\n   */\n  direction?: 'ltr' | 'rtl'\n\n  /**\n   * Translations for this locale.\n   */\n  translations?: Translations\n}\n```\n\n#### `NumberFormatOptions`\n\nNumber format options.\n\n```typescript\ninterface NumberFormatOptions {\n  /**\n   * Number style.\n   */\n  style?: 'decimal' | 'currency' | 'percent' | 'unit'\n\n  /**\n   * Currency code (for currency style).\n   */\n  currency?: string\n\n  /**\n   * Minimum fraction digits.\n   */\n  minimumFractionDigits?: number\n\n  /**\n   * Maximum fraction digits.\n   */\n  maximumFractionDigits?: number\n\n  /**\n   * Use grouping separators.\n   */\n  useGrouping?: boolean\n}\n```\n\n#### `PluralRule`\n\nPlural form resolution rule mapping a count to a translation category (zero, one, two, few, many, other).\n\n```typescript\ninterface PluralRule {\n  /**\n   * Zero count text.\n   */\n  zero?: string\n\n  /**\n   * One count text.\n   */\n  one?: string\n\n  /**\n   * Two count text.\n   */\n  two?: string\n\n  /**\n   * Few count text (for some languages).\n   */\n  few?: string\n\n  /**\n   * Many count text.\n   */\n  many?: string\n\n  /**\n   * Other count text (default).\n   */\n  other: string\n}\n```\n\n#### `Translations`\n\nTranslation key/value map.\n\n```typescript\ninterface Translations {\n  [key: string]: string | Translations\n}\n```\n\n### Types\n\n#### `InterpolationValues`\n\nKey-value map of interpolation variables for server-side translation strings.\n\n```typescript\ntype InterpolationValues = Record<string, string | number | boolean | Date>\n```\n\n#### `TranslateFunction`\n\nTranslate Function type.\n\n```typescript\ntype TranslateFunction = (\n  key: string,\n  values?: InterpolationValues,\n  options?: { defaultValue?: string; count?: number; locale?: string },\n) => string\n```\n\n#### `TranslateOptions`\n\nTranslate Options type.\n\n```typescript\ntype TranslateOptions = { defaultValue?: string; count?: number; locale?: string }\n```\n\n### Functions\n\n#### `addLocale(config)`\n\nRegisters a locale configuration (code, display name, direction, translations).\n\n```typescript\nfunction addLocale(config: LocaleConfig): void\n```\n\n- `config` — The locale configuration to add.\n\n**Returns:** Nothing.\n\n#### `addTranslations(locale, translations, namespace)`\n\nAdds translation key-value pairs for a locale. Auto-creates the locale if\nit doesn't already exist. Translations are deep-merged with existing ones.\n\n```typescript\nfunction addTranslations(locale: string, translations: Translations, namespace?: string): void\n```\n\n- `locale` — The locale code to add translations for (e.g. `'en'`, `'fr'`).\n- `translations` — The translation key-value map to merge.\n- `namespace` — Optional namespace prefix to nest translations under.\n\n**Returns:** Nothing.\n\n#### `createSimpleI18nProvider(defaultLocale)`\n\nCreates a simple in-memory i18n provider with translation lookup, interpolation,\n`Intl`-based number/date/relative-time formatting, and RTL detection.\nUsed as the default provider when no bond package is installed.\n\n```typescript\nfunction createSimpleI18nProvider(defaultLocale?: string): I18nProvider\n```\n\n- `defaultLocale` — The initial locale code (defaults to `'en'`).\n\n**Returns:** A fully functional `I18nProvider` backed by in-memory translation maps.\n\n#### `formatDate(value, options)`\n\nFormats a date according to the current locale using `Intl.DateTimeFormat`.\n\n```typescript\nfunction formatDate(value: string | number | Date, options?: DateFormatOptions): string\n```\n\n- `value` — The date to format (Date object, timestamp, or ISO string).\n- `options` — Formatting options (dateStyle, timeStyle, relative).\n\n**Returns:** The locale-formatted date string.\n\n#### `formatNumber(value, options)`\n\nFormats a number according to the current locale using `Intl.NumberFormat`.\n\n```typescript\nfunction formatNumber(value: number, options?: NumberFormatOptions): string\n```\n\n- `value` — The number to format.\n- `options` — Formatting options (style, currency, fraction digits, grouping).\n\n**Returns:** The locale-formatted number string.\n\n#### `formatRelativeTime(value, options)`\n\nFormats a relative time string (e.g. \"2 hours ago\", \"in 3 days\") using\n`Intl.RelativeTimeFormat`.\n\n```typescript\nfunction formatRelativeTime(\n  value: number | Date,\n  options?: { unit?: Intl.RelativeTimeFormatUnit },\n): string\n```\n\n- `value` — The date or timestamp to express relative to now.\n- `options` — Optional settings; `unit` forces the difference to be expressed in that unit.\n\n**Returns:** The locale-formatted relative time string.\n\n#### `getLocale()`\n\nReturns the current locale code (e.g. `'en'`, `'fr'`, `'zh-TW'`).\n\n```typescript\nfunction getLocale(): string\n```\n\n**Returns:** The active locale code.\n\n#### `getNestedValue(obj, key)`\n\nResolves a dot-notation key (e.g. `'auth.login.email'`) against a nested\ntranslations object. Checks for a flat key match first, then traverses\nthe nested structure.\n\n```typescript\nfunction getNestedValue(obj: Translations, key: string): string | undefined\n```\n\n- `obj` — The translations object to search.\n- `key` — The dot-notation key to resolve.\n\n**Returns:** The translation string if found, or `undefined`.\n\n#### `getPluralForm(count, locale)`\n\nReturns the CLDR plural category (`'zero'`, `'one'`, `'two'`, `'few'`, `'many'`,\nor `'other'`) for a given count and locale using `Intl.PluralRules`.\n\n```typescript\nfunction getPluralForm(count: number, locale: string): string\n```\n\n- `count` — The numeric count to determine the plural form for.\n- `locale` — The locale code to use for plural rule selection (e.g. `'en'`, `'ar'`).\n\n**Returns:** The plural category string.\n\n#### `getProvider()`\n\nRetrieves the bonded i18n provider. If none is bonded, auto-creates and\nbonds a simple in-memory provider with `'en'` as the default locale.\n\n```typescript\nfunction getProvider(): I18nProvider\n```\n\n**Returns:** The bonded i18n provider.\n\n#### `hasProvider()`\n\nChecks whether an i18n provider is currently bonded.\n\n```typescript\nfunction hasProvider(): boolean\n```\n\n**Returns:** `true` if an i18n provider is bonded.\n\n#### `interpolate(text, values)`\n\nReplaces `{{variable}}` placeholders in a translation string with their\ncorresponding values. Date values are formatted with `toLocaleDateString()`.\n\n```typescript\nfunction interpolate(text: string, values: InterpolationValues): string\n```\n\n- `text` — The translation string containing `{{variable}}` placeholders.\n- `values` — Key-value map of interpolation values.\n\n**Returns:** The string with placeholders replaced by their values.\n\n#### `registerLocaleModule(moduleExports)`\n\nRegisters all locale exports from a locale bond module. Iterates the module's\nnamed exports, treating each object-valued export as a translation map keyed\nby locale code (e.g. `en`, `fr`, `zhTW`). Handles `zhTW` → `zh-TW` mapping.\n\n```typescript\nfunction registerLocaleModule(moduleExports: Record<string, unknown>): void\n```\n\n- `moduleExports` — The module's named exports (e.g. `{ en: {...}, fr: {...} }`).\n\n#### `setLocale(locale)`\n\nSets the active locale. Throws if the locale hasn't been registered.\n\n```typescript\nfunction setLocale(locale: string): void\n```\n\n- `locale` — The locale code to switch to (e.g. `'fr'`, `'zh-TW'`).\n\n**Returns:** Nothing.\n\n#### `setProvider(provider)`\n\nRegisters an i18n provider as the active singleton. Called by bond\npackages during application startup.\n\n```typescript\nfunction setProvider(provider: I18nProvider): void\n```\n\n- `provider` — The i18n provider implementation to bond.\n\n#### `t(key, values, options)`\n\nTranslates a key using the bonded i18n provider. Falls back to `defaultValue` or\nthe key itself if no translation is found. Supports interpolation via `{{variable}}`\nsyntax and per-request locale override.\n\nOn the API side, use the `locale` option for per-request translation\n(e.g., emails, notifications) to avoid global state race conditions:\n\n```ts\n// Error responses — use default locale (English)\nt('user.error.usernameRequired')\n\n// Emails — translate in user's locale\nt('user.email.resetSubject', { appName }, { locale: userLocale })\n```\n\n```typescript\nfunction t(\n  key: string,\n  values?: InterpolationValues,\n  options?: { defaultValue?: string; count?: number; locale?: string },\n): string\n```\n\n- `key` — The translation key (dot-notation, e.g. `'user.error.notFound'`).\n- `values` — Optional interpolation values to substitute `{{variable}}` placeholders.\n- `options` — Optional settings.\n- `options.defaultValue` — Fallback string if no translation is found.\n- `options.count` — Count for pluralization.\n- `options.locale` — Override locale for this specific translation.\n\n**Returns:** The translated string, or `defaultValue`, or the key if nothing matches.\n\n### Constants\n\n#### `simpleProvider`\n\nDefault simple in-memory i18n provider instance with `'en'` locale.\nUsed as a fallback when no bond package provides a provider.\n\n```typescript\nconst simpleProvider: I18nProvider\n```\n\n## Available Providers\n\n| Provider | Package                     |\n| -------- | --------------------------- |\n| Simple   | `@molecule/api-i18n-simple` |\n\n## Injection Notes\n\n### Requirements\n\nPeer dependencies:\n\n- `@molecule/api-bond` ^1.0.1\n\n### Runtime Dependencies\n\n- `@molecule/api-bond`\n\n- **Never call `setLocale()` per request on the server.** The active locale is\n  PROCESS-GLOBAL shared state — switching it for one user's email races every\n  concurrent request. Pass the per-user locale in the third argument instead:\n  `t(key, values, { locale })`. `setLocale()` is for single-locale deployments.\n- Always pass `{ defaultValue }`: it's the rendered English fallback (and what\n  shows if a key is missing — otherwise users see the raw dot-notation key).\n  Keys are namespaced dot-paths (`'user.error.notFound'`), never English text.\n- Translations live in companion locale bond packages, not inline in features:\n  `registerLocaleModule(moduleExports)` registers every exported locale at once\n  (export names like `zhTW` are normalized to `zh-TW`);\n  `addTranslations(locale, map, namespace?)` deep-merges (later wins).\n- **Pluralization requires a real bonded provider.** `{ count }` resolves\n  CLDR plural-suffixed keys (`key_one` / `key_other` / …) in providers that\n  implement it (e.g. `@molecule/api-i18n-simple`); the auto-created fallback\n  provider IGNORES `count`.\n- `formatNumber`/`formatDate` have NO per-call locale override — they format\n  in the current global locale.\n\n## E2E Tests\n\nIntegration checklist — drive the real flow (no mocks), adapt each item to\nthis app's actual localized responses/emails, and check every box off one by\none. A box you can't check is an integration bug to fix — not a skip:\n\n- [ ] A user-facing server string (an API error message, an email\n      subject/body, a notification) renders TRANSLATED for a non-default locale:\n      set the user's locale (or send Accept-Language) and confirm the\n      response/email comes back in that language, not English — passed per-request\n      as `t(key, values, { locale })`, NEVER a process-global `setLocale()` per\n      request (that races concurrent users and localizes the wrong one).\n- [ ] A missing/untranslated key falls back to its `defaultValue` (rendered\n      English), NOT the raw dot-notation key — a response or email showing\n      `user.error.notFound` verbatim is exactly the bug this prevents.\n- [ ] `{{variable}}` interpolation fills correctly — the appName/count/etc.\n      appear in the message and no literal `{{appName}}` leaks through.\n- [ ] If the app pluralizes, `{ count }` resolves the right CLDR form\n      (one/other/…) — and ONLY with a real bonded provider (the auto fallback\n      ignores count), so \"1 item\" vs \"2 items\" reads correctly.\n- [ ] The locale is derived per-request from the authenticated user's\n      preference (or Accept-Language), so two concurrent users with different\n      locales each get their own language — one user's locale never leaks into\n      another's email/response.\n","readmeFilename":"README.md"}