Weave Code
Weaver
Helps Laravel developers discover, compare, and choose open-source packages. See popularity, security, maintainers, and scores at a glance to make better decisions.
Feedback
Share your thoughts, report bugs, or suggest improvements.
Subject
Message

Laravel Auto Translation Laravel Package

vildanbina/laravel-auto-translation

Automatically translate Laravel model attributes and language files with a simple trait. Supports multiple drivers like Google, DeepL, and OpenAI, plus caching and queues for fast, seamless multilingual applications.

View on GitHub
Deep Wiki
Context7

Getting Started

What this release is: 2.2.2 is a compatibility patch — the only change is Laravel 13 support (illuminate/* ^13 added to the constraint set). No API changes, no deprecations. Upgrading from 2.2.1 on Laravel 10–12 is a no-op.

Version to require:

composer require vildanbina/laravel-auto-translation:^2.2.2

On Laravel 13 you must be on 2.2.2 or later — earlier releases will fail Composer resolution against illuminate/support ^13. Confirm the PHP floor for your Laravel version (Laravel 13 requires PHP 8.3+) before bumping the framework.

Setup order:

  1. Install and publish config:
    php artisan vendor:publish --tag="auto-translation-config"
    
  2. Open config/auto-translation.php first — it is the whole package. Everything (driver, source/target locales, queue behaviour, enable flag) is decided there.
  3. Set env vars:
    AUTO_TRANSLATION_ENABLED=true
    AUTO_TRANSLATION_DRIVER=google   # google | deepl | openai | ...
    AUTO_TRANSLATION_API_KEY=...
    
  4. Read src/Drivers/ (one class per provider) and src/Contracts/ (the interface a custom driver implements) before writing model code — the contract tells you the supported options per provider.
  5. php artisan list auto-translation — the package registers commands for bulk/backfill translation.

First use case — translate a Product on save:

use Illuminate\Database\Eloquent\Model;
use Vildanbina\AutoTranslation\Concerns\HasAutoTranslation;
use Vildanbina\AutoTranslation\Contracts\AutoTranslatable;

class Product extends Model implements AutoTranslatable
{
    use HasAutoTranslation;

    // Attributes the package should translate (check HasAutoTranslation
    // for the exact hook name in your installed version — it is the
    // single method to override).
    protected array $translatable = ['name', 'description'];
}

Create a Product with name set in your source locale, then inspect the raw attributes ($product->getRawOriginal('name') or your translations table) to confirm the target locales were populated. If nothing happened, the model is not resolving as AutoTranslatable, or AUTO_TRANSLATION_ENABLED is false in that environment.

Implementation Patterns

Sync on save vs. queued. Inline translation blocks the HTTP request for the duration of N API calls (locales × attributes). For anything user-facing, move it to the queue:

// config/auto-translation.php
'queue' => [
    'enabled' => true,
    'connection' => 'redis',
    'queue' => 'translations',
],

Run a dedicated worker so a slow/rate-limited provider can't starve your default queue.

Only translate what changed. The expensive mistake is re-translating the whole model on every save() when only price changed:

public function shouldAutoTranslate(): bool
{
    return $this->isDirty(['name', 'description'])
        && app()->getLocale() === config('app.fallback_locale');
}

Gate on dirty source attributes and skip when the target locale already has a value, otherwise editing a typo in name re-bills the translation of description.

Backfill existing rows. After adding the trait, existing records have no translations. Use the package command for the bulk pass, then chunk with a rate-limited job:

Product::query()->whereNull('name->es')->chunkById(200, function ($products) {
    foreach ($products as $product) {
        TranslateProductJob::dispatch($product)->onQueue('translations');
    }
});

Add ->middleware(new RateLimited('translations')) to respect provider quotas rather than getting 429s mid-run.

Custom / self-hosted provider. Implement the driver contract in src/Contracts/, register it in the drivers map in config, then point AUTO_TRANSLATION_DRIVER at your key. This is the cleanest way to use an internal translation service, a LibreTranslate instance, or a mocked driver for local dev.

Hook into completion. Use the package's events (grep src/Events/) to purge cache, reindex in Scout, or notify an editor — don't pollute the model with that logic:

Event::listen(TranslationCompleted::class, fn ($e) => Cache::forget("product:{$e->model->id}"));

Testing. Never let tests hit a real API:

<!-- phpunit.xml -->
<env name="AUTO_TRANSLATION_ENABLED" value="false"/>

Then add targeted tests that re-enable it and fake the transport with Http::fake() per driver endpoint, asserting the outgoing payload contains the source text and the expected target locale. Keep one integration test per driver — provider request shapes drift.

CI. If you support Laravel 13, add it to the matrix now; the patch only permits the install, it doesn't prove your app's other dependencies are L13-ready.

Gotchas and Tips

Save-loop recursion. Translating inside saving and then persisting causes re-entry. The package guards against this internally in most paths, but any custom listener that calls $model->save() after translation will loop. Use saveQuietly() in your own hooks.

Source locale detection is the #1 cause of garbage output. The package sends "whatever is in the attribute" with a declared source. If app.locale and app.fallback_locale disagree, or a user saves while browsing es, you'll translate Spanish → Spanish. Explicitly pin the source locale in config and consider blocking writes from non-source locales.

Payload limits. Google caps around 5k characters per request; DeepL caps the number of texts per call. A long description HTML field silently truncates or 413s. Chunk long attributes and strip/restore markup deliberately — HTML tags often come back mangled or reordered.

Don't machine-translate everything. Slugs, SKUs, unique columns, enum values, JSON blobs, and email templates should be excluded. Machine-translated slugs break URLs and analytics; translated unique columns will collide.

Cost control. Every call is billable and non-deterministic. Cache aggressively, keyed on (attribute, source_hash, target_locale) so a retry or a reseed doesn't re-bill. Log token/character counts per job and alert on daily spend.

Rate limiting and retries. Configure backoff and maxExceptions on the translation job; providers return 429 with Retry-After. Retrying immediately burns your quota and leaves half-translated models — make the job idempotent (re-check for existing target values on retry).

Secrets in logs. Failed HTTP requests often log the full payload + Authorization header. Ensure your translation queue's exception handler redacts the API key; use a dedicated log channel at info level at most.

Localisation of the translation itself. OpenAI-family drivers accept extra instructions (tone, formality, glossary). DeepL has formality and glossaries. These are per-driver config keys — read the driver class rather than guessing, and prefer glossaries over prompt tweaks for brand terminology.

Extension points, in order of usefulness: custom driver → events → config knobs. Avoid subclassing the service provider; it's not a documented seam and will break on minor bumps.

Debugging checklist when a model won't translate: (1) implements AutoTranslatable and use HasAutoTranslation; (2) attribute listed in the translatable set; (3) AUTO_TRANSLATION_ENABLED true in that environment (Horizon workers inherit a different env than your web dyno surprisingly often); (4) queue worker running on the translations queue; (5) API key valid and provider not out of credits — a 401/402 usually surfaces as a failed job, not an exception in the UI.

Weaver

How can I help you explore Laravel packages today?

Conversation history is not saved when not logged in.
Prompt
Add packages to context
No packages found.
shitoudev/permissionmanager
johannesclimacus/laravel-tui
hocvt/seotools
vitalybaev/sypexgeo
amphibee/themosis-ignition
gito-me/fast-excel
frankyso/laravel-ipaymu
geolize-studio/laravel-chile
boomerangui/chat
jinas/dhivatar
store-doc/laravel-storage-driver
plus-it/laravel-translation-manager
diephp/perhaps
diephp/telegraph
osmaviation/spreadsheet
microsoft/fluentui-system-icons
mmccook/php-json-canonicalization-scheme
middlewares/firewall
qubiqx/montapacking
nyoncode/laravel-package-console