Content Modeling

Multi-Locale Content

Brease supports multi-locale content out of the box. Each environment can have multiple locales, and all content is stored independently per locale.


Locales in the CMS

Each environment can have multiple locales (e.g., en, sk, de-AT). One locale is marked as the default.

All content entities have per-locale content:

  • Pages: section content is localized per locale
  • Collection entries: element content is localized per locale
  • Navigation items: labels and values are localized per locale

In the CMS, the Builder and Manager have a locale switcher to edit content for each locale independently. You fill in content for one locale at a time.

Configuring Locales in brease-next

Set the default locale in your environment variables:

BREASE_DEFAULT_LOCALE=en

This tells brease-next which locale to use when no locale is detected from the URL.

Locale Derivation from URLs

brease-next determines the active locale from the first segment of the URL slug:

URLDetected LocaleSlug Passed to API
/aboutdefault (en)/about
/sk/aboutsk/sk/about
/de-AT/kontaktde-AT/de-AT/kontakt

The first segment is checked against known locale codes for the environment. If it matches a configured locale, that locale is used. Otherwise, the default locale is used.

Fetching Available Locales

Use fetchLocales() to get all active locales for the current environment:

import { fetchLocales } from 'brease-next';

const result = await fetchLocales();

if (result.success) {
  console.log('Available locales:', result.data);
  // [{ code: 'en', name: 'English', default: true }, { code: 'sk', name: 'Slovak', default: false }]
}

Each page includes alternateLinks — a Record<string, string> mapping locale codes to URLs. Use these for SEO hreflang tags:

import { fetchPage } from 'brease-next';

const result = await fetchPage('/about');

if (result.success) {
  const alternateLinks = result.data.alternateLinks;
  // { en: "/about", sk: "/sk/o-nas", de: "/de/ueber-uns" }
}

In client components, access via the useBrease() hook:

'use client';

import { useBrease } from 'brease-next';

export default function HreflangTags() {
  const { alternateLinks } = useBrease();

  if (!alternateLinks) return null;

  return (
    <>
      {Object.entries(alternateLinks).map(([locale, url]) => (
        <link
          key={locale}
          rel="alternate"
          hrefLang={locale}
          href={url}
        />
      ))}
    </>
  );
}

Language Switcher

Build a language selector using useBrease():

'use client';

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

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

  if (!alternateLinks || !availableLocales) return null;

  return (
    <div>
      {availableLocales.map(locale => (
        <Link
          key={locale.code}
          href={alternateLinks[locale.code] || '/'}
        >
          {locale.name}
        </Link>
      ))}
    </div>
  );
}

Static Generation with Multiple Locales

generateBreasePageParams() iterates all locales and all pages to generate params for [[...slug]] catch-all routes:

// src/app/[[...slug]]/page.tsx
import { generateBreasePageParams, fetchPage, BreasePage } from 'brease-next';
import { sectionMap } from '@/lib/brease-config';
import { notFound } from 'next/navigation';

export async function generateStaticParams() {
  return generateBreasePageParams();
  // Returns params for all locale/page combinations:
  // [
  //   { slug: [] },              // homepage (default locale)
  //   { slug: ['about'] },       // /about (default locale)
  //   { slug: ['sk'] },          // /sk (Slovak homepage)
  //   { slug: ['sk', 'o-nas'] }, // /sk/o-nas (Slovak about page)
  // ]
}

export default async function Page({ params }: { params: Promise<{ slug?: string[] }> }) {
  const { slug } = await params;
  const pageSlug = slug ? `/${slug.join('/')}` : '/';

  const result = await fetchPage(pageSlug);

  if (!result.success) {
    if (result.status === 404) return notFound();
    throw new Error(`Failed to load page: ${result.error}`);
  }

  return <BreasePage page={result.data} sectionMap={sectionMap} />;
}

Locale-aware content

All brease-next fetch functions automatically resolve the correct locale based on the slug you pass. You don't need to pass a locale parameter separately — the locale is derived from the URL structure.

Previous
Navigations & Redirects