# Guide Complet du Système de Traductions

## Table des matières

1. [Vue d'ensemble](#vue-densemble)
2. [Architecture](#architecture)
3. [Modèles traduisibles](#modèles-traduisibles)
4. [Ajouter des traductions dans l'admin](#ajouter-des-traductions-dans-ladmin)
5. [Utilisation dans les templates](#utilisation-dans-les-templates)
6. [Utilisation en Python](#utilisation-en-python)
7. [Rendre un nouveau modèle traduisible](#rendre-un-nouveau-modèle-traduisible)
8. [Fonctionnement technique](#fonctionnement-technique)
9. [Dépannage](#dépannage)

---

## Vue d'ensemble

Le système de traduction permet de traduire le contenu dynamique du site (articles, menus, sections, etc.) dans plusieurs langues. Il est basé sur :

- **Modèle `Dictionnaire`** : Stocke les traductions
- **Modèle `Language`** : Définit les langues disponibles
- **Mixin `TranslatableMixin`** : Ajoute les capacités de traduction aux modèles
- **Registre `TRANSLATABLE_MODELS`** : Définit quels champs sont traduisibles

### Langues supportées par défaut

| Code | Langue | Par défaut |
|------|--------|------------|
| `fr` | Français | Oui |
| `en` | English | Non |
| `de` | Deutsch | Non |

---

## Architecture

```
traduction/
├── models.py           # Language, Dictionnaire
├── registry.py         # TRANSLATABLE_MODELS - liste des champs traduisibles
├── helpers.py          # TranslatableMixin, prefetch_translations()
├── middleware.py       # LanguageMiddleware - gestion langue courante
├── admin_mixins.py     # TranslatableAdminMixin - interface admin
├── templatetags/
│   └── traduction_tags.py  # Tags template: translate, trans_text, etc.
└── context_processors.py   # Variables globales: current_language_code, etc.
```

---

## Modèles traduisibles

### Application Core

| Modèle | Champs traduisibles |
|--------|---------------------|
| `CarouselSlide` | `title`, `subtitle`, `button_text` |
| `ProgramStatistic` | `label`, `description` |
| `Partner` | `name`, `description` |

### Application CMS

| Modèle | Champs traduisibles |
|--------|---------------------|
| `Page` | `title`, `description` |
| `Section` | `title`, `description` |
| `MenuItem` | `title` |
| `Setting` | `value` |
| `PageSectionFieldValue` | `text_value` |

### Application Universities

| Modèle | Champs traduisibles |
|--------|---------------------|
| `University` | `name`, `short_name`, `description`, `academic_info` |
| `Department` | `name`, `description` |
| `IndustrialPartner` | `name`, `description`, `partnership_type` |

### Application Program

| Modèle | Champs traduisibles |
|--------|---------------------|
| `Semester` | `name`, `description`, `learning_outcomes` |
| `Course` | `name`, `description`, `objectives`, `prerequisites` |
| `Specialization` | `name`, `description`, `career_opportunities` |
| `FAQ` | `question`, `answer` |

### Application Team

| Modèle | Champs traduisibles |
|--------|---------------------|
| `Person` | `bio`, `research_interests` |
| `Professor` | `courses_taught`, `awards` |
| `PhDStudent` | `thesis_title`, `thesis_description` |
| `MasterStudent` | `thesis_title`, `current_position` |

### Application Research

| Modèle | Champs traduisibles |
|--------|---------------------|
| `ResearchArea` | `name`, `description`, `key_topics` |
| `ResearchProject` | `title`, `description`, `objectives`, `methodology`, `expected_outcomes` |
| `Publication` | `title`, `abstract` |

### Application News

| Modèle | Champs traduisibles |
|--------|---------------------|
| `NewsCategory` | `name`, `description` |
| `NewsArticle` | `title`, `content`, `meta_description` |
| `EventType` | `name`, `description` |
| `Event` | `title`, `short_description`, `description`, `location` |

### Application Contact

| Modèle | Champs traduisibles |
|--------|---------------------|
| `ContactSubject` | `name`, `description`, `auto_reply_message` |

---

## Ajouter des traductions dans l'admin

### Méthode 1 : Via l'onglet Traductions

1. Ouvrez un objet dans l'admin (ex: Article, Menu Item, Slide)
2. Cliquez sur l'onglet **"Traductions"** en haut
3. Pour chaque champ traduisible :
   - Vous verrez la valeur originale (français)
   - Entrez la traduction pour chaque langue (EN, DE, etc.)
4. Cliquez sur **"Enregistrer"**

### Méthode 2 : Via le gestionnaire de sections CMS

1. Admin > CMS > **Gestionnaire de sections**
2. Sélectionnez une page
3. Cliquez sur une section
4. Dans le panneau de droite, les champs texte ont des champs de traduction repliables
5. Dépliez et entrez les traductions

### Exemple visuel

```
┌─────────────────────────────────────────────┐
│ Article: Mon article                        │
├─────────────────────────────────────────────┤
│ [Contenu] [Traductions] [Historique]        │
├─────────────────────────────────────────────┤
│ Titre                                       │
│ ┌─────────────────────────────────────────┐ │
│ │ Mon article en français                 │ │ ← Original (FR)
│ └─────────────────────────────────────────┘ │
│                                             │
│ 🇬🇧 English                                 │
│ ┌─────────────────────────────────────────┐ │
│ │ My article in English                   │ │ ← Traduction EN
│ └─────────────────────────────────────────┘ │
│                                             │
│ 🇩🇪 Deutsch                                 │
│ ┌─────────────────────────────────────────┐ │
│ │ Mein Artikel auf Deutsch                │ │ ← Traduction DE
│ └─────────────────────────────────────────┘ │
└─────────────────────────────────────────────┘
```

---

## Utilisation dans les templates

### Méthode 1 : Accès direct (recommandé)

Quand les objets sont chargés via le context processor ou avec `prefetch_translations()`, les champs contiennent déjà les valeurs traduites :

```django
{# Les valeurs sont déjà traduites #}
{{ article.title }}
{{ slide.subtitle }}
{{ menu_item.title }}
```

### Méthode 2 : Filtre `|translate`

Pour les cas où l'objet n'a pas été pré-traduit :

```django
{% load traduction_tags %}

{{ article|translate:'title' }}
{{ category|translate:'name' }}
```

### Méthode 3 : Tag `{% trans %}`

```django
{% load traduction_tags %}

{% trans article 'title' %}
{% trans event 'description' %}
```

### Méthode 4 : Textes statiques avec `{% trans_text %}`

Pour les textes codés en dur dans les templates :

```django
{% load traduction_tags %}

{% trans_text 'Accueil' 'Home' 'Startseite' %}
{% trans_text 'Lire la suite' 'Read more' 'Weiterlesen' %}
{% trans_text 'Contactez-nous' 'Contact us' 'Kontaktieren Sie uns' %}
```

**Arguments :** `{% trans_text 'FR' 'EN' 'DE' %}`

### Variables de contexte disponibles

```django
{# Langue courante #}
{{ current_language_code }}  {# ex: 'en' #}
{{ current_language }}       {# objet Language complet #}

{# Toutes les langues actives #}
{% for lang in available_languages %}
    {{ lang.code }} - {{ lang.name }}
{% endfor %}
```

### Sélecteur de langue

```django
{% load traduction_tags %}

{# Sélecteur complet #}
{% language_selector %}

{# Ou manuellement #}
{% get_languages as languages %}
{% for lang in languages %}
    <a href="?lang={{ lang.code }}">{{ lang.name }}</a>
{% endfor %}
```

---

## Utilisation en Python

### Récupérer une traduction

```python
from traduction.helpers import get_translated_value

# Récupérer la traduction d'un champ
title_en = get_translated_value(article, 'title', language_code='en')
```

### Pré-charger les traductions (optimisé)

```python
from traduction.helpers import prefetch_translations

# Pour une liste d'objets
articles = list(NewsArticle.objects.filter(is_published=True)[:10])
prefetch_translations(articles, language_code='en')

# Maintenant article.title contient la version anglaise
for article in articles:
    print(article.title)  # Titre en anglais
```

### Définir une traduction

```python
from traduction.models import Dictionnaire, Language

# Récupérer la langue
english = Language.objects.get(code='en')

# Définir la traduction
Dictionnaire.set_translation(
    obj=article,
    field='title',
    language=english,
    translation='My Article Title'
)
```

### Dans une vue

```python
from traduction.helpers import TranslatedViewMixin, prefetch_translations

class MyListView(TranslatedViewMixin, ListView):
    model = MyModel
    translate_fields = ['title', 'description']

    def get_queryset(self):
        queryset = super().get_queryset()
        return self.translate_queryset(queryset)
```

### Utiliser le mixin TranslatableMixin

```python
# Dans un modèle avec TranslatableMixin
article = NewsArticle.objects.get(pk=1)

# Récupérer la traduction (utilise la langue courante ou spécifiée)
title = article.get_translated('title')
title_en = article.get_translated('title', language_code='en')
```

---

## Rendre un nouveau modèle traduisible

### Étape 1 : Ajouter le mixin au modèle

```python
# myapp/models.py
from traduction.helpers import TranslatableMixin

class MyModel(TranslatableMixin, models.Model):
    title = models.CharField(max_length=200)
    description = models.TextField()
    # ... autres champs
```

### Étape 2 : Enregistrer dans le registre

```python
# traduction/registry.py
TRANSLATABLE_MODELS = {
    # ... autres modèles ...

    'myapp.mymodel': [
        'title',
        'description',
    ],
}
```

### Étape 3 : Ajouter le mixin à l'admin

```python
# myapp/admin.py
from django.contrib import admin
from traduction.admin_mixins import TranslatableAdminMixin
from .models import MyModel

@admin.register(MyModel)
class MyModelAdmin(TranslatableAdminMixin, admin.ModelAdmin):
    list_display = ['title', 'description']
```

### Étape 4 : Appliquer les traductions dans les vues/context processors

```python
# Dans un context processor ou une vue
from traduction.helpers import prefetch_translations

items = list(MyModel.objects.filter(is_active=True))
prefetch_translations(items, language_code=language_code)
```

---

## Fonctionnement technique

### Flux de traduction

```
1. Utilisateur sélectionne langue (ex: ?lang=en)
           ↓
2. LanguageMiddleware stocke en session
           ↓
3. request.current_language_code = 'en'
           ↓
4. Context processor charge les données
           ↓
5. prefetch_translations() applique les traductions
           ↓
6. Les champs des objets contiennent les valeurs traduites
           ↓
7. Template affiche {{ object.field }} → valeur traduite
```

### Structure de la table Dictionnaire

```sql
CREATE TABLE dictionnaire (
    id INT PRIMARY KEY,
    content_type_id INT,     -- Type du modèle (ex: NewsArticle)
    object_id INT,           -- ID de l'objet
    field VARCHAR(100),      -- Nom du champ (ex: 'title')
    language_id INT,         -- Langue de la traduction
    translation TEXT,        -- Texte traduit
    created_at TIMESTAMP,
    updated_at TIMESTAMP
);
```

### Exemple de données

| content_type | object_id | field | language | translation |
|--------------|-----------|-------|----------|-------------|
| newsarticle | 1 | title | en | My First Article |
| newsarticle | 1 | title | de | Mein erster Artikel |
| newsarticle | 1 | content | en | Article content... |
| menuitem | 5 | title | en | Home |
| menuitem | 5 | title | de | Startseite |

---

## Dépannage

### Les traductions ne s'affichent pas

1. **Vérifier que la traduction existe**
   ```python
   from traduction.models import Dictionnaire
   from django.contrib.contenttypes.models import ContentType

   ct = ContentType.objects.get_for_model(MyModel)
   translations = Dictionnaire.objects.filter(
       content_type=ct,
       object_id=obj.pk
   )
   print(list(translations.values('field', 'language__code', 'translation')))
   ```

2. **Vérifier la langue courante**
   ```python
   # Dans une vue
   print(request.current_language_code)
   ```

3. **Vérifier que prefetch_translations est appelé**
   - Les données doivent passer par `prefetch_translations()` pour être traduites

4. **Vider le cache**
   ```bash
   python manage.py shell -c "from django.core.cache import cache; cache.clear()"
   ```

### Les menus ne sont pas traduits

Les menus utilisent `get_root_items()` et `get_children()`. Assurez-vous d'utiliser le tag `{% get_menu %}` qui applique automatiquement les traductions :

```django
{% load cms_tags %}
{% get_menu 'front-menu' as nav_menu %}

{% for item in nav_menu.get_root_items %}
    {{ item.title }}  {# Déjà traduit #}
{% endfor %}
```

### Ajouter une nouvelle langue

1. **Dans l'admin** : Traduction > Langues > Ajouter
2. **Remplir** :
   - Code : `es`
   - Nom : `Español`
   - Code drapeau : `ES`
   - Actif : ✓

3. **Ajouter les traductions** pour cette nouvelle langue dans chaque objet

### Erreur "Translation not found"

C'est normal si la traduction n'existe pas. Le système retourne la valeur originale (français) comme fallback.

### Performance

Pour éviter les requêtes N+1, utilisez toujours `prefetch_translations()` avec une liste d'objets plutôt que de traduire objet par objet :

```python
# ❌ Mauvais (N+1 requêtes)
for article in articles:
    title = get_translated_value(article, 'title', 'en')

# ✅ Bon (2 requêtes max)
prefetch_translations(articles, language_code='en')
for article in articles:
    title = article.title  # Déjà traduit
```

---

## Commandes utiles

```bash
# Générer les traductions manquantes (si commande disponible)
python manage.py generate_translations

# Vider le cache des traductions
python manage.py shell -c "from django.core.cache import cache; cache.clear()"

# Lister les traductions d'un modèle
python manage.py shell -c "
from traduction.models import Dictionnaire
from django.contrib.contenttypes.models import ContentType
from cms.models import MenuItem
ct = ContentType.objects.get_for_model(MenuItem)
for t in Dictionnaire.objects.filter(content_type=ct):
    print(f'{t.object_id} | {t.field} | {t.language.code} | {t.translation[:50]}')
"
```

---

## Résumé rapide

| Action | Code/Méthode |
|--------|--------------|
| Traduire dans template | `{{ obj.field }}` (si prefetch) ou `{{ obj\|translate:'field' }}` |
| Texte statique | `{% trans_text 'FR' 'EN' 'DE' %}` |
| Charger menu traduit | `{% get_menu 'slug' as menu %}` |
| Pré-charger traductions | `prefetch_translations(objects, language_code='en')` |
| Définir traduction | `Dictionnaire.set_translation(obj, 'field', lang, 'text')` |
| Langue courante | `request.current_language_code` ou `{{ current_language_code }}` |
| Changer langue | `?lang=en` dans l'URL |
