Internationalization
Path-based locales, synchronous pre-rendering, strict key parity and hreflang.
On this page
Locale is part of the URL. English is unprefixed; Chinese lives under /zh, so every page is shareable, cacheable and indexable in both languages.
First visit#
A tiny script in <head> reads the stored preference, then navigator.languages. A Chinese browser entering an unprefixed URL is sent to /zh before first paint; an English browser stays. The redirect is deliberately one-way: a /zh URL is never redirected, same-site deep links keep the language being read, and crawlers are skipped.
- A rendered locale is stored, and the language menu writes it before navigating.
- The redirect preserves the path, query and hash.
- Both locales are pre-rendered; the script only chooses an entry point, never generates a page.
Routing#
The route table is generated per locale, so a product page and its translation are the same component. The locale provider derives the current language from useLocation() and selects the matching i18next instance.
Synchronous pre-render#
i18next is initialized with initAsync: false and bundled resources. That makes initialization synchronous, which is required for static generation: a Chinese route must contain Chinese HTML at build time, not after hydration.
Content#
- UI copy lives in
app/lib/i18n/resources/{en,zh}.ts. - Long-form docs live in
app/content/docs/{en,zh}.tsusing the sameDocBlockmodel. - A test compares the English and Chinese key trees; a missing key fails before runtime.
- Technical identifiers (
chrome.userScripts,GM_setValue) stay in English.
SEO#
- Each route emits its own title, description, canonical, Open Graph and Twitter tags.
hreflangpairs both languages and includesx-defaultfor the English page.- The sitemap is generated from the pre-rendered HTML after the build.
Add a locale#
- 1
Add the resource
Create the translation object, typed against the English shape.
- 2
Extend the manifest
Add the locale to
LOCALESandLOCALE_META. Route generation and the language menu pick it up. - 3
Add content
Translate the docs collection. The integrity test will list missing slugs.
- 4
Pre-render
Add the locale to the doc-path list in
react-router.config.ts.