Quick Start (React Router)
-
Install packages
Terminal window pnpm add @fluenti/core @fluenti/react react-router-dompnpm add -D @fluenti/cli @fluenti/vite-plugin @vitejs/plugin-react -
Configure Vite
vite.config.ts import { defineConfig } from 'vite'import react from '@vitejs/plugin-react'import fluenti from '@fluenti/vite-plugin'export default defineConfig({plugins: [fluenti({ framework: 'react' }),react(),],}) -
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 root with I18nProvider and routing
src/main.tsx import { createRoot } from 'react-dom/client'import { BrowserRouter, Routes, Route } from 'react-router-dom'import { I18nProvider } from '@fluenti/react'import { getDirection } from '@fluenti/core'import { useState, useEffect } from 'react'import en from './locales/compiled/en'import zhCN from './locales/compiled/zh-CN'import ja from './locales/compiled/ja'import { Home } from './pages/Home'const messages = { en, 'zh-CN': zhCN, ja }function getInitialLocale(): string {const match = document.cookie.match(/(?:^|;\s*)locale=([^;]*)/)if (match) return decodeURIComponent(match[1])return 'en'}function Root() {const [locale, setLocale] = useState(getInitialLocale)useEffect(() => {document.documentElement.lang = localedocument.documentElement.dir = getDirection(locale)}, [locale])const handleLocaleChange = (loc: string) => {document.cookie = `locale=${loc};path=/;max-age=31536000`setLocale(loc)}return (<I18nProvider locale={locale} fallbackLocale="en" messages={messages}><BrowserRouter><Routes><Route path="/" element={<Home onLocaleChange={handleLocaleChange} />} /></Routes></BrowserRouter></I18nProvider>)}createRoot(document.getElementById('root')!).render(<Root />) -
Write a page component
src/pages/Home.tsx export function Home({ onLocaleChange }: { onLocaleChange: (loc: string) => void }) {const name = 'World'return (<div><h1>{t`Welcome to my app`}</h1><p>{t`Hello, ${name}!`}</p><button onClick={() => onLocaleChange('en')}>English</button><button onClick={() => onLocaleChange('zh-CN')}>中文</button><button onClick={() => onLocaleChange('ja')}>日本語</button></div>)}The
t`...`tagged template is a compiler macro injected by the Vite plugin — no import needed. -
Extract, translate, and compile
Terminal window npx fluenti extract# ... translate the .po files ...npx fluenti compile
Code splitting with lazy routes
Section titled “Code splitting with lazy routes”React Router works well with lazy-loaded routes. The Vite plugin can tree-shake messages per chunk:
const About = lazy(() => import('./pages/About'))
<Route path="/about" element={ <Suspense fallback={<p>Loading...</p>}> <About /> </Suspense>} />For more on code splitting, see Code Splitting.
Key differences from React SPA
Section titled “Key differences from React SPA”- Cookie-based locale persistence (server-readable for future SSR migration)
- Lazy-loaded route components with
Suspensefor code splitting preloadLocale()on hover for instant locale switching
Next steps
Section titled “Next steps”- React Router guide — full integration reference
- Translating Content — all translation APIs