# Internationalization (i18n) Guide

This document describes the internationalization implementation in Syndarix.

## Overview

The application supports multiple languages using [next-intl](https://next-intl-docs.vercel.app/) v4.5.3, a modern i18n library for Next.js 15 App Router.

**Supported Locales:**

- English (`en`) - Default
- Italian (`it`)

## Architecture

### URL Structure

All routes are locale-prefixed using the `[locale]` dynamic segment:

```
/en/login          → English login page
/it/login          → Italian login page
/en/settings       → English settings
/it/settings       → Italian settings
```

### Core Files

```
frontend/
├── src/
│   ├── lib/
│   │   ├── i18n/
│   │   │   ├── routing.ts           # Locale routing configuration
│   │   │   ├── utils.ts             # Locale utility functions
│   │   │   └── metadata.ts          # SEO metadata helpers
│   ├── app/
│   │   └── [locale]/                # Locale-specific routes
│   │       └── layout.tsx           # Locale layout with NextIntlClientProvider
│   └── components/
│       └── navigation/
│           └── LocaleSwitcher.tsx   # Language switcher component
├── messages/
│   ├── en.json                      # English translations
│   └── it.json                      # Italian translations
└── types/
    └── next-intl.d.ts              # TypeScript type definitions
```

## Usage

### Client Components

Use the `useTranslations` hook from `next-intl`:

```typescript
'use client';

import { useTranslations } from 'next-intl';

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

  return (
    <div>
      <h1>{t('title')}</h1>
      <p>{t('description')}</p>
    </div>
  );
}
```

### Server Components

Use `getTranslations` from `next-intl/server`:

```typescript
import { getTranslations } from 'next-intl/server';

export default async function MyPage() {
  const t = await getTranslations('namespace');

  return (
    <div>
      <h1>{t('title')}</h1>
      <p>{t('description')}</p>
    </div>
  );
}
```

### Navigation

**Always use the locale-aware navigation utilities:**

```typescript
import { Link, useRouter, usePathname } from '@/lib/i18n/routing';

// Link component (automatic locale prefix)
<Link href="/settings">Settings</Link>  // → /en/settings

// Router hooks
function MyComponent() {
  const router = useRouter();
  const pathname = usePathname();

  const handleClick = () => {
    router.push('/dashboard');  // → /en/dashboard
  };

  return <button onClick={handleClick}>Go to Dashboard</button>;
}
```

**⚠️ Never import from `next/navigation` directly** - always use `@/lib/i18n/routing`

### Forms with Validation

Create dynamic Zod schemas that accept translation functions:

```typescript
import { useTranslations } from 'next-intl';
import { z } from 'zod';

const createLoginSchema = (t: (key: string) => string) =>
  z.object({
    email: z.string().min(1, t('validation.required')).email(t('validation.email')),
    password: z.string().min(1, t('validation.required')),
  });

export function LoginForm() {
  const t = useTranslations('auth.login');
  const tValidation = useTranslations('validation');

  const schema = createLoginSchema((key) => {
    if (key.startsWith('validation.')) {
      return tValidation(key.replace('validation.', ''));
    }
    return t(key);
  });

  // Use schema with react-hook-form...
}
```

## Translation Files

### Structure

Translations are organized hierarchically in JSON files:

```json
{
  "common": {
    "loading": "Loading...",
    "save": "Save"
  },
  "auth": {
    "login": {
      "title": "Sign in to your account",
      "emailLabel": "Email",
      "passwordLabel": "Password"
    }
  }
}
```

### Access Patterns

```typescript
// Nested namespace access
const t = useTranslations('auth.login');
t('title'); // → "Sign in to your account"

// Multiple namespaces
const tAuth = useTranslations('auth.login');
const tCommon = useTranslations('common');

tAuth('title'); // → "Sign in to your account"
tCommon('loading'); // → "Loading..."
```

## SEO & Metadata

### Page Metadata

Use the `generatePageMetadata` helper for locale-aware metadata:

```typescript
import { Metadata } from 'next';
import { generatePageMetadata, type Locale } from '@/lib/i18n/metadata';
import { getTranslations } from 'next-intl/server';

export async function generateMetadata({
  params,
}: {
  params: Promise<{ locale: string }>;
}): Promise<Metadata> {
  const { locale } = await params;
  const t = await getTranslations({ locale, namespace: 'auth.login' });

  return generatePageMetadata(locale as Locale, t('title'), t('subtitle'), '/login');
}
```

This automatically generates:

- Open Graph tags
- Twitter Card tags
- Language alternates (hreflang)
- Canonical URLs

### Sitemap

The sitemap (`/sitemap.xml`) automatically includes all public routes for both locales with language alternates.

### Robots.txt

The robots.txt (`/robots.txt`) allows crawling of public routes and references the sitemap.

## Locale Switching

Users can switch languages using the `LocaleSwitcher` component in the header:

```typescript
import { LocaleSwitcher } from '@/components/navigation/LocaleSwitcher';

<LocaleSwitcher />
```

The switcher:

- Displays the current locale
- Lists available locales
- Preserves the current path when switching
- Uses the locale-aware router

## Type Safety

TypeScript autocomplete for translation keys is enabled via `types/next-intl.d.ts`:

```typescript
import en from '@/messages/en.json';

type Messages = typeof en;

declare global {
  interface IntlMessages extends Messages {}
}
```

This provides:

- Autocomplete for translation keys
- Type errors for missing keys
- IntelliSense in IDEs

## Testing

### Unit Tests

Mock `next-intl` in `jest.setup.js`:

```javascript
jest.mock('next-intl', () => ({
  useTranslations: (namespace) => {
    return (key) => key; // Return key as-is for tests
  },
  useLocale: () => 'en',
}));

jest.mock('next-intl/server', () => ({
  getTranslations: jest.fn(async () => (key) => key),
}));
```

### E2E Tests

Update Playwright tests to include locale prefixes:

```typescript
test('navigates to login', async ({ page }) => {
  await page.goto('/en/login'); // Include locale prefix
  await expect(page).toHaveURL('/en/login');
});
```

## Adding New Languages

1. **Create translation file:**

   ```bash
   cp messages/en.json messages/fr.json
   # Translate all values in fr.json
   ```

2. **Update routing configuration:**

   ```typescript
   // src/lib/i18n/routing.ts
   export const routing = defineRouting({
     locales: ['en', 'it', 'fr'], // Add 'fr'
     defaultLocale: 'en',
   });
   ```

3. **Update type definitions:**

   ```typescript
   // src/lib/i18n/metadata.ts
   export type Locale = 'en' | 'it' | 'fr'; // Add 'fr'
   ```

4. **Update LocaleSwitcher:**
   ```typescript
   // src/components/navigation/LocaleSwitcher.tsx
   const localeNames: Record<string, string> = {
     en: 'English',
     it: 'Italiano',
     fr: 'Français', // Add French
   };
   ```

## Best Practices

### DO ✅

- Use locale-aware navigation (`@/lib/i18n/routing`)
- Create dynamic validation schemas
- Use nested translation keys for organization
- Test with multiple locales
- Keep translation files in sync
- Use TypeScript types for autocomplete

### DON'T ❌

- Don't hardcode text in components
- Don't import from `next/navigation` directly
- Don't use template strings for validation messages (use static messages)
- Don't forget to update both `en.json` and `it.json`
- Don't skip testing translated components

## Performance

The implementation is optimized for performance:

- **Server-side translation loading**: Messages loaded on server, passed to client
- **Lazy loading**: Only current locale messages are loaded
- **Font optimization**: `display: 'swap'` prevents layout shift
- **Preloading**: Primary font preloaded, secondary font lazy-loaded
- **Caching**: Next.js automatically caches translation files

## Common Issues

### "Module not found: Can't resolve 'next/navigation'"

**Solution**: Use `@/lib/i18n/routing` instead:

```diff
- import { useRouter } from 'next/navigation'
+ import { useRouter } from '@/lib/i18n/routing'
```

### E2E tests failing with "Page not found"

**Solution**: Add locale prefix to URLs:

```diff
- await page.goto('/login')
+ await page.goto('/en/login')
```

### TypeScript error: "Property does not exist on type"

**Solution**: Ensure the key exists in `messages/en.json` and restart TypeScript server.

### ICU message format error

**Solution**: Use static messages instead of templates:

```diff
// ❌ Bad (ICU format not configured)
- "minLength": "Must be at least {count} characters"

// ✅ Good
+ "minLength": "Must be at least 8 characters"
```

## Resources

- [next-intl Documentation](https://next-intl-docs.vercel.app/)
- [Next.js Internationalization](https://nextjs.org/docs/app/building-your-application/routing/internationalization)
- [Implementation Plan](./I18N_IMPLEMENTATION_PLAN.md)

## Summary

The i18n implementation provides:

- ✅ Multi-language support (EN, IT) with easy extensibility
- ✅ Type-safe translations with autocomplete
- ✅ SEO-optimized with proper metadata and sitemaps
- ✅ Performance-optimized loading
- ✅ Comprehensive test coverage
- ✅ Developer-friendly API

For questions or issues, refer to the [next-intl documentation](https://next-intl-docs.vercel.app/) or check existing tests for examples.
