# Internationalization (i18n) Guide

This document explains how to work with translations in the DQM React Component.

## Overview

The DQM component supports multiple languages with a modular translation system. Translations are organized by **namespace** (feature area) and **language**, making it easy to add new languages or update specific sections.

## Supported Languages

| Language | Code | Status |
|----------|------|--------|
| English | `en` | ✅ Default / Fallback |
| German | `de` | ✅ Complete |
| Spanish | `es` | ✅ Complete |

### Regional Variants

Regional variants (e.g., `de-AT`, `es-MX`) automatically fall back to their base language:

- `de-AT` → `de` → `en`
- `de-CH` → `de` → `en`
- `es-MX` → `es` → `en`
- `en-GB` → `en`

## File Structure

```
src/i18n/
├── index.ts              # Main configuration, combines all namespaces
├── common/               # Shared UI strings
│   ├── en.ts
│   ├── de.ts
│   ├── es.ts
│   └── index.ts
├── sidebar/              # DQM sidebar strings (~100 keys)
│   ├── en.ts
│   ├── de.ts
│   ├── es.ts
│   └── index.ts
├── auth/                 # Authentication strings
│   ├── en.ts
│   ├── de.ts
│   ├── es.ts
│   └── index.ts
└── demo/                 # Demo app strings (dev only)
    ├── en.ts
    ├── de.ts
    ├── es.ts
    └── index.ts
```

## Adding a New Language

### Step 1: Create translation files

For each namespace, create a new file with your language code:

```typescript
// src/i18n/common/fr.ts
export const common = {
  language: 'Langue',
  language_switch_label: 'Langue',
  // ... copy all keys from en.ts and translate
} as const;
```

### Step 2: Export from namespace index

```typescript
// src/i18n/common/index.ts
export { common as en } from './en';
export { common as de } from './de';
export { common as es } from './es';
export { common as fr } from './fr';  // Add this line
```

### Step 3: Add to main configuration

```typescript
// src/i18n/index.ts
import * as common from './common';
// ...

const resources = {
  en: { common: common.en, /* ... */ },
  de: { common: common.de, /* ... */ },
  es: { common: common.es, /* ... */ },
  fr: { common: common.fr, /* ... */ },  // Add this
} as const;
```

### Step 4: Update locale.ts

```typescript
// src/locale.ts
const SUPPORTED_LOCALES = ['en', 'de', 'es', 'fr'] as const;
```

### Step 5: Add language name translations

In **each** language file's `common` namespace, add the new language name:

```typescript
// common/en.ts
language_fr: 'French',

// common/de.ts
language_fr: 'Französisch',

// common/fr.ts
language_fr: 'Français',
```

## Adding New Translation Keys

### Step 1: Add to English (fallback) first

```typescript
// src/i18n/sidebar/en.ts
export const sidebar = {
  // ... existing keys
  my_new_feature: 'My new feature',
} as const;
```

### Step 2: Add to all other languages

```typescript
// src/i18n/sidebar/de.ts
my_new_feature: 'Meine neue Funktion',

// src/i18n/sidebar/es.ts
my_new_feature: 'Mi nueva función',
```

### Step 3: Use in components

```tsx
import { useTranslation } from 'react-i18next';

const MyComponent = () => {
  const { t } = useTranslation('sidebar');
  return <span>{t('my_new_feature')}</span>;
};
```

## Interpolation

Use `{{variable}}` for dynamic values:

```typescript
// Translation file
translation_progress: '{{done}} / {{total}} checkpoints',

// Usage
t('sidebar:translation_progress', { done: 5, total: 10 })
// Output: "5 / 10 checkpoints"
```

## Namespaces

| Namespace | Purpose | Used in |
|-----------|---------|---------|
| `common` | Shared strings (language names, buttons) | All components |
| `sidebar` | Main DQM sidebar UI | `DQMSidebar.tsx` |
| `auth` | Login/authentication | `DQMLogin.tsx` |
| `demo` | Demo application (dev only) | `App.tsx` |

### Using namespaces

```tsx
// Single namespace
const { t } = useTranslation('sidebar');
t('title')  // Uses sidebar:title

// Multiple namespaces
const { t } = useTranslation(['sidebar', 'common']);
t('sidebar:title')
t('common:logout')

// With namespace prefix
t('sidebar:translation_progress', { done: 5, total: 10 })
```

## Type Safety

Translation keys are typed. TypeScript will warn if you use a non-existent key:

```typescript
import type { SidebarTranslationKeys } from './i18n';

// This is type-safe
const key: SidebarTranslationKeys = 'title';  // ✅
const bad: SidebarTranslationKeys = 'nonexistent';  // ❌ Type error
```

## Best Practices

1. **Always add to English first** – English is the fallback language
2. **Keep keys descriptive** – Use `translation_progress` not `tp`
3. **Group related keys** – Use comments to organize sections
4. **Test all languages** – Switch languages in the UI to verify
5. **Don't hardcode strings** – All user-visible text should be translated

## Changing the User's Language

The library exports the i18next instance for programmatic language control:

```tsx
import { i18n, SUPPORTED_LOCALES } from '@crownpeak/dqm-react-component';

// Change language programmatically
i18n.changeLanguage('de');

// Get current language
const currentLang = i18n.language;

// Check supported locales
console.log(SUPPORTED_LOCALES); // ['en', 'de', 'es']
```

### Handling Regional Variants

```tsx
import { resolveLanguage, normalizeLocale } from '@crownpeak/dqm-react-component';

// Resolve regional variant to base language
resolveLanguage('de-AT');  // Returns 'de'
resolveLanguage('es-MX');  // Returns 'es'
resolveLanguage('fr');     // Returns 'en' (fallback)

// Validate and normalize locale input
normalizeLocale('de-AT');  // Returns 'de'
normalizeLocale('fr');     // Returns null (unsupported)
```

### Using the LanguageSwitch Component

```tsx
import { LanguageSwitch } from '@crownpeak/dqm-react-component';

// Built-in language switcher (used in sidebar footer)
<LanguageSwitch />
```

### Listening for Language Changes

```tsx
import { i18n } from '@crownpeak/dqm-react-component';
import { useEffect } from 'react';

function MyComponent() {
  useEffect(() => {
    const handleLanguageChange = (lng: string) => {
      console.log('DQM language changed to:', lng);
    };
    
    i18n.on('languageChanged', handleLanguageChange);
    return () => i18n.off('languageChanged', handleLanguageChange);
  }, []);
  
  return <div>Current: {i18n.language}</div>;
}
```

## Troubleshooting

### Missing translation shows key name

If you see `sidebar:my_key` instead of the translation:
- Check the key exists in all language files
- Verify the namespace is correct
- Ensure the language file is exported in `index.ts`

### Regional variant not working

Regional variants (e.g., `de-AT`) fall back to the base language. If you need region-specific translations:

1. Create `de-AT.ts` alongside `de.ts`
2. Export it in the namespace's `index.ts`
3. Add to `REGIONAL_FALLBACKS` in `src/i18n/index.ts`

### TypeScript errors on translation keys

Ensure all translation files export `as const` for proper type inference:

```typescript
export const sidebar = {
  // ...
} as const;  // ← Important!
```
