aurawindsurfing/google-translate
Laravel integration for Google Translate. Translate text between languages from your PHP app with a simple, configurable wrapper, service provider and facade support, and an easy setup for localizing content and dynamic strings.
1. Install and confirm compatibility first.
composer require aurawindsurfing/google-translate
Before writing any code, open vendor/aurawindsurfing/google-translate/composer.json and read the require block. The last release was December 2021, so the illuminate/support constraint almost certainly stops at Laravel 8. If you are on Laravel 9/10/11, either bump the constraint in a fork ("illuminate/support": "^9.0|^10.0|^11.0"), or vendor the single client class into app/Services/. This is the decision that determines whether the rest of this assessment applies to you.
2. Publish the config and set the key.
php artisan vendor:publish --provider="Aurawindsurfing\GoogleTranslate\GoogleTranslateServiceProvider"
(The exact --tag/provider string is worth grepping — grep -r "publishes" vendor/aurawindsurfing/google-translate/src.) Then in .env:
GOOGLE_TRANSLATE_API_KEY=AIza...
This is a Google Cloud Translation API v2 key, created in the Google Cloud Console with the Cloud Translation API enabled and billing attached to the project. The word "free" in the package description means the package is free — the API itself is metered per character (~$20 per million characters). Set a budget alert and a quota cap on the key on day one.
3. First use case: translate one string.
use Aurawindsurfing\GoogleTranslate\Facades\GoogleTranslate;
$text = GoogleTranslate::translate('Hello world', 'es'); // target language
Grep the src/ directory for public function to get the real method names — most packages in this space expose something close to translate(string $text, string $target, ?string $source = null) plus detect() and languages(). Read the facade and the client class (typically src/GoogleTranslate.php); it is likely 200–400 lines and you can understand all of it in ten minutes.
4. Where to look first, in order: the client class (the whole API surface), the config file (key name, endpoint, timeout), the service provider (is the client a singleton? is it bound to an interface?), and the README (2021-era READMEs often omit error handling entirely).
Wrap it — don't call the facade everywhere. Because this package is small and unmaintained, treat it as a thin HTTP adapter and put your own interface in front of it:
interface Translator { public function translate(string $text, string $target, ?string $source = null): string; }
final class GoogleTranslator implements Translator
{
public function __construct(private \Aurawindsurfing\GoogleTranslate\GoogleTranslate $client) {}
public function translate(string $text, string $target, ?string $source = null): string
{
return $this->client->translate($text, $target, $source);
}
}
Bind Translator to GoogleTranslator in a service provider. When the package finally breaks, you swap one binding instead of editing fifty call sites — and you can add caching, retries, and placeholder masking in exactly one place.
Cache aggressively; it is the single biggest cost lever.
$key = 'gt:' . md5($source . '>' . $target . '|' . $text);
return Cache::remember($key, now()->addMonths(6), fn () => $this->client->translate($text, $target, $source));
Translations are deterministic for a given input, so a long TTL is safe. Use a persistent store (Redis/database), not array, and make sure config('cache.prefix') is set so multiple apps sharing a Redis instance don't collide.
Translate lang files via an artisan command, not at request time. For UI strings, the natural workflow is a bespoke command:
// app/Console/Commands/TranslateLangCommand.php
foreach (Lang::get('en') as $key => $value) { /* recurse nested arrays */ }
Read lang/en/*.php, translate only keys missing from lang/{target}/, and write the result back with var_export() so the files stay diff-friendly in git. Commit the generated files. This keeps the API out of the request path entirely, makes translation reviewable in PRs, and means a quota exhaustion event can't take down your site.
Batch where the API allows it. Translation v2 accepts an array of q values (up to ~128 segments per request). If the package exposes a bulk/array variant, use it: it cuts latency and request count dramatically. If it doesn't, either loop (simple, more requests) or extend the class — most such clients build the payload in one spot and adding q[] support is a five-line change.
Queue bulk work. Wrap backfills in a job with $timeout, $tries = 3, and backoff() of [10, 60, 300]. Dispatch one job per file/section so a single 429 doesn't discard a 5,000-string run.
Mask placeholders before sending. Google will happily translate :attribute or mangle %s/{name}. Replace them with opaque tokens (__PH1__) before the call and restore after. A regex over /:(\w+)|%[sd]|\{\w+\}/ covers most Laravel message strings.
Localize locale codes. Laravel uses pt_BR/zh_CN; Google wants pt-BR/zh-CN. Do the conversion in your wrapper (str_replace('_', '-', $locale)), and keep a small map for cases Google abbreviates (pt-BR → pt, en_GB → en).
?key= in the query string; v3 requires OAuth2/service-account bearer tokens. This package targets v2. If your key is restricted by HTTP referrer, server-side calls will 403 — use IP address restrictions or no restriction plus a server-side proxy.' for apostrophes and " for quotes. Run results through html_entity_decode($text, ENT_QUOTES, 'UTF-8') or your Spanish looks like Está bien, 'gracias'. This is the most common "the package is broken" report and it never is.source = null on every call means Google auto-detects each time — slower and occasionally wrong on short strings. Detect on your longest sample and pass the code explicitly thereafter.config:cache and env. The key is read from config('google-translate.api_key'). If your service provider reads env() directly (common in 2021 packages), php artisan config:cache will silently give you null. Verify by running php artisan config:cache && php artisan tinker and dumping the config value.GuzzleHttp\Client directly, Http::fake() does nothing — you'll get real network calls in CI. Either bind a fake Translator in the container for feature tests, or inject a mock GuzzleHttp\ClientInterface if the constructor allows it. The absence of an injectable client is a strong reason to write your own adapter.dailyLimitExceeded (quota), 403 with usageLimits / billing disabled, and 429 on bursts. Catch and classify in your wrapper; retry only 429/5xx. Never retry a 403 — you'll just burn the same quota faster.composer update is more likely to remove the package (constraint conflict) than to upgrade it. "aurawindsurfing/google-translate": "1.0.*" in require is safer than an open constraint.Verdict: usable as a reference implementation of the Translation v2 endpoint, but not something to build a production dependency strategy on. Read the client, port ~150 lines into app/Services/GoogleTranslator.php behind your own interface, and you get the same functionality with a maintainable upgrade path, real error handling, caching, and Laravel 11 support.
How can I help you explore Laravel packages today?