CLI
The saykit command-line interface, every command and flag
The saykit CLI extracts messages from your source files. It's installed with @saykit/config and exposes two commands: extract and clean.
saykit --help
saykit help [command]saykit extract
Walk every bucket in saykit.config.ts, extract messages from the files matched by include, and write the source locale catalogue. Other locales are never edited; a locale with no file yet is created empty so a TMS can register it.
saykit extract
saykit extract --watch
saykit extract --verbose
saykit extract --quietOptions
Prop
Type
What it does
For each bucket:
- Globs
include(and excludesexclude). - Asks each transformer to parse each file and return a list of messages.
- Merges entries with the same text + context, unioning their references.
- Hashes ids for messages without a custom id.
- Writes the source locale catalogue via the bucket's formatter, and creates an empty placeholder for any locale that has no file yet. Existing non-source files are left untouched.
- Writes a
{locale}.d.{extension}.tsdeclaration next to each catalogue.
Exit codes
| Code | Meaning |
|---|---|
| 0 | Success. |
| 1 | Failure during config load, extraction, or write. |
The CLI throws on unrecoverable errors (missing config, invalid config, formatter parse failure). Use --verbose to see the full stack.
saykit clean
Remove dead entries from every non-source locale file. clean only ever subtracts, it never writes new keys into a locale, so running it can only shrink your locale files.
saykit clean
saykit clean --verbose
saykit clean --quietFor each bucket, and each locale after the source, clean:
- drops keys that no longer exist in the source catalogue (orphans),
- drops entries with an empty translation, which resolve through fallback anyway,
- leaves every remaining entry byte-for-byte as it is on disk.
Keys that exist in the source but not in a locale file are deliberately left alone, adding them is your translation management system's job.
Options
Prop
Type
clean is optional and never required for correctness. If your TMS already prunes orphaned keys,
you may never need it, extraction plus load-time fallback is enough on its own.
Configuration discovery
The CLI searches for saykit.config.{ts,mts,cts,js,mjs,cjs} starting from the current working directory and walking up the tree. The first match wins.
TypeScript configs are read by the runtime directly, which needs Node 22.18+ or a runtime that loads TypeScript itself (Bun, Deno, tsx). Nothing is written to disk, and a config can import from alongside it as normal — using the real extension, ./formatter.ts rather than ./formatter.js.
Running from package.json
A typical setup wires the CLI into npm scripts so you don't have to remember the binary path:
{
"scripts": {
"extract": "saykit extract",
"extract:watch": "saykit extract --watch"
}
}pnpm extract
pnpm extract:watchCI usage
The most common CI check is: extraction has been run, and translations are up-to-date with code:
- run: pnpm install
- run: pnpm saykit extract
- run: git diff --exit-code -- 'src/locales/*'This fails the build if anyone forgot to run extract after changing or adding messages.
Future commands
The CLI is intentionally small today. New commands (compile, lint, stats) may land before 1.0. Anything published outside extract and clean will go through the same saykit <command> --help discovery.