Keep terms consistent
Goal: decide once how your key terms carry across languages (product names, UI actions, the words your domain depends on) and have kapi flag anything that drifts before it ships. The same terms store guides translation up front and validates it after. Concepts: Terminology; storage models: Memory & terms storage.
kapi keeps terms in a terms bundle (terms.json). To bring in a list your team already maintains elsewhere, import it across the boundary, a spreadsheet exported to CSV for example:
| source | target | domain |
|---|---|---|
| password | mot de passe | security |
| log in | se connecter | ui |
| dashboard | tableau de bord | ui |
| settings | paramètres | ui |
- Desktop
- Agent (Claude)
- CLI
Context → Terms is where that list lives:
- Bring in the list. Import the CSV from the CLI (
kapi terms import, below) or land entries throughkapi apply; both write the committed record the recipe binds withdefaults.terms_source. The view lists terms by language pair and domain, ready to browse and search. - Spot-check a term. Look up an entry to confirm the approved target before a full pass, and open its occurrences to see where the project uses it.
- Enforce it. With the terms store in the project, term findings surface in the Checks view, in the terminology gate of
check --ship, and against each unit in the Review queue: the same drift, caught wherever you look.
Ask for enforcement, or for curation:
Check the French files against our approved terms and fix what drifts.
The assistant looks up approved terms before it writes (kapi terms lookup), runs term-check after, and fixes flagged targets through the round-trip. It can also grow the list: candidate terms it spots (or kapi exec term-extract surfaces) land as kind:"term" change-set entries through kapi apply, written to the committed terms source the recipe binds with defaults.terms_source, for you to approve in git diff.
Import once into a named terms store, verify, then check deliveries:
kapi terms import terms.csv --name product-terms \
--format csv --header -s en -t fr # once; persists across sessions
kapi terms lookup "log in" --name product-terms -s en -t fr
kapi exec term-check messages_fr.json \
--source-lang en --target-lang fr --termstore product-terms
The term-check tool flags targets that don't use the approved equivalent for a source term ("code secret" where the terms store says "mot de passe") and exits non-zero on violations, so it doubles as a CI gate. Scale with globs and -j 4; keep the terms store current with re-imports (concepts merge) and kapi terms export for vendor kits. Flags: kapi terms, kapi exec term-check.
A source term counts in its plural and other regular forms, so "Alerts" uses the term "alert", while a longer word built on it, such as "workflow" for "flow", does not. A translation passes when it contains the approved term, any admitted term for the concept, or a word built around one of them ("kaiplassene" contains "kaiplass"). A form that changes the word, such as the Norwegian plural "varsler" for "varsel", passes once the term lists it as a form. kapi terms validate lists the translated terms that have no forms yet, and kapi terms expand proposes them for you to review before committing.
Two neighbours of term-check cover what a store alone cannot say:
- Rules without a store.
term_rules:is the same shape a voice profile's vocabulary uses (one term, what to use instead, a severity), andterm-check,translate,recycleandpseudo-translateall take it in a flow step'sconfig:or underdefaults.tools. A rule can carry aconcept_idthat ties it to the concept in the store; a rule with noreplacementis skipped, because "say this instead" needs a this. The fields are in the voice profile reference. - Terms that must survive verbatim.
kapi exec dnt-check(do-not-translate) fails a target where a product name, trademark or code identifier listed under--termswas translated, transliterated or dropped; the translate step masks those spans, so the model never sees them. The two routes differ in strength: a--termsstring is masked and cannot be translated, while a concept the terms store marks do-not-translate is asked for in the prompt and then enforced, withterm-checkfailing a target that does not keep it.
In a project, the check resolves the terms bound where each file sits and the recipe's languages automatically, with no flags, and the terminology gate folds into kapi check --ship. Terms bound on a profile with profiles.<name>.termstore hold the content at that profile's channels, and the project's own terms hold the rest. The gate counts content whose language no bound terms answer for as not_governed and holds it to nothing. A governed target kapi cannot read back counts as not_checked, and the gate does not pass while one remains. kapi terms occurrences "log in" (a term as written, or a concept id, with --locale and --collection to narrow) shows where the project's extracted content uses it, so a retirement is sized before it is decided.
Try it
The in-browser build pre-seeds a terms store from the list above: inspect it, look up terms, then pseudo-translate and run term-check to see enforcement against a real backend:
Loading the walkthrough…
Next
- Reuse what you've translated: the terms store guiding translation as well as checking it.
- Memory & terms storage: the three places a terms store can live.
- Terminology: how discovery and enforcement work.