Internationalization
Understand app locale routing, copy loading, language switching, SEO, and the docs-only language switch.
ShipNext has two different language concerns:
- Product and marketing pages can use route-aware locale behavior.
- The docs use an in-page language switch at the bottom of docs pages. Docs URLs do not include locale prefixes.
Docs language behavior
Docs currently support:
| Locale | Name | URL behavior |
|---|---|---|
en | English | Default docs language |
zh | Chinese | Same /docs/... URL, selected through the docs switcher |
The selected docs language is stored in both:
localStorage:shipnext-docs-locale- cookie:
shipnext-docs-locale
The cookie lets the server render the selected language on the first paint. localStorage keeps the browser preference and can resync the cookie if needed.
Product locale routing
If the full app uses route-based i18n, the typical pattern is:
export const i18nConfig = {
defaultLocale: "en",
locales: {
en: { flag: "US", name: "English", hreflang: "en" },
zh: { flag: "CN", name: "Chinese", hreflang: "zh-CN" },
},
localePrefix: "as-needed",
} as const;Default-language pages should avoid /en prefixes, while non-default languages may use prefixes such as /zh.
Docs content structure
Docs content is stored by locale:
content/docs/
├── en/
│ ├── meta.json
│ └── ...
└── zh/
├── meta.json
└── ...Both locale trees keep the same slugs. That means /docs/getting-started/installation can render either English or Chinese without changing the URL.
Copy loading
If product pages use JSON message files, keep the same keys in every locale:
src/i18n/messages/
├── en/
│ ├── common.json
│ └── ...
└── zh/
├── common.json
└── ...New namespaces must be registered in the request loader before components can read them.
Navigation
For route-aware product pages, prefer locale-aware navigation helpers where available:
import { Link, useRouter } from "@/i18n/navigation";For docs language switching, do not push a new URL. Update storage/cookie and refresh the current route.
SEO
- Product pages should generate canonical URLs and alternate languages based on app routing.
- Docs pages should not generate separate
/en/docsor/zh/docsroutes. - Docs frontmatter still provides page
titleanddescription.
Adding a new product language
- Add the locale to the product i18n config.
- Copy and translate all JSON message namespaces.
- Register any new namespace in the request loader.
- Add content for docs only if docs should support the new language.
- Verify canonical and alternate metadata.
Adding a new docs language
- Add the language to the docs i18n config.
- Add
content/docs/<locale>/**with the same slugs as other docs languages. - Add the language option to the docs language switcher.
- Ensure the cookie/localStorage validation accepts the new locale.
- Verify search indexes include the new locale.
Checklist
- Docs language switching never changes the URL.
- Docs content exists for each supported docs locale.
- Product locale routing does not affect
/docs. - Search filters by the selected docs language.
- Server render uses the docs language cookie.