lukasccb / laravel-ai-translations
Scan, manage, and AI-translate __() strings stored in the database for Laravel applications.
Package info
github.com/LukasCCB/laravel-ai-translations
pkg:composer/lukasccb/laravel-ai-translations
Requires
- php: ^8.2
- illuminate/cache: ^11.0||^12.0||^13.0
- illuminate/console: ^11.0||^12.0||^13.0
- illuminate/contracts: ^11.0||^12.0||^13.0
- illuminate/database: ^11.0||^12.0||^13.0
- illuminate/queue: ^11.0||^12.0||^13.0
- illuminate/support: ^11.0||^12.0||^13.0
- illuminate/translation: ^11.0||^12.0||^13.0
Requires (Dev)
- laravel/pint: ^1.0
- orchestra/testbench: ^9.0||^10.0||^11.0
- phpunit/phpunit: ^11.0||^12.0
- prism-php/prism: ^0.1||^1.0
Suggests
- prism-php/prism: Required for AI-powered translations (translations:start command)
README
A Laravel package that automatically scans your codebase for __() translation strings, stores them in the database, and translates them to any language using AI — powered by Prism.
What It Does
Instead of manually maintaining JSON/PHP translation files for every language, this package:
- Scans your entire codebase (Blade, PHP, JS, Vue) for
__(),trans(),@lang(), andLang::get()calls - Stores every unique string in a
translationsdatabase table - Translates all strings to any target language using AI (OpenAI, Anthropic, etc. via Prism)
- Serves translations at runtime by hooking into Laravel's translation system — zero code changes needed
Your existing __('Hello World') calls just work. No file management, no copy-pasting, no manual editing.
Benefits
- Zero migration effort — works with any existing Laravel app that uses
__()strings - Database-driven — all translations live in one table, easy to query, export, or edit
- AI-powered — translate hundreds of strings to any language in minutes, not days
- Case-sensitive — distinguishes between "paid" and "Paid" as separate entries
- Database column scanning — also picks up translatable strings stored in your database tables
- Cached — translations are cached per locale with configurable TTL
- Auto-invalidation — cache clears automatically when translations are created, updated, or deleted
- Pluggable AI — swap the default Prism translator for any provider via a simple interface
- 24 languages included out of the box (en, pt, es, fr, de, it, nl, ru, zh, and more)
Requirements
- PHP 8.2+
- Laravel 11, 12, or 13
- MySQL (recommended, for case-sensitive collation) or SQLite/PostgreSQL
- Prism (optional — only needed for AI translation commands)
Installation
1. Install the package
composer require lukasccb/laravel-ai-translations
The service provider is auto-discovered. No manual registration needed.
2. Publish the config and migration
php artisan vendor:publish --tag=ai-translations-config php artisan vendor:publish --tag=ai-translations-migrations
3. Run the migration
php artisan migrate
4. (Optional) Install Prism for AI translations
composer require prism-php/prism
Configuration
After publishing, edit config/translation.php:
return [ // The source language of your project 'source_language' => 'en_US', // Default batch size for AI translation runs 'batch_size' => env('TRANSLATION_BATCH_SIZE', 500), // Directories and file types to scan 'scan' => [ 'paths' => [ resource_path('views'), app_path(), base_path('lang'), resource_path('js'), ], 'extensions' => ['php', 'blade.php', 'js', 'vue'], 'exclude' => [ base_path('vendor'), base_path('node_modules'), // ... ], ], // Database columns that contain translatable strings (read-only) 'database_scan' => [ 'roles' => ['name', 'description'], 'settings' => [ 'column' => 'value', 'filter_by' => 'key', 'filter_values' => ['site_description', 'meta_title'], ], ], // AI translator class (implements TranslatorInterface) 'translator' => \LukasCCB\AiTranslations\Translators\PrismTranslator::class, // AI provider settings (used by PrismTranslator) 'ai' => [ 'provider' => env('TRANSLATION_AI_PROVIDER', 'openai'), 'model' => env('TRANSLATION_AI_MODEL', 'gpt-4o-mini'), 'max_tokens' => env('TRANSLATION_AI_MAX_TOKENS', 500), ], // Cache TTL in seconds (0 = disabled) 'cache_ttl' => env('TRANSLATION_CACHE_TTL', 3600), // Custom locale resolver for the SetLocale middleware (null = use session) 'locale_resolver' => null, ];
Add these to your .env:
TRANSLATION_AI_PROVIDER=openai TRANSLATION_AI_MODEL=gpt-4o-mini TRANSLATION_BATCH_SIZE=500 TRANSLATION_CACHE_TTL=3600
Usage
Step 1: Scan your codebase
php artisan translations:scan
This will:
- Find every
__(),trans(),@lang(), andLang::get()call in your project - Extract translatable strings from configured database columns
- Insert new strings into the
translationstable (source language) - Automatically clean up orphaned strings that no longer exist in the codebase
Options:
# Custom batch size for DB insertion php artisan translations:scan --batch=200 # Force mode: re-insert and delete obsolete records php artisan translations:scan --force
Step 2: Translate to a target language
php artisan translations:start --lang=pt_BR --alias="Portugues (Brasil)"
This sends each source string to the configured AI provider and stores the translation.
Options:
# Limit how many strings to translate in one run php artisan translations:start --lang=pt_BR --alias="Portugues (Brasil)" --batch=100 # Re-translate everything, even already translated strings php artisan translations:start --lang=pt_BR --alias="Portugues (Brasil)" --force
Step 3: Auto-translate all languages
If you have multiple target languages already registered:
php artisan translations:auto-translate
This finds all languages with at least one record and translates any missing strings.
Cleanup orphaned strings
php artisan translations:cleanup
Removes translation records (across all languages) for strings that no longer exist in your codebase. This is also called automatically before every scan.
Middleware
Register the SetLocale middleware to automatically set the application locale per request:
// bootstrap/app.php (Laravel 11+) ->withMiddleware(function (Middleware $middleware) { $middleware->web(append: [ \LukasCCB\AiTranslations\Middleware\SetLocale::class, ]); })
By default, it reads from session('locale') and falls back to the configured source_language. You can customize this with a locale resolver:
// config/translation.php 'locale_resolver' => function (\Illuminate\Http\Request $request): ?string { return $request->user()?->preferred_locale; },
Dispatching Translations via Queue
For long-running translation batches, use the built-in job:
use LukasCCB\AiTranslations\Jobs\TranslateLanguageJob; TranslateLanguageJob::dispatch( lang: 'es_ES', alias: 'Espanol (Espana)', batch: 200, force: false, );
Custom AI Translator
The package uses TranslatorInterface to decouple from any specific AI provider. To use your own:
1. Implement the interface
<?php declare(strict_types=1); namespace App\Translators; use LukasCCB\AiTranslations\Contracts\TranslatorInterface; class MyCustomTranslator implements TranslatorInterface { public function translate(string $text, string $targetLanguage, string $targetAlias): string { // Call your preferred API (DeepL, Google, custom LLM, etc.) $response = MyTranslationApi::translate($text, $targetLanguage); return $response->translatedText; } }
2. Register it in config
// config/translation.php 'translator' => \App\Translators\MyCustomTranslator::class,
That's it. The translations:start and translations:auto-translate commands will use your implementation.
Database Column Scanning
You can scan database columns for translatable content (e.g., role names, setting values). The package reads these columns but never modifies the original tables.
// config/translation.php 'database_scan' => [ // Simple: scan all rows in these columns 'roles' => ['name', 'description'], 'categories' => ['title'], // Filtered: only scan specific rows 'settings' => [ 'column' => 'value', 'filter_by' => 'key', 'filter_values' => ['site_title', 'site_description'], ], ],
How It Works Under the Hood
__('Hello World')
|
v
Laravel Translator calls load($locale, '*', '*')
|
v
DatabaseTranslationLoader intercepts raw-string group
|
v
TranslationResolverService loads from DB (cached)
|
v
Returns ['Hello World' => 'Ola Mundo'] for pt_BR
|
v
User sees "Ola Mundo"
The package extends Laravel's default FileLoader with a DatabaseTranslationLoader that intercepts raw-string translation calls (namespace='*', group='*') and serves them from the database. File-based translations (validation.required, etc.) continue to work normally.
Source language behavior
- Source language (e.g., en_US): Returns ALL non-null
translatedvalues, regardless ofis_translated. This lets you customize display text (e.g., "Liquid Balance" to "Available Balance") without breaking defaults. - Other locales: Only returns strings where
is_translated = true. Untranslated strings are not served to avoid showing placeholder text.
Available Commands
| Command | Description |
|---|---|
translations:scan |
Scan codebase and DB columns for __() strings |
translations:cleanup |
Remove orphaned strings no longer in codebase |
translations:start |
Translate source strings to a target language via AI |
translations:auto-translate |
Translate all untranslated strings for all registered languages |
Supported Languages
The package ships with 24 pre-defined languages in resources/language-support.json:
| Code | Language |
|---|---|
| en_US | English (United States) |
| en_GB | English (United Kingdom) |
| pt_BR | Portugues (Brasil) |
| pt_PT | Portugues (Portugal) |
| es_ES | Espanol (Espana) |
| es_MX | Espanol (Mexico) |
| fr_FR | Francais (France) |
| de_DE | Deutsch (Deutschland) |
| it_IT | Italiano (Italia) |
| nl_NL | Nederlands (Nederland) |
| ru_RU | Russian |
| uk_UA | Ukrainian |
| pl_PL | Polski (Polska) |
| tr_TR | Turkce (Turkiye) |
| sv_SE | Svenska (Sverige) |
| no_NO | Norsk (Norge) |
| da_DK | Dansk (Danmark) |
| fi_FI | Suomi (Suomi) |
| cs_CZ | Cestina (Cesko) |
| ro_RO | Romana (Romania) |
| hu_HU | Magyar (Magyarorszag) |
| el_GR | Greek |
| zh_CN | Chinese (Simplified) |
| zh_TW | Chinese (Traditional) |
You can translate to any language — this list is just a reference. Pass any ISO locale code to translations:start.
Testing
composer test
Full Example: From Zero to Translated
# 1. Install composer require lukasccb/laravel-ai-translations composer require prism-php/prism # 2. Publish and migrate php artisan vendor:publish --tag=ai-translations-config php artisan vendor:publish --tag=ai-translations-migrations php artisan migrate # 3. Configure AI provider in .env # TRANSLATION_AI_PROVIDER=openai # TRANSLATION_AI_MODEL=gpt-4o-mini # 4. Scan your project php artisan translations:scan # 5. Translate to Portuguese php artisan translations:start --lang=pt_BR --alias="Portugues (Brasil)" # 6. Translate to Spanish php artisan translations:start --lang=es_ES --alias="Espanol (Espana)" # 7. Done! Your __() calls now return translated strings # based on the user's locale.
License
The MIT License (MIT). Please see License File for more information.
