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

v1.0.0 2026-02-02 02:44 UTC

This package is auto-updated.

Last update: 2026-02-02 02:45:41 UTC


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-Language header
  • Sets Laravel's app locale based on the detected language
  • Provides HasTranslations trait for models with JSON translation columns
  • Provides TranslatableResource trait 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.

Credits