The raw key on your live site
You add a label in English and forget the Dutch file. Nothing complains. A Dutch customer finds nav.settings.title on your settings page. Here, that gap fails the build, not the demo.
Your site speaks English and Dutch from day one, with no missing lines.
The public site ships complete in English and Dutch. If a translation is missing, the build fails before anyone sees it. Pages load in the right language instantly, with no flash of the wrong one.
The mechanism end to end, as implemented in the repository.
The URL decides first
A /nl prefix means Dutch. Without one, the app falls back to the account preference, then a validated cookie, then the default.
Pages render from built-in catalogs
All copy reads from typed catalogs compiled into the app, so the server and the first client render already speak the right language.
Switching keeps your place
The language switcher rewrites the current URL, keeping the path, query, and hash, and updates the page language immediately.
The choice sticks
The pick is saved in a checked cookie and, for signed-in users, on the account, so the next visit opens in the same language.
Interactive example
This walkthrough demonstrates the implemented backend contract without using an account, credentials, or provider calls.
Interactive example
Deterministic sample data only. No account, provider, or network connection is used by the interaction.
Without a shared foundation, every team rebuilds these edge cases — differently.
You add a label in English and forget the Dutch file. Nothing complains. A Dutch customer finds nav.settings.title on your settings page. Here, that gap fails the build, not the demo.
A Dutch reader shares your pricing page. Their colleague opens it and lands on the English version, because the language only lived in a cookie. Here, the language is in the URL, so it travels with the link.
Provider-based i18n loads translations after the page. Every first visit flickers from keys or English to the real text. Here, translations are compiled in, so there's nothing to wait for.
Highlights
Both languages live side by side in one file. Add a phrase in one and forget the other, and the build fails instead of shipping a gap.
Dutch pages live under /nl, so a shared link opens in the same language the sender saw.
Translations are compiled into the app, not fetched at runtime, so the first paint is already in the right language.
Engineering guarantees
This translates your app's own words, in English and Dutch. It doesn't machine-translate anything, generate hreflang tags for you, or translate what your customers write.
The boundary above is code, not a claim. These files carry the contract:
src/modules/i18n/messages.tssrc/modules/i18n/locale-navigation.tssrc/modules/i18n/MODULE.mdThese capabilities share contracts and boundaries with this one.
The docs describe the same contracts this page demonstrates.