next-intl Internationalization

Conventions for multi-language Next.js apps using next-intl, including translation patterns, locale detection, and common pitfalls.

AuthorNeexoCore
Apply to**/*.{ts,tsx}, **/messages/**
Updated
i18nnextjsnext-intl

Overview

next-intl provides type-safe internationalization for Next.js App Router apps. Neexo projects typically use Danish as the primary language with English and optionally German as secondaries.

Setup

Translation files live in messages/ as JSON:

messages/
  da.json    # Danish (primary source)
  en.json    # English
  de.json    # German (optional)

Translation Pattern

"use client";

import { useTranslations } from "next-intl";

export default function HeroSection() {
  const t = useTranslations("hero");
  return (
    <section>
      <h1>{t("title")}</h1>
      <p>{t("description")}</p>
    </section>
  );
}

Rules

  • Danish is the source language — always write Danish text first, then translate to other languages
  • Use useTranslations() hook in client components — never inline text strings
  • Namespace translations by feature/page: hero.title, contact.submit, nav.home
  • Keep translation keys in kebab-case or camelCase — be consistent within the project

Message File Structure

{
  "nav": {
    "home": "Forside",
    "about": "Om os",
    "contact": "Kontakt"
  },
  "hero": {
    "title": "Industriel 3D-visualisering",
    "description": "Vi omdanner tekniske CAD-data til visuelle oplevelser"
  }
}

Language Switching

For apps without locale in the URL (single-domain approach):

"use client";

import { useLocale } from "next-intl";

function LanguageSwitcher() {
  const locale = useLocale();
  // Switch by updating cookie or context
}

Danish Text Rules

  • Use proper Danish characters: æ, ø, å — never ae, oe, aa
  • Do not use em-dashes (—) in translations — rephrase with commas or "herunder"
  • Avoid AI/corporate buzzwords: "transformér", "unik", "robust", "gnidningsfrit"
  • Write naturally as a Dane would speak

Common Pitfalls

  • Do not use useTranslations() in Server Components — use getTranslations() instead
  • Keep defaultLocale set to "da" in the i18n config
  • Ensure all three language files have the same keys — missing keys cause runtime fallback warnings
  • Do not create inline translation objects — always use the message files

Raw content

Copy this into your project — e.g. .instructions.md, .agent.md, or SKILL.md

## Overview

next-intl provides type-safe internationalization for Next.js App Router apps. Neexo projects typically use Danish as the primary language with English and optionally German as secondaries.

## Setup

Translation files live in `messages/` as JSON:

```
messages/
  da.json    # Danish (primary source)
  en.json    # English
  de.json    # German (optional)
```

## Translation Pattern

```tsx
"use client";

import { useTranslations } from "next-intl";

export default function HeroSection() {
  const t = useTranslations("hero");
  return (
    <section>
      <h1>{t("title")}</h1>
      <p>{t("description")}</p>
    </section>
  );
}
```

## Rules

- **Danish is the source language** — always write Danish text first, then translate to other languages
- Use `useTranslations()` hook in client components — never inline text strings
- Namespace translations by feature/page: `hero.title`, `contact.submit`, `nav.home`
- Keep translation keys in kebab-case or camelCase — be consistent within the project

## Message File Structure

```json
{
  "nav": {
    "home": "Forside",
    "about": "Om os",
    "contact": "Kontakt"
  },
  "hero": {
    "title": "Industriel 3D-visualisering",
    "description": "Vi omdanner tekniske CAD-data til visuelle oplevelser"
  }
}
```

## Language Switching

For apps without locale in the URL (single-domain approach):

```tsx
"use client";

import { useLocale } from "next-intl";

function LanguageSwitcher() {
  const locale = useLocale();
  // Switch by updating cookie or context
}
```

## Danish Text Rules

- Use proper Danish characters: æ, ø, å — never ae, oe, aa
- Do not use em-dashes (—) in translations — rephrase with commas or "herunder"
- Avoid AI/corporate buzzwords: "transformér", "unik", "robust", "gnidningsfrit"
- Write naturally as a Dane would speak

## Common Pitfalls

- Do not use `useTranslations()` in Server Components — use `getTranslations()` instead
- Keep `defaultLocale` set to `"da"` in the i18n config
- Ensure all three language files have the same keys — missing keys cause runtime fallback warnings
- Do not create inline translation objects — always use the message files