Documentation

Internationalization (i18n)

Learn how to add multi-language support to your Sushify Next.js application using next-intl

Sushify Next.js includes built-in internationalization (i18n) support powered by next-intl, making it easy to build multilingual applications with type-safe translations.

Features

  • Multiple Languages: Support for unlimited languages
  • Type-Safe Translations: Full TypeScript support with autocomplete
  • Locale-Specific Routing: Automatic locale detection and routing
  • Number & Date Formatting: Locale-aware formatting
  • Server & Client Components: Works in both server and client components
  • SEO-Friendly: Proper hreflang tags and locale-specific URLs
  • Dynamic Content: Translate dynamic content from your database

Configuration

1. Supported Locales

Configure supported languages in your config:

config/index.ts
export const config = {
  i18n: {
    enabled: true,
    locales: {
      en: {
        currency: "USD",
        label: "English",
      },
      zh: {
        currency: "CNY",
        label: "简体中文",
      },
      es: {
        currency: "EUR",
        label: "Español",
      },
      de: {
        currency: "EUR",
        label: "Deutsch",
      },
    },
    defaultLocale: "en",
    defaultCurrency: "USD",
    localeCookieName: "NEXT_LOCALE",
  },
};

2. Translation Files

Translations are organized in JSON files by locale:

packages/i18n/translations/
├── en.json      # English translations
├── zh.json      # Chinese (Simplified) translations
├── es.json      # Spanish translations
└── de.json      # German translations

Example translation file:

packages/i18n/translations/en.json
{
  "navigation": {
    "home": "Home",
    "pricing": "Pricing",
    "about": "About",
    "contact": "Contact"
  },
  "buttons": {
    "submit": "Submit",
    "cancel": "Cancel",
    "save": "Save",
    "delete": "Delete"
  },
  "messages": {
    "success": "Operation completed successfully",
    "error": "An error occurred",
    "loading": "Loading..."
  }
}
packages/i18n/translations/de.json
{
  "navigation": {
    "home": "Startseite",
    "pricing": "Preise",
    "about": "Über uns",
    "contact": "Kontakt"
  },
  "buttons": {
    "submit": "Absenden",
    "cancel": "Abbrechen",
    "save": "Speichern",
    "delete": "Löschen"
  },
  "messages": {
    "success": "Vorgang erfolgreich abgeschlossen",
    "error": "Ein Fehler ist aufgetreten",
    "loading": "Wird geladen..."
  }
}

Usage

Server Components

Use translations in server components:

app/[locale]/page.tsx
import { getTranslations } from "next-intl/server";

export default async function HomePage() {
  const t = await getTranslations();

  return (
    <div>
      <h1>{t("navigation.home")}</h1>
      <button>{t("buttons.submit")}</button>
    </div>
  );
}

Client Components

Use translations in client components:

components/SubmitButton.tsx
"use client";

import { useTranslations } from "next-intl";

export function SubmitButton() {
  const t = useTranslations();

  return (
    <button type="submit">
      {t("buttons.submit")}
    </button>
  );
}

Rich Text Formatting

Format text with HTML tags:

{
  "terms": "By signing up, you agree to our <link>Terms of Service</link>"
}
import { useTranslations } from "next-intl";
import Link from "next/link";

function SignupPage() {
  const t = useTranslations("auth");

  return (
    <p>
      {t.rich("terms", {
        link: (chunks) => (
          <Link href="/terms" className="underline">
            {chunks}
          </Link>
        ),
      })}
    </p>
  );
}

Email Translations

Send localized emails:

import { sendEmail } from "@repo/mail";

await sendEmail({
  to: user.email,
  templateId: "welcome",
  locale: user.locale, // Use user's preferred language
  context: {
    name: user.name,
  },
});

Adding a New Language

  1. Add to config:
config/index.ts
locales: {
  // ...existing locales
  ja: {
    currency: "JPY",
    label: "日本語",
  },
}
  1. Create translation file:
cp packages/i18n/translations/en.json packages/i18n/translations/ja.json
  1. Translate content: Update the JSON file with Japanese translations

  2. Test: Verify all pages render correctly in the new language