Skip to content

rawnoq/laravel-locale-detector

Repository files navigation

Laravel Locale Detector

A professional Laravel package for automatic locale detection from HTTP headers and translation key extraction from your codebase.

📋 Table of Contents

✨ Features

  • Automatic Locale Detection - Automatically detects user's preferred language from Accept-Language header
  • Translation Key Extraction - Extract all translation keys from your codebase
  • Multiple Detection Methods - Supports Laravel's getPreferredLanguage() and direct header parsing
  • Configurable Supported Locales - Define which locales your application supports
  • Global Middleware - Automatically registered middleware for seamless integration
  • Multiple Output Formats - Export translation keys as JSON, PHP, or array format
  • Namespace Filtering - Filter translation keys by namespace
  • Exclude Paths - Exclude specific directories from key extraction
  • Translation Key Synchronization - Sync translation keys to language files automatically
  • 40+ Language Files - Includes translation files for auth, pagination, passwords, and validation in 40+ languages
  • Translatable Models - Wrapper for Astrotomic Translatable with additional helper methods
  • Database Migrations - Helper traits and classes for creating translation tables
  • Translation Format Converter - Convert between attribute-based and locale-based translation formats

📦 Requirements

  • PHP 8.2 or higher
  • Laravel 11.0+ or Laravel 12.0+

🚀 Installation

Step 1: Install via Composer

composer require rawnoq/laravel-locale-detector

The package will be automatically discovered and registered by Laravel.

Step 2: Publish Configuration (Optional)

php artisan vendor:publish --tag=locale-detector-config

This will publish the configuration file to config/locale-detector.php.

Step 3: Publish Language Files (Optional)

php artisan vendor:publish --tag=locale-detector-lang

This will publish language files to lang/ directory. The package includes translation files for 40+ languages (auth, pagination, passwords, validation).

⚙️ Configuration

The configuration file is located at config/locale-detector.php:

return [
    /*
    |--------------------------------------------------------------------------
    | Auto Detect Locale
    |--------------------------------------------------------------------------
    |
    | Enable automatic locale detection from Accept-Language header.
    |
    */

    'auto_detect_locale' => env('AUTO_DETECT_LOCALE', true),

    /*
    |--------------------------------------------------------------------------
    | Auto Detect Preferred Language
    |--------------------------------------------------------------------------
    |
    | Use Laravel's getPreferredLanguage() method for locale detection.
    | If false, uses the Accept-Language header directly.
    |
    */

    'auto_detect_preferred_language' => env('AUTO_DETECT_PREFERRED_LANGUAGE', true),

    /*
    |--------------------------------------------------------------------------
    | Supported Locales
    |--------------------------------------------------------------------------
    |
    | List of supported locales for automatic detection.
    |
    */

    'supported_locales' => env('SUPPORTED_LOCALES', 'en,ar') 
        ? explode(',', env('SUPPORTED_LOCALES', 'en,ar')) 
        : ['en', 'ar'],
];

Environment Variables

You can configure the package using environment variables in your .env file:

AUTO_DETECT_LOCALE=true
AUTO_DETECT_PREFERRED_LANGUAGE=true
SUPPORTED_LOCALES=en,ar,fr,es

🎯 Usage

Automatic Locale Detection

The middleware automatically detects the user's preferred language from the Accept-Language header and sets the application locale accordingly.

No additional code required! The middleware is automatically registered and works out of the box.

Manual Locale Setting

You can still manually set the locale in your code:

app()->setLocale('ar');

Accessing Current Locale

$locale = app()->getLocale();

🔍 Translation Key Extraction

The package provides a powerful command to extract all translation keys from your codebase.

Basic Usage

# Extract all translation keys from the entire codebase
php artisan locale:extract-keys

# Extract keys from a specific path
php artisan locale:extract-keys --path=app

# Extract keys and save to a file
php artisan locale:extract-keys --output=translation-keys.json

# Extract keys in PHP format
php artisan locale:extract-keys --format=php --output=keys.php

# Extract keys in array format
php artisan locale:extract-keys --format=array

# Extract keys with file path and line number
php artisan locale:extract-keys --with-location

# Extract keys with location and save to JSON file
php artisan locale:extract-keys --with-location --output=translation-keys.json

Options

Option Description Default
--path The path to search for translation keys base_path()
--output The output file path for extracted keys Display in console
--format Output format (json, php, array) json
--exclude Comma-separated paths to exclude None
--namespace Filter keys by namespace None
--with-location Include file path and line number for each key false

Examples

Extract Keys from App Directory

php artisan locale:extract-keys --path=app

Extract Keys and Save to File

php artisan locale:extract-keys --output=storage/app/translation-keys.json

Extract Keys in PHP Format

php artisan locale:extract-keys --format=php --output=config/translation-keys.php

Exclude Vendor and Storage Directories

php artisan locale:extract-keys --exclude=vendor,storage

Filter Keys by Namespace

php artisan locale:extract-keys --namespace=blog

This will only extract keys that start with blog::.

Extract Keys with Location Information

php artisan locale:extract-keys --with-location --output=translation-keys.json

This will extract keys with file path and line number information. The output will include:

  • key: The translation key
  • file: The relative file path
  • line: The line number where the key was found
  • location: A formatted string like file:line
  • locations: An array of all locations where the key appears (if the same key appears multiple times)

Example output:

[
    {
        "key": "welcome",
        "file": "app/Http/Controllers/TestController.php",
        "line": 11,
        "location": "app/Http/Controllers/TestController.php:11",
        "locations": [
            "app/Http/Controllers/TestController.php:11",
            "app/Http/Controllers/TestController.php:12"
        ]
    }
]

Supported Translation Patterns

The command extracts keys from the following patterns:

  • __('key') - Laravel's translation helper
  • trans('key') - Translation function
  • @lang('key') - Blade directive
  • Lang::get('key') - Lang facade method
  • Lang::trans('key') - Lang facade trans method
  • trans_choice('key', ...) - Translation choice function
  • __('namespace::key') - Namespaced translations
  • trans('namespace::key') - Namespaced translations

Output Formats

JSON Format

[
    "validation.required",
    "validation.email",
    "messages.welcome",
    "blog::post.title"
]

PHP Format

<?php

return [
    'validation.required',
    'validation.email',
    'messages.welcome',
    'blog::post.title',
];

Array Format

[
    'validation.required',
    'validation.email',
    'messages.welcome',
    'blog::post.title',
]

🌐 Translatable Models

The package provides a wrapper for Astrotomic Translatable with additional helper methods and utilities.

Using the Translatable Trait

<?php

namespace App\Models;

use Illuminate\Database\Eloquent\Model;
use Rawnoq\LocaleDetector\Concerns\Translatable;

class Post extends Model
{
    use Translatable;
    
    public $translatedAttributes = ['title', 'content'];
    
    protected $fillable = ['author', 'title', 'content'];
}

Creating Models with Translations

// Using locale-based format (Astrotomic standard)
$post = Post::create([
    'author' => 'John Doe',
    'en' => [
        'title' => 'My First Post',
        'content' => 'This is the content.'
    ],
    'ar' => [
        'title' => 'منشوري الأول',
        'content' => 'هذا المحتوى.'
    ]
]);

// Accessing translations
echo $post->translate('en')->title; // My First Post
echo $post->translate('ar')->title; // منشوري الأول

App::setLocale('ar');
echo $post->title; // منشوري الأول

Converting Translation Formats

The package provides helper functions to convert between different translation formats:

Using Helper Functions

// Convert from attribute-based to locale-based format
$data = [
    'author' => 'John',
    'title' => [
        'en' => 'My Post',
        'ar' => 'منشوري'
    ],
    'content' => [
        'en' => 'Content',
        'ar' => 'المحتوى'
    ]
];

$converted = to_locale_based($data, ['title', 'content']);

// Result:
// [
//     'author' => 'John',
//     'en' => ['title' => 'My Post', 'content' => 'Content'],
//     'ar' => ['title' => 'منشوري', 'content' => 'المحتوى']
// ]

// Convert back to attribute-based format
$original = to_attribute_based($converted, ['title', 'content']);

Using Model Methods

// Using the model's static methods
$converted = Post::convertToLocaleBased($data);
$original = Post::convertToAttributeBased($converted);

Database Migrations with Translations

The package provides helper traits and classes for creating translation tables:

Using MigrationWithTranslations

<?php

use Rawnoq\LocaleDetector\Database\Migrations\MigrationWithTranslations;
use Illuminate\Database\Schema\Blueprint;

class CreatePostsTable extends MigrationWithTranslations
{
    public function up(): void
    {
        $this->createTableWithTranslations(
            'posts',
            function (Blueprint $table) {
                $table->id();
                $table->string('author');
                $table->boolean('is_published')->default(false);
                $table->timestamps();
            },
            function (Blueprint $table) {
                $table->string('title');
                $table->text('content');
                $table->string('slug')->unique();
            }
        );
    }

    public function down(): void
    {
        $this->dropIfExistsWithTranslations('posts');
    }
}

Using the Trait Directly

<?php

use Illuminate\Database\Migrations\Migration;
use Rawnoq\LocaleDetector\Concerns\CreateTableWithTranslations;
use Illuminate\Database\Schema\Blueprint;

class CreatePostsTable extends Migration
{
    use CreateTableWithTranslations;

    public function up(): void
    {
        $this->createTableWithTranslations(/* ... */);
    }
}

Using UUID for Foreign Keys

$this->createTableWithTranslations(
    'posts',
    function (Blueprint $table) {
        $table->uuid('id')->primary();
        // ...
    },
    function (Blueprint $table) {
        // ...
    },
    true // useUuid = true
);

🎓 Advanced Usage

Custom Locale Detection

You can customize the locale detection logic by modifying the middleware or creating your own:

// In your custom middleware
if (config('locale-detector.auto_detect_locale')) {
    $locale = $request->header('Accept-Language');
    // Your custom logic here
    app()->setLocale($locale);
}

Integration with HMVC Modules

If you're using the rawnoq/laravel-hmvc package, you can extract translation keys from modules:

# Extract keys from all modules
php artisan locale:extract-keys --path=modules

# Extract keys from a specific module
php artisan locale:extract-keys --path=modules/Blog --namespace=blog

Automated Translation Key Management

You can create a script to automatically extract and update translation files:

#!/bin/bash
# Extract keys and save to a file
php artisan locale:extract-keys --output=storage/app/keys.json

# Process the keys and update translation files
# Your custom script here

🔧 Troubleshooting

Middleware Not Working

If locale detection is not working:

  1. Check if middleware is registered: php artisan route:list
  2. Verify configuration: php artisan config:show locale-detector
  3. Check Accept-Language header in requests
  4. Ensure supported locales are configured correctly

Translation Keys Not Found

If the extraction command finds no keys:

  1. Verify the path contains PHP files
  2. Check if translation functions are used correctly
  3. Ensure files are readable
  4. Check excluded paths

Command Not Found

If locale:extract-keys command is not found:

  1. Run php artisan package:discover
  2. Clear cache: php artisan optimize:clear
  3. Verify Service Provider is registered

📝 Examples

Example 1: Extract All Keys

php artisan locale:extract-keys

Example 2: Extract from Specific Path

php artisan locale:extract-keys --path=app/Http/Controllers

Example 3: Extract and Save to File

php artisan locale:extract-keys --output=storage/app/translation-keys.json --format=json

Example 4: Extract with Exclusions

php artisan locale:extract-keys --exclude=vendor,storage,node_modules

Example 5: Extract Namespaced Keys Only

php artisan locale:extract-keys --namespace=blog

🤝 Contributing

Contributions are welcome! Please feel free to submit a Pull Request.

  1. Fork the repository
  2. Create your feature branch (git checkout -b feature/AmazingFeature)
  3. Commit your changes (git commit -m 'Add some AmazingFeature')
  4. Push to the branch (git push origin feature/AmazingFeature)
  5. Open a Pull Request

🧪 Testing

The package comes with a comprehensive test suite:

# Run tests
composer test

# Run tests with coverage
composer test-coverage

Test Coverage

The test suite includes:

  • ✅ Middleware locale detection tests
  • ✅ ServiceProvider registration tests
  • ✅ Translation key extraction command tests
  • ✅ Configuration tests
  • ✅ Translation format converter tests
  • ✅ Helper functions tests
  • ✅ Edge cases and error handling

📄 License

This package is open-sourced software licensed under the MIT license.

🙏 Credits

  • Author: Rawnoq
  • Package: rawnoq/laravel-locale-detector
  • Version: 1.0.0

Made with ❤️ for the Laravel community

About

A Laravel package for automatic locale detection and translation key extraction

Resources

License

Contributing

Stars

Watchers

Forks

Packages

No packages published

Languages