jeromejhipolito / laravel-translation-middleware
Automatic locale detection middleware and translation traits for Laravel APIs. Detects Accept-Language header and provides HasTranslations trait for models.
Installs: 0
Dependents: 0
Suggesters: 0
Security: 0
Stars: 0
Watchers: 0
Forks: 0
Open Issues: 0
pkg:composer/jeromejhipolito/laravel-translation-middleware
Requires
- php: ^8.2
- illuminate/database: ^11.0|^12.0
- illuminate/http: ^11.0|^12.0
- illuminate/support: ^11.0|^12.0
Requires (Dev)
- laravel/pint: ^1.0
- orchestra/testbench: ^9.0
- pestphp/pest: ^2.0|^3.0
README
Automatic locale detection middleware and translation traits for Laravel APIs. Detects Accept-Language header and provides HasTranslations trait for models with JSON-stored translations.
Features
- Automatically detects user's preferred language from
Accept-Languageheader - Sets Laravel's app locale based on the detected language
- Provides
HasTranslationstrait for models with JSON translation columns - Provides
TranslatableResourcetrait for API resources - Supports locale fallbacks
- Configurable supported locales
- Excludes specific routes from locale detection
Requirements
- PHP 8.2+
- Laravel 11.0+ or 12.0+
Installation
composer require jeromejhipolito/laravel-translation-middleware
The package will auto-register its service provider.
Configuration
Publish the configuration file:
php artisan vendor:publish --tag=translation-config
This will create config/translation.php:
return [ // HTTP header name for locale detection 'header' => env('TRANSLATION_HEADER', 'Accept-Language'), // Default locale when no header is provided 'default' => env('TRANSLATION_DEFAULT', 'en'), // Supported locales (empty array = accept all) 'supported_locales' => ['en', 'ja', 'ko', 'zh', 'es', 'fr', 'de', 'pt', 'it', 'ru'], // Fallback when translation not available 'fallback' => env('TRANSLATION_FALLBACK', 'en'), // Column suffix for translations (e.g., title_translations) 'column_suffix' => '_translations', // Parse 'en-US' to 'en' (true) or keep full code (false) 'parse_language_only' => true, // Routes to skip locale detection 'excluded_routes' => [], ];
Usage
1. Register the Middleware
Add the middleware to your routes in bootstrap/app.php:
use JeromeJHipolito\TranslationMiddleware\Middleware\SetLocaleMiddleware; ->withMiddleware(function (Middleware $middleware) { $middleware->api(append: [ SetLocaleMiddleware::class, ]); })
2. Add HasTranslations Trait to Models
use Illuminate\Database\Eloquent\Model; use JeromeJHipolito\TranslationMiddleware\Traits\HasTranslations; class Article extends Model { use HasTranslations; protected $fillable = [ 'title', 'content', 'title_translations', 'content_translations', ]; protected $casts = [ 'title_translations' => 'array', 'content_translations' => 'array', ]; // Define which attributes are translatable protected array $translatable = ['title', 'content']; }
3. Database Migration
Schema::create('articles', function (Blueprint $table) { $table->id(); $table->string('title'); // Default value $table->json('title_translations')->nullable(); // Translations $table->text('content'); $table->json('content_translations')->nullable(); $table->timestamps(); });
4. Store Translations
$article = Article::create([ 'title' => 'Hello World', 'content' => 'This is the content.', ]); // Set individual translations $article->setTranslation('title', 'ja', 'こんにちは世界'); $article->setTranslation('title', 'ko', '안녕하세요 세계'); $article->save(); // Or set multiple at once $article->setTranslations('title', [ 'ja' => 'こんにちは世界', 'ko' => '안녕하세요 세계', 'zh' => '你好世界', ]); $article->save();
5. Retrieve Translations
// Uses current app locale (set by middleware) $title = $article->getTranslation('title'); // Specify locale explicitly $title = $article->getTranslation('title', 'ja'); // Get all translations $translations = $article->getTranslations('title'); // ['ja' => 'こんにちは世界', 'ko' => '안녕하세요 세계'] // Check if translation exists if ($article->hasTranslation('title', 'fr')) { // ... } // Get available locales $locales = $article->getAvailableLocales('title'); // ['ja', 'ko', 'zh']
6. Use TranslatableResource in API Resources
use Illuminate\Http\Resources\Json\JsonResource; use JeromeJHipolito\TranslationMiddleware\Traits\TranslatableResource; class ArticleResource extends JsonResource { use TranslatableResource; public function toArray($request): array { return [ 'id' => $this->id, 'title' => $this->translated('title'), // Auto-translated 'content' => $this->translated('content'), // Auto-translated 'available_translations' => $this->availableTranslations('title'), 'created_at' => $this->created_at, ]; } }
Client-Side Usage
Send the preferred language in the Accept-Language header:
fetch('/api/articles/1', { headers: { 'Accept-Language': 'ja', }, }); // Response: // { // "id": 1, // "title": "こんにちは世界", // "content": "これはコンテンツです", // "available_translations": ["ja", "ko", "zh"] // }
API Reference
HasTranslations Trait Methods
| Method | Description |
|---|---|
getTranslation($attribute, $locale = null) |
Get translated value |
setTranslation($attribute, $locale, $value) |
Set translation for locale |
setTranslations($attribute, $translations) |
Set multiple translations |
getTranslations($attribute) |
Get all translations array |
hasTranslation($attribute, $locale) |
Check if translation exists |
removeTranslation($attribute, $locale) |
Remove translation |
getAvailableLocales($attribute) |
Get available locale codes |
getAllAvailableLocales() |
Get all locales across attributes |
getTranslatableAttributes() |
Get list of translatable attributes |
translated($locale = null) |
Get all translated attributes |
toArrayTranslated($locale = null) |
Convert model to array with translations |
TranslatableResource Trait Methods
| Method | Description |
|---|---|
getLocale() |
Get current locale |
translated($attribute) |
Get translated value |
translatedWhen($condition, $attribute) |
Conditional translation |
availableTranslations($attribute) |
Get available locales |
allAvailableTranslations() |
Get all available locales |
withTranslationMetadata() |
Get metadata array |
mergeTranslationMetadataWhen($condition) |
Conditional metadata |
Testing
composer test
License
The MIT License (MIT). Please see License File for more information.