Terms and translations

Terms and translations

The atomic units of LangSync — translation keys (marks) and their per-language values, with the rules that govern them.

Not verified yet

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

FieldWhat it's forRules
MarkThe key your code references.Unique within the namespace (creating a duplicate is rejected with a conflict error).
ContextA free-text note about where and how the string is used — for your team and translators reviewing the namespace.Optional.
Default language valueThe 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.
TranslationsOne 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:

  1. One at a time in the dashboard — Manage terms.
  2. Bulk import from CSV, TSV, XLSX, or XLS — Bulk import.
  3. The CLInrc langsync mark add, or wholesale from your repository's JSON files via nrc langsync sync.
  4. The API — see the API reference.

Best practices for marks

  • Hierarchical dotted keys. auth.signin.title reads better than signinTitle, 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-change sync 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.

On this page