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 :
<?phpnamespace 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
<?phpnamespace 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 :
<?phpreturn [
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, pasblog.titledans 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
<?phpnamespace 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 :
<?phpreturn [
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
app/Specifics/{Module}/lang/fr.json, es.json, etc.)app/Specifics/{Module}/Providers/{Module}ServiceProvider.phpboot() avec chargement conditionnelbootstrap/providers.phptests/Feature/Specifics/{Module}/TranslationLoadingTest.php__('module.key')10. Exemples de modules avec traductions
Module Blog ✅
app/Specifics/Blog/Providers/BlogServiceProvider.phpapp/Specifics/Blog/lang/fr.json, es.jsontests/Feature/Specifics/Blog/TranslationLoadingTest.phpModule Shop (à faire)
Pour ajouter des traductions au module Shop, suivez le même pattern :
app/Specifics/Shop/Providers/ShopServiceProvider.phpapp/Specifics/Shop/lang/fr.json et es.jsonbootstrap/providers.php11. Support et ressources
app/Specifics/Blog/Providers/BlogServiceProvider.phptests/Feature/Specifics/Blog/TranslationLoadingTest.phpdocs/prd/epic-5-optimizations-and-extensions.mdDernière mise à jour : 25 janvier 2026