Twenty-two languages, with hreflang clusters, self-referential canonicals, per-section translation tracking, and sitemaps that list a page only in the languages it genuinely exists in. Most multilingual sites get this wrong in ways that actively suppress their own rankings.
| Measure | Value | Source | Measured |
|---|---|---|---|
| Languages served | 22 | messages/*.json in the marketing site repository | |
| Threshold for counting a language as translated for a section | at least 90% of strings present, fewer than 30% identical to English | app/lib/message-locales.ts | |
| Translated strings in the marketing dictionary, per language | 6,517 | key count of the English dictionary bundle | |
| Sitemap generation | Per request, from the same sources the pages read β no maintained list | app/lib/sitemap-source.ts |
What building it taught us
International SEO is mostly a set of rules about honesty. A page that exists in one language and is served under twelve prefixes is twelve near-duplicates, and search engines will pick one and file the rest as unindexable. The common failure is not malice, it is optimism: a site launches its language switcher before its translations, then wonders why the foreign-language versions never rank.
We made the machinery tell the truth. Whether a page counts as translated into a language is computed, not asserted: the language's own bundle must carry at least ninety per cent of that page's strings before merging with English, and fewer than thirty per cent of them may be byte-identical to the English original. That second test exists because a machine translation provider returning the source text unchanged produces a bundle that looks complete and is not β measured on real output, an echoing provider comes out almost entirely identical, and that is not a translation.
Everything follows from that one computation. An untranslated page points its canonical at the English original and is excluded from that language's sitemap, so nothing unindexable is ever submitted. When the translation lands, the page becomes its own canonical and appears in the sitemap automatically. Sitemaps are generated per request from the same sources the pages read, so they cannot drift β the two hand-maintained copies this replaced had already disagreed with each other, and neither listed a single blog post.
Structural fields are protected from translators by construction. Copy lives in a dictionary and is merged over the typed object, so only string leaves can be replaced and only where the shape still matches; a list whose length has drifted falls back to English rather than rendering half-translated. A translator cannot break a slug, a route or a comparison matrix, because those never leave TypeScript.
Built with
- next-intl
- hreflang
- XML sitemaps
- Next.js App Router
- self-hosted machine translation
What this qualifies us for
Tell us what you are trying to do
A short conversation is usually enough to tell whether we are the right people. If we are not, we will say so and point you somewhere better.