Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Get default locale for language in PHP

Tags:

php

locale

I have a PHP back-end to which several types of devices communicate via a public API. Requests normally contain a required language for the response (e.g. 'en' or 'fr' or 'ru', etc.) - but not the full locale. This has worked fine for everything I needed over the last couple of years. However now I need to include date information in the response - and need a locale to format dates.

How can I get a locale from the language? I do understand that a language is not enough to uniquely identify a locale, but I need at least something. If I can get at least one locale, e.g. en_GB for 'en' or 'ru_RU' for 'ru', etc. - that would be sufficient.

like image 619
Aleks G Avatar asked Dec 19 '11 23:12

Aleks G


3 Answers

Perhaps you could use $_SERVER['HTTP_ACCEPT_LANGUAGE']; instead of the supplied language in order to get the locale. Quite often, this will contain the actual locale with a hyphen instead of an underscore.

Example $_SERVER['HTTP_ACCEPT_LANGUAGE']:

en-ca,en;q=0.8,fr-ca;q=0.5,fr;q=0.3

Just get everything before the first , and you're all set. This is also better than populating an array of locales because it lets the browser tell the server what language it prefers, not the other way around, however an array as in hakre's answer should be used as a backup system in case an invalid/empty/missing $_SERVER['HTTP_ACCEPT_LANGUAGE'] is provided.

Something else you may want to look into are the locale class and the perhaps the locale::acceptFromHttp method

Also, you may want to consider modifying your API to allow users to explicitly set their locale, just make sure it will gracefully fall back to whatever system you choose to implement now.

like image 24
Mike Avatar answered Nov 16 '22 17:11

Mike


Having thought more about the problem and the particular setup I have, I came up with this solution, which seems to work. Note that I don't have control over what languages I need to support: there are translation files dropped into a predefined place and system locales installed by someone else. During runtime, I need to support a particular language if corresponding translation file exists and and system locale is installed. This got me to this solution:

function getLocale($lang)
{
    $locs = array();
    exec('locale -a', $locs);

    $locale = 'en_GB';
    foreach($locs as $l)
    {
        $regex = "/$lang\_[A-Z]{2}$/";
        if(preg_match($regex, $l) && file_exists(TRANSROOT . "/$lang.php"))
        {
            $locale = $l;
            break;
        }
    }

    return $locale;
}

I'm defaulting to en_GB if I cannot resolve a locale, because I know for certain that en_GB is installed (we're located in the UK as are our servers).

like image 195
Aleks G Avatar answered Nov 16 '22 18:11

Aleks G


Do I understand you right that you need just a map from language (like en) to locale (like en_GB)? If so, you can compile one for the languages you use:

$localeMap = array(
    'en' => 'en_GB',
    'fr' => 'fr_FR',
    # ...  
);

# Usage:

$locale = $localeMap[$lang];

But this is so trivial that I'm unsure if I properly understood your question.

If you are unsure what the locale is for a language, just take the language itself which should be a valid locale, just without a country:

l => ll

As long as the language is in the two letter format looks fine to me (ISO standard 639, "Code for the representation of names of languages"), See as well Tags for the Identification of Languages (RFC 1766).

$locale = isset($localeMap[$lang]) ? $localeMap[$lang] : $lang;

However this can differ depending which kind of locale format the function you're using is expecting.


class System
{
    /**
     * @return array
     */
    public function getLocales()
    {
        $locales = array();
        exec('locale -a', $locales, $retCode);
        !$retCode || $locales = array();
        return $locales;
    }
    /**
     * @return string something matching 
     * @note Improve by creating your system aware locale class to move
     *       away the responsibility to map system locales onto strings
     *       of certain kinds and to deal with the different locale types.
     */
    public function getLocaleByLang($lang)
    {
        ...
    }
}


$lang = ...
$system = new System;
$locale = $system->getLocaleByLang($lang);
like image 1
hakre Avatar answered Nov 16 '22 18:11

hakre