Search code examples
phpdatetimetimezonelocale

IntCalendar outputting wrong locale in php


I have the following code which I believe should output fr_FR as the locale but for some reason is outputting en_US_POSIX (it does this on any timezone). What have I done wrong?

$loc = IntlCalendar::createInstance(new DateTimeZone('Europe/Paris'));
echo $loc->getLocale(Locale::VALID_LOCALE);

For refs: https://www.php.net/manual/en/intlcalendar.createinstance.php and https://www.php.net/manual/en/intlcalendar.getlocale.php

As it appears this isn't the correct way (even though the code is valid) - is there a more suitable way to find a "default" locale for a given timezone?


Solution

  • You can start by getting the country (and country code) associated with a given timezone:

    $userTimezone = new DateTimeZone('Europe/Paris');
    
    $location = $userTimezone->getLocation();
    /*
    array(4) {
      ["country_code"]=>  string(2) "FR"
      ["latitude"]=>  float(48.866659999999996)
      ["longitude"]=>  float(2.3333299999999895)
      ["comments"]=>  string(0) ""
    }
    */
    
    $countryCode = $location['country_code'];
    

    You can then combine that information with the resources available in the ICU library to get the most-likely language of a given country code:

    // From @ausi's answer in https://stackoverflow.com/a/58512299/1456201
    function getLanguage(string $country): string {
        $subtags = \ResourceBundle::create('likelySubtags', 'ICUDATA', false);
        $country = \Locale::canonicalize('und_'.$country);
        $locale = $subtags->get($country) ?: $subtags->get('und');
        return \Locale::getPrimaryLanguage($locale);
    }
    

    Note that that will not be correct for every user. It's a decent default starting place, but you should always ask the user what their language preference is.

    $possibleLocale = getLanguage($countryCode) . '_' . $countryCode; // fr_FR