Skip to content
fluenti

Quick Start (Next.js)

  1. Install packages

    Terminal window
    pnpm add @fluenti/core @fluenti/react @fluenti/next
    pnpm add -D @fluenti/cli
  2. Configure Next.js with withFluenti

    next.config.ts
    import { withFluenti } from '@fluenti/next'
    export default withFluenti()({
    reactStrictMode: true,
    })

    withFluenti() adds the Fluenti compiler plugin to the Next.js build pipeline and generates the server/client modules your app needs.

  3. Create fluenti.config.ts

    fluenti.config.ts
    import { defineConfig } from '@fluenti/cli'
    export default defineConfig({
    sourceLocale: 'en',
    locales: ['en', 'zh-CN', 'ja'],
    catalogDir: './locales',
    format: 'po',
    include: ['./src/**/*.{tsx,ts}'],
    compileOutDir: './src/locales/compiled',
    })
  4. Set up the root layout

    src/app/layout.tsx
    import { cookies } from 'next/headers'
    import { getDirection } from '@fluenti/core'
    // @ts-expect-error — generated at build time by withFluenti()
    import { FluentProvider } from '@fluenti/next/__generated'
    export default async function RootLayout({ children }: { children: React.ReactNode }) {
    const locale = (await cookies()).get('locale')?.value ?? 'en'
    return (
    <html lang={locale} dir={getDirection(locale)}>
    <body>
    <FluentProvider locale={locale}>
    {children}
    </FluentProvider>
    </body>
    </html>
    )
    }
  5. Write a client page component

    src/app/page.tsx
    'use client'
    import { useRouter } from 'next/navigation'
    import { useI18n } from '@fluenti/react'
    export default function Home() {
    const { setLocale, preloadLocale } = useI18n()
    const router = useRouter()
    const switchLocale = async (loc: string) => {
    document.cookie = `locale=${loc};path=/;max-age=31536000`
    await setLocale(loc)
    router.refresh()
    }
    return (
    <div>
    <h1>{t`Welcome to my app`}</h1>
    <p>{t`Hello, ${'World'}!`}</p>
    <button onClick={() => switchLocale('en')}>English</button>
    <button
    onMouseEnter={() => preloadLocale('zh-CN')}
    onClick={() => switchLocale('zh-CN')}
    >中文</button>
    <button
    onMouseEnter={() => preloadLocale('ja')}
    onClick={() => switchLocale('ja')}
    >日本語</button>
    </div>
    )
    }
  6. React Server Components

    Server Components use the same t`...` syntax. The withFluenti() plugin detects the component type and applies the correct transform:

    src/app/about/page.tsx
    export default async function AboutPage() {
    return (
    <div>
    <h1>{t`About us`}</h1>
    <p>{t`We build great software.`}</p>
    </div>
    )
    }

    For advanced RSC patterns (streaming, server actions), see the Server Components guide.

  7. Extract and compile messages

    Terminal window
    npx fluenti extract
    # ... translate the .po files ...
    npx fluenti compile
  8. Update build script

    {
    "scripts": {
    "build": "fluenti compile && next build"
    }
    }
  • Uses withFluenti() in next.config.ts instead of the Vite plugin
  • FluentProvider is generated by @fluenti/next — no manual client provider needed
  • Cookie-based locale detection on the server via cookies() from next/headers
  • router.refresh() after locale switch — triggers the server layout to re-read the cookie and update <html lang>
  • t`...` works in both Client and Server Components — withFluenti() handles the transform