minhyung/laravel-translator

Unified translation services (DeepL, Google Cloud Translation, ...) for Laravel.

Maintainers

Package info

github.com/overworks/laravel-translator

pkg:composer/minhyung/laravel-translator

Statistics

Installs: 0

Dependents: 0

Suggesters: 0

Stars: 0

Open Issues: 0

0.1.0 2026-06-29 13:04 UTC

This package is auto-updated.

Last update: 2026-06-29 15:01:11 UTC


README

Latest Version on Packagist Tests Total Downloads License

English | 한국어

A Laravel package that puts multiple translation services (DeepL, Google Cloud Translation, LLMs, ...) behind one unified API. It is built on Laravel's standard Manager/Driver pattern, so drivers are easy to add or swap, and it ships with translation-result caching out of the box.

Supported drivers: DeepL, Google Cloud Translation (v2), and LLM (powered by Prism — OpenAI/Anthropic/Gemini, etc.).

Requirements

  • PHP ^8.3
  • Laravel 12 / 13 (illuminate/support: ^12.0|^13.0)

The Google driver uses Translation API v2 and works with an API key alone — no service-account credentials or the ext-grpc PECL extension required.

Installation

composer require minhyung/laravel-translator

Publish the config file (optional):

php artisan vendor:publish --tag=translator-config

Configuration

In config/translator.php or your .env:

TRANSLATOR_DRIVER=deepl        # default driver: deepl | google | openai | anthropic | ...

# DeepL
DEEPL_AUTH_KEY=xxxxxxxx:fx

# Google Cloud Translation (v2, API key)
GOOGLE_TRANSLATE_KEY=AIza...

# LLM (Prism) — default model for openai
TRANSLATOR_LLM_MODEL=gpt-4o-mini

# Caching
TRANSLATOR_CACHE=true
TRANSLATOR_CACHE_STORE=          # empty = the application's default store
TRANSLATOR_CACHE_TTL=86400       # seconds; empty = cache forever

LLM translation uses Prism. Provider API keys and the like are managed in Prism's own config (config/prism.php). Batch translation uses structured output to guarantee one in-order result per input, and throws if the counts don't match.

LLM providers (register as many as you like)

Any driver name that is not a built-in (deepl, google, fallback) is treated as a Prism LLM driver. In other words, the key in the drivers array is the Prism provider name, and each entry just needs a model (plus optional options). This is handy for registering several LLM providers and dropping them into a failover chain.

// config/translator.php
'drivers' => [
    'openai'    => ['model' => 'gpt-4o-mini'],
    'anthropic' => ['model' => 'claude-3-5-sonnet-latest'],
    'gemini'    => ['model' => 'gemini-2.0-flash'],

    // Use the key as an alias by pointing 'provider' at the real Prism provider
    'claude'    => ['provider' => 'anthropic', 'model' => 'claude-3-5-sonnet-latest'],
],
Translator::driver('anthropic')->translate('Hello', 'ko'); // result's ->driver is "anthropic"

Usage

Single translation

use Minhyung\LaravelTranslator\Facades\Translator;

$result = Translator::translate('Hello, world!', 'ko');

$result->text;               // "안녕하세요, 여러분!"
$result->detectedSourceLang; // "en"
$result->driver;             // "deepl"
(string) $result;            // the translated text (Stringable)

Specify the source language and pass options:

Translator::translate('How are you?', 'de', 'en', ['formality' => 'less']);

Batch translation (keys and order preserved)

$results = Translator::translateBatch(
    ['greeting' => 'Hello', 'farewell' => 'Goodbye'],
    'ko',
);

$results['greeting']->text; // "안녕하세요"
$results['farewell']->text; // "안녕히 가세요"

Selecting a driver

Translator::driver('google')->translate('Hello', 'ko');

// LLM driver — options can be passed per call
Translator::driver('openai')->translate('Hello', 'ko', 'en', [
    'temperature'   => 0.0,
    'system_prompt' => 'Translate from {source} into {target}. Keep it formal.',
]);

Dependency injection

The Translator contract is bound to the default driver.

use Minhyung\LaravelTranslator\Contracts\Translator;

public function __construct(private Translator $translator) {}

Caching

When translator.cache.enabled is on, every driver is wrapped in a CachingTranslator. Identical inputs (text · source/target language · options) are served straight from the Laravel cache, cutting API calls and cost. For batch translation, only the cache misses are sent to the provider in a single call.

Failover

To automatically switch to the next provider when one fails, use the fallback driver. It tries each driver in the listed order and moves on to the next whenever a driver throws.

// config/translator.php
'default' => 'fallback',

'drivers' => [
    // Freely combine multiple LLM providers
    'anthropic' => ['model' => 'claude-3-5-sonnet-latest'],
    'gemini'    => ['model' => 'gemini-2.0-flash'],

    'fallback' => [
        'drivers' => ['deepl', 'anthropic', 'gemini'],
    ],
],
Translator::translate('Hello', 'ko'); // if deepl fails, try anthropic → gemini in order
  • Each child driver is cached individually (the fallback itself is not cached, to avoid double caching), and every fallback attempt is logged at warning level via a PSR logger.
  • If every driver fails, an AllTranslationDriversFailedException is thrown; use getErrors() to get the underlying exception per driver.

Extending with a custom driver

Implement Contracts\Translator and register it on the manager.

use Minhyung\LaravelTranslator\TranslatorManager;

app(TranslatorManager::class)->extend('papago', function ($app) {
    return new \App\Translation\PapagoTranslator(/* ... */);
});

Testing

composer install
vendor/bin/pest

License

MIT