giggsey/locale
Up-to-date Unicode CLDR locale data packaged as native PHP arrays. Created to avoid requiring the PHP intl extension and to provide newer locale data than many operating systems ship. Used primarily by libphonenumber-for-php (GeoCoder support).
Installation:
composer require giggsey/locale
Pin the version (e.g., ^2.9) to avoid auto-updates breaking CLDR structure.
First Usage:
use Giggsey\Locale\Locale;
$locale = new Locale();
$countryName = $locale->getCountryName('US', 'en'); // "United States"
$countries = $locale->getCountries(); // Array of all countries with metadata
Laravel Integration: Register as a service provider (optional but recommended):
// app/Providers/AppServiceProvider.php
public function register()
{
$this->app->singleton('locale', function () {
return new Locale();
});
}
Now use app('locale')->getCountryName('US') anywhere in Laravel.
Dynamic Country Dropdowns: Replace hardcoded country arrays in Blade templates with CLDR data:
<select name="country">
@foreach(app('locale')->getCountries() as $code => $data)
<option value="{{ $code }}">
{{ $data['en']['displayName'] }}
</option>
@endforeach
</select>
Locale-Aware Country Names:
$locale = new Locale();
$nameEn = $locale->getCountryName('US', 'en'); // "United States"
$nameEs = $locale->getCountryName('US', 'es'); // "Estados Unidos"
Supported Locales:
$supportedLocales = $locale->getSupportedLocales(); // ['en', 'es', 'fr', ...]
Country Metadata:
$countryData = $locale->getCountry('US');
// Returns array with:
// - 'name': 'United States'
// - 'region': 'Americas'
// - 'subregion': 'North America'
// - 'languages': ['en']
Region Filtering:
$americanCountries = $locale->getCountriesForRegion('019'); // 'Americas' region code
Service Provider Binding:
// app/Providers/AppServiceProvider.php
public function boot()
{
view()->composer('*', function ($view) {
$view->with('countries', app('locale')->getCountries());
});
}
Now access $countries in all Blade views.
Validation Rules:
use Illuminate\Validation\Rule;
$validator->addRules([
'country' => [
Rule::in(array_keys(app('locale')->getCountries())),
],
]);
API Response Helper:
// app/Http/Controllers/CountryController.php
public function index()
{
return response()->json([
'countries' => app('locale')->getCountries(),
]);
}
Database Seeding:
// database/seeders/CountrySeeder.php
public function run()
{
$locale = new Locale();
foreach ($locale->getCountries() as $code => $data) {
DB::table('countries')->updateOrCreate(
['code' => $code],
[
'name' => $data['en']['displayName'],
'native_name' => $data['en']['nativeDisplayName'] ?? null,
'region' => $data['region'] ?? null,
]
);
}
}
Caching CLDR Data:
// Cache for 1 hour
$cachedCountries = Cache::remember('locale.countries', now()->addHour(), function () {
return app('locale')->getCountries();
});
Lazy-Loading for Large Apps:
// Load only countries for a specific region
$regionCode = '019'; // Americas
$americanCountries = app('locale')->getCountriesForRegion($regionCode);
Frontend Integration:
// Fetch CLDR data once and cache in Vue/React
axios.get('/api/locale/countries')
.then(response => {
this.countries = response.data;
cache.set('locale.countries', response.data);
});
CLDR Version Locking:
2.9.0) and test thoroughly after updates.Memory Usage:
getCountriesForRegion()).Locale Fallbacks:
'en'):
$name = $locale->getCountryName('US', 'es', 'en'); // Fallback to English
Territory vs. Country:
'BQ' for Bonaire, Sint Eustatius and Saba).getCountries() for all entries or filter by type:
$countries = array_filter($locale->getCountries(), fn($data) => $data['type'] === 'country');
PHP Version Mismatch:
^2.0 for PHP 7.2-7.4, but expect outdated CLDR (e.g., v41).Validate CLDR Data:
$countries = app('locale')->getCountries();
dd(array_key_exists('US', $countries)); // Debug missing entries
Check for Deprecated Methods:
Handle Missing Locales:
try {
$name = $locale->getCountryName('ZZ', 'xx'); // Invalid locale
} catch (\InvalidArgumentException $e) {
// Fallback logic
}
Custom CLDR Data:
Locale class:
class CustomLocale extends \Giggsey\Locale\Locale
{
public function __construct()
{
parent::__construct();
$this->data = array_merge($this->data, $this->customData());
}
protected function customData()
{
return [
'XX' => [
'en' => ['displayName' => 'Custom Land'],
'region' => '000',
],
];
}
}
Add Territory Groups:
$locale = new Locale();
$europeanCountries = $locale->getCountriesForRegion('150'); // 'Europe' region code
Integrate with libphonenumber-for-php:
use libphonenumber\PhoneNumberUtil;
use Giggsey\Locale\Locale;
$phoneUtil = PhoneNumberUtil::getInstance();
$locale = new Locale();
$phoneNumber = $phoneUtil->parse('+14155552671', 'US');
$countryName = $locale->getCountryName($phoneUtil->getRegionCode($phoneNumber));
Autoloading:
vendor/autoload.php is included in Laravel’s autoloader (handled automatically by Composer).Composer Build:
composer run build
Laravel Facade:
php artisan make:facade LocaleFacade
Then update app/Facades/LocaleFacade.php:
public static function getCountryName($code, $locale = 'en', $fallbackLocale = null)
{
return app('locale')->getCountryName($code, $locale, $fallbackLocale);
}
Now use LocaleFacade::getCountryName('US').// database/seeders/Initialize
How can I help you explore Laravel packages today?