Quick Start (Next.js)
-
Install packages
Terminal window pnpm add @fluenti/core @fluenti/react @fluenti/nextpnpm add -D @fluenti/cli -
Configure Next.js with
withFluentinext.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. -
Create
fluenti.config.tsfluenti.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',}) -
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.ReactNodeparams: Promise<{ locale: string }>}) {const { locale } = await paramsreturn (<html lang={locale} dir={getDirection(locale)}><body><I18nProvider locale={locale}>{children}</I18nProvider></body></html>)} -
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.nextUrlconst hasLocale = locales.some(l => pathname.startsWith(`/${l}/`) || pathname === `/${l}`)if (hasLocale) returnconst locale = request.cookies.get('locale')?.value ?? defaultLocalereturn NextResponse.redirect(new URL(`/${locale}${pathname}`, request.url))}export const config = { matcher: ['/((?!_next|api|favicon).*)'] } -
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><buttononMouseEnter={() => preloadLocale('zh-CN')}onClick={() => switchLocale('zh-CN')}>中文</button><buttononMouseEnter={() => preloadLocale('ja')}onClick={() => switchLocale('ja')}>日本語</button></div>)} -
React Server Components
Server Components use the same
t`...`syntax. ThewithFluenti()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.
-
Extract and compile messages
Terminal window npx fluenti extract# ... translate the .po files ...npx fluenti compile -
Update build script
{"scripts": {"build": "fluenti compile && next build"}}
Key differences from React SPA
Section titled “Key differences from React SPA”- Uses
withFluenti()innext.config.tsinstead of the Vite plugin I18nProvideris 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, orrouter.refresh()with cookie-basedt`...`works in both Client and Server Components via@fluenti/react—withFluenti()handles the server transform
Next steps
Section titled “Next steps”- Next.js guide — full integration reference
- Server Components — RSC deep dive
- Translating Content — all translation APIs