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 locale layout

    src/app/[locale]/layout.tsx
    import { getDirection } from '@fluenti/core'
    import { I18nProvider } from '@fluenti/next'
    export default async function LocaleLayout({
    children,
    params,
    }: {
    children: React.ReactNode
    params: Promise<{ locale: string }>
    }) {
    const { locale } = await params
    return (
    <html lang={locale} dir={getDirection(locale)}>
    <body>
    <I18nProvider locale={locale}>
    {children}
    </I18nProvider>
    </body>
    </html>
    )
    }
  5. Add locale redirect middleware (optional)

    Redirect requests without a locale prefix to the default locale:

    src/middleware.ts
    import { NextResponse, type NextRequest } from 'next/server'
    const locales = ['en', 'zh-CN', 'ja']
    const defaultLocale = 'en'
    export function middleware(request: NextRequest) {
    const { pathname } = request.nextUrl
    const hasLocale = locales.some(l => pathname.startsWith(`/${l}/`) || pathname === `/${l}`)
    if (hasLocale) return
    const locale = request.cookies.get('locale')?.value ?? defaultLocale
    return NextResponse.redirect(new URL(`/${locale}${pathname}`, request.url))
    }
    export const config = { matcher: ['/((?!_next|api|favicon).*)'] }
  6. Write a client page component

    src/app/[locale]/page.tsx
    'use client'
    import { useRouter } from 'next/navigation'
    import { t, 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.push(`/${loc}`)
    }
    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>
    )
    }
  7. 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
    import { t } from '@fluenti/react'
    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.

  8. Extract and compile messages

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

    {
    "scripts": {
    "build": "fluenti compile && next build"
    }
    }
  • Uses withFluenti() in next.config.ts instead of the Vite plugin
  • I18nProvider is generated by @fluenti/next — no manual client provider needed
  • Path-based locale detection (recommended) or cookie-based
  • router.push() for locale switch with path-based routing, or router.refresh() with cookie-based
  • t`...` works in both Client and Server Components via @fluenti/reactwithFluenti() handles the server transform