CLI and x18n check

Check locale files like tsc, read and change keys from the terminal, and pick a reporter for CI.

The x18n CLI is for humans, CI and agents. Every command prints human output by default, and the JSON contract with --json. The CLI reference lists every command and option.

Run x18n with no command to see the status of the project and the main commands.

x18n check

x18n check runs every check on every project and reports the diagnostics. It is to i18n what tsc --noEmit is to types:

x18n check
src/App.vue:17:15
 ERROR  "app.titel" is not defined in en.  missing-key
16 │   <main>
17 │     <p>{{ $t('app.titel') }}</p>
   │               ~~~~~~~~~
18 │   </main>

src/locales/de.json:8:6
 WARNING  "nav.about" is empty in de.  empty-translation
7 │   "nav": {
8 │     "about": ""
  │      ~~~~~
9 │   }

✖ 1 error  ⚠ 1 warning  2 files

Each problem starts with the path, the line and the column. The next line has the severity, the message and the check id. A code frame follows, with one line of context on each side. The last line counts the errors, the warnings and the files. Paths are relative to the current directory, so editors and terminals can open them.

Options

OptionEffect
--strictTurn every warning into an error. The config option strict: true does the same.
--max-warnings <n>Fail when there are more than n warnings.
--only <checks>Run only these check ids, for example --only placeholder-mismatch,invalid-syntax.
--skip <checks>Skip these check ids.
--locale <locale>Report only for these locales. Diagnostics without a locale stay.
--watchCheck again when a file changes.
--reporter <id>Pick the output format. See Reporters.
--output <file>Write the output of a reporter to a file.

To change the severity of a check for every run, use checks in the config. See Checks.

Exit codes

Exit codeMeaning
0No errors, and no more warnings than --max-warnings.
1At least one error, or more warnings than --max-warnings.
2The config or the command line is invalid.

Exit codes lists the codes of every command.

Reporters

A reporter turns diagnostics into text. Pick one or more with --reporter:

ReporterOutput
prettyThe default. The path and position, the severity badge with the message and check id, a code frame, then a summary.
jsonThe JSON contract. --json picks it too.
markdownA summary, a coverage table per locale and a table of diagnostics. For pull request comments and job summaries.
githubGitHub Actions workflow commands. GitHub shows them as annotations on the changed lines.
sarifSARIF 2.1.0, for code scanning.

--reporter and --output are repeatable. The first --output belongs to the first --reporter, the second to the second, and so on. A reporter without an --output prints to stdout:

x18n check --reporter markdown --output summary.md --reporter pretty

This command writes the markdown report to summary.md and prints the pretty output. See CI for workflow examples.

Read keys and usages

CommandShows
x18n statusLocales with coverage, and the counts of resources, keys, usages and diagnostics.
x18n keys [glob]Keys. --missing <locale>, --unused and --namespace <ns> filter them. --values adds the value per locale.
x18n get <key>The value in each locale with file and line, the locales that lack the key, the usages and the diagnostics.
x18n usages [key]The usages of a key, or every usage. --file <path> filters by file.
x18n localesThe locale codes as found, with display names and resources.
x18n doctorHow x18n understood the project: presets, locale finders, formats, scanners, conflicts, errors and config origins.

A key glob uses * inside one segment and ** across segments: x18n keys "pages.**".

List commands page their output. --limit <n> sets the page size. The output ends with a --cursor value for the next page, and the JSON output has it as nextCursor:

x18n keys --missing de --limit 50
x18n keys --missing de --limit 50 --cursor 50

Change keys

Do not edit locale files by hand. These commands keep the format, the indent, the key style and the order of each file, and they check placeholders:

CommandDoes
x18n set <key> --value <text>Sets one value. --locale picks the locale, and the default is the source locale. --value - reads stdin.
x18n apply <file>Sets many values from JSON: { "<locale>": { "<key>": "<value>" } }. - reads stdin.
x18n rename <from> <to>Renames a key in every locale and every usage in code. --no-usages keeps the code.
x18n delete <key>Deletes a key in every locale. --locale limits it. Code is not changed.
x18n fillAdds the missing keys of each locale with empty values. --copy-source copies the source value. --locale limits it.
x18n formatWrites the resources again with the configured write.sort and write.indent.

A rename or delete of a parent key changes every key under it. x18n rename pages screens moves pages.home.title to screens.home.title, and updates prefix usages such as t(`pages.${id}.title`). A rename to a key that exists stops with X18N4002.

x18n apply refuses values whose placeholders differ from the source value, and writes nothing. It lists the rejected values and exits with code 1. Fix them, or pass --force to write them anyway.

Every command that writes files accepts --dry-run. It prints the changes as a small diff and writes nothing:

x18n rename app.title app.heading --dry-run
edit src/locales/de.json
-     "title": "Meine App",
+     "heading": "Meine App",
edit src/locales/en.json
-     "title": "My App",
+     "heading": "My App",
edit src/App.vue
- const title = t('app.title')
+ const title = t('app.heading')

If a change needs a decision, such as the file for a new key, x18n asks in a terminal. --yes accepts the default answers. See Plan and decision.

Extract hard strings

x18n extract finds hard-coded strings in source files and turns them into keys. Each candidate has a proposed key, a message and the replacement code.

  • x18n extract --list prints the candidates.
  • In a terminal, x18n extract asks for each string: accept the proposed key, type another key, skip it, or stop.
  • x18n extract --yes extracts every candidate with its proposed key.
  • x18n extract --plan plan.json writes the candidates to a file. Edit the keys, remove the items that you do not want, then run x18n extract --apply plan.json.

Pass files or globs to limit the search: x18n extract src/components/**. Files that users never see are never scanned: tests, fixtures, mocks, stories, configs and type declarations, by the conventions of common languages. For example *.test.ts, *_test.go, test_*.py, *_spec.rb, *Test.java, *.stories.tsx, vite.config.ts, *.d.ts, and directories such as test/, tests/, spec/, e2e/, fixtures/ and __tests__/. Control comments, in any comment syntax, skip more:

CommentSkips
x18n-ignore-fileThe whole file, wherever the comment is.
x18n-ignore-start ... x18n-ignore-endEverything between the two comments. Without an end, everything to the end of the file.
x18n-ignoreStrings on the line of the comment and on the next line.

The same rules apply to the hard-string check. The extract options of the config set the key style and the strings to ignore. The presets add the replacement code for their library. See Extraction templates.

Global options

OptionEffect
--root <dir>Use <dir> as the project root. x18n does not look in parent directories.
--config <file>Use this config file.
--project <name>Work on one project of a monorepo.
--jsonPrint the JSON contract.
--no-cacheIgnore the persistent cache in node_modules/.cache/x18n.
--yesAccept the default answers of decisions.

Output rules

  • Results go to stdout. Logs and progress go to stderr, so x18n keys > keys.txt works.
  • Colors appear only in a terminal. x18n honors NO_COLOR and FORCE_COLOR.
  • With --json, stdout is one JSON document, also when the command fails.