Next.js Integration
@lingo.dev/compiler integrates with Next.js App Router through an async configuration wrapper that supports both Webpack and Turbopack.
Setup
1. Install Package
pnpm install @lingo.dev/compiler
2. Configure Next.js
Update your next.config.ts to use the async withLingo() wrapper:
import type { NextConfig } from "next";
import { withLingo } from "@lingo.dev/compiler/next";
const nextConfig: NextConfig = {
// Your existing Next.js config
};
export default async function (): Promise<NextConfig> {
return await withLingo(nextConfig, {
sourceRoot: "./app",
sourceLocale: "en",
targetLocales: ["es", "de", "fr"],
models: "lingo.dev",
dev: {
usePseudotranslator: true,
},
});
}
Why async? The wrapper lazy-loads plugins and resolves configuration dynamically. This keeps your build fast and allows for conditional plugin loading.
3. Add Provider
Wrap your app with LingoProvider in your root layout:
// app/layout.tsx
import { LingoProvider } from "@lingo.dev/compiler/react";
export default function RootLayout({
children,
}: {
children: React.ReactNode;
}) {
return (
<LingoProvider>
<html>
<body>{children}</body>
</html>
</LingoProvider>
);
}
Important: Place LingoProvider inside <html> but wrapping all content. It works with both Server and Client Components.
React Server Components
The compiler fully supports React Server Components (RSC). Server Components are translated at build time, and the translations are embedded in the server output.
// app/page.tsx (Server Component)
export default function Page() {
return (
<div>
<h1>Welcome to our app</h1>
<p>This is a server component—translated at build time</p>
</div>
);
}
No client-side JavaScript is added for translated text in Server Components.
Client Components
For Client Components, use the "use client" directive:
"use client";
import { useLocale, setLocale } from "@lingo.dev/compiler/react";
export function LanguageSwitcher() {
const locale = useLocale();
return (
<select value={locale} onChange={(e) => setLocale(e.target.value)}>
<option value="en">English</option>
<option value="es">Español</option>
<option value="de">Deutsch</option>
</select>
);
}
Client Components receive optimized translation bundles. Only translations used in that component are included.
Locale Detection
By default, locale is stored in a cookie (locale). The compiler automatically handles locale detection and persistence.
Custom Server Locale Detection
For custom logic (database, headers, subdomain), create .lingo/locale-resolver.server.ts:
// .lingo/locale-resolver.server.ts
import { headers } from "next/headers";
export async function getServerLocale(): Promise<string> {
const headersList = await headers();
const acceptLanguage = headersList.get("accept-language");
// Parse accept-language header
const locale = acceptLanguage?.split(",")[0]?.split("-")[0] || "en";
return locale;
}
This function is called on the server for every request. It should return the locale code (e.g., "en", "es").
Custom Client Locale Persistence
For custom client-side logic (localStorage, URL params), create .lingo/locale-resolver.client.ts:
// .lingo/locale-resolver.client.ts
export function getClientLocale(): string {
// Check URL parameter first
const params = new URLSearchParams(window.location.search);
const urlLocale = params.get("lang");
if (urlLocale) return urlLocale;
// Fall back to localStorage
return localStorage.getItem("locale") || "en";
}
export function persistLocale(locale: string): void {
localStorage.setItem("locale", locale);
// Optionally update URL
const url = new URL(window.location.href);
url.searchParams.set("lang", locale);
window.history.replaceState({}, "", url.toString());
}
See Custom Locale Resolvers for more details.
Middleware for Locale Routing
If you want locale-based routing (/en/about, /es/about), implement Next.js middleware:
// middleware.ts
import { NextRequest, NextResponse } from "next/server";
const locales = ["en", "es", "de", "fr"];
const defaultLocale = "en";
export function middleware(request: NextRequest) {
const { pathname } = request.nextUrl;
// Check if pathname already has a locale
const pathnameHasLocale = locales.some(
(locale) => pathname.startsWith(`/${locale}/`) || pathname === `/${locale}`
);
if (pathnameHasLocale) return;
// Get locale from cookie or accept-language header
const localeCookie = request.cookies.get("locale")?.value;
const acceptLanguage = request.headers.get("accept-language");
const locale =
localeCookie ||
acceptLanguage?.split(",")[0]?.split("-")[0] ||
defaultLocale;
// Redirect to localized pathname
request.nextUrl.pathname = `/${locale}${pathname}`;
return NextResponse.redirect(request.nextUrl);
}
export const config = {
matcher: ["/((?!api|_next|_vercel|.*\\..*).*)"],
};
Update your routes to use [locale] dynamic segment:
app/
[locale]/
page.tsx
about/
page.tsx
layout.tsx
Build Configuration
Development Build
{
dev: {
usePseudotranslator: true, // Fast fake translations
}
}
Run npm run dev to start the development server with instant pseudotranslations.
Production Build
{
buildMode: "cache-only", // Use pre-generated translations
}
Run npm run build to build for production. No API keys needed—translations come from .lingo/metadata.json.
Best practice: Generate real translations in CI before building for production. See Build Modes for the recommended workflow.
Turbopack Support
The compiler works with both Webpack and Turbopack (Next.js 15+).
To use Turbopack in development:
next dev --turbo
The compiler automatically detects and configures the appropriate bundler.
TypeScript
The compiler is fully typed. Import types from @lingo.dev/compiler:
import type { LingoConfig } from "@lingo.dev/compiler";
const config: LingoConfig = {
sourceRoot: "./app",
sourceLocale: "en",
targetLocales: ["es", "de"],
models: "lingo.dev",
};
Common Issues
"Cannot find module '@lingo.dev/compiler/react'"
Make sure you've installed the package: pnpm install @lingo.dev/compiler
HMR not working after adding LingoProvider
Ensure LingoProvider is placed correctly in your root layout, not in a nested layout or page.
Translations not showing in production build
Check that you're using buildMode: "cache-only" and that .lingo/metadata.json contains translations for all locales.
"Missing translations for locale X"
Run your dev server with usePseudotranslator: false to generate real translations, or run a CI build to populate .lingo/metadata.json.
Next Steps
- Configuration Reference — All configuration options
- Custom Locale Resolvers — Customize locale detection
- Manual Overrides — Override specific translations
- Best Practices — Recommended patterns and workflows