Pattern : Traductions dans les Modules

Version : 1.0 Date : 2026-01-25 Story : Epic 5, Story 5.2


Vue d'ensemble

Ce guide explique comment ajouter des traductions JSON dans un module spécifique (app/Specifics/{Module}/). Les traductions sont chargées automatiquement via un Service Provider et sont disponibles dans toute l'application.


1. Structure requise

Pour ajouter des traductions à un module, vous devez créer la structure suivante :

app/Specifics/{Module}/
├── lang/
│   ├── fr.json
│   ├── es.json
│   └── ... (autres locales)
└── Providers/
    └── {Module}ServiceProvider.php

Exemple : Module Blog

app/Specifics/Blog/
├── lang/
│   ├── fr.json
│   └── es.json
└── Providers/
    └── BlogServiceProvider.php


2. Créer le Service Provider

Étape 1 : Créer le Service Provider

Créez un Service Provider dans app/Specifics/{Module}/Providers/{Module}ServiceProvider.php :

<?php

namespace App\Specifics\{Module}\Providers;

use Illuminate\Support\ServiceProvider;

class {Module}ServiceProvider extends ServiceProvider { /** * Register services. */ public function register(): void { // }

/** * Bootstrap services. */ public function boot(): void { // Charger les traductions JSON du module si les traductions interface sont activées if (translation_component_enabled('interface')) { $langPath = __DIR__.'/../lang';

// Vérifier que le dossier lang existe avant de charger if (is_dir($langPath)) { $this->loadJsonTranslationsFrom($langPath); } } } }

Exemple concret : app/Specifics/Blog/Providers/BlogServiceProvider.php

<?php

namespace App\Specifics\Blog\Providers;

use Illuminate\Support\ServiceProvider;

class BlogServiceProvider extends ServiceProvider { public function register(): void { // }

public function boot(): void { if (translation_component_enabled('interface')) { $langPath = __DIR__.'/../lang';

if (is_dir($langPath)) { $this->loadJsonTranslationsFrom($langPath); } } } }

Étape 2 : Enregistrer le Service Provider

Ajoutez le Service Provider dans bootstrap/providers.php :

<?php

return [ App\Providers\AppServiceProvider::class, // ... autres providers App\Specifics\Blog\Providers\BlogServiceProvider::class, // ... autres providers ];


3. Créer les fichiers de traduction

Format des fichiers JSON

Les fichiers JSON doivent utiliser un format clé-valeur simple avec des clés en notation pointée :

Fichier : app/Specifics/Blog/lang/fr.json

{
    "blog.title": "Blog",
    "blog.posts": "Articles",
    "blog.create_post": "Créer un article",
    "blog.edit_post": "Modifier l'article",
    "blog.published": "Publié",
    "blog.draft": "Brouillon"
}

Fichier : app/Specifics/Blog/lang/es.json

{
    "blog.title": "Blog",
    "blog.posts": "Artículos",
    "blog.create_post": "Crear un artículo",
    "blog.edit_post": "Modificar el artículo",
    "blog.published": "Publicado",
    "blog.draft": "Borrador"
}

Important :

  • Utilisez des clés en notation pointée (ex: blog.title, pas blog.title dans un objet imbriqué)
  • Préfixez les clés avec le nom du module pour éviter les conflits (ex: blog., shop.)

  • 4. Utilisation

    Une fois le Service Provider enregistré et les fichiers créés, les traductions sont automatiquement disponibles :

    // Dans le code PHP
    __('blog.title')        // "Blog"
    __('blog.posts')        // "Articles" (fr) ou "Artículos" (es)
    __('blog.create_post')  // "Créer un article" (fr) ou "Crear un artículo" (es)
    

    {{-- Dans les vues Blade --}}
    <h1>{{ __('blog.title') }}</h1>
    <p>{{ __('blog.posts') }}</p>
    


    5. Exemple complet : Module Blog

    Structure

    app/Specifics/Blog/
    ├── lang/
    │   ├── fr.json
    │   └── es.json
    └── Providers/
        └── BlogServiceProvider.php
    

    Service Provider

    <?php

    namespace App\Specifics\Blog\Providers;

    use Illuminate\Support\ServiceProvider;

    class BlogServiceProvider extends ServiceProvider { public function boot(): void { if (translation_component_enabled('interface')) { $langPath = __DIR__.'/../lang';

    if (is_dir($langPath)) { $this->loadJsonTranslationsFrom($langPath); } } } }

    Fichiers de traduction

    app/Specifics/Blog/lang/fr.json :

    {
        "blog.title": "Blog",
        "blog.posts": "Articles",
        "blog.create_post": "Créer un article",
        "blog.edit_post": "Modifier l'article",
        "blog.post_title": "Titre de l'article",
        "blog.post_content": "Contenu de l'article",
        "blog.published": "Publié",
        "blog.draft": "Brouillon",
        "blog.archived": "Archivé"
    }
    

    app/Specifics/Blog/lang/es.json :

    {
        "blog.title": "Blog",
        "blog.posts": "Artículos",
        "blog.create_post": "Crear un artículo",
        "blog.edit_post": "Modificar el artículo",
        "blog.post_title": "Título del artículo",
        "blog.post_content": "Contenido del artículo",
        "blog.published": "Publicado",
        "blog.draft": "Borrador",
        "blog.archived": "Archivado"
    }
    

    Enregistrement

    bootstrap/providers.php :

    <?php

    return [ App\Providers\AppServiceProvider::class, App\Providers\AuthServiceProvider::class, App\Providers\EventServiceProvider::class, App\Providers\ShopServiceProvider::class, App\Specifics\Blog\Providers\BlogServiceProvider::class, // ← Ajouté App\Providers\Filament\AdminPanelProvider::class, App\Providers\Filament\AppPanelProvider::class, Lab404\Impersonate\ImpersonateServiceProvider::class, ];


    6. Bonnes pratiques

    Préfixage des clés

    Toujours préfixer les clés avec le nom du module pour éviter les conflits :

    Bon :

    {
        "blog.title": "Blog",
        "blog.posts": "Articles"
    }
    

    Mauvais :

    {
        "title": "Blog",
        "posts": "Articles"
    }
    

    Organisation des clés

    Organisez les clés de manière logique :

    {
        "blog.title": "Blog",
        "blog.posts": "Articles",
        "blog.create_post": "Créer un article",
        "blog.edit_post": "Modifier l'article",
        "blog.status.published": "Publié",
        "blog.status.draft": "Brouillon",
        "blog.status.archived": "Archivé"
    }
    

    Vérification conditionnelle

    Le Service Provider vérifie automatiquement si les traductions interface sont activées :

    if (translation_component_enabled('interface')) {
        // Charger les traductions
    }
    

    Si les traductions sont désactivées, les fichiers ne sont pas chargés, ce qui évite les erreurs.


    7. Tests

    Des tests sont disponibles dans tests/Feature/Specifics/{Module}/TranslationLoadingTest.php.

    Exemple : tests/Feature/Specifics/Blog/TranslationLoadingTest.php

    it('can load translations from Blog module lang directory', function () {
        expect(__('blog.title'))->toBe('Blog');
        expect(__('blog.posts'))->toBe('Articles');
        expect(__('blog.create_post'))->toBe('Créer un article');
    });
    


    8. FAQ

    Q : Les traductions sont-elles mises en cache ?

    R : Oui, les traductions JSON sont automatiquement mises en cache par le système de cache des traductions (Story 5.1). Utilisez php artisan translate:clear-cache pour vider le cache.

    Q : Puis-je utiliser des clés imbriquées dans les fichiers JSON ?

    R : Non, Laravel attend un format clé-valeur simple avec des clés en notation pointée. Utilisez blog.title plutôt qu'un objet { "blog": { "title": "..." } }.

    Q : Que se passe-t-il si le dossier lang/ n'existe pas ?

    R : Le Service Provider vérifie que le dossier existe avant de charger les traductions. Si le dossier n'existe pas, aucune erreur n'est générée.

    Q : Les traductions du module sont-elles fusionnées avec les traductions globales ?

    R : Oui, les traductions du module sont ajoutées aux traductions globales. Si une clé existe à la fois dans lang/fr.json et app/Specifics/Blog/lang/fr.json, la valeur du module prend le dessus.

    Q : Puis-je créer des sous-dossiers dans lang/ ?

    R : Non, loadJsonTranslationsFrom() charge uniquement les fichiers JSON à la racine du dossier spécifié. Utilisez des clés préfixées pour organiser vos traductions.


    9. Checklist pour ajouter des traductions à un module

  • [ ] Créer le dossier app/Specifics/{Module}/lang/
  • [ ] Créer les fichiers JSON pour chaque locale (fr.json, es.json, etc.)
  • [ ] Utiliser des clés préfixées avec le nom du module
  • [ ] Créer le Service Provider app/Specifics/{Module}/Providers/{Module}ServiceProvider.php
  • [ ] Implémenter la méthode boot() avec chargement conditionnel
  • [ ] Enregistrer le Service Provider dans bootstrap/providers.php
  • [ ] Créer des tests dans tests/Feature/Specifics/{Module}/TranslationLoadingTest.php
  • [ ] Vérifier que les traductions fonctionnent avec __('module.key')

  • 10. Exemples de modules avec traductions

    Module Blog ✅

  • Service Provider : app/Specifics/Blog/Providers/BlogServiceProvider.php
  • Traductions : app/Specifics/Blog/lang/fr.json, es.json
  • Tests : tests/Feature/Specifics/Blog/TranslationLoadingTest.php
  • Module Shop (à faire)

    Pour ajouter des traductions au module Shop, suivez le même pattern :

  • Créer app/Specifics/Shop/Providers/ShopServiceProvider.php
  • Créer app/Specifics/Shop/lang/fr.json et es.json
  • Enregistrer le Service Provider dans bootstrap/providers.php

  • 11. Support et ressources

  • Service Provider exemple : app/Specifics/Blog/Providers/BlogServiceProvider.php
  • Tests exemple : tests/Feature/Specifics/Blog/TranslationLoadingTest.php
  • Documentation Laravel : JSON Translation Files
  • PRD : docs/prd/epic-5-optimizations-and-extensions.md

Dernière mise à jour : 25 janvier 2026

Prendre rendez-vous