# Internationalization (i18n) Documentation

Complete guide to the multi-language support system in the portfolio application.

## Overview

This portfolio supports **3 languages** with full internationalization:

| Language | Code | Flag | Region |
|----------|------|------|--------|
| **German** (default) | `de` | 🇩🇪 | Germany |
| **English** | `en` | 🇬🇧 | United States |
| **Serbian** | `sr` | 🇷🇸 | Serbia |

### Tech Stack

- **next-intl** - Next.js internationalization library
- **JSON-based translations** - Simple, maintainable translation files
- **Type-safe locale handling** - TypeScript ensures locale consistency
- **SEO optimized** - Hreflang tags, Content-Language headers, localized metadata

### Key Features

- ✅ Automatic locale detection from URL path
- ✅ Fallback to default locale (German)
- ✅ Server-side translation loading
- ✅ Type-safe locale validation
- ✅ SEO-friendly URL structure (`/de/`, `/en/`, `/sr/`)
- ✅ Localized metadata for social sharing
- ✅ Support for nested translation keys
- ✅ Legacy migration path (locales-old)

## Quick Start

### Using Translations in Components

```tsx
import { useTranslations } from 'next-intl';

export default function MyComponent() {
  const t = useTranslations('common');

  return (
    <div>
      <h1>{t('nav.home')}</h1>
      <p>{t('siteDescription')}</p>
    </div>
  );
}
```

### Adding a New Translation Key

#### Step-by-Step Guide

Follow this process to add new translation keys to the application:

##### 1. Identify the Appropriate Namespace

Before adding a new translation key, determine where it should live based on its purpose:

- **`meta`** - Site metadata, author information, SEO keywords
- **`common`** - Shared UI elements (buttons, navigation, errors, cookies)
- **`navigation`** - All navigation-related text (main menu, footer links, mobile menu)
- **`footer`** - Footer content (sections, legal links, copyright)
- **`pages`** - Page-specific content organized by route
  - `pages.home` - Homepage content
  - `pages.about` - About page content
  - `pages.contact` - Contact page content
  - `pages.privacy` - Privacy policy content
  - `pages.terms` - Terms and conditions content
  - `pages.notfound` - 404 page content
- **`portfolio`** - Portfolio page content and filters
- **`blog`** - Blog page content and UI elements
- **`login`** - Login page content
- **`dashboard`** - Dashboard content and metrics

**Best Practice:** Use `common` for elements that appear across multiple pages. Use page-specific namespaces for content unique to a single page.

##### 2. Open All Three Translation Files

You must update all three locale files to maintain consistency:

```bash
# Open in your editor:
src/messages/de.json    # German (default)
src/messages/en.json    # English
src/messages/sr.json    # Serbian
```

##### 3. Add the Translation Key

Add your key to the **exact same location** in each file. The JSON structure must be identical across all locales.

**Example: Adding a new action button**

```json
// de.json
{
  "common": {
    "actions": {
      "readMore": "Weiterlesen",
      "viewMore": "Mehr anzeigen",
      "viewAll": "Alle anzeigen",
      "download": "Herunterladen"  // ← New key
    }
  }
}

// en.json
{
  "common": {
    "actions": {
      "readMore": "Read More",
      "viewMore": "View More",
      "viewAll": "View All",
      "download": "Download"  // ← New key
    }
  }
}

// sr.json
{
  "common": {
    "actions": {
      "readMore": "Procitaj vise",
      "viewMore": "Prikazi vise",
      "viewAll": "Prikazi sve",
      "download": "Preuzmi"  // ← New key
    }
  }
}
```

**Example: Adding a new page section**

```json
// de.json
{
  "pages": {
    "services": {  // ← New namespace
      "hero": {
        "title": "Unsere Dienstleistungen",
        "subtitle": "Maßgeschneiderte Lösungen für Ihr Unternehmen"
      }
    }
  }
}

// en.json
{
  "pages": {
    "services": {  // ← New namespace
      "hero": {
        "title": "Our Services",
        "subtitle": "Tailored solutions for your business"
      }
    }
  }
}

// sr.json
{
  "pages": {
    "services": {  // ← New namespace
      "hero": {
        "title": "Naše usluge",
        "subtitle": "Prilagođena rešenja za vaše poslovanje"
      }
    }
  }
}
```

##### 4. Use the Translation in Your Component

Import the `useTranslations` hook and specify the namespace:

```tsx
import { useTranslations } from 'next-intl';

export default function MyComponent() {
  // Option 1: Access top-level namespace
  const t = useTranslations('common.actions');

  return (
    <button className="btn-primary">
      {t('download')}
    </button>
  );
}
```

**Multiple namespaces in one component:**

```tsx
import { useTranslations } from 'next-intl';

export default function ServicesPage() {
  const tHero = useTranslations('pages.services.hero');
  const tCommon = useTranslations('common.actions');

  return (
    <div>
      <h1>{tHero('title')}</h1>
      <p>{tHero('subtitle')}</p>
      <button>{tCommon('readMore')}</button>
    </div>
  );
}
```

##### 5. Verify Your Changes

1. **Build the application** to ensure no TypeScript errors:
   ```bash
   npm run build
   ```

2. **Test in all three languages:**
   - German: `http://localhost:3000/de`
   - English: `http://localhost:3000/en`
   - Serbian: `http://localhost:3000/sr`

3. **Check for missing translations** - The browser console will warn if a key is missing

#### JSON Structure & Organization

##### Hierarchical Namespace Pattern

Translation files use a **deeply nested JSON structure** to organize translations logically:

```json
{
  "namespace": {           // Top-level category
    "subnamespace": {      // Feature or section
      "key": "value",      // Leaf node (actual translation)
      "nested": {
        "key": "value"     // Deeper nesting allowed
      }
    }
  }
}
```

**Real example from the codebase:**

```json
{
  "pages": {                    // Namespace: Page content
    "home": {                   // Subnamespace: Homepage
      "hero": {                 // Section: Hero section
        "title": "FULLSTACK DEVELOPER",
        "subtitle": "AI AGENTS | VOICE AI",
        "navigation": {         // Nested object
          "experience": "EXPERIENCE",
          "skills": "SKILLS"
        }
      }
    }
  }
}
```

**Access in code:**

```tsx
const t = useTranslations('pages.home.hero');
console.log(t('title'));                    // "FULLSTACK DEVELOPER"
console.log(t('navigation.experience'));    // "EXPERIENCE"
```

##### Special Data Types

**Arrays** - For lists of items:

```json
{
  "meta": {
    "site": {
      "keywords": [
        "Fullstack Developer",
        "AI Developer Germany",
        "Process Automation"
      ]
    }
  }
}
```

**Usage:**

```tsx
const t = useTranslations('meta.site');
const keywords = t.raw('keywords'); // Returns array
```

**Objects** - For structured data:

```json
{
  "pages": {
    "home": {
      "experience": {
        "positions": [
          {
            "role": "Process Automation Specialist",
            "company": "Everlast Consulting GmbH",
            "period": "12/2024 - PRESENT",
            "highlights": [
              "Development of AI agents",
              "Web scraping solutions"
            ]
          }
        ]
      }
    }
  }
}
```

**Usage:**

```tsx
const t = useTranslations('pages.home.experience');
const positions = t.raw('positions'); // Returns array of objects

positions.map((position) => (
  <div key={position.role}>
    <h3>{position.role}</h3>
    <p>{position.company}</p>
    <span>{position.period}</span>
    <ul>
      {position.highlights.map((highlight) => (
        <li key={highlight}>{highlight}</li>
      ))}
    </ul>
  </div>
));
```

#### Advanced Usage Examples

##### Dynamic Translation Keys

Access translations dynamically based on variables:

```tsx
import { useTranslations } from 'next-intl';

export default function CategoryFilter({ categories }: { categories: string[] }) {
  const t = useTranslations('portfolio.filters.categories');

  return (
    <div>
      {categories.map((category) => (
        <button key={category}>
          {t(category as any)}  // Dynamic key lookup
        </button>
      ))}
    </div>
  );
}

// If categories = ["Data Science", "AI Development"]
// Output: "Data Science" → "Data Science" (en) or "Data Science" (de)
//         "AI Development" → "AI Development" (en) or "KI-Entwicklung" (de)
```

##### String Interpolation

Use variables in translations:

```tsx
import { useTranslations } from 'next-intl';

export default function Pagination({ start, end, total }: PaginationProps) {
  const t = useTranslations('blog.ui.pagination');

  // Translation: "Showing {start}-{end} of {total} articles"
  return (
    <p>
      {t('showing', { start, end, total })}
    </p>
  );
}
```

**In JSON:**

```json
{
  "blog": {
    "ui": {
      "pagination": {
        "showing": "Showing {start}-{end} of {total} articles"
      }
    }
  }
}
```

##### Accessing Rich Content

For translations containing HTML or rich content:

```tsx
import { useTranslations } from 'next-intl';

export default function RichText() {
  const t = useTranslations('pages.about');

  return (
    <div>
      {/* Simple text */}
      <h1>{t('hero.title')}</h1>

      {/* Raw access for objects/arrays */}
      <div>
        {t.raw('hero.expertise.processAutomation')}
      </div>
    </div>
  );
}
```

#### Common Patterns & Best Practices

##### ✅ DO: Keep Structure Consistent

```json
// Good: Same structure across all locales
// de.json
{ "common": { "actions": { "save": "Speichern" } } }

// en.json
{ "common": { "actions": { "save": "Save" } } }

// sr.json
{ "common": { "actions": { "save": "Sačuvaj" } } }
```

##### ❌ DON'T: Mix Structures

```json
// Bad: Different structures
// de.json
{ "common": { "actions": { "save": "Speichern" } } }

// en.json
{ "common": { "save": "Save" } }  // ❌ Missing "actions" level
```

##### ✅ DO: Use Semantic Naming

```json
{
  "common": {
    "actions": {
      "submit": "Submit",      // ✅ Clear, semantic
      "cancel": "Cancel",
      "delete": "Delete"
    }
  }
}
```

##### ❌ DON'T: Use Generic Names

```json
{
  "common": {
    "button1": "Submit",  // ❌ Non-descriptive
    "btn": "Cancel",      // ❌ Abbreviated
    "text1": "Delete"     // ❌ Generic
  }
}
```

##### ✅ DO: Group Related Translations

```json
{
  "pages": {
    "contact": {
      "contactForm": {              // ✅ Grouped by feature
        "title": "Contact Me",
        "name": { "label": "Name", "placeholder": "Your name" },
        "email": { "label": "Email", "placeholder": "your@email.com" },
        "submit": "Send Message"
      }
    }
  }
}
```

##### ✅ DO: Reuse Common Translations

```tsx
// Good: Reuse common translations
import { useTranslations } from 'next-intl';

export default function MyForm() {
  const tCommon = useTranslations('common.actions');

  return (
    <form>
      <button type="submit">{tCommon('submit')}</button>
      <button type="button">{tCommon('cancel')}</button>
    </form>
  );
}
```

## Documentation Structure

This documentation is organized into the following sections:

### 📁 Directory Structure & Organization

The i18n system is organized into three main directories, each serving a specific purpose in the translation infrastructure.

#### Overview of Directory Structure

```
src/
├── i18n/                          # Configuration Layer
│   ├── config.ts                  # ✅ Locale definitions & metadata
│   ├── request.ts                 # ✅ next-intl integration
│   └── locales-old/               # ⚠️ DEPRECATED - Do NOT use
│       ├── de.ts
│       ├── en.ts
│       └── sr.ts
│
└── messages/                      # ✅ Active Translation Files
    ├── de.json                    # German translations
    ├── en.json                    # English translations
    └── sr.json                    # Serbian translations
```

---

#### `src/i18n/` - Configuration Directory

This directory contains the core configuration files that define how the i18n system operates.

**Purpose:** Centralized configuration for locale definitions, metadata, and next-intl integration.

##### `config.ts` - Locale Metadata & Settings

**Location:** `src/i18n/config.ts`

This is the **single source of truth** for all locale-related configuration.

**What it contains:**

1. **Locales Array** - Defines all supported languages
   ```typescript
   export const locales = ['de', 'en', 'sr'] as const;
   ```

2. **Default Locale** - Fallback language
   ```typescript
   export const defaultLocale = 'de' as const;
   ```

3. **Locale Type** - TypeScript type for type-safe locale handling
   ```typescript
   export type Locale = (typeof locales)[number];
   ```

4. **Display Names** - Human-readable language names
   ```typescript
   export const localeNames: Record<Locale, string> = {
     de: 'Deutsch',
     en: 'English',
     sr: 'Srpski',
   };
   ```

5. **Locale Flags** - Emoji flags for UI
   ```typescript
   export const localeFlags: Record<Locale, string> = {
     de: '🇩🇪',
     en: '🇬🇧',
     sr: '🇷🇸',
   };
   ```

6. **Extended Metadata** - SEO and regional data
   ```typescript
   export const localeMetadata: Record<Locale, {
     language: string;      // ISO 639-1 code (e.g., 'de')
     region: string;        // ISO 3166-1 code (e.g., 'DE')
     hreflang: string;      // For <link rel="alternate"> tags
     ogLocale: string;      // For Open Graph meta tags
     script: string;        // Writing system (e.g., 'Latn')
     territory: string;     // Full country name
     currency: string;      // ISO 4217 code (e.g., 'EUR')
   }> = {
     de: {
       language: 'de',
       region: 'DE',
       hreflang: 'de-DE',
       ogLocale: 'de_DE',
       script: 'Latn',
       territory: 'Germany',
       currency: 'EUR',
     },
     // ... en, sr
   };
   ```

7. **SEO Keywords** - Localized keywords for each language
   ```typescript
   export const seoKeywords: Record<Locale, string[]> = {
     de: ['Fullstack Developer', 'KI Entwickler', 'Köln', ...],
     en: ['AI Developer', 'Remote Developer Europe', 'London', ...],
     sr: ['AI Programer Srbija', 'Beograd', 'Novi Sad', ...],
   };
   ```

**When to modify this file:**
- ✅ Adding a new language
- ✅ Updating SEO keywords
- ✅ Changing metadata for Open Graph or hreflang
- ❌ Adding translation strings (use `src/messages/` instead)

---

##### `request.ts` - next-intl Integration

**Location:** `src/i18n/request.ts`

This file integrates the translation system with next-intl and handles runtime locale resolution.

**What it does:**

```typescript
import { getRequestConfig } from 'next-intl/server';
import { locales, type Locale } from './config';

export default getRequestConfig(async ({ requestLocale }) => {
  let locale = await requestLocale;

  // Validate locale and fallback to default if invalid
  if (!locale || !locales.includes(locale as Locale)) {
    locale = 'de';
  }

  return {
    locale,
    messages: (await import(`../messages/${locale}.json`)).default,
  };
});
```

**Key responsibilities:**

1. **Locale Validation** - Ensures only valid locales are used
2. **Fallback Logic** - Defaults to German (`de`) if locale is invalid or missing
3. **Dynamic Import** - Loads the appropriate translation JSON file at runtime
4. **Type Safety** - Uses the `Locale` type from `config.ts` for validation

**Flow:**
1. Receives `requestLocale` from next-intl (extracted from URL)
2. Validates against the `locales` array
3. Falls back to `de` if validation fails
4. Dynamically imports the corresponding JSON file from `src/messages/`
5. Returns locale and messages to next-intl

**When to modify this file:**
- ✅ Changing fallback locale logic
- ✅ Adding custom locale resolution rules
- ✅ Implementing locale persistence (cookies, etc.)
- ❌ Most use cases don't require changes

---

#### `src/messages/` - Active Translation Files ✅

**Location:** `src/messages/`

This directory contains the **active, production-ready** translation files in JSON format.

**Files:**
- `de.json` - German translations (default)
- `en.json` - English translations
- `sr.json` - Serbian translations

**Why JSON?**
- ✅ Simple, human-readable format
- ✅ Easy to edit without TypeScript knowledge
- ✅ Smaller bundle size (dynamic imports)
- ✅ Better IDE support for JSON
- ✅ Easier integration with translation tools

**Structure:**

Each file contains nested JSON objects organized by namespace:

```json
{
  "meta": {
    "site": { "name": "...", "title": "..." },
    "author": { "name": "...", "role": "..." },
    "social": { "linkedin": "...", "github": "..." }
  },
  "common": {
    "nav": { "home": "...", "about": "..." },
    "actions": { "readMore": "...", "submit": "..." }
  },
  "pages": {
    "home": { "hero": { "title": "..." } },
    "about": { "title": "..." }
  }
}
```

**Best Practices:**

1. **Keep keys synchronized** - All three files should have identical structure
2. **Use nested namespaces** - Organize by feature or page (e.g., `common`, `pages.home`)
3. **Descriptive keys** - Use semantic names like `hero.title` instead of `text1`
4. **No hardcoded text** - All user-facing text should be in these files

**When to modify these files:**
- ✅ Adding new translation keys
- ✅ Updating existing translations
- ✅ Fixing typos or improving wording
- ✅ Adding new pages or features

---

#### `src/i18n/locales-old/` - Legacy System ⚠️ DEPRECATED

**Location:** `src/i18n/locales-old/`

This directory contains **deprecated** TypeScript-based translations from a previous implementation.

**Files:**
- `de.ts` - Old German translations
- `en.ts` - Old English translations
- `sr.ts` - Old Serbian translations

**⚠️ IMPORTANT:** **Do NOT use these files!**

**Why it exists:**
- These files were part of an older TypeScript-based translation system
- Kept temporarily during migration for reference
- **Not loaded by the application** - they are completely inactive

**Why the migration happened:**
- JSON is simpler and more maintainable than TypeScript objects
- Better performance with dynamic imports
- Easier for non-developers to edit translations
- Better tooling support for JSON translation files

**What to do:**
- ❌ Do NOT add new keys here
- ❌ Do NOT reference these files in code
- ✅ Use `src/messages/*.json` for all translations
- ✅ These files can be safely deleted once migration is verified complete

---

#### File Relationships

```mermaid
graph TD
    A[config.ts] -->|Defines locales| B[request.ts]
    B -->|Loads messages| C[messages/*.json]
    B -->|Validates locale| A
    D[Components] -->|useTranslations| C
    E[locales-old/*] -.->|DEPRECATED| F[Not Used]
```

**Summary:**

| Directory/File | Status | Purpose | When to Edit |
|----------------|--------|---------|--------------|
| `src/i18n/config.ts` | ✅ Active | Locale definitions & metadata | Adding locales, SEO keywords |
| `src/i18n/request.ts` | ✅ Active | next-intl integration | Rarely (fallback logic) |
| `src/messages/*.json` | ✅ Active | Translation strings | Frequently (new translations) |
| `src/i18n/locales-old/` | ⚠️ Deprecated | Legacy TypeScript translations | Never (can be deleted) |

---

### 🔑 Adding Translation Keys
> Step-by-step guide to adding and managing translations
>
> **Topics covered:**
> - JSON structure and namespaces
> - Nested translation keys
> - Adding keys across all locales
> - Code examples using `useTranslations()`
> - Best practices for key naming

### ⚙️ Configuration & Setup

This section explains how the i18n system integrates with Next.js through next-intl, covering the configuration in `request.ts` and `next.config.ts`.

#### `getRequestConfig()` Function

**Location:** `src/i18n/request.ts`

The `getRequestConfig()` function is the **core integration point** between next-intl and the application. It handles locale resolution and message loading for every request.

**Full Implementation:**

```typescript
import { getRequestConfig } from 'next-intl/server';
import { locales, type Locale } from './config';

export default getRequestConfig(async ({ requestLocale }) => {
  let locale = await requestLocale;

  // Validate locale and fallback to default if invalid
  if (!locale || !locales.includes(locale as Locale)) {
    locale = 'de';
  }

  return {
    locale,
    messages: (await import(`../messages/${locale}.json`)).default,
  };
});
```

**How it works:**

1. **Receives `requestLocale`** - next-intl extracts the locale from the URL path (e.g., `/de/`, `/en/`, `/sr/`)
2. **Awaits the locale** - The locale is a promise that resolves to the URL segment
3. **Validates the locale** - Checks if it exists and is in the allowed `locales` array
4. **Falls back if invalid** - Defaults to `'de'` (German) for invalid/missing locales
5. **Returns configuration** - Provides the validated locale and dynamically loaded messages

**Key Features:**

- ✅ **Type-safe validation** - Uses the `Locale` type from `config.ts`
- ✅ **Automatic fallback** - Never breaks, always provides a valid locale
- ✅ **Dynamic imports** - Only loads the required translation file (better performance)
- ✅ **Server-side execution** - Runs on the server for every request

---

#### Locale Validation Logic

**Purpose:** Ensure only valid locales are used, preventing errors and security issues.

**Validation Flow:**

```typescript
if (!locale || !locales.includes(locale as Locale)) {
  locale = 'de';
}
```

**What it checks:**

1. **Existence check** - `!locale` ensures a value was provided
2. **Whitelist check** - `!locales.includes(...)` verifies it's an allowed locale
3. **Fallback** - Defaults to `'de'` if either check fails

**Examples:**

| URL Path | `requestLocale` | Valid? | Result | Reason |
|----------|----------------|--------|--------|--------|
| `/de/about` | `'de'` | ✅ Yes | `'de'` | Valid locale |
| `/en/contact` | `'en'` | ✅ Yes | `'en'` | Valid locale |
| `/sr/portfolio` | `'sr'` | ✅ Yes | `'sr'` | Valid locale |
| `/fr/home` | `'fr'` | ❌ No | `'de'` | Not in `locales` array |
| `/` | `null` | ❌ No | `'de'` | No locale provided |
| `/invalid123` | `'invalid123'` | ❌ No | `'de'` | Not in whitelist |

**Why this matters:**

- 🔒 **Security** - Prevents path traversal attacks (e.g., `../../etc/passwd`)
- 🛡️ **Reliability** - Guarantees the application always has a valid locale
- 📦 **Bundle safety** - Ensures only existing translation files are loaded
- 🎯 **User experience** - Provides predictable behavior for invalid URLs

**Alternative approaches (not used):**

```typescript
// ❌ DON'T: No validation (unsafe)
export default getRequestConfig(async ({ requestLocale }) => {
  const locale = await requestLocale;
  return {
    locale,
    messages: (await import(`../messages/${locale}.json`)).default, // Could fail!
  };
});

// ❌ DON'T: Throwing errors (breaks user experience)
export default getRequestConfig(async ({ requestLocale }) => {
  const locale = await requestLocale;
  if (!locales.includes(locale as Locale)) {
    throw new Error('Invalid locale'); // User sees error page
  }
  return { locale, messages: ... };
});

// ✅ DO: Validate and fallback (current implementation)
```

---

#### Dynamic Message Loading

**How translations are loaded:**

```typescript
messages: (await import(`../messages/${locale}.json`)).default
```

**This line performs several critical functions:**

1. **Dynamic import** - Uses `import()` instead of static `import` statement
2. **Path interpolation** - Constructs the file path using the validated locale
3. **Async loading** - Waits for the file to be loaded
4. **Default export** - Extracts the JSON content from the module

**Benefits of dynamic imports:**

| Feature | Static Import | Dynamic Import (Current) |
|---------|--------------|--------------------------|
| **Bundle size** | All locales loaded upfront | Only requested locale loaded |
| **Initial load time** | Slower (3 files) | Faster (1 file) |
| **Memory usage** | Higher | Lower |
| **Server-side rendering** | Supported | ✅ Supported |
| **Code splitting** | No | ✅ Yes |

**Performance comparison:**

```typescript
// ❌ Static imports (loads ALL locales on every request)
import deMessages from '../messages/de.json';
import enMessages from '../messages/en.json';
import srMessages from '../messages/sr.json';

const messageMap = { de: deMessages, en: enMessages, sr: srMessages };
return { locale, messages: messageMap[locale] };
// Bundle size: ~150KB (all locales)

// ✅ Dynamic import (loads ONLY requested locale)
messages: (await import(`../messages/${locale}.json`)).default
// Bundle size: ~50KB (single locale)
```

**File path resolution:**

```typescript
// If locale = 'de'
await import(`../messages/de.json`)  // Resolves to: src/messages/de.json

// If locale = 'en'
await import(`../messages/en.json`)  // Resolves to: src/messages/en.json

// If locale = 'sr'
await import(`../messages/sr.json`)  // Resolves to: src/messages/sr.json
```

**Error handling:**

If a translation file is missing, Next.js will throw a build error:

```bash
Error: Cannot find module '../messages/fr.json'
```

**Why this is safe:**

- ✅ Locale validation ensures only `de`, `en`, or `sr` are used
- ✅ All three files are required to exist for the build to succeed
- ✅ TypeScript catches typos in locale codes at compile time

---

#### `createNextIntlPlugin()` in next.config.ts

**Location:** `next.config.ts`

The `createNextIntlPlugin()` function wraps the Next.js configuration to integrate next-intl into the build process.

**Implementation:**

```typescript
import type { NextConfig } from 'next';
import createNextIntlPlugin from 'next-intl/plugin';

// Create the next-intl plugin, pointing to request.ts
const withNextIntl = createNextIntlPlugin('./src/i18n/request.ts');

const nextConfig: NextConfig = {
  // ... Next.js configuration options
};

// Wrap the config with the plugin
export default withNextIntl(nextConfig);
```

**What `createNextIntlPlugin()` does:**

1. **Registers request.ts** - Tells next-intl where to find the `getRequestConfig` function
2. **Enables server-side translations** - Sets up the infrastructure for SSR
3. **Configures webpack** - Adds necessary loaders for JSON imports
4. **Optimizes builds** - Ensures proper code splitting for translation files
5. **Sets up middleware hooks** - Integrates with Next.js request lifecycle

**Plugin composition:**

This project uses **multiple plugins** together:

```typescript
import createMDX from '@next/mdx';
import createNextIntlPlugin from 'next-intl/plugin';

// Create both plugins
const withNextIntl = createNextIntlPlugin('./src/i18n/request.ts');
const withMDX = createMDX({ options: { ... } });

// Compose plugins: next-intl wraps MDX wraps config
export default withNextIntl(withMDX(nextConfig));
```

**Plugin order matters:**

```
nextConfig → withMDX → withNextIntl → Final Config
```

**Why this pattern:**

- ✅ Modular configuration - Each plugin adds specific functionality
- ✅ Composable - Plugins can be added/removed independently
- ✅ Maintainable - Clear separation of concerns
- ✅ Type-safe - TypeScript validates the entire config chain

**Without the plugin:**

If you remove `withNextIntl`, the application would:

- ❌ Fail to resolve `useTranslations()` calls
- ❌ Not load translation messages
- ❌ Break server-side rendering of translated content
- ❌ Lose locale detection capabilities

**Plugin configuration path:**

```typescript
createNextIntlPlugin('./src/i18n/request.ts')
                      ↑
                      Relative to next.config.ts
                      Points to getRequestConfig export
```

**Troubleshooting:**

| Issue | Cause | Solution |
|-------|-------|----------|
| "Cannot find module 'next-intl/server'" | Plugin not installed | Run `npm install next-intl` |
| "getRequestConfig is not defined" | Wrong path in plugin | Check path matches `request.ts` location |
| Translations not loading | Plugin not applied | Ensure `withNextIntl(...)` wraps config |
| Build errors with MDX | Wrong plugin order | Place `withNextIntl` outermost |

---

#### Server-Side vs. Client-Side Translations

**How translations work in different contexts:**

##### Server Components (Recommended)

**Usage:**

```tsx
import { useTranslations } from 'next-intl';

export default function ServerComponent() {
  const t = useTranslations('common');

  return <h1>{t('nav.home')}</h1>;
}
```

**How it works:**

1. Component renders on the server
2. `useTranslations()` reads messages from the `getRequestConfig` result
3. Translation is resolved on the server
4. HTML with translated text is sent to the client
5. No translation data sent to the browser

**Benefits:**

- ✅ **Faster initial load** - No client-side JavaScript for translations
- ✅ **Better SEO** - Translated content available immediately
- ✅ **Smaller bundle** - Translations not included in client JS
- ✅ **Secure** - Translation logic stays on the server

##### Client Components

**Usage:**

```tsx
'use client';

import { useTranslations } from 'next-intl';

export default function ClientComponent() {
  const t = useTranslations('common');

  return <button>{t('actions.submit')}</button>;
}
```

**How it works:**

1. Component marked with `'use client'`
2. Messages serialized and passed from server to client
3. `useTranslations()` reads from client-side context
4. Translations available for dynamic updates

**When to use:**

- ✅ Interactive components (forms, modals)
- ✅ Components with onClick handlers
- ✅ Real-time updates based on user actions
- ✅ Stateful UI elements

**Performance consideration:**

```tsx
// ❌ DON'T: Use client components unnecessarily
'use client';

export default function StaticText() {
  const t = useTranslations('common');
  return <p>{t('siteDescription')}</p>; // This could be a server component
}

// ✅ DO: Use server components for static content
export default function StaticText() {
  const t = useTranslations('common');
  return <p>{t('siteDescription')}</p>; // Server component (default)
}
```

##### Hybrid Pattern (Best Practice)

**Split components by interactivity:**

```tsx
// app/[locale]/page.tsx (Server Component)
import { useTranslations } from 'next-intl';
import ContactForm from '@/components/ContactForm'; // Client component

export default function ContactPage() {
  const t = useTranslations('pages.contact');

  return (
    <div>
      <h1>{t('hero.title')}</h1>          {/* Server-rendered */}
      <p>{t('hero.subtitle')}</p>         {/* Server-rendered */}
      <ContactForm />                     {/* Client interactive */}
    </div>
  );
}

// components/ContactForm.tsx (Client Component)
'use client';

import { useTranslations } from 'next-intl';

export default function ContactForm() {
  const t = useTranslations('pages.contact.contactForm');

  return (
    <form>
      <label>{t('name.label')}</label>
      <input placeholder={t('name.placeholder')} />
      <button type="submit">{t('submit')}</button>
    </form>
  );
}
```

**Translation data flow:**

```
Request → getRequestConfig() → Messages loaded
                ↓
Server Components → useTranslations() → Direct access
                ↓
Client Components → Serialized via props → useTranslations() → Client access
```

**Bundle size impact:**

| Scenario | Server Component | Client Component |
|----------|------------------|------------------|
| **JavaScript sent** | 0 KB (translations) | ~50 KB (translations) |
| **HTML size** | Larger (translated text) | Smaller (placeholders) |
| **Time to Interactive** | Faster | Slower |
| **SEO crawlability** | ✅ Perfect | ⚠️ May need hydration |

**Best practices:**

1. ✅ **Default to server components** - Use client components only when necessary
2. ✅ **Split by interactivity** - Keep static content in server components
3. ✅ **Pass translations as props** - Avoid duplicating translation calls
4. ✅ **Minimize client boundaries** - Fewer `'use client'` directives = better performance

**Example optimization:**

```tsx
// ❌ BEFORE: Everything is a client component
'use client';

export default function Dashboard() {
  const t = useTranslations('dashboard');
  const [count, setCount] = useState(0);

  return (
    <div>
      <h1>{t('title')}</h1>              {/* Static - could be server */}
      <p>{t('description')}</p>           {/* Static - could be server */}
      <button onClick={() => setCount(count + 1)}>
        {t('increment')}                  {/* Interactive - needs client */}
      </button>
      <p>{count}</p>
    </div>
  );
}

// ✅ AFTER: Split into server + client components
// app/[locale]/dashboard/page.tsx (Server)
import { useTranslations } from 'next-intl';
import Counter from '@/components/Counter';

export default function Dashboard() {
  const t = useTranslations('dashboard');

  return (
    <div>
      <h1>{t('title')}</h1>              {/* Server-rendered */}
      <p>{t('description')}</p>           {/* Server-rendered */}
      <Counter />                         {/* Client component */}
    </div>
  );
}

// components/Counter.tsx (Client)
'use client';

import { useTranslations } from 'next-intl';
import { useState } from 'react';

export default function Counter() {
  const t = useTranslations('dashboard');
  const [count, setCount] = useState(0);

  return (
    <>
      <button onClick={() => setCount(count + 1)}>
        {t('increment')}
      </button>
      <p>{count}</p>
    </>
  );
}
```

**Result:**

- 📦 **Bundle size reduced** by ~40 KB (translations moved to server)
- ⚡ **Faster initial render** (server-rendered HTML)
- 🎯 **Better SEO** (title and description immediately available)

---

#### Summary: Configuration & Setup

**Key files:**

| File | Purpose | When to modify |
|------|---------|----------------|
| `src/i18n/request.ts` | Locale resolution & message loading | Rarely (fallback logic, custom validation) |
| `next.config.ts` | next-intl plugin integration | When adding/removing plugins |
| `src/i18n/config.ts` | Locale definitions | When adding new languages |

**Core concepts:**

- ✅ `getRequestConfig()` - Validates locale and loads messages
- ✅ Locale validation - Whitelist check with fallback to `'de'`
- ✅ Dynamic imports - Only load required translation file
- ✅ `createNextIntlPlugin()` - Integrates next-intl with Next.js build
- ✅ Server components - Preferred for better performance
- ✅ Client components - Use only for interactive elements

**Common patterns:**

```typescript
// Pattern 1: Server component (default)
export default function Page() {
  const t = useTranslations('namespace');
  return <h1>{t('key')}</h1>;
}

// Pattern 2: Client component (interactive)
'use client';
export default function Interactive() {
  const t = useTranslations('namespace');
  return <button>{t('action')}</button>;
}

// Pattern 3: Multiple namespaces
export default function Complex() {
  const tCommon = useTranslations('common');
  const tPage = useTranslations('pages.home');
  return <div>...</div>;
}
```

### 🌐 Locale Configuration & Metadata
> Detailed breakdown of locale settings and SEO data
>
> **Topics covered:**
> - Locales array and default locale
> - Locale names and flags
> - Metadata for hreflang and Open Graph
> - SEO keywords per locale
> - Currency and territory settings

### 🔍 SEO & Hreflang Implementation
> How multilingual SEO is implemented
>
> **Topics covered:**
> - Hreflang tags in layout.tsx
> - alternates.languages configuration
> - Content-Language HTTP headers
> - Localized meta tags and Open Graph
> - Sitemap generation for multiple locales

### 📦 Legacy Migration (locales-old)
> Understanding the deprecated TypeScript-based translation system
>
> **Topics covered:**
> - What locales-old contains
> - Why the migration happened
> - Do NOT use these files
> - Migration from TypeScript to JSON
> - Safe removal considerations

### 🛤️ Routing & URL Structure
> How locale-based routing works with Next.js App Router
>
> **Topics covered:**
> - `[locale]` dynamic route segment
> - URL patterns: `/de/`, `/en/`, `/sr/`
> - Locale detection in middleware
> - `generateStaticParams()` for static generation
> - Locale switching and redirects

### 💡 Usage Examples & Best Practices
> Practical examples and common patterns
>
> **Topics covered:**
> - `useTranslations()` hook patterns
> - Accessing nested keys
> - Formatting dates and numbers
> - Pluralization (if implemented)
> - Common pitfalls and solutions
> - Performance considerations

## Architecture Overview

```
Portfolio i18n System
│
├── Configuration Layer
│   ├── src/i18n/config.ts          # Locale definitions & metadata
│   └── src/i18n/request.ts         # next-intl integration
│
├── Translation Files (Active)
│   ├── src/messages/de.json        # German translations
│   ├── src/messages/en.json        # English translations
│   └── src/messages/sr.json        # Serbian translations
│
├── Legacy System (Deprecated)
│   └── src/i18n/locales-old/       # Old TypeScript translations
│
├── Routing Layer
│   ├── src/app/[locale]/layout.tsx # Locale-based layout
│   ├── src/middleware.ts           # Locale detection
│   └── next.config.ts              # createNextIntlPlugin
│
└── Application Layer
    └── Components using useTranslations()
```

## Translation File Structure

Current structure of active translation files:

```json
{
  "meta": {
    "site": { ... },
    "author": { ... },
    "social": { ... }
  },
  "common": {
    "siteTitle": "...",
    "nav": { ... },
    "actions": { ... },
    "errors": { ... },
    "cookies": { ... }
  },
  "home": { ... },
  "about": { ... },
  "portfolio": { ... },
  "blog": { ... },
  "contact": { ... }
}
```

## Supported Locales

| Locale | Language | hreflang | OG Locale | Currency | Region |
|--------|----------|----------|-----------|----------|--------|
| `de` | Deutsch | de-DE | de_DE | EUR | Germany |
| `en` | English | en-US | en_US | USD | United States |
| `sr` | Srpski | sr-RS | sr_RS | RSD | Serbia |

## Important Notes

⚠️ **Legacy System**: The `src/i18n/locales-old/` directory contains deprecated TypeScript-based translations from a previous implementation. **Do NOT use these files.** All new translations should go in `src/messages/*.json`.

✅ **Active System**: Use only the JSON files in `src/messages/` for all translation work.

🔒 **Type Safety**: The locale type is derived from the `locales` array in `config.ts`, ensuring compile-time validation of locale codes.

🌍 **Default Locale**: German (`de`) is the default locale. Invalid or missing locale parameters will fallback to German.

## Getting Help

- Check specific sections above for detailed topics
- Review code examples in the pattern files
- Examine existing translation keys in `src/messages/de.json`
- Look at component usage in `src/app/[locale]/page.tsx`

---

**Framework:** next-intl + Next.js 15 App Router
**Default Locale:** German (de)
**Supported Locales:** de, en, sr
**Translation Format:** JSON
