forci/locale-bundle
forci/locale-bundle is a PHP locale management bundle for multilingual applications. It provides locale configuration and detection utilities to help route users to the right language and integrate localized content, making it easier to build and maintain localized experiences.
What you're actually holding: forci/locale-bundle is a Symfony bundle (Symfony 3/4 era), not a Laravel package. There is no service provider, no config/locale.php, and no facades. If you're on Laravel, the correct first step is not composer require — it's git clone and read it as a reference implementation. Its value to a Laravel developer is as a ~200-line spec for locale negotiation and fallback; its value as a dependency is close to zero.
If you're on Symfony (the only case where this installs cleanly): add the bundle to config/bundles.php, import its YAML config, and point your framework.default_locale and translator.fallbacks at it. The bundle wires a locale resolver and a request listener; you interact with it via the injected locale service and the translator, not a facade.
Where to look first, in order:
LocaleListener integration — this is the real behavior: how the locale is picked from route, then query, then Accept-Language, then default.First use case to validate: a request to /fr/products with Accept-Language: de-DE,de;q=0.9 and no ?locale= query. Confirm the resulting Request::getLocale() is fr (route wins), not de (header). If that ordering doesn't match your product requirement, the bundle's opinion is wrong for you and you're better off writing the middleware yourself.
Pattern 1 — Symfony native usage. Inject the bundle's locale service, read the resolved locale, and pass it to Translator::setLocale(). The bundle expects Symfony's LocaleListener to run after it; don't fight that ordering. Config lives in one YAML file with default + fallback locale and a priority list of detection sources.
Pattern 2 — the Laravel port (recommended). The bundle's real logic collapses to a SetLocale middleware:
public function handle($request, Closure $next) {
$locale = $request->route('locale')
?? $request->query('locale')
?? $request->getPreferredLanguage(config('app.locales'))
?? config('app.fallback_locale');
App::setLocale($locale);
return $next($request);
}
$request->getPreferredLanguage() is native and handles Accept-Language q-values correctly — you don't need the bundle for the hardest-looking part. Register the middleware globally (before SubstituteBindings) and you have parity with the bundle's feature set in under two hours.
Pattern 3 — locale-prefixed routing. In Laravel, wrap your frontend routes in Route::prefix('{locale}')->middleware(SetLocale::class)->group(...) and add a Route::pattern('locale', 'en|fr|de|pt-BR') constraint to prevent unmatched paths from reaching the middleware. This is roughly what the bundle does in Symfony with route defaults, but Laravel's route model gives you more explicit control.
Pattern 4 — persistence. Session first (session(['locale' => $locale])), cookie second, header last. Pick an order and document it — the bundle encodes one; you should encode yours explicitly rather than inheriting an undocumented one.
Pattern 5 — if you need more than the simple case. Reach for mcamara/laravel-localization (MIT, actively maintained, real adoption). It covers URL prefixes, hreflang, and the switcher endpoint. Do not bridge this bundle through a service provider to get the same result — you inherit a Symfony constraint pin and zero upstream support.
Testing pattern worth copying: a data-provider matrix of [route locale, query locale, Accept-Language, session, expected] covering regional variants (pt-BR vs pt), an RTL locale (ar, he), an unsupported locale in the header, and a missing translation key. The bundle likely ships something similar; if not, it's the first thing to add to your port.
NOASSERTION. This is a stop-ship, not a nitpick. GitHub could not identify an OSI license, which means there may be no grant of commercial use at all. Escalate to legal before any line lands in a repo. If legal clears it, you still own the fork forever.Kernel::registerBundles() in Laravel, no DI extension auto-loading, no compiler-pass pipeline. Any class extending Symfony\Component\HttpKernel\Bundle\Bundle will never execute. Only plain service classes and value objects are portable — and for this package, that's the minority of the lines.symfony/framework-bundle in ^3|^4; Laravel 10/11 ships Symfony 6/7 components. composer require will fail resolution or force a replace hack that destabilizes every other symfony/* constraint. Check composer.json before spending any time on a bridge; if it references symfony/symfony (the monolith), walk away — it conflicts with Laravel's per-component requirements outright.Cache-Control, a CDN, spatie/laravel-responsecache) must vary on it. Set Vary: Accept-Language and exclude locale-sensitive routes from the cache. This is the single most common production failure in locale middleware and is harder to audit when the logic is behind a third-party bundle.route('products.index', ['locale' => 'fr']) produces /fr/products and not /products. This breaks silently in Laravel because route() helpers don't fail on missing optional segments.pt-BR vs pt vs pt-PT: decide whether pt-BR falls back to pt or to the default. The bundle's fallback chain is one opinion; Laravel's lang/{locale}/ directory structure is another. Test both directions.How can I help you explore Laravel packages today?