Weave Code
Weaver
Helps Laravel developers discover, compare, and choose open-source packages. See popularity, security, maintainers, and scores at a glance to make better decisions.
Feedback
Share your thoughts, report bugs, or suggest improvements.
Subject
Message

Ux Translator Laravel Package

symfony/ux-translator

Symfony UX Translator brings Symfony's translation system to JavaScript. Translate messages in JS with ICU MessageFormat support, share catalogs between frontend and backend, and keep strings consistent across your entire Symfony app without duplication.

View on GitHub
Deep Wiki
Context7

Getting Started

symfony/ux-translator is the Symfony UX package that gives JavaScript access to your server-side translations via a global trans() function, plus console tooling to extract and dump message catalogs into JSON for the front-end. It is not a Laravel package: it ships as a Symfony bundle and depends on Symfony's Translation contracts, Twig, and (optionally) AssetMapper. A Laravel developer will get the most value from it in one of two situations: (a) you maintain a Symfony/UX front-end alongside a Laravel API, or (b) you want its extraction/dump model as a reference for wiring your own lang/*.json → Vite pipeline.

Minimal path:

  1. composer require symfony/ux-translator (v3.6.0 is a patch release — a drop-in from 3.5.x).
  2. Enable the bundle (config/bundles.php) and, if you want the JS runtime auto-wired, have AssetMapper or Webpack Encore present.
  3. Set the dump directory in config/packages/ux_translator.yaml:
    ux_translator:
        dump_directory: '%kernel.project_dir%/assets/translations'
    
  4. Run php bin/console ux:translator:extract and check assets/translations/ for the generated messages+intl-icu.<locale>.json.
  5. First real use case: extract every {{ 'checkout.title'|trans }} from Twig plus trans('checkout.title') from JS into one catalog, import it in your entrypoint, and call trans('checkout.title') from a Stimulus controller.

Look first at config/packages/ux_translator.yaml, the generated dump directory, and the two console commands (ux:translator:extract, ux:translator:warm-cache) — they are the entire day-to-day surface area.

Implementation Patterns

Build-time extraction, not request-time. Treat the extract command as a build step, not something a developer runs ad hoc. Wire it into composer.json scripts or CI so the dumped catalogs are always in sync with the templates:

"scripts": {
  "translations": [
    "@php bin/console ux:translator:extract --force"
  ],
  "post-install-cmd": ["@translations"]
}

Run extraction before your asset build so the JSON files exist when the bundler resolves the import.

Dump directory + AssetMapper registration. As of 3.6.0 the configured dump directory is properly registered with AssetMapper, so the generated translations/*.json files are importable by logical path (import { trans } from 'translations/messages+intl-icu.en.json') without extra paths config. Previously you often had to add a manual paths entry pointing at the dump dir — if you have such a workaround, try removing it after upgrading.

Deploy-time cache warming. ux:translator:warm-cache pre-populates the translator so the first request after a deploy doesn't pay the catalog-parsing cost. Put it next to cache:clear in your deploy script. 3.6.0 fixed this command writing empty translations, so re-run it after upgrading — stale empty files from older versions can survive a deploy and will silently render blank labels.

Translating in JS with ICU params. Use the Intl variant catalog (messages+intl-icu.<locale>.json) if you need {count, plural, ...}. Parameters are passed as the second argument and HTML-escaped by default; reach for trans(..., {}, 'raw') only for trusted strings.

Laravel-side integration tip. If you're only after the extraction behaviour (finding __() / trans() keys across templates and emitting JSON), you can run this package's extractor in a standalone Symfony console app inside the same monorepo as your Laravel app, dumping into resources/js/lang/. That keeps your Laravel translation loading untouched while giving you a single source of truth for JS catalogs.

Watch the AssetMapper version pairing. 3.6.0 declares a conflict with symfony/asset-mapper 8.2+, so composer will hold AssetMapper below 8.2. If you're on a bleeding-edge AssetMapper, expect the solver to downgrade it — pin deliberately rather than letting an unrelated composer update surprise you.

Gotchas and Tips

  • This is a patch release. No BC breaks, no new features, no deprecations. Upgrade is low-risk; the only behavioural changes are bug fixes, and two of them (escaping, warm-cache) change generated output — so regenerate and diff your dump directory rather than trusting a clean composer update.
  • Escaped translation IDs (3.6.0 fix). IDs containing quotes or backslashes are now fully escaped in the generated JSON. If you had hand-patched or excluded keys with apostrophes, you can drop the workaround — but expect a diff in the dumped files.
  • Empty translations after warm-cache were a real trap. Prior versions could write empty strings into the cache. Symptom: translations work in dev, render as blank or as the raw key in prod after a deploy. Clear the cache dir and re-warm once after upgrading.
  • Container build without a dump directory. If dump_directory is unset, 3.6.0 now still dumps translation files at container-build time. If you relied on the old "nothing is dumped unless configured" behaviour, check whether files are now appearing in an unexpected location.
  • Debugging dumps. When trans() returns the key instead of the message, compare in this order: (1) is the key present in the dumped JSON? (2) is the dump directory actually imported in your entrypoint? (3) is the locale file the one the runtime requested? Nearly every "translations don't work" report is step 1 — a stale dump.
  • Escape hatch for custom lookups. The domain/locale arguments of trans() map straight onto Symfony's translator domains, so you can register a custom loader or translator decorator and the JS runtime picks it up without changes. That's the extension point to use if your catalogs come from a database or a Laravel-side translation API.
  • Don't confuse the two trans functions. The JS one is global and provided by the UX package; Laravel's __()/trans() helpers are server-side and unrelated. In a mixed codebase, namespace your imports explicitly to avoid a bundler pulling in a JS shim where you expected a server helper.
  • README install snippets now use an X.Y.Z placeholder (3.6.0). Copy versions from your composer.lock, not the docs — easy to paste a literal placeholder into a Dockerfile.
Weaver

How can I help you explore Laravel packages today?

Conversation history is not saved when not logged in.
Prompt
Add packages to context
No packages found.
socialdept/tenant-domains
tautvydasr/blade-class-names
socialdept/color-scales
maherelgamil/controller
coleus/widgets
coleus/table
coleus/users
coleus/music
coleus/health
coleus/calendar
coleus/notes
coleus/support
coleus/settings
coleus/apps
seampact/laravel
emmyconceptng/laravel-ng-postcode
jjsquady/round-robin
skyraptor/chatter
edlugz/sasapay
abbasudo/artisan-route