- How is symfony/translation different from Laravel's built-in translator?
- Laravel ships illuminate/translation, which was historically derived from this component but has long since diverged: it loads PHP arrays and JSON, uses :name placeholders plus a legacy MessageSelector for plurals, and exposes __() and Lang::get(). symfony/translation adds ICU MessageFormat, XLIFF, PO, YAML, CSV, INI and Qt loaders, a different MessageCatalogue model, and translation-provider adapters for Crowdin, Lokalise and Phrase. Adding it to Laravel creates two parallel i18n stacks unless you deliberately pick one; it does not replace Laravel's translator automatically.
- How do I install symfony/translation in a Laravel application?
- Run composer require symfony/translation:^7.4 alongside Laravel — there are no namespace or autoload collisions. You then wire a Translator instance yourself in a service provider, registering the loaders and formatters that Symfony's FrameworkBundle would normally configure for you. Install ext-intl for ICU formatting and symfony/yaml if you load YAML files; symfony/console and symfony/dependency-injection are only needed for the provider pull/push commands.
- Can I use symfony/translation side by side with Laravel's __() helper?
- Yes, and this is the lowest-risk option: bind a Symfony Translator as a separate container singleton and use it only for a bounded domain such as transactional emails, API error catalogues, or ICU plural strings. It never touches Illuminate\Contracts\Translation\Translator, so Laravel's __() and Lang::get() keep working exactly as before. The tradeoff is that locale state must be kept in sync manually, because App::setLocale() and Translator::setLocale() will otherwise drift.
- How do I use ICU plurals and gender select with symfony/translation in Laravel?
- ICU formatting lives in the IntlFormatter and requires ext-intl; you opt into it explicitly when constructing the Translator with a MessageFormatter. That gives you {count, plural, ...}, select and gender syntax that Laravel's MessageSelector does not support. Be aware that existing :count strings will produce different output for locales with complex plural rules such as pl, ru and ar, so migrate per locale with regression fixtures rather than spot checks.
- Which PHP and Laravel versions does symfony/translation support?
- The component follows Symfony's release cadence with parallel 6.4, 7.4, 8.0 and 8.1 branches. Pin ^7.4 (LTS, PHP 8.2+) as the safest match for typical Laravel deployments, and treat ^8 as a deliberate later migration because Symfony 8.x requires PHP 8.4 or newer. The package is framework-agnostic, so your Laravel version matters far less than your PHP floor.
- How do I load Laravel lang files (lang/{locale}/*.php and JSON) into Symfony Translator?
- Symfony expects domain.locale.format resources such as messages.fr.yaml, while Laravel uses lang/{locale}/{file}.php plus lang/{locale}.json. The cleanest options are a small custom loader that reads Laravel's PHP arrays into a MessageCatalogue, or a build step that compiles your lang directory into Symfony catalogues. Handle Laravel's JSON-key fallback explicitly, since Symfony's catalogue model does not mirror it.
- Can I replace Laravel's translator with Symfony's Translator via an adapter?
- It is technically possible: implement Illuminate\Contracts\Translation\Translator backed by Symfony's engine and rebind it in a service provider. The hard part is fidelity — you must reproduce get(), choice(), has(), getLocale()/setLocale(), getSelector(), package::file.key namespacing, JSON fallback and :placeholder replacement. A wholesale swap of illuminate/translation is not recommended, because validation, pagination, auth, password resets and mail notifications all resolve messages through that contract, so framework error output breaks first.
- How should I test translations when using symfony/translation in Laravel?
- Instantiate a Translator in your tests the same way your service provider does, load fixture catalogues per locale, and assert exact output strings. Build a per-locale regression fixture set covering complex plural rules in pl, ru and ar before migrating any :count strings to ICU. Also assert that App::setLocale() and Translator::setLocale() agree, since locale drift between the two stacks is the most likely silent production bug.
- Is it safe to load third-party XLIFF files with symfony/translation?
- Treat third-party XLIFF as untrusted input. XLIFF loading pulls in libxml and needs entity-loading hardening — the component has shipped fixes such as XliffUtils::shouldEnableEntityLoader for exactly this scenario. Keep the entity loader disabled unless you genuinely need it, and validate or vendor translation files before loading them at runtime.
- Does symfony/translation integrate with Crowdin, Lokalise, or Phrase?
- Yes. The component ships translation-provider adapters for Crowdin, Lokalise and Phrase with pull and push console commands, which is functionality Laravel does not offer out of the box. Those commands need symfony/console and symfony/dependency-injection wired up in your application. In a Laravel codebase you would typically wrap the provider services in custom Artisan commands rather than register the Symfony console application.