# I18N - Internationalization Slothlet's error messages, warnings, and debug output are fully internationalized. The i18n system auto-initializes when slothlet is used. --- ## Contents - [Usage](#usage) - [Auto-Initialization](#auto-initialization) - [Available Languages](#available-languages) - [API](#api) - [Language Files](#language-files) - [Environment-Based Language Detection](#environment-based-language-detection) --- ## Usage If you already have an API instance, i18n is exposed as a dev-facing convenience alias on `api.slothlet.i18n`: ```js import slothlet from "@cldmv/slothlet"; const api = await slothlet({ dir: "./api" }); api.slothlet.i18n.setLanguage("es-mx"); const msg = api.slothlet.i18n.t("MODULE_NOT_FOUND", { modulePath: "./api/math.mjs", hint: "Check the file exists." }); console.log(msg); ``` ## Auto-Initialization The i18n module auto-initializes when first imported. It detects the system language from environment variables in this order: 1. `process.env.LANG` 2. `process.env.LANGUAGE` 3. `process.env.LC_ALL` If none are set, or if the detected language is not available, it defaults to `en-us` (English). Slothlet imports the i18n module internally, so auto-initialization occurs on all slothlet usage. Note: the active language is process-global (shared across all Slothlet instances in the same Node.js process). --- ## Available Languages | Code | Language | | ------- | ----------------------------- | | `en-us` | English (US) - default | | `en-gb` | English (UK) | | `hi-in` | Hindi (India) | | `zh-cn` | Mandarin Chinese (Simplified) | | `es-es` | Spanish (Spain) | | `es-mx` | Spanish (Mexico) | | `pt-br` | Portuguese (Brazil) | | `ru-ru` | Russian (Russia) | | `de-de` | German (Germany) | | `ja-jp` | Japanese (Japan) | | `fr-fr` | French (France) | | `ko-kr` | Korean (Korea) | Partial translations fall back to English for any missing keys. > **Installing the language pack:** the published `@cldmv/slothlet` package ships only the `en-us` base locale. Every other locale is provided by the optional **`@cldmv/slothlet-i18n`** package — install it alongside slothlet (`npm install @cldmv/slothlet-i18n`) and it is auto-detected; there is nothing to import, register, or configure. Without it, requesting a non-English locale warns and falls back to `en-us`. When developing slothlet itself (the `slothlet-dev` condition), all locale source files are present in-repo, so the pack is not needed. To validate that all locale JSON files contain the same translation keys as the base `en-us.json`, run: ```sh npm run i18n:check ``` This runs the checker at `tools/check-i18n-languages.mjs` and reports missing/extra keys per locale. --- ## API ### `setLanguage(lang)` Sets the active language. Synchronous. ```js api.slothlet.i18n.setLanguage("es-mx"); ``` If the requested language file cannot be loaded, a console warning is emitted and the language falls back to `en-us`. | Parameter | Type | Description | | --------- | -------- | ------------------------------------------ | | `lang` | `string` | Language code (e.g., `"en-us"`, `"es-mx"`) | --- ### `getLanguage()` Returns the currently active language code. ```js console.log(api.slothlet.i18n.getLanguage()); // "en-us" ``` **Returns:** `string` - the active language code. --- ### `translate(errorCode, params?)` / `t(errorCode, params?)` Translates an internal error/warning code with optional parameter interpolation. `t` is a shorthand alias for `translate`. ```js const msg = api.slothlet.i18n.t("MODULE_NOT_FOUND", { modulePath: "./api/math.mjs", hint: "Check the file exists." }); console.log(msg); // "Module not found: ./api/math.mjs. Check the file exists." ``` | Parameter | Type | Description | | ----------- | -------- | --------------------------------------------------------------------------------- | | `errorCode` | `string` | Internal error/warning code | | `params` | `object` | Optional - key/value pairs interpolated into `{placeholder}` slots in the message | **Returns:** `string` - translated and interpolated message. Falls back to English if the code is missing from the active language. Falls back to a generic `"Error: "` string if the code is not found in any language. --- ### `initI18n(options?)` Re-initializes the i18n system. This is usually only needed if you want to force a specific language after auto-detection has already run. ```js api.slothlet.i18n.initI18n({ language: "es-mx" }); ``` You can also set the language at initialization time via config: ```js import slothlet from "@cldmv/slothlet"; const api = await slothlet({ dir: "./api", i18n: { language: "es-mx" } }); ``` | Option | Type | Default | Description | | ---------- | -------- | --------------- | ------------------------------------------------------------------------------- | | `language` | `string` | _(auto-detect)_ | Force a specific language code. If omitted, detects from environment variables. | If initialization fails for any reason, the system silently falls back to `en-us`. --- ## Language Files Language files are JSON objects, one per locale (`.json`). In the repository they live at `src/lib/i18n/languages/`; in the published packages, `en-us.json` ships inside `@cldmv/slothlet` and the remaining locales ship in `@cldmv/slothlet-i18n`. Each file contains a `translations` object keyed by error code, with `{placeholder}` slots for interpolated values: ```json { "translations": { "MODULE_NOT_FOUND": "Module not found: {modulePath}. {hint}", "INVALID_CONFIG": "Invalid configuration: {option} is {value}, expected {expected}. {hint}" } } ``` > **Note:** The `setLanguage()` runtime lookup resolves a non-base locale in priority order: the installed `@cldmv/slothlet-i18n` pack first, then slothlet's own `languages/` directory (present when developing from the repo), and finally — if neither has the file — a console warning with fallback to `en-us`. Partial translations are supported - any key missing from the active language falls back to the English value automatically. --- ## Environment-Based Language Detection When `initI18n()` runs without an explicit `language` option, it reads: ```bash process.env.LANG // e.g., "en_US.UTF-8" process.env.LANGUAGE // fallback process.env.LC_ALL // fallback ``` Values are normalized before lookup - the charset suffix and region code are stripped, then remapped to a known language code: | Detected value | Resolved code | | ---------------------------- | --------------------------------------------------------------------------------------------------------------------- | | `en`, `en_US`, `en_US.UTF-8` | `en-us` | | `en_GB`, `en_GB.UTF-8` | `en-gb` | | `es` | `es-mx` | | `es_ES`, `es_ES.UTF-8` | `es-es` | | `es_MX`, `es_MX.UTF-8` | `es-mx` | | `es_` | `es-mx` | | _(anything else)_ | region-aware pass-through; falls back to default per base language when known, otherwise `en-us` after lookup failure | > Detection is region-aware: exact locale files are preferred first (for example `es-mx`, `es-es`, `en-gb`). If a region-specific file is not available, Slothlet falls back to a default locale for the detected base language (for example `es` -> `es-mx`).