jawabapp/localization

A comprehensive, modern Laravel package for managing multilingual applications with database-driven translations, automatic locale detection, and a beautiful admin interface.

Fund package maintenance!
jawabapp

Installs: 19

Dependents: 0

Suggesters: 0

Security: 0

Stars: 0

Watchers: 2

Forks: 0

Open Issues: 0

Language:CSS

1.1.3 2025-09-14 06:25 UTC

This package is auto-updated.

Last update: 2025-09-14 09:39:52 UTC


README

Latest Version on Packagist Total Downloads MIT Licensed PHP Laravel

A comprehensive, modern Laravel package for managing multilingual applications with database-driven translations, automatic locale detection, and a beautiful admin interface. Built for Laravel 10+ with full support for the latest language directory structure.

✨ Features

  • 🌐 12+ Languages: Pre-configured support for major world languages
  • 🎯 Smart Locale Detection: Browser, URL, session, and cookie-based detection
  • πŸ“ Modern Laravel Compatibility: Laravel 10/11 lang/ directory structure
  • πŸ—‚οΈ Dual Format Support: Both PHP arrays and JSON translations
  • πŸ—ƒοΈ Database-Driven Translations: Store translations in database with file fallback
  • πŸŽ›οΈ Professional Admin Interface: Beautiful Tailwind CSS interface
  • ⚑ Performance Optimized: Built-in caching and file-based translations
  • πŸ”§ Artisan Commands: CLI tools for import/export and management
  • πŸ›£οΈ SEO Friendly: Automatic hreflang tags and localized URLs
  • πŸ“± API Support: RESTful API with intelligent locale detection
  • πŸ”„ Hot Reloading: Automatic file export on database changes
  • πŸ”€ Flexible Loading: Database-first with automatic file fallback

πŸ“‹ Requirements

  • PHP: 8.2 or higher
  • Laravel: 10.0 or higher
  • Extensions: mbstring, json

πŸš€ Quick Installation

1. Install via Composer

composer require jawabapp/localization

2. Publish Configuration

# Publish config file
php artisan vendor:publish --tag=localization-config

# Publish and run migrations
php artisan vendor:publish --tag=localization-migrations
php artisan migrate

3. Configure Middleware

For Laravel 11+, add the middleware to your bootstrap/app.php:

<?php

use Illuminate\Foundation\Application;
use Illuminate\Foundation\Configuration\Exceptions;
use Illuminate\Foundation\Configuration\Middleware;

return Application::configure(basePath: dirname(__DIR__))
    ->withMiddleware(function (Middleware $middleware): void {
        // Register localization middleware
        $middleware->alias([
            'localization' => \Jawabapp\Localization\Http\Middleware\Web\Localization::class,
            'localization.web' => \Jawabapp\Localization\Http\Middleware\Web\Localization::class,
            'localization.api' => \Jawabapp\Localization\Http\Middleware\Api\Localization::class,
        ]);
    })
    ->withExceptions(function (Exceptions $exceptions): void {
        //
    })->create();

For Laravel 10 and earlier, add the middleware to your app/Http/Kernel.php:

protected $middlewareGroups = [
    'web' => [
        // ... other middleware
        \Jawabapp\Localization\Http\Middleware\Web\Localization::class,
    ],

    'api' => [
        // ... other middleware
        \Jawabapp\Localization\Http\Middleware\Api\Localization::class,
    ],
];

4. Setup Route Prefixes

Update your App\Providers\RouteServiceProvider.php:

use Jawabapp\Localization\Libraries\Localization;

public function boot(): void
{
    // Web routes with locale prefix
    Route::prefix(Localization::routePrefix())
        ->middleware('web')
        ->group(base_path('routes/web.php'));
}

5. Access the Admin Interface

Visit /localization in your browser to manage translations!

πŸ—ƒοΈ Database-Driven Translations

The package automatically uses database-driven translations with file fallback. This means:

  • βœ… Primary: Translations are loaded from the database first
  • βœ… Fallback: If database is unavailable, files are used automatically
  • βœ… Performance: Results are cached for optimal performance
  • βœ… Flexibility: You can disable database translations if needed

Configuration

Control database translations in config/localization.php:

'database_translations' => [
    'enabled' => true, // Enable database translations
    'fallback_to_files' => true, // Fallback to file translations if database fails
],

How It Works

  1. Translation Request: When you call __('messages.welcome') or trans('auth.failed')
  2. Database Check: Package checks the database for the translation first
  3. File Fallback: If not found in database, loads from lang/ files
  4. Caching: Results are cached to avoid repeated database queries
  5. Admin Interface: Manage all translations through the web interface at /localization

Automatic Setup

The database translation system is automatically configured when you install the package:

  • πŸ”§ Auto-Discovery: Laravel automatically registers the TranslationServiceProvider
  • πŸ”„ Seamless Integration: Replaces Laravel's default translator with our enhanced version
  • πŸ“Š No Code Changes: Your existing __() and trans() calls work unchanged
  • πŸ›‘οΈ Safe Fallback: If database fails, translations load from files automatically

Disabling Database Translations

To use only file-based translations, set in your config:

'database_translations' => [
    'enabled' => false, // Disable database translations - use files only
],

βš™οΈ Configuration

The main configuration file is published to config/localization.php:

<?php

return [
    // Supported locales
    'supported_locales' => ['en', 'ar', 'es', 'fr', 'de'],

    // Locale detection
    'detect_browser_locale' => true,
    'store_in_session' => true,
    'store_in_cookie' => true,

    // URL configuration
    'url' => [
        'hide_default' => true, // Hide default locale in URLs
        'force_locale_in_url' => false,
    ],

    // Cache settings
    'cache' => [
        'enabled' => true,
        'duration' => 60 * 24, // 24 hours
    ],

    // Translation groups
    'translation_groups' => [
        'auth', 'validation', 'general', 'messages'
    ],
];

Available Locales

The package comes pre-configured with these locales:

Code Language Native Name
en English English
ar Arabic Ψ§Ω„ΨΉΨ±Ψ¨ΩŠΨ©
es Spanish EspaΓ±ol
fr French FranΓ§ais
de German Deutsch
it Italian Italiano
pt Portuguese PortuguΓͺs
ru Russian Русский
zh Chinese δΈ­ζ–‡
ja Japanese ζ—₯本θͺž
ko Korean ν•œκ΅­μ–΄
tr Turkish TΓΌrkΓ§e

πŸ“– Usage Guide

Basic Translation Management

Use Laravel's built-in translation functions:

// In controllers or views
echo __('messages.welcome');
echo trans('auth.failed');
echo trans_choice('messages.items', 5);

// With parameters
echo __('messages.hello', ['name' => 'John']);

Dynamic Locale Switching

use Jawabapp\Localization\Libraries\Localization;

// Set locale programmatically
Localization::setLocale('fr');

// Get current locale
$locale = app()->getLocale();

// Get all supported locales
$locales = Localization::getSupportedLocales();

// Get locale native name
$name = Localization::getLocaleName('ar'); // Returns: Ψ§Ω„ΨΉΨ±Ψ¨ΩŠΨ©

Working with Localized Routes

Create routes that automatically work with all locales:

Route::localized(function ($locale) {
    Route::get('/', [HomeController::class, 'index'])->name('home');
    Route::get('/about', [AboutController::class, 'index'])->name('about');
    Route::get('/products', [ProductController::class, 'index'])->name('products');
});

Generate localized URLs:

// Current locale URL
$url = route('products');

// Specific locale URL
$url = Route::localizedUrl('products', 'fr');

// Get all locale URLs for hreflang tags
$alternateUrls = Localization::getAlternateUrls();

Model Integration

For models with translatable fields, use the _key suffix:

class Post extends Model
{
    protected $fillable = ['title_key', 'content_key', 'slug'];

    // Accessors for translated content
    public function getTitleAttribute()
    {
        return $this->title_key ? __($this->title_key) : '';
    }

    public function getContentAttribute()
    {
        return $this->content_key ? __($this->content_key) : '';
    }
}

// Usage
$post = Post::create([
    'title_key' => 'My Blog Post Title',
    'content_key' => 'This is the blog post content...',
    'slug' => 'my-blog-post'
]);

πŸŽ›οΈ Admin Interface

Access the admin interface at /localization to:

Translation Management

  • βœ… View all translations by language and group
  • βœ… Add, edit, and delete translations
  • βœ… Search and filter translations
  • βœ… Bulk operations (delete, export)
  • βœ… Visual translation status indicators

Import/Export Tools

  • βœ… Export translations to PHP/JSON files
  • βœ… Import from existing language files
  • βœ… Sync translations between locales
  • βœ… Translation statistics and completion rates

Features

  • πŸ“± Responsive Design: Works perfectly on mobile and desktop
  • 🎨 Modern UI: Beautiful Tailwind CSS interface
  • ⚑ Real-time Updates: Live search and filtering
  • πŸ”„ Batch Operations: Handle multiple translations at once

πŸ”§ Artisan Commands

The package includes powerful CLI commands:

Export Translations

# Export all translations
php artisan localization:export

# Export specific locale
php artisan localization:export --locale=fr

# Export specific group
php artisan localization:export --locale=en --group=auth

# Export only JSON format
php artisan localization:export --format=json

Import Translations

# Import all translations from files
php artisan localization:import

# Import specific locale
php artisan localization:import --locale=fr

# Overwrite existing translations
php artisan localization:import --overwrite

Sync Between Locales

# Sync missing translations from English to French
php artisan localization:sync --from=en --to=fr --missing-only

# Copy all translations (overwrite existing)
php artisan localization:sync --from=en --to=de --overwrite

Cache Management

# Clear translation cache
php artisan localization:clear-cache

# Clear cache for specific locale
php artisan localization:clear-cache --locale=fr

🌐 API Usage

The package provides full API support with intelligent locale detection:

Request Headers

# Custom headers
curl -H "X-Localization: fr" /api/endpoint
curl -H "X-Locale: es" /api/endpoint

# Standard Accept-Language header
curl -H "Accept-Language: fr,en;q=0.8" /api/endpoint

Query Parameters

curl /api/endpoint?locale=fr

Response Headers

The API middleware automatically adds:

  • Content-Language: fr header to responses
  • Proper locale detection from multiple sources

πŸ—‚οΈ File Structure

The package supports Laravel's modern language directory structure:

lang/
β”œβ”€β”€ en/
β”‚   β”œβ”€β”€ auth.php
β”‚   β”œβ”€β”€ validation.php
β”‚   └── messages.php
β”œβ”€β”€ fr/
β”‚   β”œβ”€β”€ auth.php
β”‚   └── validation.php
β”œβ”€β”€ ar/
β”‚   └── messages.php
β”œβ”€β”€ en.json
β”œβ”€β”€ fr.json
└── ar.json

File Types

  • PHP Files (lang/{locale}/group.php): Structured translations with nested arrays
  • JSON Files (lang/{locale}.json): Simple key-value translations

πŸ” SEO Features

Automatic Hreflang Tags

Add to your layout:

@foreach(Localization::getAlternateUrls() as $locale => $url)
    <link rel="alternate" hreflang="{{ $locale }}" href="{{ $url }}" />
@endforeach

Localized URLs

// Generates: /en/products or /products (if default)
Route::get('/products', [ProductController::class, 'index'])->name('products');

⚑ Performance Optimization

Caching

Translations are automatically cached:

// Cache keys:
// localization.{locale} - All translations for locale
// localization.{locale}.{group} - Specific group translations

Static File Export

Export to static files for optimal performance:

php artisan localization:export

Static files load faster than database queries and are automatically cached by Laravel.

πŸ”§ Advanced Configuration

Custom Database Connection

'database' => [
    'connection' => 'translations_db',
    'table' => 'app_translations',
],

Custom Translation Groups

'translation_groups' => [
    'auth', 'validation', 'emails',
    'custom_module', 'product_catalog'
],

Middleware Configuration

'routes' => [
    'enabled' => true,
    'prefix' => 'admin/localization', // Custom admin path
    'middleware' => ['web', 'auth', 'admin'],
],

πŸ“š Examples

Complete Laravel Application Setup

  1. Install and Configure:
composer require jawabapp/localization
php artisan vendor:publish --tag=localization-config
php artisan migrate
  1. Create Localized Routes:
// routes/web.php
Route::localized(function ($locale) {
    Route::get('/', function () {
        return view('welcome');
    })->name('home');

    Route::get('/products', function () {
        return view('products.index');
    })->name('products');

    Route::get('/contact', function () {
        return view('contact');
    })->name('contact');
});
  1. Add Language Switcher:
<!-- resources/views/layouts/app.blade.php -->
<div class="language-switcher">
    @foreach(Localization::getSupportedLocales() as $locale)
        <a href="{{ Route::localizedUrl(Route::currentRouteName(), $locale) }}"
           class="{{ app()->getLocale() === $locale ? 'active' : '' }}">
            {{ Localization::getLocaleName($locale) }}
        </a>
    @endforeach
</div>
  1. Use Translations in Views:
<!-- resources/views/welcome.blade.php -->
<h1>{{ __('messages.welcome') }}</h1>
<p>{{ __('messages.description', ['app' => config('app.name')]) }}</p>

API Integration

// app/Http/Controllers/Api/ProductController.php
class ProductController extends Controller
{
    public function index(Request $request)
    {
        // Locale is automatically set by middleware
        $locale = app()->getLocale();

        $products = Product::select([
            'id', 'name_key', 'description_key', 'price'
        ])->get()->map(function ($product) {
            return [
                'id' => $product->id,
                'name' => __($product->name_key),
                'description' => __($product->description_key),
                'price' => $product->price,
            ];
        });

        return response()->json($products);
    }
}

πŸ› Troubleshooting

Common Issues

1. Translations not loading

# Clear cache and regenerate
php artisan localization:clear-cache
php artisan localization:export

2. Middleware not working (Laravel 11)

// Ensure middleware is registered in bootstrap/app.php
$middleware->alias([
    'localization' => \Jawabapp\Localization\Http\Middleware\Web\Localization::class,
]);

2b. Middleware not working (Laravel 10 and earlier)

// Ensure middleware is registered in Kernel.php
\Jawabapp\Localization\Http\Middleware\Web\Localization::class,

3. Routes not found

// Make sure RouteServiceProvider is configured
Route::prefix(Localization::routePrefix())
    ->middleware('web')
    ->group(base_path('routes/web.php'));

4. Admin interface 404

# Check if routes are enabled
'routes' => ['enabled' => true]

5. "Call to a member function total() on array" error

# This error occurs when the layout expects paginated data but receives an array
# The fix is included in the updated controller - no action needed for users

6. "Class Jawabapp\Localization\Libraries\Localization not found" error

# This error occurs when trying to update translations
# The fix is included in the updated controller - no action needed for users

7. Export functionality not working

# If Artisan commands don't work from web interface, try from command line:
php artisan localization:export

# The web interface now includes direct export functionality as fallback

8. "SQLSTATE[23000]: Integrity constraint violation: 19 NOT NULL constraint failed: translations.key"

# This occurs when translation key parsing fails
# Ensure your translations have proper namespace, group, and key structure
# The updated controller handles this automatically

Debug Mode

Enable debug logging:

'fallback' => [
    'log_missing' => env('APP_DEBUG', false),
],

Performance Issues

# Enable caching
php artisan config:cache

# Export translations to static files
php artisan localization:export

πŸ”„ Upgrading from v1.x

The package uses a new database schema:

  1. Backup translations:
php artisan localization:export
  1. Run migration:
php artisan migrate
  1. Verify data: The migration automatically converts language_code β†’ locale and extracts groups from keys.

🀝 Contributing

We welcome contributions! Please see CONTRIBUTING.md for details.

Development Setup

# Clone repository
git clone https://github.com/jawabapp/localization
cd localization

# Install dependencies
composer install
npm install

# Run tests
composer test

πŸ” Security

If you discover security vulnerabilities, please email i.qanah@gmail.com instead of using the issue tracker.

πŸ“œ License

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

πŸ‘¨β€πŸ’» Credits

🌟 Support

Made with ❀️ for the Laravel community

Documentation β€’ Report Bug β€’ Request Feature