horde/nls

Native language support library

v3.0.0 2026-06-26 00:00 UTC

Requires

Requires (Dev)

Suggests

Provides

None

Conflicts

None

Replaces

None

LGPL-2.1-only a25c11613dd172b078415c86672d12d2149b9bab

  • Jan Schneider <jan.woop@horde.org>
  • Chuck Hagenbuch <chuck.woop@horde.org>

languagecountrytld


README

A library for handling language data, country codes, timezones, TLD lookups and IP-to-country resolution.

Installation

composer require horde/nls

Optional dependencies

# For reverse-DNS hostname lookups
composer require mikepultz/netdns2

# For MaxMind GeoIP2/GeoLite2 database lookups
composer require geoip2/geoip2

Usage

Basic usage (injectable service)

use Horde\Nls\Nls;

$nls = new Nls();

// Country lookup
$nls->countries()->get('DE'); // 'Germany'
$nls->countries()->all(); // ['AD' => 'Andorra', 'AE' => 'United Arab Emirates', ...]
$nls->countries()->translated(); // Localized names, sorted by locale

// Language lookup
$nls->languages()->get('fr'); // 'French'

// Timezones
$nls->getTimezones(); // ['Africa/Abidjan' => 'Africa/Abidjan', ...]

// Charset validation
$nls->checkCharset('UTF-8'); // true
$nls->checkCharset('NOT-REAL'); // false

Data classes as arrays

All data classes implement IteratorAggregate, ArrayAccess, and Countable:

$countries = new \Horde\Nls\Countries();

foreach ($countries as $code => $name) {
 echo "$code: $name\n";
}

echo $countries['US']; // 'United States'
echo count($countries); // 249
isset($countries['XX']); // false

Translation (explicit)

Translation is never applied implicitly. Call translated() when you need localized output:

$countries = new \Horde\Nls\Countries();

$countries->all(); // English names (default)
$countries->translated(); // Localized via gettext, sorted by locale

Country lookup from hostname/IP

use Horde\Nls\Nls;
use Horde\Nls\Dns\NativeResolver;
use Horde\Nls\Geoip\Geoip2Driver;

$nls = new Nls(
 resolver: new NativeResolver(),
 geoip: new Geoip2Driver('/path/to/GeoLite2-Country.mmdb'),
);

$result = $nls->getCountryByHost('example.de');
// ['code' => 'de', 'name' => 'Germany']

$result = $nls->getCountryByHost('8.8.8.8');
// ['code' => 'us', 'name' => 'United States'] (via GeoIP)

Legacy code resolution

Retired ISO-3166 codes and old country names are handled by LegacyCodes:

$legacy = new \Horde\Nls\LegacyCodes();

$legacy->resolve('AN'); // 'BQ' (Netherlands Antilles โ†’ Bonaire)
$legacy->resolve('YU'); // 'RS' (Yugoslavia โ†’ Serbia)
$legacy->resolveName('Czech Republic'); // 'CZ'
$legacy->resolveName('Swaziland'); // 'SZ'

GeoIP drivers

use Horde\Nls\Geoip\Geoip2Driver;
use Horde\Nls\Geoip\LegacyDatDriver;
use Horde\Nls\Geoip\NullDriver;

// MaxMind GeoIP2 (recommended)
$geoip = new Geoip2Driver('/path/to/GeoLite2-Country.mmdb');

// Legacy .dat format
$geoip = new LegacyDatDriver('/path/to/GeoIP.dat');

// No GeoIP (default)
$geoip = new NullDriver();

DNS resolvers

use Horde\Nls\Dns\NullResolver;
use Horde\Nls\Dns\NativeResolver;
use Horde\Nls\Dns\NetDns2Resolver;

// No reverse DNS (default)
$resolver = new NullResolver();

// PHP built-in gethostbyaddr
$resolver = new NativeResolver();

// NetDNS2 library
$resolver = new NetDns2Resolver($netdns2Instance);

Architecture

src/
โ”œโ”€โ”€ Nls.php # Main injectable service
โ”œโ”€โ”€ Translation.php # Horde\Translation integration
โ”œโ”€โ”€ Countries.php # ISO-3166 country data
โ”œโ”€โ”€ Languages.php # ISO-639-1 language data
โ”œโ”€โ”€ Tld.php # TLD โ†’ country mapping
โ”œโ”€โ”€ Alpha3.php # Alpha-2 โ†’ Alpha-3 codes
โ”œโ”€โ”€ Carsigns.php # License plate prefixes
โ”œโ”€โ”€ LegacyCodes.php # Retired code resolution
โ”œโ”€โ”€ Coordinates/
โ”‚ โ”œโ”€โ”€ CoordinatesInterface.php # Provider contract
โ”‚ โ””โ”€โ”€ StaticCoordinates.php # Bundled city data
โ”œโ”€โ”€ Dns/
โ”‚ โ”œโ”€โ”€ ResolverInterface.php # Reverse DNS contract
โ”‚ โ”œโ”€โ”€ NullResolver.php
โ”‚ โ”œโ”€โ”€ NativeResolver.php
โ”‚ โ””โ”€โ”€ NetDns2Resolver.php
โ”œโ”€โ”€ Geoip/
โ”‚ โ”œโ”€โ”€ GeoipInterface.php # IPโ†’country contract
โ”‚ โ”œโ”€โ”€ Geoip2Driver.php # MaxMind GeoIP2/GeoLite2
โ”‚ โ”œโ”€โ”€ LegacyDatDriver.php # MaxMind legacy .dat
โ”‚ โ””โ”€โ”€ NullDriver.php
โ””โ”€โ”€ DataRegeneration/
 โ””โ”€โ”€ IanaTldUpdater.php # IANA TLD list updater

Upgrading from Horde_Nls

See doc/UPGRADING.md for a complete migration guide from the legacy Horde_Nls static API to the new injectable Horde\Nls\Nls service.

Requirements

  • PHP 8.1+
  • ext-mbstring
  • horde/translation ^3

License

LGPL-2.1-only. See LICENSE for details.