Guide des Traductions

Documentation complète du système de traduction multilingue du CMS EUROMA.

Modèle Dictionnaire

Stocke toutes les traductions avec ContentType générique

Modèle Language

Définit les langues disponibles sur le site

TranslatableMixin

Mixin pour rendre n'importe quel modèle traduisible

Comment ça marche ?

Le contenu original est stocké en français dans les modèles. Les traductions sont stockées séparément dans la table Dictionnaire. Quand un utilisateur change de langue, le système charge automatiquement les traductions correspondantes.

Architecture

traduction/
├── models.py           # Language, Dictionnaire
├── registry.py         # TRANSLATABLE_MODELS
├── helpers.py          # TranslatableMixin, prefetch_translations()
├── middleware.py       # LanguageMiddleware
├── admin_mixins.py     # TranslatableAdminMixin
├── templatetags/
│   └── traduction_tags.py  # translate, trans_text, etc.
└── context_processors.py   # current_language_code

Middleware

LanguageMiddleware intercepte chaque requête et :

  • Détecte le paramètre ?lang=xx
  • Stocke la langue en session
  • Ajoute request.current_language_code

Registry

TRANSLATABLE_MODELS définit les champs traduisibles :

'news.newsarticle': [
    'title',
    'content',
],

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 News

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

Application Universities

Modèle Champs traduisibles
University name, short_name, description, academic_info
Department name, description

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 Program

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

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 du formulaire

3

Entrez les traductions

Pour chaque champ et chaque langue

4

Enregistrez

Les traductions sont sauvegardées automatiquement

Exemple visuel

Article: Mon article
Contenu Traductions Historique
Original (FR)

Astuce

Pour les sections CMS, utilisez le Gestionnaire de sections (Admin > CMS > Gestionnaire de sections) qui offre une interface plus pratique avec les champs de traduction intégrés.

Utilisation dans les templates

RECOMMANDÉ

Méthode 1 : Accès direct

Quand les objets sont chargés via le context processor, les champs contiennent déjà les valeurs traduites :

{# Les valeurs sont déjà traduites automatiquement #}
{{ article.title }}
{{ slide.subtitle }}
{{ menu_item.title }}
{{ event.description }}

Méthode 2 : Filtre |translate

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

{% load traduction_tags %}

{{ article|translate:'title' }}
{{ category|translate:'name' }}
{{ person|translate:'bio' }}

Méthode 3 : Textes statiques

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

{% 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' %}

{# Format: {% trans_text 'FR' 'EN' 'DE' %} #}

Variables de contexte disponibles

{# Langue courante #}
{{ current_language_code }}  {# ex: 'en' #}
{{ current_language }}       {# objet Language complet #}
{{ current_language.name }}  {# ex: 'English' #}

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

Sélecteur de langue

{% load traduction_tags %}

{# Sélecteur complet (inclusion tag) #}
{% language_selector %}

{# Ou manuellement #}
{% get_languages as languages %}
{% for lang in languages %} {{ lang.name }} {% endfor %}

Utilisation en Python

RECOMMANDÉ

Pré-charger les traductions

Méthode optimisée pour charger les traductions d'une liste d'objets en une seule requête :

from traduction.helpers import prefetch_translations

# Charger les articles
articles = list(NewsArticle.objects.filter(is_published=True)[:10])

# Appliquer les traductions (modifie les objets en place)
prefetch_translations(articles, language_code='en')

# Maintenant article.title contient la version anglaise
for article in articles:
    print(article.title)  # Affiche le titre en anglais

Récupérer une traduction unique

from traduction.helpers import get_translated_value

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

# Avec fallback automatique si traduction inexistante
title = get_translated_value(article, 'title', language_code='en', fallback=True)

Définir une traduction

from traduction.models import Dictionnaire, Language

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

# Définir/mettre à jour la traduction
Dictionnaire.set_translation(
    obj=article,
    field='title',
    language=english,
    translation='My Article Title in English'
)

# La méthode crée ou met à jour automatiquement

Dans une vue (Class-Based View)

from django.views.generic import ListView
from traduction.helpers import TranslatedViewMixin, prefetch_translations

class ArticleListView(TranslatedViewMixin, ListView):
    model = NewsArticle
    template_name = 'news/list.html'
    translate_fields = ['title', 'content']

    def get_queryset(self):
        queryset = NewsArticle.objects.filter(is_published=True)
        # translate_queryset applique automatiquement les traductions
        return self.translate_queryset(queryset)

    def get_context_data(self, **kwargs):
        context = super().get_context_data(**kwargs)
        lang_code = self.get_current_language_code()

        # Traduire d'autres objets manuellement
        categories = list(NewsCategory.objects.all())
        prefetch_translations(categories, language_code=lang_code)
        context['categories'] = categories

        return context

Utiliser TranslatableMixin sur un modèle

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

# Méthode get_translated() du mixin
title = article.get_translated('title')  # Langue par défaut
title_en = article.get_translated('title', language_code='en')

# Vérifier si une traduction existe
has_en = article.has_translation('title', language_code='en')

Rendre un nouveau modèle traduisible

1

Ajouter le mixin au modèle

# myapp/models.py
from django.db import models
from traduction.helpers import TranslatableMixin

class Product(TranslatableMixin, models.Model):
    name = models.CharField(max_length=200)
    description = models.TextField()
    price = models.DecimalField(max_digits=10, decimal_places=2)

    # name et description seront traduisibles
    # price ne sera pas traduit (nombre)
2

Enregistrer dans le registre

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

    'myapp.product': [
        'name',
        'description',
    ],
}
3

Configurer l'admin

# myapp/admin.py
from django.contrib import admin
from traduction.admin_mixins import TranslatableAdminMixin
from .models import Product

@admin.register(Product)
class ProductAdmin(TranslatableAdminMixin, admin.ModelAdmin):
    list_display = ['name', 'price']
    search_fields = ['name', 'description']

    # L'onglet "Traductions" apparaîtra automatiquement
4

Appliquer les traductions (vue ou context processor)

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

def get_products(language_code):
    products = list(Product.objects.filter(is_active=True))
    prefetch_translations(products, language_code=language_code)
    return products

# Dans le template, {{ product.name }} affichera le nom traduit

C'est tout !

Votre modèle est maintenant traduisible. Vous pouvez ajouter des traductions via l'interface admin et elles seront automatiquement chargées selon la langue de l'utilisateur.

Fonctionnement technique

Flux de traduction

1. Utilisateur clique sur "English" ou ?lang=en
           ↓
2. LanguageMiddleware détecte et stocke en session
           ↓
3. request.current_language_code = 'en'
           ↓
4. Context processor charge les données
           ↓
5. prefetch_translations() récupère les traductions
           ↓
6. Les champs des objets sont remplacés par les traductions
           ↓
7. Template affiche {{ object.field }} → valeur traduite

Structure de la table Dictionnaire

CREATE TABLE traduction_dictionnaire (
    id              INT PRIMARY KEY AUTO_INCREMENT,
    content_type_id INT NOT NULL,      -- FK vers ContentType (ex: 'news.newsarticle')
    object_id       INT NOT NULL,      -- ID de l'objet traduit
    field           VARCHAR(100),      -- Nom du champ (ex: 'title')
    language_id     INT NOT NULL,      -- FK vers Language
    translation     TEXT,              -- Le texte traduit
    created_at      DATETIME,
    updated_at      DATETIME,

    UNIQUE KEY unique_translation (content_type_id, object_id, field, language_id)
);

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 in English...
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

from traduction.models import Dictionnaire
from django.contrib.contenttypes.models import ContentType
from news.models import NewsArticle

ct = ContentType.objects.get_for_model(NewsArticle)
article = NewsArticle.objects.get(pk=1)

translations = Dictionnaire.objects.filter(
    content_type=ct,
    object_id=article.pk
)
for t in translations:
    print(f"{t.field} ({t.language.code}): {t.translation[:50]}")

2. Vérifier la langue courante

# Dans une vue ou template
print(request.current_language_code)  # Devrait afficher 'en', 'de', etc.

3. Vider le cache

python manage.py shell -c "from django.core.cache import cache; cache.clear()"

Les menus ne sont pas traduits

Assurez-vous d'utiliser le tag {% get_menu %} qui applique automatiquement les traductions :

{% load cms_tags %}

{# ✅ Correct - utilise get_menu #}
{% get_menu 'front-menu' as nav_menu %}
{% for item in nav_menu.get_root_items %}
    {{ item.title }}  {# Traduit automatiquement #}
{% endfor %}

{# ❌ Incorrect - accès direct sans traduction #}
{% for item in menu.items.all %}
    {{ item.title }}  {# NON traduit #}
{% endfor %}

Performance : Éviter les requêtes N+1

❌ Mauvais (N+1 requêtes)

for article in articles:
    # Fait une requête par article !
    title = get_translated_value(
        article, 'title', 'en'
    )

✅ Bon (2 requêtes max)

# Une seule requête pour toutes les traductions
prefetch_translations(articles, language_code='en')

for article in articles:
    title = article.title  # Déjà traduit

Fallback automatique

Si une traduction n'existe pas pour la langue demandée, le système retourne automatiquement la valeur originale (français). Ce n'est pas une erreur.

Commandes utiles

# 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]}')"

# Vérifier les langues actives

python manage.py shell -c "
from traduction.models import Language
for lang in Language.objects.filter(is_active=True):
    print(f'{lang.code} - {lang.name} (default: {lang.is_default})')"

# Compter les traductions par langue

python manage.py shell -c "
from traduction.models import Dictionnaire
from django.db.models import Count
stats = Dictionnaire.objects.values('language__code').annotate(count=Count('id'))
for s in stats:
    print(f\"{s['language__code']}: {s['count']} traductions\")"

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 (Python) request.current_language_code
Langue courante (Template) {{ current_language_code }}
Changer langue ?lang=en dans l'URL