petercoles/multilingual-country-list
Install via Composer:
composer require petercoles/multilingual-country-list
On Laravel 5.5+ the service provider and Countries facade are auto-discovered. On older versions add the provider and alias manually in config/app.php. If the package ships a config file, publish it and read it before writing any code:
php artisan vendor:publish --provider="PeterColes\\MultilingualCountryList\\CountriesServiceProvider"
Look first at three places:
vendor/petercoles/multilingual-country-list/README.md — the authoritative method list for the version you installed.Countries) and its underlying class, so you know what's bound in the container.vendor/umpirsky/country-list/data/ — this is where the actual translated names live; the package is a thin wrapper over it. If a locale or country name looks wrong, that is the source of truth, not your code.The first use case you'll hit is a country select in a registration or address form. In a controller:
use Countries; // facade alias
public function create()
{
return view('profile.create', [
'countries' => Countries::lookup(app()->getLocale()),
]);
}
Then render a simple select with the ISO code as the value and the localized name as the label. Confirm the exact method name (lookup, keyValue, all, or similar) against the README once — the API is small but has shifted between releases.
Keep codes in storage, names in the UI. Always persist the ISO 3166-1 alpha-2 code (GB, DE, BR), never the display name. Render the localized name at read time. This is the single most important pattern: it lets you switch locales without a data migration and lets the user change language mid-session.
// store
$validated = $request->validate([
'country' => ['required', Rule::in(array_keys(Countries::lookup('en')))],
]);
$user->update(['country_code' => $validated['country']]);
Validate against the same source you populate from. Use Rule::in(array_keys($lookup)) rather than a hand-maintained list. If you also need the alpha-3 code, derive it from the same lookup instead of hardcoding a mapping.
Wrap the facade in a small domain service. The package gives you raw arrays; you want {code, name} objects, sorting, and a default locale in one place.
class CountryOptions
{
public function forLocale(?string $locale = null): array
{
$locale = $locale ?? app()->getLocale();
return collect(Countries::lookup($locale))
->map(fn ($name, $code) => ['value' => $code, 'label' => $name])
->values()
->all();
}
}
Use this in a Blade component or view composer so every form gets identical behavior, and swap the implementation later if you outgrow the package.
Cache per locale, not globally. The data is static per install, so caching is safe — but a common bug is a single cache key that leaks the first requested locale into subsequent requests.
$countries = Cache::rememberForever("countries:{$locale}", fn () =>
Countries::lookup($locale)
);
Clear the tag (or the whole cache) after composer update so renames and newly added territories appear.
Fall back deliberately. Use config('app.fallback_locale') (en) when the current locale isn't shipped by umpirsky/country-list, and guard the call so a missing locale returns English rather than an empty array.
In APIs, return a stable shape. Flatten to [{code: 'GB', name: 'United Kingdom'}] and document that name is locale-dependent while code is not. Clients can then cache by (Accept-Language, code).
Test against known fixtures. Assert specific pairs (GB → "United Kingdom", DE in German locale) rather than snapshotting the whole array, which churns on every data update.
umpirsky/country-list uses directory names like en, fr, de, and region variants such as zh-CN or pt-BR. Passing en_US when only en exists can yield an empty result or an exception depending on version. Normalize with a small map or a try/catch fallback.umpirsky/country-list, so refresh with composer update petercoles/multilingual-country-list umpirsky/country-list --with-all-dependencies and review diffs in stored codes before deploying.composer.json in the vendor directory before assuming incompatibility, and pin versions in composer.json rather than relying on ^.Countries, alias the package facade explicitly in config/app.php or inject the class instead.ksort. If you re-sort, use PHP's Collator (new \Collator($locale)) so accented names sort correctly. Sorting by code is only appropriate for internal lists.config:cache and route:cache don't touch this data. If country lists look stale after deploy, it's the vendor snapshot or your app cache key — not the config cache. Run php artisan cache:clear and re-check.app()->bound()), or a typo'd method name for your version. Dump app()->getLocale() and the raw call result side by side.How can I help you explore Laravel packages today?