tonydev / lara-glot
Smart Auto-Translation for Laravel Models with JSON/HTML support
Requires
- php: ^8.2
- illuminate/database: ^11.0|^12.0|^13.0
- illuminate/support: ^11.0|^12.0|^13.0
- stichoza/google-translate-php: ^5.3
README
Smart Auto-Translation for Laravel Models, Language Files & Nested Content
LaraGlot is an industrial-strength translation pipeline for Laravel applications. It intelligently translates:
- Eloquent models
- Nested JSON structures
- Filament Page Builder sections
- Static PHP language files
- SEO metadata
- Rich HTML content
β¦while protecting placeholders, HTML, IDs, slugs, application logic, and structural data from being corrupted by translation engines or LLMs.
Built for modern Laravel applications, LaraGlot combines:
- Queue-based background processing
- Smart recursive traversal
- Multi-layer caching
- AI-powered translation drivers
- Filament admin tooling
- Retry & timeout protection
- Batch translation optimization
Table of Contents
- Requirements
- Installation
- Configuration
- Driver Architecture
- Model Setup
- Language File Translation
- Queue Setup & Timeouts
- Artisan Commands
- Filament Integration
- Caching Strategy
- Architecture
- Service Responsibilities
- Logging & Monitoring
- Failure Recovery
- Performance Optimizations
- License
Requirements
| Requirement | Version |
|---|---|
| PHP | ^8.1 |
| Laravel | ^10.0 | ^11.0 |
| Filament | ^3.0 |
| spatie/laravel-translatable | ^6.0 |
Installation
composer require tonydev/lara-glot
Publish the Config
php artisan vendor:publish --tag=lara-glot-config
Register the Commands
Laravel 10
Register commands inside app/Console/Kernel.php:
protected $commands = [ \Tonydev\LaraGlot\Commands\TranslateFilesCommand::class, \Tonydev\LaraGlot\Commands\DispatchTranslations::class, ];
Laravel 11
Register commands inside bootstrap/app.php:
->withCommands([ \Tonydev\LaraGlot\Commands\TranslateFilesCommand::class, \Tonydev\LaraGlot\Commands\DispatchTranslations::class, ])
Configuration
After publishing, open:
config/lara-glot.php
Example configuration:
return [ /* |-------------------------------------------------------------------------- | Source Locale |-------------------------------------------------------------------------- */ 'source_locale' => 'en', /* |-------------------------------------------------------------------------- | Translation Driver |-------------------------------------------------------------------------- | Supported: | - openai | - google | - deepl | - ollama */ 'translator' => env('LARAGLOT_DRIVER', 'openai'), /* |-------------------------------------------------------------------------- | Registered Models |-------------------------------------------------------------------------- */ 'models' => [ \App\Models\Page::class, \App\Models\Post::class, ], /* |-------------------------------------------------------------------------- | Target Languages |-------------------------------------------------------------------------- */ 'languages' => [ 'es' => ['name' => 'EspaΓ±ol', 'flag' => 'πͺπΈ'], 'fr' => ['name' => 'FranΓ§ais', 'flag' => 'π«π·'], 'de' => ['name' => 'Deutsch', 'flag' => 'π©πͺ'], 'ak' => ['name' => 'Twi', 'flag' => 'π¬π'], 'pt' => ['name' => 'PortuguΓͺs', 'flag' => 'π§π·'], 'ar' => ['name' => 'Ψ§ΩΨΉΨ±Ψ¨ΩΨ©', 'flag' => 'πΈπ¦'], ], /* |-------------------------------------------------------------------------- | Ignored Structural Keys |-------------------------------------------------------------------------- | Keys that should NEVER be translated. */ 'ignored_keys' => [ 'id', 'uuid', 'slug', 'url', 'image', 'icon', 'sort_order', 'layout_type', 'created_at', 'updated_at', 'color', 'is_active', ], /* |-------------------------------------------------------------------------- | Excluded Language Files |-------------------------------------------------------------------------- */ 'exclude_files' => [ 'auth', 'pagination', 'passwords', 'validation', ], /* |-------------------------------------------------------------------------- | Queue Name |-------------------------------------------------------------------------- */ 'queue' => 'translations', /* |-------------------------------------------------------------------------- | Cache Expiry |-------------------------------------------------------------------------- | Default: 30 days */ 'cache_expiry' => 2592000, ];
Driver Architecture
LaraGlot is driver-agnostic and supports both traditional translation engines and modern AI/LLM providers.
Supported Drivers
| Driver | Purpose |
|---|---|
openai |
AI-powered contextual translations |
google |
Fast traditional translations |
deepl |
High-quality professional translations |
ollama |
Local/self-hosted LLM translation |
OpenAI Driver (Recommended)
The OpenAI driver is optimized for large-scale translation workloads.
Features
- JSON-mode batch translation
- Chunked translation pipelines
- Concurrent processing
- Retry handling
- API timeout protection
- Structured response validation
Batch Optimization
Instead of translating one string at a time:
[
"title" => "Welcome",
"button" => "Read More",
"footer" => "Contact Us",
]
LaraGlot sends grouped translation chunks to dramatically reduce:
- API requests
- latency
- token usage
- overall cost
Google / DeepL Drivers
Traditional translation APIs optimized for:
- speed
- consistency
- lower latency
- deterministic outputs
Ideal for applications needing high-volume static translations.
Ollama Driver
Run translations entirely locally using self-hosted LLMs.
Perfect for:
- private deployments
- air-gapped systems
- sensitive data
- cost reduction
Model Setup
LaraGlot works alongside spatie/laravel-translatable.
1. Add the Traits
namespace App\Models; use Illuminate\Database\Eloquent\Model; use Spatie\Translatable\HasTranslations; use Tonydev\LaraGlot\Traits\HasSmartTranslations; class Page extends Model { use HasTranslations, HasSmartTranslations; public array $translatable = [ 'title', 'content', 'meta_title', 'meta_description', ]; public function getTranslatableAttributes(): array { return $this->translatable; } }
2. Page Builder & Recursive Translation
LaraGlot automatically detects nested structures and recursively traverses them.
Example:
class Page extends Model { use HasTranslations, HasSmartTranslations; public function sections(): HasMany { return $this->hasMany(PageSection::class) ->orderBy('sort_order'); } }
What Gets Translated?
LaraGlot intelligently translates:
β
Nested arrays
β
JSON blocks
β
Builder content
β
Rich text HTML
β
{ "en": "..." } language maps
β
Repeater blocks
β
Filament Builder sections
What Gets Ignored?
Structural/system keys are automatically skipped:
[
'id',
'slug',
'url',
'image',
'layout_type',
'sort_order',
]
This prevents corruption of application logic and relationships.
3. SEO Auto-Population
If a model contains a title but empty SEO fields:
meta_title meta_description
LaraGlot automatically pre-fills them from the English title before translation.
This guarantees multilingual SEO completeness even when editors forget metadata.
Language File Translation
LaraGlot translates:
lang/en/*.php
into every configured locale.
Placeholder Protection
Laravel placeholders are protected before sending content to the translator.
Input
'hello' => 'Hello :name'
Protected API Payload
Hello <span translate="no">:name</span>
Final Output
'hello' => 'Bonjour :name'
This prevents engines from corrupting placeholders into invalid variants.
Pluralization Support
Pipe-delimited plural strings are translated segment-by-segment.
Input
'items' => '{0} No items|[1,19] :count items|[20,*] :count items (bulk)'
Output
'items' => '{0} Aucun article|[1,19] :count articles|[20,*] :count articles (en vrac)'
PHP Array Preservation
Files are:
- flattened via
Arr::dot - translated safely
- rebuilt recursively
- saved using short-array syntax
Output is written to:
lang/{locale}/{file}.php
Directories are created automatically if missing.
Queue Setup & Timeouts
LaraGlot dispatches heavy translation work onto Laravel queues.
This keeps:
- web requests fast
- Filament responsive
- admin actions non-blocking
Start a Queue Worker
php artisan queue:work --queue=translations,default
Recommended production command:
php artisan queue:work \
--queue=translations,default \
--timeout=620 \
--tries=3
Cascading Timeout Strategy
Because AI providers can be slow, LaraGlot uses layered timeout protection.
| Layer | Setting | Default |
|---|---|---|
| Queue Job | $timeout |
600s |
| Concurrent Worker | Concurrency::timeout() |
300s |
| HTTP Request | Http::timeout() |
120s |
This prevents:
- hanging workers
- zombie jobs
- stalled queue pipelines
Supervisor Configuration
[program:laraglot-worker] process_name=%(program_name)s_%(process_num)02d command=php /var/www/html/artisan queue:work redis --queue=translations,default --timeout=620 --tries=3 autostart=true autorestart=true numprocs=2 redirect_stderr=true stdout_logfile=/var/log/supervisor/laraglot-worker.log
Job Retry Behaviour
| Setting | Value |
|---|---|
$tries |
3 |
backoff() |
[30, 60, 120] |
| Model Timeout | 600s |
| File Timeout | 300s |
If providers rate-limit requests, LaraGlot retries automatically with progressive delays.
Artisan Commands
laraglot:sync
Translate database models.
Process All Models
php artisan laraglot:sync
Process One Model
php artisan laraglot:sync "App\Models\Page"
Force Re-Translation
php artisan laraglot:sync --force
Force Specific Model
php artisan laraglot:sync "App\Models\Post" --force
Internal Optimizations
The sync command uses:
chunkById(100)
to safely process very large tables without memory exhaustion.
laraglot:files
Translate PHP language files.
Translate Everything
php artisan laraglot:files
Single File
php artisan laraglot:files messages
Single Locale
php artisan laraglot:files --locale=fr
Force Overwrite
php artisan laraglot:files --force
Run Synchronously
Useful for CI pipelines:
php artisan laraglot:files --sync
Combined Example
php artisan laraglot:files messages --locale=es --force --sync
Filament Integration
LaraGlot ships with a full Filament admin interface.
Default route:
/admin/lara-glot-manager
LaraGlot Manager Features
1. Multi-File Selection
Choose one or many language files simultaneously.
2. AI Translation Preview
Synchronously translate a file and preview the output before saving.
Features:
- side-by-side diff table
- editable translations
- manual correction support
- save reviewed output
3. Queue Dispatching
Bulk-send translations to the background queue without waiting.
Perfect for:
- production deployments
- large multilingual sites
- mass content updates
4. Force Overwrite Toggle
Control whether existing translations should be replaced.
5. Sync All Files
Header action that dispatches:
every file Γ every locale
combination automatically.
6. Force Re-Translate All
Rebuild your entire translation set from scratch.
Useful when:
- changing AI providers
- improving prompts
- updating source English content
Resource Table Actions
Add translation buttons directly to your Filament resources.
use Filament\Tables; use Tonydev\LaraGlot\Jobs\TranslateModelJob; public static function table(Table $table): Table { return $table ->actions([ Tables\Actions\Action::make('translate') ->label('Translate') ->icon('heroicon-m-language') ->color('warning') ->requiresConfirmation() ->action(fn ($record) => TranslateModelJob::dispatch( get_class($record), $record->getKey(), true )->onQueue(config('lara-glot.queue'))), ]) ->bulkActions([ Tables\Actions\BulkAction::make('translate_selected') ->label('Translate Selected') ->icon('heroicon-m-language') ->requiresConfirmation() ->action(fn ($records) => $records->each( fn ($record) => TranslateModelJob::dispatch( get_class($record), $record->getKey(), true )->onQueue(config('lara-glot.queue')) )), ]); }
Caching Strategy
LaraGlot uses a two-layer cache architecture to minimize API usage.
Layer 1 β RAM Cache
Per-request in-memory storage:
$localCache
If the same string appears multiple times during one translation job, LaraGlot instantly reuses the result.
Layer 2 β Persistent Cache
Stored using Laravel's cache driver:
- Redis
- File
- Memcached
- Database
Cache key format:
lara-glot.translation.{hash}
Where {hash} is:
md5(locale + source_string)
Cache Expiry
Default:
2592000 // 30 days
Configurable via:
cache_expiry
Force Cache Busting
Passing:
--force
or enabling Force Overwrite:
- clears cached entries
- forces fresh API translations
Architecture
LaraGlot
βββ Commands
β βββ TranslateFilesCommand
β βββ DispatchTranslations
β
βββ Jobs
β βββ TranslateFilesJob
β βββ TranslateModelJob
β
βββ Drivers
β βββ OpenAiDriver
β βββ GoogleDriver
β βββ DeepLDriver
β βββ OllamaDriver
β βββ AbstractDriver
β
βββ Services
β βββ TranslationService
β βββ FileTranslationService
β βββ SmartTranslationService
β
βββ Traits
β βββ HasSmartTranslations
β
βββ Filament
βββ Pages
βββ LaraGlotManager
Service Responsibilities
TranslationService
Core translation engine.
Responsibilities:
- API communication
- caching
- batching
- retries
- chunking
- timeout handling
- force refresh logic
FileTranslationService
Handles PHP language files.
Responsibilities:
- file parsing
Arr::dotflattening- placeholder masking
- pluralization handling
- nested array rebuilding
SmartTranslationService
Recursive model translator.
Responsibilities:
- nested JSON traversal
- Filament Builder recursion
- SEO auto-population
- change detection
- HTML chunking
- structural key skipping
Logging & Monitoring
All activity is logged to:
storage/logs/laravel.log
Log Events
| Emoji | Message | Meaning |
|---|---|---|
| π | Translation Job Started | Worker picked up the job |
| βοΈ | Skipping Existing Translation | Translation already exists |
| π | Translating Chunk | Active API request |
| β | Translation Completed | Successfully saved |
| β οΈ | Model Not Found | Record deleted before execution |
| β | API Error | Provider failure / timeout |
Failure Recovery
Failed jobs are stored in Laravel's failed_jobs table.
Inspect failures:
php artisan queue:failed
Retry one job:
php artisan queue:retry {id}
Retry everything:
php artisan queue:retry all
Performance Optimizations
LaraGlot is heavily optimized for large-scale applications.
Smart Chunking
Large HTML content is automatically split into manageable chunks before translation.
Prevents:
- token overflow
- API payload failures
- malformed responses
Concurrent Translation
Multiple chunks can be translated simultaneously for significant speed improvements.
Change Detection
LaraGlot detects whether source English content has changed before re-translating.
This avoids:
- unnecessary API usage
- duplicate translations
- wasted queue time
Translation Deduplication
If the same phrase appears across:
- Pages
- Posts
- Products
- Language files
β¦the cached translation is reused globally.
License
The MIT License (MIT).
Copyright Β© 2026 Tonydev.
Built with β€οΈ for the Laravel community.