Translate

Check translations with pre-commit

With pre-commit, a commit that touches a locale file runs kaeris check first and is refused when a translation lost a placeholder or a key. It is offline and free: no API key, no account.

The recipe

The hook

Save it as .pre-commit-config.yaml in the project root. It is a local hook: pre-commit builds its own environment and installs kaeris from PyPI into it, so nothing else has to be installed. files limits it to commits that stage something under locales/.

Config.pre-commit-config.yaml
repos:
  - repo: local
    hooks:
      - id: kaeris-check
        name: kaeris check (translations)
        entry: kaeris check --source locales/en.json --langs de,fr --ci
        language: python
        additional_dependencies: ["kaeris==0.2.35"]
        files: ^locales/
        pass_filenames: false

What it prints, on real runs

Output of kaeris 0.2.35, captured 27 October 2026. The last line of each box is the exit code the CI job sees.

What a commit prints

Left: a commit with files that are fine. Right: a commit with de.json that has {nam} instead of {name} and the checkout key missing; the commit is refused.

Files that are finegit commit
$ git commit -m "add locales"
kaeris check (translations)..............................................Passed
[main (root-commit) 96c8a87] add locales
 4 files changed, 25 insertions(+)
 create mode 100644 .pre-commit-config.yaml
 create mode 100644 locales/de.json
 create mode 100644 locales/en.json
 create mode 100644 locales/fr.json
exit code: 0
A broken translationgit commit
$ git commit -m "break de"
kaeris check (translations)..............................................Failed
- hook id: kaeris-check
- exit code: 1

✗ de: 1 missing key(s): checkout
✗ de: 1 placeholder mismatch(es):
    greeting: missing ['{name}'], added ['{nam}']
✗ de: 2 translation fault(s):
    greeting: lost placeholder {name}
    greeting: invented placeholder {nam} (not in source)
✓ fr: complete & placeholder-safe
✗ 1 missing key, 1 placeholder mismatch, 2 translation faults

exit code: 1

A commit that touches no locale file

The hook is skipped, so unrelated commits stay fast.

Nothing to checkgit commit
$ git commit -m "readme"   # nothing under locales/ is staged
kaeris check (translations)..........................(no files to check)Skipped
[main e82b41d] readme
 1 file changed, 1 insertion(+)
 create mode 100644 README.md
exit code: 0

Set it up in three steps

  1. Add the hook

    Save the config above as .pre-commit-config.yaml and set your own --source and --langs. Keep the version pin and raise it when you upgrade.

  2. Install the git hook

    Run pip install pre-commit and then pre-commit install once per clone.

  3. Commit as usual

    A commit that stages a file under locales/ runs the check and is refused when it fails. pre-commit run --all-files runs the same check on demand, for example in CI.

How we checked this

Every command on this page was run before it was written here. What was not run is listed too.

Options worth knowing

Questions

Does it need an API key or an account?

No. kaeris check is described in its own help as static, local and no-API, so the job needs no secret. Translating is a separate command that does need a key.

What does the check catch?

A lost or invented placeholder ({name}, %s, {{x}}, ICU plurals), a missing key and a locale file that is not there. The comparison is local and static. What it checks, with every flag

Does it slow every commit down?

Only commits that stage a file matching files. The first run builds the hook environment, which needs network; later runs reuse it. We did not time it, so no figure here.

Keep going

Other recipes: GitHub Actions · GitLab CI · Make and npm scripts

CLI reference · Check reference · GitHub Action reference · Free check in the browser · Translate in the browser