symfony/polyfill-intl-icu
Symfony polyfill providing limited “en”-locale fallbacks for the Intl extension’s ICU functions and classes, including Collator, NumberFormatter, Locale, IntlDateFormatter, and IntlListFormatter, for environments without intl installed.
Architecture fit. This is a compatibility shim, not a feature library. It sits underneath the PHP intl API surface and silently substitutes userland implementations of Collator, NumberFormatter, Locale, IntlDateFormatter, and IntlListFormatter when ext-intl is absent. For a Laravel application it slots in at the framework boundary — Laravel's localization layer, Carbon date handling, and any Blade/validation code that calls NumberFormatter or IntlDateFormatter continue to call the same symbols. Nothing in the application architecture changes. The correct mental model for a TPM is insurance: it converts a hard runtime dependency (a compiled PHP extension that must exist on every host) into a soft one (a Composer package that is guaranteed to resolve).
Integration feasibility. High, with one important nuance: this is almost never a deliberate direct dependency. It typically arrives transitively through Symfony components already in a Laravel tree, which means the realistic decision is not "should we install it" but "should we allow it to be the fallback, or should we mandate ext-intl and treat the polyfill as dead weight." Both are defensible. Installation cost is a single Composer entry with no configuration, no service provider, no migration, and no runtime bootstrapping. The 1.x line is stable and SemVer-managed, and the polyfill is designed to no-op when the extension is present — so adding it cannot break an environment that already has ext-intl.
Technical risk. The dominant risk is not instability, it is silent divergence. The polyfill does not warn, log, or fail when it activates; it just produces different output. In an environment matrix where CI has ext-intl and one production node does not, the same code path yields different collation order and different date/number formatting with no signal. Secondary risks:
en locale. Any non-English locale routed through this path produces English-shaped output — wrong date patterns, wrong numerals, wrong list separators. This is a correctness issue in user-facing surfaces, not a performance footnote.MessageFormatter / IntlDatePatternGenerator / pluralization rules beyond the fallback) is absent, and code that assumes broader ICU availability will fatal rather than degrade.Dependents: 0 is implausible for a package of this reach and should be treated as a metadata artifact, not evidence of low adoption.Key questions.
ext-intl is loaded? If we cannot answer this today, the answer is effectively "unknown," and the polyfill is masking a real gap.NumberFormatter, IntlDateFormatter, or Collator, the polyfill is not a valid fallback — it is a defect generator.ext-intl — required in the base image, or optional? The polyfill only makes sense under "optional." Under "required" it is just noise in the dependency graph.Stack fit. Strong for Laravel + Symfony-based trees: no service provider, no config publishing, no PSR-4 namespace collisions, and compatibility with the supported PHP range including 8.5 additions. It is a pure Composer-level fit and requires no alignment with Laravel's container, middleware, or queue infrastructure.
Migration path. Treat this as a dependency-hygiene and test-coverage task rather than a feature rollout:
^1.34) in composer.json if we intend to depend on IntlListFormatter or locale_is_right_to_left; otherwise accept the transitive version and move on.extension_loaded('intl') — surfaced in health checks and structured logs, so polyfill activation is observable rather than invisible.ext-intl disabled). This is the highest-value step and the one most teams skip.en-shaped outputs we have validated.Compatibility. Non-breaking in both directions: adding the package to an ext-intl host changes nothing, and removing it from a non-ext-intl host is exactly the change that would break. The real compatibility constraint is the locale matrix, not the PHP version — validate the locales you ship, not the versions you support.
Sequencing. Ship the dependency and the probe together (invisible, low risk), then the CI job that exercises the fallback, then any user-visible RTL or list-formatting behavior. Do not reverse this order; enabling feature behavior before you can detect and test the fallback is how silent degradations reach users.
Maintenance. Near-zero. No schema, no config, no cron, no secrets. Version bumps are routine and the changelogs are usually "no significant changes." The maintenance cost is not in the package — it is in keeping the environment probe and the polyfill-only CI job alive, which is a small but permanent testing obligation.
Support. Low volume, but the failure tickets are hard to triage because the symptom is "the date looks wrong" rather than an exception. Support runbooks should include a first-step check of extension_loaded('intl') and the resolved polyfill version, otherwise engineers will debug application code that is behaving exactly as the fallback dictates.
Scaling. Scales with application traffic, not with data volume — but per-operation cost is higher than the native extension. The scaling concern is specifically batch and export workloads where collation or formatting runs per record over large sets; that is where the multiplier becomes a wall-clock and cost problem. Request-path usage (rendering a localized date on a page) is not a scaling risk.
Failure modes. Ranked by likelihood and blast radius:
ext-intl for those paths.composer update shifts the polyfill version.Ramp-up. Effectively nil for engineers — the API surface is PHP's own, so no new concepts. The ramp-up cost is organizational: getting the team to internalize that "works on my machine" is not evidence of correctness here when the machines differ in ext-intl. Budget one short note in the onboarding docs and one line in the environment README; anything more is over-investment for a package this small.
Recommendation. Adopt as an accepted transitive dependency and invest in observability of when it activates, not in leveraging it as a feature. Position it as the safety net that lets non-ext-intl environments run, while keeping ext-intl required for any production locale other than English. If the team is contemplating building RTL or localized-formatting features on top of the polyfill specifically to avoid installing the extension, that is the wrong trade — install the extension and let the polyfill remain dormant.
How can I help you explore Laravel packages today?