codedor/laravel-locale-collection
A Laravel package that provides a ready-made collection of locales and language data, making it easy to list, filter, and look up locale names and codes in your application.
wotzebra/laravel-locale-collection is a small data package: it gives you the world's locales as a Laravel Collection so you don't hand-maintain an array of codes and display names in every project.
composer require wotzebra/laravel-locale-collection
Package auto-discovery means there is nothing to register. If the package ships publishable config/translations, publish them once and commit the result:
php artisan vendor:publish --provider="Wotzebra\LocaleCollection\LocaleCollectionServiceProvider"
Where to look first: the package's facade/entry point (usually a singleton bound in the container) and its config/locale-collection.php. The collection is static reference data, so read the source once — it is short and tells you exactly which keys (code, name, native, etc.) are available.
First use case: a locale switcher. Pull the collection, pluck('native', 'code'), and render it as a <select>; you immediately get a correctly-labelled dropdown without a translation service or a database table.
On v2.1.0: this release is essentially a compatibility bump — PHP 8.5 and Laravel 13 constraints were widened, and the only other changes are Dependabot updates to CI actions (fetch-metadata, composer-install). No runtime code changed. Upgrade is a drop-in composer update, and it is required if you are moving to Laravel 13, since older tags will likely block the install on framework constraints.
Locale switcher with persistence. Store the chosen locale in the session (or a user column) and apply it in middleware. Keep the locale list read-only — never mutate the collection instance, ->map()/->filter() into a new one instead:
$locales = LocaleCollection::all()->pluck('native', 'code');
// middleware
if (in_array($request->input('locale'), $locales->keys()->all(), true)) {
session(['locale' => $request->input('locale')]);
}
app()->setLocale(session('locale', config('app.locale')));
Validation. Bind the collection into a rule rather than duplicating codes:
$request->validate([
'locale' => ['required', Rule::in(LocaleCollection::all()->pluck('code'))],
]);
Content negotiation. For APIs, intersect the parsed Accept-Language header with the collection and return the first match, falling back to config('app.fallback_locale'). Emit Content-Language on the response so clients can cache per-locale.
Forms and seeders. pluck('name', 'code') maps cleanly onto Blade::select-style helpers and onto Seeder loops when you need a locales table for per-locale content rows (translations, pricing, CMS pages).
Pairing with translatable models. Use the package as the source of truth for which locales exist, and spatie/laravel-translatable (or similar) for the content. Deriving the translatable field list from the same collection keeps admin UIs and validation in sync.
Testing. Because the data is static, assertions are cheap: assert the switcher renders N options, assert an unsupported Accept-Language falls back, and assert the session key round-trips.
en_US, en-US, or en and stick to it. app()->setLocale() and lang/ directory names must match what the collection returns, or translations silently fall back to the default. Normalise once at the boundary.Collator (intl) for anything user-facing; a plain sortBy('name') looks broken in a dropdown.php artisan config:clear. Same class of problem if you cache the collection in a singleton — remember to reset it between tests.^2.1 — anything below it will not satisfy Laravel 13. If CI installs fail right after upgrading the framework, this package's constraint is a likely culprit alongside other small utility packages.fetch-metadata and composer-install bumps are GitHub Actions only — they don't affect your application and shouldn't factor into your upgrade decision.How can I help you explore Laravel packages today?