Internationalization (i18n)

We can internationalize (i18n) a vite-plugin-ssr app by using a onBeforeRoute() hook.

// /renderer/

export { onBeforeRoute }

function onBeforeRoute(pageContext) {
  const { urlWithoutLocale, locale } = extractLocale(pageContext.urlOriginal)
  return {
    pageContext: {
      // We make `locale` available as `pageContext.locale`
      // We overwrite `pageContext.urlOriginal`
      urlOriginal: urlWithoutLocale

// We can also use a library instead of implementing our own locale retrieval mechanism
function extractLocale(url) {
  // We determine the locale, for example:
  //  extractLocale('/en-US/film/42').locale === 'en-US'
  //  extractLocale('/de-DE/film/42').locale === 'de-DE'
  const locale = /* ... */

  // We remove the locale, for example:
  //  extractLocale('/en-US/film/42').urlWithoutLocale === '/film/42'
  //  extractLocale('/de-DE/film/42').urlWithoutLocale === '/film/42'
  //  ...
  urlWithoutLocale = /* ... */

  return { locale, urlWithoutLocale }

Upon rendering a page, onBeforeRoute() is the first hook that vite-plugin-ssr calls, which means that the rest of our app doesn't have to deal with localized URLs anymore and we can simply use pageContext.locale instead.

See Guides > Access pageContext anywhere for being able to access pageContext.locale in any React/Vue component.

This technique also works with:

  • ?lang=fr query parameters

  • domain TLDs

  • Accept-Language: fr-FR headers

    The Accept-Language header can be used for redirecting the user to the right localized URL (e.g. URL /about + Header Accept-Language: de-DE => redirect to /de-DE/about). Once the user is redirected to a localized URL, we can use the technique described above. We can perform the redirection by using our server (e.g. Express.js) independently of vite-plugin-ssr.

    Using the Accept-Language header to show different languages for the same URL is considered bad practice for both SEO and UX reasons. It's recommended to use Accept-Language only to redirect the user.


See /examples/i18n/.


For pre-rendering we can use onBeforePrerender().


export { onBeforePrerender }

const locales = ['en-US', 'de-DE', 'fr-FR']

function onBeforePrerender(prerenderContext) {
  const pageContexts = []
  prerenderContext.pageContexts.forEach((pageContext) => {
      locale: localeDefault
    // We add the localized pages to the list of pages that are going to be pre-rendered
      .filter((locale) => locale !== localeDefault)
      .forEach((locale) => {
          urlOriginal: `/${locale}${pageContext.urlOriginal}`,
  return {
    prerenderContext: {

See /examples/i18n/ for an example of using onBeforePrerender().