Terms and translations
The atomic units of LangSync — translation keys (marks) and their per-language values, with the rules that govern them.
A term is a translation key — welcome.title, errors.network,
button.submit. A translation is the actual string for that term
in one specific language. In LangSync's own vocabulary (you'll see this
in the dashboard dialogs and the CLI), the key itself is called the
mark.
namespace: marketing-site
term (mark): welcome.title
en-US: "Welcome" ← default language value (the source)
de-DE: "Willkommen"
fr-FR: "Bienvenue"Terms live inside namespaces. The same mark in two different namespaces refers to two unrelated keys.
A term has
| Field | What it's for | Rules |
|---|---|---|
| Mark | The key your code references. | Unique within the namespace (creating a duplicate is rejected with a conflict error). |
| Context | A free-text note about where and how the string is used — for your team and translators reviewing the namespace. | Optional. |
| Default language value | The string in the namespace's default language. This is the source every AI translation is generated from. | Required when creating a term in the dashboard. |
| Translations | One value per attached target language. | Filled by humans, single-cell AI suggestions, or batch auto-translate. |
A translation itself carries its value, its language, and audit metadata (who last changed it and when).
Where terms come from
Four ways to get terms into a namespace, all interchangeable:
- One at a time in the dashboard — Manage terms.
- Bulk import from CSV, TSV, XLSX, or XLS — Bulk import.
- The CLI —
nrc langsync mark add, or wholesale from your repository's JSON files vianrc langsync sync. - The API — see the API reference.
Best practices for marks
- Hierarchical dotted keys.
auth.signin.titlereads better thansigninTitle, groups related keys when sorted, and searches well. - Stable mark, mutable value. Never rename a mark to change its meaning — your deployed code references the old mark.
- Source string ≠ mark. Don't use the English copy as the key. When the copy changes, you don't want every code reference to break.
- Write context. "Hero heading on the homepage" takes five seconds and pays off every time someone else (or future you) reviews the namespace.
Empty vs. missing translations
A translation can be missing entirely (no value stored for that language) or explicitly empty (saved as an empty string). Both show up in the missing translations filters and both are candidates for auto-translate. Billing counts only non-empty stored translations — empty values cost nothing.
One consequence worth knowing: the Public API returns only terms that have a stored translation in the requested language, so a term that was never translated into German simply won't appear in the German response. Build your app-side fallback (usually "fall back to the default language") with that in mind.
Behaviour and edge cases
- Deleting a term removes the term and every translation across every language. No undo. Both the dashboard and the CLI ask for confirmation first.
- Renaming a mark takes effect immediately. Any deployed app fetching by the old mark stops finding it — treat mark renames like API breaking changes.
- Editing the default-language value does not re-translate the
other languages. They keep showing their existing values until you
re-run auto-translate, edit them manually, or use the CLI's
--retranslate-on-source-changesync flag, which clears stale translations so the AI regenerates them. - Concurrent edits are last-write-wins. If two people edit the same translation at the same time, the later save overwrites the earlier one. There is no per-translation history — the audit log records that a term changed and by whom, not every previous value.
Related
Manage terms in the dashboard
The list view, filters, translation dialog, and the side-by-side editor.
Auto-translate
Batch-fill every missing translation, or ask the AI for one suggestion at a time.
Bulk import
CSV / TSV / XLSX / XLS onboarding with column mapping.
Fetch translations
Read the finished strings from your application.