Every bilingual project we have inherited had the same defect: the second language was behind. Not catastrophically — a missing button label here, an untranslated error message there — but consistently, because keeping two files in sync is a discipline problem, and discipline degrades under deadline.
The structural fix is to make one language the type source and every other language a value that must satisfy it.
// en.ts — the source of truth. Note: no `as const`.
export const en = {
nav: { home: 'Home', about: 'About' },
}
export type Dictionary = typeof en
// fr.ts — cannot compile until every key exists.
import type { Dictionary } from './en'
export const fr: Dictionary = {
nav: { home: 'Accueil', about: 'À propos' },
}Now a missing French string is not a content oversight discovered by a user — it is a red squiggle in the editor and a failed build in CI. The guarantee moves from "we remember to translate" to "it cannot ship otherwise".