SDK: types CLI
@lionrapid/cli turns your translations into TypeScript types, so translation
keys and their ICU parameters become compile-time errors instead of runtime
surprises: t('welcome', { name }) compiles, t('welcome') with a missing
parameter does not, and a typo in the key itself is caught by the compiler.
Install it as a dev dependency:
npm install --save-dev @lionrapid/cliThe binary is lionrapid. Type generation lives under the types command,
with two subcommands: generate and check.
Configuration
Section titled “Configuration”The CLI reads lionrapid.yml from your project root — it is the single
source of truth for which files hold your translations, so the type commands
take almost no flags. Scaffold one with lionrapid init, or write it by hand:
server: https://your-lionrapid-hostsourceLocale: entargetLocales: [es, de]namespace: appfiles: - format: json source: locales/en.json target: "locales/{locale}.json"target carries a {locale} placeholder, which the CLI expands per target
locale. source may be a glob (locales/en/*.json), in which case target
and namespace must carry a {basename} token.
Supported format values: json, yaml, po, ios-strings, xcstrings,
android-xml, arb, xliff.
Two optional keys control type output directly:
| Key | Default | Meaning |
|---|---|---|
typesOutput |
types/translations.d.ts |
Where the declaration file is written |
generateTypes |
false |
Regenerate types automatically after pull |
Pass -c, --config <path> to any command to point at a config elsewhere.
generate
Section titled “generate”By default the generator works offline, deriving keys and ICU parameter types from the local source files listed in your config:
npx lionrapid types generate| Option | Alias | Default | Meaning |
|---|---|---|---|
--output <path> |
-o |
types/translations.d.ts |
Path of the generated declaration file |
--server |
off | Read the schema from the backend instead of local files | |
--strict-icu |
off | Strict ICU mode (see below) | |
--config <path> |
-c |
lionrapid.yml |
Path to the config file |
--json |
off | Emit the result as JSON on stdout |
Generating from the server
Section titled “Generating from the server”--server fetches the source-locale bundle from the platform instead of
reading local files, which is the option you want when translators are adding
keys that haven’t been pulled yet:
npx lionrapid types generate --serverThis is the only type command that talks to the network, so it is the only
one that needs an API key. Provide it with lionrapid login, which saves it
to ~/.lionrapid/credentials, or set LIONRAPID_API_KEY for a one-off or CI
run. The offline default needs no credential at all.
What gets generated
Section titled “What gets generated”The file augments the core package’s TranslationKeys interface via module
augmentation. Keys are sorted, keys without parameters map to
Record<string, never>, and keys with parameters map to a typed object:
declare module '@lionrapid/core' { interface TranslationKeys { 'app.title': Record<string, never>; 'items.count': { count: number }; welcome: { name: string }; }}
export type AvailableKeys = keyof import('@lionrapid/core').TranslationKeys;The core’s t() is typed conditionally against this interface, which is what
produces the enforcement:
lionRapid.t('app.title'); // ok — zero-parameter keylionRapid.t('welcome', { name: 'Ada' }); // oklionRapid.t('welcome'); // error: 'name' missinglionRapid.t('items.count', { count: 'x' }); // error: count must be numberlionRapid.t('app.titel'); // unknown key: falls back to the// untyped signature — no autocomplete, params uncheckedImport the generated file once (an entry-point
import './types/translations.d.ts' or a tsconfig.json include that
covers it) and restart the TypeScript server in your IDE after the first
generation.
How parameter types are inferred
Section titled “How parameter types are inferred”The CLI analyzes each key’s ICU message and its parameter names:
| Signal in the message / name | Inferred type |
|---|---|
{count, plural, …}, selectordinal, number |
number |
{gender, select, male {…} female {…}} |
'male' | 'female' | (string & {}) |
Name is count / ends in Count |
number |
Name starts is/has/can, ends enabled/visible/active |
boolean |
Name is id / ends in Id/_id |
string | number |
Name contains date/time/timestamp |
Date | string |
| Anything else | string |
Strict vs hybrid ICU mode
Section titled “Strict vs hybrid ICU mode”By default the CLI runs in hybrid mode; --strict-icu switches to
strict. The difference shows up in two places:
- Select unions. Hybrid types a select parameter as the known options
plus any string —
'male' | 'female' | (string & {})— so autocomplete suggests the real options but unexpected values still compile (they hit the message’sotherarm at runtime). Strict emits the literal options only, so an unknown select value is a compile error. - Missing
otherarms. ICU requires anotherarm in every plural and select. Hybrid tolerates a message that lacks one; strict fails generation with an error, which is what you want in CI.
Start hybrid while translations are in flux; turn on --strict-icu once the
catalog stabilizes.
check reports ICU problems in your source translations without writing
anything:
npx lionrapid types checkIt prints the key count and any issues found, and exits 2 when there are
issues — a cheap gate for catching a malformed message before it reaches
translators. Like the default generate, it reads local files only and needs
no credential. Add --json to consume the result in a script.
Regenerating after a pull
Section titled “Regenerating after a pull”pull downloads translations into your target files. Add --types to
regenerate the declaration file in the same step, so freshly-synced keys are
typed immediately:
npx lionrapid pull --typesSetting generateTypes: true in lionrapid.yml makes that the default and
lets you drop the flag.
CI usage
Section titled “CI usage”Regenerate types in CI and let tsc fail the build when code and
translations have drifted apart:
- run: npx lionrapid types generate --strict-icu- run: npx tsc --noEmitThat catches, at merge time: code using keys that no longer exist, parameters
that changed type, and ICU messages missing their other arm. Add --server
if you want CI checked against the live schema rather than the committed
source files — that variant needs LIONRAPID_API_KEY in the job environment.
The CLI uses a stable exit-code taxonomy, so scripts can branch on the failure class:
| Code | Meaning |
|---|---|
0 |
Success |
1 |
Unexpected failure (file I/O, parse error, bug) |
2 |
Bad config, or validation gaps such as ICU issues |
3 |
Missing or invalid credentials |
4 |
Request never reached the server, or a 5xx |
5 |
Partial — some items succeeded and some failed |
Working without generated types
Section titled “Working without generated types”Type generation is progressive enhancement. Without the declaration file, every key is accepted with optional untyped parameters — the library behaves identically at runtime. Unknown keys keep working through the untyped fallback signature even after types are in place.