DEV Community

Eray Gündoğmuş
Eray Gündoğmuş

Posted on

Build a Multilingual Next.js App in 5 Minutes with App Router

TL;DR

A production-ready Next.js 15 + App Router i18n starter template with server-side translations, instant locale switching, and 15 languages out of the box.

GitHub Repo | Live Demo

What You Get

  • Next.js 15 with App Router and Server Components
  • 🌍 15 languages pre-configured (EN, TR, DE, ES, FR, JA, KO, ZH, AR, RU, IT, NL, HI, PL, PT)
  • 🔄 Instant locale switching — no full page reload
  • 🖥️ SSR translations — no flash of untranslated content
  • 📦 Cloud-managed translations via better-i18n CDN
  • 🎨 Tailwind CSS 4 + shadcn/ui components
  • 🔍 SEO-ready — hreflang tags, Open Graph, JSON-LD schemas, sitemap

Quick Start

Step 1: Clone and install

npx create-next-app -e https://github.com/better-i18n/nextjs-i18n-starter my-i18n-app
cd my-i18n-app
Enter fullscreen mode Exit fullscreen mode

Step 2: Create a free project at dash.better-i18n.com, add your languages, and set the env variable:

echo 'NEXT_PUBLIC_BETTER_I18N_PROJECT=your-org/your-project' > .env
Enter fullscreen mode Exit fullscreen mode

Step 3: Run it

npm run dev
# Open http://localhost:3000
Enter fullscreen mode Exit fullscreen mode

Done. You have a multilingual Next.js app.

How It Works

The entire setup is 3 files:

Config (i18n.config.ts)

import { createI18n } from "@better-i18n/next";

export const i18n = createI18n({
  project: process.env.NEXT_PUBLIC_BETTER_I18N_PROJECT || "better-i18n/demo",
  defaultLocale: "en",
  localePrefix: "always",
});
Enter fullscreen mode Exit fullscreen mode

Middleware (middleware.ts)

import { i18n } from "./i18n.config";

export default i18n.betterMiddleware();
Enter fullscreen mode Exit fullscreen mode

Yes, that's it. One line handles locale detection, redirects, and path prefixing.

Layout (src/app/[locale]/layout.tsx)

export default async function LocaleLayout({ children, params }) {
  const { locale } = await params;
  const messages = await i18n.getMessages(locale);

  return (
    <html lang={locale}>
      <body>
        <BetterI18nProvider config={i18n.config} locale={locale} messages={messages}>
          {children}
        </BetterI18nProvider>
      </body>
    </html>
  );
}
Enter fullscreen mode Exit fullscreen mode

Translations load server-side from CDN → passed to provider → available everywhere via useTranslations().

Customization

Add a new language

Just add it in the better-i18n dashboard. The useManifestLanguages hook in the language switcher picks it up automatically — no code changes needed.

Add a new page

// src/app/[locale]/pricing/page.tsx
import { useTranslations } from "next-intl";

export default function PricingPage() {
  const t = useTranslations("pricing");
  return <h1>{t("title")}</h1>;
}
Enter fullscreen mode Exit fullscreen mode

Add your translation keys in the dashboard, and the page works in all languages.

Deploy to Vercel

npm run build
# Or push to GitHub and connect to Vercel for automatic deploys
Enter fullscreen mode Exit fullscreen mode

The starter works out of the box on Vercel with zero configuration.

Links

If this is useful, drop a ⭐ on the repo!

Top comments (0)