Pricing comparison
Real pricing based on monthly character volume. All prices in USD.
| Volume | Google Translate | DeepL | Langbly | You Save |
|---|---|---|---|---|
| 500K chars/mo | $0 | Check live plan | $0 | Both included/evaluation |
| 1M chars/mo | $10 | Check live plan | $2.50 | 75% vs Google |
| 5M chars/mo | $90 | Check live plan | $22.50 | 75% vs Google |
| 25M chars/mo | $490 | Check live plan | $122.50 | 75% vs Google |
| 100M chars/mo | $1,990 | Above Growth limit | $497.50 | 75% vs Google |
Feature comparison
| Feature | Google Translate | DeepL | Langbly |
|---|---|---|---|
| Composer package | google/cloud-translate | deeplcom/deepl-php | langbly/langbly-php |
| Install command | composer require google/cloud-translate | composer require deeplcom/deepl-php | composer require langbly/langbly-php |
| Auth method | Service account JSON | API key string | API key string |
| Lines of code to translate | 7–9 lines | 3 lines | 3 lines |
| Works with plain Guzzle or Http facade | Needs OAuth token | ||
| Auto-retry on 429 and 5xx | Manual | Manual | Built-in |
| Typed exception classes | Google exceptions | DeepLException | RateLimitException, AuthenticationException |
| Retry-After support | |||
| Batch translate in one call | |||
| HTML-safe translation | |||
| Google v2 compatible | |||
| Languages | 100+ | 30+ | 100+ |
| Published usage rate | $20/1M after 500K | Check live Growth plan | $5/1M after 500K |
| Included/evaluation usage | 500K/mo | Developer: 1M total | 500K/mo |
| Translation quality | NMT | NMT + AI | Next-gen AI |
| Context-aware | Limited |
PHP translation APIs compared: the actual code
Marketing pages all sound the same. Code does not. Here is what it takes to translate one string in PHP with each provider.
Google Translate (google/cloud-translate):
<?php
require 'vendor/autoload.php';
use Google\Cloud\Translate\V2\TranslateClient;
putenv('GOOGLE_APPLICATION_CREDENTIALS=/path/to/service-account.json');
$translate = new TranslateClient();
$result = $translate->translate('Hello world', [
'target' => 'nl',
]);
echo $result['text']; // Hallo wereld
Before that snippet runs you need a Google Cloud project, the Translation API enabled, a billing account attached, a service account, and a JSON key file sitting somewhere your deploy pipeline can reach. Shipping a credentials file to production is its own small project.
DeepL (deeplcom/deepl-php):
<?php
require 'vendor/autoload.php';
$translator = new \DeepL\Translator('your-api-key');
$result = $translator->translateText('Hello world', null, 'NL');
echo $result->text;
Langbly (langbly/langbly-php):
<?php
require 'vendor/autoload.php';
$client = new \Langbly\Client('your-api-key');
$result = $client->translate('Hello world', 'nl');
echo $result->text; // Hallo wereld
echo $result->source; // en
The Langbly package needs PHP 7.4 or newer and Guzzle 7, nothing else. Install it with composer require langbly/langbly-php, pass a key string, done. It also takes an array of strings for batch calls, exposes detect() and languages(), and retries 429 and 5xx responses with exponential backoff while respecting the Retry-After header. You do not write that loop yourself.
One more thing worth knowing before you pick: Langbly is a drop-in replacement for the Google Translate v2 API. Same request shape, same response shape. If you already have Google calls scattered through a legacy PHP codebase, you swap the base URL and the auth header and the rest of your code keeps working.
POST https://api.langbly.com/language/translate/v2
Authorization: Bearer YOUR_API_KEY
Content-Type: application/json
{"q": "Hello world", "target": "nl"}
{
"data": {
"translations": [
{
"translatedText": "Hallo wereld",
"detectedSourceLanguage": "en"
}
]
}
}Laravel integration: a service class you can actually ship
Most Laravel apps do not need an SDK at all. The HTTP client that ships with the framework is enough, and it keeps your dependency list short. Start with config, never with a hardcoded key.
// config/services.php
'langbly' => [
'key' => env('LANGBLY_API_KEY'),
'url' => env('LANGBLY_URL', 'https://api.langbly.com'),
],
Then a small service class. It returns a plain string, throws on failure, and stays easy to fake in tests.
<?php
namespace App\Services;
use Illuminate\Support\Facades\Http;
class Translator
{
public function translate(
string $text,
string $target,
?string $source = null,
string $format = 'text'
): string {
$response = Http::withToken(config('services.langbly.key'))
->acceptJson()
->timeout(30)
->post(config('services.langbly.url') . '/language/translate/v2', array_filter([
'q' => $text,
'target' => $target,
'source' => $source,
'format' => $format,
]))
->throw();
return $response->json('data.translations.0.translatedText');
}
}
Bind it as a singleton if you want constructor injection everywhere:
// app/Providers/AppServiceProvider.php
public function register(): void
{
$this->app->singleton(\App\Services\Translator::class);
}
Now any controller, command, or job can type-hint Translator and get a working client. Because the endpoint follows the Google v2 contract, Http::fake() stubs written against Google responses keep passing without edits.
Prefer the SDK? Bind that instead and get retries and typed exceptions for free:
use Langbly\Client as LangblyClient;
$this->app->singleton(LangblyClient::class, fn () =>
new LangblyClient(config('services.langbly.key'))
);
For EU data residency, point the client at new LangblyClient($key, 'https://eu.langbly.com'). Translation processing and temporary storage stay in the EU.
Queued jobs and caching: translating without blocking a request
Translating inside a web request is a trap. A page with forty strings turns into forty round trips, and your p95 goes through the roof. Push it onto the queue.
<?php
namespace App\Jobs;
use App\Models\Post;
use App\Services\Translator;
use Illuminate\Bus\Queueable;
use Illuminate\Contracts\Queue\ShouldQueue;
use Illuminate\Foundation\Bus\Dispatchable;
use Illuminate\Queue\InteractsWithQueue;
use Illuminate\Queue\SerializesModels;
class TranslatePost implements ShouldQueue
{
use Dispatchable, InteractsWithQueue, Queueable, SerializesModels;
public int $tries = 3;
/** Seconds to wait between attempts. */
public array $backoff = [10, 60, 300];
public function __construct(
public Post $post,
public string $locale,
) {
}
public function handle(Translator $translator): void
{
$this->post->translations()->updateOrCreate(
['locale' => $this->locale],
[
'title' => $translator->translate($this->post->title, $this->locale, 'en'),
'body' => $translator->translate($this->post->body, $this->locale, 'en', 'html'),
],
);
}
}
Dispatch it from an observer or a controller and move on: TranslatePost::dispatch($post, 'nl');. Note the html format on the body field. Markup and attributes are left alone, only the visible text gets translated, so your links and classes survive the trip.
The other half of the bill is repetition. UI strings, product categories, error messages, and email subjects repeat constantly. Cache them and you stop paying for the same sentence twice.
use Illuminate\Support\Facades\Cache;
public function cached(string $text, string $target): string
{
$key = 'translation:' . $target . ':' . sha1($text);
return Cache::remember(
$key,
now()->addDays(30),
fn () => $this->translate($text, $target)
);
}
Google and Langbly both include the first 500,000 characters each month. Langbly requires payment details to activate API access and charges $5 per million additional input characters with no base fee. DeepL Developer includes one million characters in total; check the live Growth plan for recurring use.
Frequently asked questions
What is the best translation API for PHP?
For most PHP teams, Langbly gives the best balance: a Composer package that installs in seconds, plain API key auth, built-in retries, and $5 per million characters. DeepL is a strong choice if you only translate a handful of European languages. Google Translate has broad coverage but the heaviest setup, since every call needs a service account and a credentials file.
How do I translate text in Laravel?
The simplest path is the built-in HTTP client. Call Http::withToken(config('services.langbly.key'))->post('https://api.langbly.com/language/translate/v2', ['q' => $text, 'target' => 'nl']) and read data.translations.0.translatedText from the JSON response. Wrap that in a small service class, bind it as a singleton, and dispatch it from a queued job so translation never blocks a web request.
Is there an official Langbly PHP SDK?
Yes. Install it with composer require langbly/langbly-php. It requires PHP 7.4 or newer and Guzzle 7, supports single and batch translation, language detection, HTML format, automatic retries with exponential backoff on 429 and 5xx responses, and typed exceptions such as RateLimitException and AuthenticationException.
Is the Google Translate API free for PHP developers?
Google Cloud Translation includes the first 500,000 characters each month, then charges $20 per million for standard NMT. Langbly also includes the first 500,000 input characters each month and charges $5 per million additional input characters. DeepL Developer includes one million characters in total; check the live Growth plan for recurring use.
Can I switch from Google Translate to Langbly without rewriting my PHP code?
In most cases yes. Langbly is a drop-in replacement for the Google Translate v2 API, so the request body and the response JSON are identical. Point your existing calls at https://api.langbly.com/language/translate/v2, send Authorization: Bearer YOUR_API_KEY instead of a Google OAuth token, and delete the service account file. Existing parsing code and Http::fake() test stubs keep working.