Implementation Patterns

Multi-Locale Sites

Brease supports multi-locale sites out of the box. Locale is embedded in the page slug (e.g. sk/about-us) and handled automatically by fetchPage and BreaseContext. No separate [locale] route segment is needed.


How Locale Routing Works

The [[...slug]] catch-all route handles all locales:

URLslug arrayLocalePage slug
/undefineddefault/
/about['about']default/about
/sk/o-nas['sk', 'o-nas']sk/sk/o-nas
/de/uber-uns['de', 'uber-uns']de/de/uber-uns

When you pass the slug string to fetchPage, it automatically detects the locale prefix and returns the correct localized content.

parseSlugAndLocale

The parseSlugAndLocale utility extracts the locale and remaining slug from a combined slug string:

import { parseSlugAndLocale } from 'brease-next/server'

parseSlugAndLocale('sk/about-us')
// Returns: { slug: 'about-us', locale: 'sk' }

parseSlugAndLocale('about-us')
// Returns: { slug: 'about-us', locale: undefined }
// (falls back to BREASE_DEFAULT_LOCALE)

The function checks the first segment against known locale codes. If it matches a configured locale, it is extracted. Otherwise, the entire string is treated as the page slug with the default locale applied.

No [locale] segment needed

Unlike many i18n setups in Next.js, Brease does not require a [locale] dynamic segment. The locale is part of the slug, and BreaseContext plus fetchPage handle locale derivation automatically.


Static Generation for All Locales

generateBreasePageParams() already handles all locale/page combinations. It iterates every locale and every page, returning params for all of them:

export async function generateStaticParams() {
  return generateBreasePageParams()
  // Returns:
  // [
  //   { locale: 'en', slug: ['about'] },
  //   { locale: 'en', slug: ['contact'] },
  //   { locale: 'sk', slug: ['sk', 'o-nas'] },
  //   { locale: 'sk', slug: ['sk', 'kontakt'] },
  //   ...
  // ]
}

No additional configuration is needed for multi-locale static generation.


Fetching Locales

To get the list of all available locales for your site:

import { fetchLocales } from 'brease-next/server'

const result = await fetchLocales()

if (result.success) {
  result.data.forEach((locale) => {
    console.log(locale.code) // 'en', 'sk', 'de'
    console.log(locale.name) // 'English', 'Slovak', 'German'
    console.log(locale.isDefault) // true for the default locale
  })
}

The return type is BreaseResponse<BreaseLocale[]> where:

interface BreaseLocale {
  uuid: string
  code: string
  name: string
  isDefault: boolean
}

Language Switcher Component

The useBrease() hook provides availableLocales, locale, and alternateLinks -- everything needed for a language switcher. The alternateLinks object maps locale codes to the corresponding URL for the current page in that language.

// src/components/language-switcher.tsx
'use client'

import { useBrease } from 'brease-next'
import Link from 'next/link'

export function LanguageSwitcher() {
  const { availableLocales, locale, alternateLinks } = useBrease()

  return (
    <ul className="flex items-center gap-2">
      {availableLocales.map((loc) => (
        <li key={loc}>
          <Link
            href={alternateLinks[loc] || `/${loc}`}
            className={`rounded px-2 py-1 text-sm ${
              loc === locale
                ? 'bg-blue-600 font-bold text-white'
                : 'text-gray-600 hover:text-gray-900'
            }`}
          >
            {loc.toUpperCase()}
          </Link>
        </li>
      ))}
    </ul>
  )
}

For a page /about that has a Slovak translation at /sk/o-nas, the alternateLinks object looks like:

{
  en: '/about',
  sk: '/sk/o-nas'
}

If the current page does not have a translation in a given locale, the switcher falls back to /${loc} (the locale's homepage).

Placing the switcher

Add it to your header alongside the navigation:

// src/components/header.tsx
'use client'

import { useBrease, BreaseLink } from 'brease-next'
import { LanguageSwitcher } from './language-switcher'

export default function Header() {
  const { navigations } = useBrease()
  const headerNav = navigations.header

  return (
    <header className="border-b bg-white">
      <div className="mx-auto max-w-7xl px-6">
        <div className="flex h-16 items-center justify-between">
          <nav className="flex items-center gap-6">
            {headerNav?.items.map((item) => (
              <BreaseLink key={item.uuid} linkData={item}>
                {item.label}
              </BreaseLink>
            ))}
          </nav>
          <LanguageSwitcher />
        </div>
      </div>
    </header>
  )
}

If you need alternate links outside of BreaseContext (e.g. for <link rel="alternate"> tags), use fetchAlternateLinks:

import { fetchAlternateLinks } from 'brease-next/server'

const result = await fetchAlternateLinks('about')

if (result.success) {
  // result.data contains alternate link data for the page
}

The generateBreasePageMetadata function automatically includes alternates in the returned metadata when alternate links are available, so you typically do not need to call this directly.


Locale-Aware Data Fetching

When fetching data outside BreaseContext (e.g. in server components or API routes), you must pass the locale explicitly to functions that require it:

import {
  fetchCollectionById,
  fetchEntryById,
  fetchNavigation,
  fetchAllPages,
} from 'brease-next/server'

// All require a locale parameter
const collection = await fetchCollectionById('col-uuid', 'sk')
const entry = await fetchEntryById('col-uuid', 'entry-uuid', 'sk')
const navigation = await fetchNavigation('nav-uuid', 'sk')
const pages = await fetchAllPages('sk')

fetchPage derives locale automatically

fetchPage does not take a separate locale parameter. Instead, it derives the locale from the slug. For example, fetchPage('sk/about-us') will automatically fetch the Slovak version. All other fetch functions require an explicit locale.


Next Steps

Previous
Navigation & Links