Languages and Translations


Module translations are stored in Modules/{ModuleName}/lang/ and are loaded with the module's alias as the namespace.

#Directory Structure

Copied!
Modules/Blog/
└── lang/
├── en/
│ ├── messages.php
│ └── validation.php
└── fr/
├── messages.php
└── validation.php

#Loading Translations

The generated service provider registers translations automatically:

Copied!
protected function registerTranslations(): void
{
$langPath = resource_path('lang/modules/' . $this->moduleNameLower);
 
if (is_dir($langPath)) {
$this->loadTranslationsFrom($langPath, $this->moduleNameLower);
$this->loadJsonTranslationsFrom($langPath);
} else {
$this->loadTranslationsFrom(module_path($this->moduleName, 'lang'), $this->moduleNameLower);
$this->loadJsonTranslationsFrom(module_path($this->moduleName, 'lang'));
}
}

The method checks whether the application has published translations to resources/lang/modules/blog. If so, those take priority, allowing users to override module translations without modifying the module itself.

#Array Translation Files

Create translation files in lang/en/messages.php:

Copied!
<?php
 
return [
'welcome' => 'Welcome to the Blog',
'post_created' => 'Post created successfully.',
'post_deleted' => 'Post deleted.',
'not_found' => 'The requested post could not be found.',
];

Use the moduleAlias::file.key syntax:

Copied!
// In PHP
__('blog::messages.welcome')
trans('blog::messages.post_created')
 
// In Blade
{{ __('blog::messages.welcome') }}
@lang('blog::messages.post_deleted')

With parameters:

Copied!
// messages.php
'post_count' => 'You have :count posts.',
 
// Usage
__('blog::messages.post_count', ['count' => $user->posts()->count()])

#Nested Translation Groups

Organise translation strings into groups within a file:

Copied!
// lang/en/posts.php
return [
'actions' => [
'create' => 'Create Post',
'edit' => 'Edit Post',
'delete' => 'Delete Post',
'publish' => 'Publish',
],
'status' => [
'draft' => 'Draft',
'published' => 'Published',
'scheduled' => 'Scheduled',
],
];

Access nested keys:

Copied!
__('blog::posts.actions.create')
__('blog::posts.status.published')

#JSON Translation Files

JSON translations allow you to use the original string as the key, which is especially useful for front-end and multi-language sites.

Create lang/fr.json:

Copied!
{
"Welcome to the Blog": "Bienvenue sur le Blog",
"Create Post": "Créer un article",
"Post created successfully.": "Article créé avec succès."
}

Use them exactly like any other translation string — no namespace required:

Copied!
__('Create Post')
__('Post created successfully.')

The loadJsonTranslationsFrom call in the service provider enables this.

#Checking Missing Translation Keys

Identify missing translations across module language files:

Copied!
php artisan module:lang Blog

#Publishing Translations

Publish module translation files to resources/lang/modules/blog/ so they can be customised at the application level:

Copied!
php artisan module:publish-translation Blog

#Pluralisation

Copied!
// lang/en/messages.php
'posts' => '{0} No posts|{1} One post|[2,*] :count posts',

Use with trans_choice:

Copied!
trans_choice('blog::messages.posts', $count, ['count' => $count])

#Locale Fallback

Laravel's translation system handles locale fallback automatically. If a key is not found in the current locale, it falls back to the fallback_locale set in config/app.php.



Laravel Package built by Nicolas Widart.

Maintained by David Carr follow on X @dcblogdev