Home » Php » Simplest way to detect client locale in PHP

Simplest way to detect client locale in PHP

Posted by: admin April 23, 2020 Leave a comment


I would like to be able to detect what country a visitor is from on my website, using PHP.

Please note that I’m not trying to use this as a security measure or for anything important, just changing the spelling of some words (Americans seems to believe that the word “enrolment” has 2 Ls…. crazy yanks), and perhaps to give a default option in a “Select your country” list.

As such, using a Geolocation database is a tad over-the-top and I really don’t want to muck about with installing new PHP libraries just for this, so what’s the easiest/simplest way to find what country a visitor is from?

How to&Answers:

Not guaranteed, but most browsers submit an Accept-Language HTTP header that specifies en-us if they’re from the US. Some older browsers only said they are en, though. And not all machines are set up correctly to indicate which locale they prefer. But it’s a good first guess.

English-UK based-users usually set their system or user locale to English-UK, which in default browser configurations should result in en-gb as the Accept Language header. (An earlier version of this said en-uk; that was a typo, sorry.) Other countries also have en locales, such as en-za (south africa), and, primarily theoretically, combinations like en-jp are also possible.

Geo-IP based guesses will less likely be correct on the preferred language/locale, however. Google thinks that content-negotiation based on IP address geolocation makes sense, which really annoys me when I’m in Japan or Korea…


PHP provides a function since 5.3.0 to parse the $_SERVER['HTTP_ACCEPT_LANGUAGE'] variable into a locale.

$locale = Locale::acceptFromHttp($_SERVER['HTTP_ACCEPT_LANGUAGE']);
echo $locale; // returns "en_US"

Documentation: https://www.php.net/manual/en/locale.acceptfromhttp.php


You can check out the HTTP_ACCEPT_LANGUAGE header (from $_SERVER) that most browsers will send.

Take a look at Zend_Locale for an example, or maybe you might even want to use the lib.


You can do some IP comparaison without having a whole library to do it.

Solution #1

Use an API, this way nothing is needed from your side. This is a web API that let you know the country:

 Example: http://api.hostip.info/get_html.php?ip=
 Return : Country: UNITED STATES (US)

Solution #2

But, Have you think to use the browser agent language? You might be able to know the type of english from it.

Solution #3

This website called BlockCountry let you have a list of IP by country. Of course, you do not want to block, but you can use the list of IP and compare them (get all US IP…) this might not be accurate…


Given your stated purpose, the Accept-Language header is a more suitable solution than IP-based geolocation. Indeed, it’s precisely the intended purpose of Accept-Language.


Parse $_SERVER["HTTP_ACCEPT_LANGUAGE"] to get country and browser’s locale.


For identifying your visitors country I’ve used GeoIP extension, very simple to use.



    $localePreferences = explode(",",$_SERVER['HTTP_ACCEPT_LANGUAGE']);
    if(is_array($localePreferences) && count($localePreferences) > 0) {
       $browserLocale = $localePreferences[0];
       $_SESSION['browser_locale'] = $browserLocale;


The http://countries.nerd.dk service is what I use for IP-to-country mapping. It works really well and being based on DNS, is cached well too.

You can also download the database for local use if you don’t want to rely on an external service.


Or you can do the following:

download ‘geoip.dat’ and geoip.inc from http://www.maxmind.com/app/geoip_country

in geoip.inc header you will find how to use it (eg. initialize and the rest…)


GeoIP extension is good choice.


One thing is which language viewer wants, second – which you can serve:

$SystemLocales = explode("\n", shell_exec('locale -a'));
$BrowserLocales = explode(",",str_replace("-","_",$_SERVER["HTTP_ACCEPT_LANGUAGE"])); // brosers use en-US, Linux uses en_US
for($i=0;$i<count($BrowserLocales);$i++) {         
  list($BrowserLocales[$i])=explode(";",$BrowserLocales[$i]); //trick for "en;q=0.8"
  for($j=0;$j<count($SystemLocales);$j++) {
    if ($BrowserLocales[$i]==substr($SystemLocales[$j],0,strlen($BrowserLocales[$i]))){
      setlocale(LC_ALL, $SystemLocales[$j]);
      break 2; // found and set, so no more check is needed

for example, mine system serves only:

  • C
  • pl_PL.UTF-8

and my browser languages are: pl, en-US, en => so the only correct locale is pl_PL.UTF-8.

When no successful comparison is found – there’s no setlocale at all.