Internationalization (i18n) New in 2026-09-03

SveltePress can serve multiple locales from one site. Internationalization is opt-in: omit locales and the site stays single-locale with unchanged behavior.

Opt-in locales

Enable locales

Pass a locales map to sveltepress(). Keys are URL prefixes ('/' for the default locale, '/zh/', '/bn/', …). Each entry needs a BCP 47 lang, a user-facing label for the language switcher, and that locale's full theme options:

vite.config.ts
import {  } from '@sveltepress/theme-default'
import {  } from '@sveltepress/vite'
import {  } from 'vite'
import {  } from './config/locales'

export default ({
  : [
    ({
      : ({
        // Site-wide options shared by every locale (logo, github, pwa, ...)
      }),
      ,
    }),
  ],
})
ts
config/locales.ts
import type {  } from '@sveltepress/vite'
import  from './navbar'
import  from './sidebar'
import  from './zh/i18n'
import  from './zh/navbar'
import  from './zh/sidebar'

export const :  = {
  '/': {
    : 'en',
    : 'English',
    : { ,  },
  },
  '/zh/': {
    : 'zh',
    : '中文',
    : {
      : ,
      : ,
      : ,
    },
  },
}
ts

Without locales, SveltePress does not rewrite paths, emit a language switcher, or scan locale route trees.

Locale routes and prefixes

Routes and prefixes

Place translated pages beside the default locale under matching route IDs:

src/routes/
├─ guide/introduction/+page.md          # English → /guide/introduction/
├─ zh/guide/introduction/+page.md       # Chinese → /zh/guide/introduction/
└─ bn/guide/introduction/+page.md       # Bengali → /bn/guide/introduction/
txt

The default locale stays unprefixed at /. Other locales use their configured prefixes (/zh/, /bn/, …). Logical paths are the same across locales; only the prefix changes. Navbar, sidebar, home action, and feature-card links should use those logical paths (for example /guide/introduction/); the Default Theme prefixes them with the active locale.

Language switcher and fallbacks

Language switcher and fallbacks

When locales is configured, the Default Theme renders a language switcher in the navbar. Switching locales keeps the same documentation version, the same logical page, and the in-view heading (#hash). On a historical version page (/v/<id>/… or /zh/v/<id>/…), the switcher prefers the same frozen version in the target locale. Only if that frozen page is missing does it fall back to the current version of the same logical page, then to that locale's home with a short notice (svp-locale-fallback=1).

Customize switcher and notice copy with theme i18n.localeSwitcher and i18n.localePageUnavailable.

virtual/locale

virtual:sveltepress/locale

Themes and custom layouts can import locale helpers from the virtual module:

import {
  ,
  ,
  ,
  ,
} from 'virtual:sveltepress/locale'

const  = ('/zh/guide/introduction/')
const  = ('/guide/quick-start/', )
const  = ('/zh/guide/introduction/', '/')
ts
  • locales — the configured map, or null when i18n is off
  • resolveLocale(pathname) — active locale (lang, label, prefix, theme, …)
  • resolveLocalizedPath(to, locale) — rewrite an internal link into the active locale
  • resolveLocaleSwitch(pathname, targetPrefix){ href, fallback } for the switcher
createLocaleHandle

SSR <html lang>

Use createLocaleHandle from @sveltepress/vite/hooks so the initial HTML carries the correct language for crawlers and assistive technology. The Default Theme keeps document.documentElement.lang in sync after client-side navigation.

src/hooks.server.js
// @noErrors
import { createLocaleHandle } from '@sveltepress/vite/hooks'
import { locales } from '../config/locales'

export const handle = createLocaleHandle(locales)
js
Per-locale llms and hreflang sitemap

Per-locale llms and sitemap

With llms enabled, production builds write locale-scoped llms.txt / llms-full.txt (for example /llms.txt and /zh/llms.txt), listing only that locale's pages with prefixed URLs. Historical indexes land under each locale's version base (/v/<id>/, /zh/v/<id>/, …).

sitemap.xml lists every locale's current pages with hreflang alternates for locales that share the logical route, plus eligible historical version URLs from each locale manifest. EOL history is excluded unless a version opts out with noIndex: false.

Locale-aware versioning

Locale-aware versioning

Adding a locale does not require changes to SveltePress packages. Configure the prefix in locales, put pages under src/routes/<slug>/, and if you use document versions run sveltepress versions init --locale <slug>. Language switching, sidebar localization, and historical URLs follow that prefix automatically.

Each locale can keep its own document-version manifest:

Locale prefixManifestVersion base
/ (default)sveltepress.versions.json/v
/<slug>/ (for example /zh/, /bn/, /ja/)sveltepress.versions.<slug>.json/<slug>/v

A default sveltepress versions build drafts every configured locale and composes each locale's /v/ tree into one output. Pass --locale to init, create, validate, and single-locale draft jobs:

pnpm exec sveltepress versions build
pnpm exec sveltepress versions create 8.2 --label "8.2" --locale zh
pnpm exec sveltepress versions validate --locale zh
sh

versions init --locale zh creates sveltepress.versions.zh.json with base path /zh/v by default. Incremental deltas live in version-deltas-zh/ (or the manifest's artifacts.sources). See Document version management for the full release workflow.

Search per locale

Local Search indexes respect <html lang="…">. DocSearch and custom search should use per-locale theme options (separate indexes). Details and version-aware behavior: Search .

Last update at: 2026/09/05 03:57