Internationalization
SSX generates a page per locale and keeps the current locale in the page's entity.
Locales
Configure locales in src/site.config.js:
javascript
export default {
i18n: {
defaultLocale: "en",
locales: ["en", "it", "pt"],
},
}SSX generates localized variants for both static and dynamic pages:
- Static page
src/pages/about.js:/about(default locale)/it/about/pt/about
- Dynamic page
src/pages/posts/_slug.jswithstaticPaths():/posts/hello-world/it/posts/hello-world/pt/posts/hello-world
On the client, SSX automatically keeps entity.locale in sync on navigation (routeChange), so pages can usually just render from entity.locale:
javascript
const messages = {
en: "Hello world!",
it: "Ciao mondo!",
pt: "Olá mundo!",
}
export const Hello = {
render(entity) {
return html`<h1>${messages[entity.locale] ?? messages.en}</h1>`
},
}SSX automatically injects page.locale into entity.locale during server-side build/render too, so load is optional for locale initialization.
If you need custom behavior, you can still override it in load:
javascript
export async function load(entity, page) {
entity.locale = page.locale || "en"
}Notes:
- The default locale is not prefixed (
/about, not/en/about). - Locale-prefixed routes are handled in both build output and client-side navigation.
entity.localealso sets<html lang>, on the server and after client-side navigation, unless the page's metadata setslang.<html dir>follows the language, so Arabic, Hebrew, Persian and Urdu pages are laid out right to left.- SSX picks the locale; to translate strings (catalogues, plurals, dates, markup in translations), use
@inglorious/i18nwith its entity namedi18n. SSX switches it to the locale of each page and loads that catalogue beforeloadruns and the page renders, on the server and before the client hydrates, so translations always match the URL rather than the browser's language. Translate insiderender,loador ametadatafunction rather than when a module is imported, so each page gets its own language. Create it withisServerRendered: true, so the browser starts in the language the server rendered instead of first loading the catalogue of its own language:createI18n({ catalogues, isServerRendered: true }).
