<?php
/*
* Copyright 2008 Blandware (http://www.blandware.com)
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
/**
* Language tools.
*
* @package AtleapLite
* @author Roman Puchkovskiy
* @license http://www.apache.org/licenses/LICENSE-2.0 Apache License, Version 2.0
*/
/**
* Class which represents a language.
*
* @package AtleapLite
*/
class Language {
var $code;
}
/**
* Returns the current language.
*
* @return string code of the current language
*/
function getCurrentLanguage() {
return $_SESSION['currentLanguage'];
}
/**
* Sets the current language.
*
* @param string $lang language code
*/
function setCurrentLanguage($lang) {
$_SESSION['currentLanguage'] = $lang;
}
/**
* Returns all known languages.
*
* @global array languages
* @return all known languages
*/
function getLanguages() {
global $languages;
return $languages;
}
/**
* Returns a language by its code.
*
* @param string $code language code
* @return object language
*/
function getLanguage($code) {
$langs = getLanguages();
return $langs[$code];
}
/**
* Returns the default language code.
*
* @return string default language code
*/
function getDefaultLanguage() {
global $defaultLanguage;
return $defaultLanguage;
}
/**
* If current language is not in session, determines it and puts there. When
* determining, first Accept-Language header is used. If any of our languages
* matches this header, 'the most matching' language is treated as the result.
* If there's no such header or no languages match it, the default language is
* used as the current language.
*/
function ensureCurrentLanguageIsInitialized() {
$lang = getCurrentLanguage();
if (!$lang) {
$lang = detectCurrentLanguage();
if (!$lang) {
$lang = getDefaultLanguage();
}
}
setCurrentLanguage($lang);
}
/**
* Detects the current language using the Accept-Language header. If exists and
* some known languages match it, the code of 'the most matching' language is
* returned. If there's no such header or no known languages match it, null is
* returned.
*
* @return string|null language code or null if could not detect
*/
function detectCurrentLanguage() {
$acceptLanguage = $_SERVER['HTTP_ACCEPT_LANGUAGE'];
if (!$acceptLanguage) {
return null;
}
$rangesAndQualities = explode(',', $acceptLanguage);
foreach ($rangesAndQualities as $key => $value) {
$rangesAndQualities[$key] = trim($value);
}
// convert strings to weighted langs retaining only those that match our
// languages
$langs = array();
foreach ($rangesAndQualities as $rq) {
$pos = strpos($rq, ';');
if ($pos === false) {
$range = $rq;
$weight = 1.0;
} else {
list($range, $weight) = explode(';', $rq, 2);
}
$range = trim($range);
$weight = floatval(trim($weight));
if ($range == '*' || (float) $weight <= 0) {
continue;
}
$lang = findExactLangMatch($range);
if (!$lang) {
// TODO: here only one match is taken while several are possible...
// rework?
$lang = findPrefixLangMatch($range);
}
if (!$lang) {
// the range does not match
continue;
}
if (isset($langs[$lang]) && (float) $weight <= (float) $langs[$lang]) {
// avoiding loosing more valuable weight
continue;
}
$langs[$lang] = $weight;
}
if (count($langs) == 0) {
// no languages matched
return null;
}
// now returning the most valuable language
$maxWeight = 0.0;
foreach ($langs as $l => $weight) {
if ((float) $weight > (float) $maxWeight) {
$maxWeight = $weight;
$lang = $l;
}
}
return $lang;
}
/**
* Finds exact range match to one of known languages.
*
* @param string range to match
* @return string|null language code or null if not found
*/
function findExactLangMatch($range) {
$code = rangeToLanguageCode($range);
if (getLanguage($code) != null) {
return $code;
} else {
return null;
}
}
/**
* Finds prefix range match to one of known languages.
*
* @param string range to match
* @return string|null language code or null if not found
*/
function findPrefixLangMatch($range) {
$code = rangeToLanguageCode($range);
foreach (getLanguages() as $lang) {
if (startsWith($lang->code, $code . '_')) {
return $lang->code;
}
}
}
/**
* Converts a range to language code. When converting, fragment separators which
* are dashes ('-') are replaced with underscores ('_'). First fragment is
* converted to the lowercase, while the second fragment is converted to the
* uppercase.
*
* @param string $range the range to convert
* @return string converted range
*/
function rangeToLanguageCode($range) {
$fragments = explode('-', $range);
$count = count($fragments);
if ($count > 0) {
$fragments[0] = strtolower($fragments[0]);
}
if ($count > 1) {
$fragments[1] = strtoupper($fragments[1]);
}
return implode('_', $fragments);
}
/**
* If a language is set using the GET parameter and the specified language is
* supported, sets the current language to this value.
*/
function setLanguageFromParameter() {
if (isset($_GET['language']) && getLanguage($_GET['language']) != null) {
setCurrentLanguage($_GET['language']);
}
}
/**
* Returns an assoc array from language codes to their titles in the current
* language plus element for 'all', if requested.
*
* @param bool $addNotSelected if true, 'all' element will be added
* @return array assoc array
*/
function getLanguagesForSelect($addNotSelected = false) {
$languages =& getLanguages();
$currentLang = getCurrentLanguage();
$result = array();
if ($addNotSelected) {
$result[-1] = getMessage('common.all');
}
foreach ($languages as $language) {
$result[$language->code] = getMessage('language.' . $language->code);
}
return $result;
}
?>