maximepinot/google-translate-command-bundle
Symfony bundle providing console commands to automatically translate translation files via the Google Translate API. Configure your API credentials and target locales, then run the command to generate translated message catalogs.
composer require maximepinot/google-translate-command-bundle
If you're on Symfony Flex the bundle usually registers itself; otherwise add it to config/bundles.php:
MaximePinot\GoogleTranslateCommandBundle\GoogleTranslateCommandBundle::class => ['all' => true],
Next, get a Google Cloud Translation API key (enable Cloud Translation API in a GCP project, create an API key or service-account credential), then add a config file:
# config/packages/google_translate_command.yaml
google_translate_command:
api_key: '%env(GOOGLE_TRANSLATE_API_KEY)%'
Store the key in .env.local (never commit it). Then discover the actual command name — the bundle exposes a single console command, so:
bin/console list | grep -i trans
You'll find something like translation:translate / trans:translate. Your first use case is the obvious one: take your canonical source file (e.g. translations/messages.en.yaml) and produce/refresh a target locale from it.
bin/console translation:translate
Before running it for real, commit your current translations/ directory so you can review the diff — the command writes into your existing translation files.
Source-of-truth → fan-out workflow. Treat one locale (usually en) as the golden source. Write keys there by hand, commit, then run the command to propagate into the other locales. The typical loop is:
messages.en.yaml.git diff translations/ and review/spot-fix the machine output.bin/console lint:translation (or debug:translation --only-missing) to confirm key parity.Only-translate-missing behaviour. Most versions of this bundle skip keys already present in the target file, which is what you want day-to-day: it makes the command idempotent and safe to re-run. This means editing an existing English string won't retranslate it automatically — delete the stale target key first (or script a diff-and-remove step) and re-run.
One locale at a time in CI/dev. Rather than regenerating every locale on every PR, generate for the locales you actively ship (say fr, de) and keep machine output in a dedicated commit ("chore: sync translations"). Reviewing a diff that touches eight locales at once is where QA pain starts.
Pair it with a manual-override layer. Keep machine output in one place and hand-tuned strings (marketing copy, legal, placeholders with brand names) in a separate file or in a later-merged override, depending on your file layout. In YAML with multiple messages.<locale>.yaml files, Symfony merges them — so you can let the command own a generated file and keep curated strings in a hand-maintained one that takes precedence.
Local dev loop. Point the bundle at a disposable copy first (check whether the config exposes a target directory you can redirect), so you can iterate on placeholder escaping without dirtying your real translation files. Once output looks right, let it write to translations/ directly.
CI gating. Run a lint:translation step on PRs to fail when a source key is missing from a locale; run the Google Translate command only on a scheduled/nightly job (or manually) so you don't spend API budget on every push.
%name%, {{ var }}, :count, {count}, HTML tags, or ICU plural syntax are frequent casualties — Google will happily translate or reorder them. Always diff generated output and prefer keeping such strings out of the automatic run (or verify placeholder preservation on a test locale first).git diff is your review surface and your undo button.bin/console debug:config google_translate_command and list rather than trusting a README that may predate your Symfony version. Pin the version in composer.json.pt-BR vs pt_BR vs pt). Run with -vvv to see HTTP errors.en_GB directory may map oddly. Keep a mapping or standardise on tags Google recognises.How can I help you explore Laravel packages today?