Commit acae5433 authored by Côme Chilliet's avatar Côme Chilliet

feat(core) Move Language handling to a clean class

This also fix the workflow to make sure the language in the header is
 correct in all cases.
A PHP error is triggered if setlocale fails or if the wrong language
 header was sent.

issue #5820
parent d11c5f8e
......@@ -95,7 +95,7 @@ class standAlonePage {
}
if ($this->interactive) {
initLanguage();
Language::init();
if (session::global_is_set('plist')) {
session::global_un_set('plist');
......@@ -345,7 +345,7 @@ class passwordRecovery extends standAlonePage {
$smarty->append('css_files', get_template_path('login.css'));
$lang = session::global_get('lang');
$smarty->assign('lang', preg_replace('/_.*$/', '', $lang));
$smarty->assign('rtl', language_is_rtl($lang));
$smarty->assign('rtl', Language::isRTL($lang));
$smarty->display(get_template_path('headers.tpl'));
$smarty->assign('version', FD_VERSION);
......
......@@ -90,7 +90,7 @@ function displayLogin()
$smarty->assign("usePrototype", "false");
$smarty->assign("date", date("l, dS F Y H:i:s O"));
$smarty->assign("lang", preg_replace('/_.*$/', '', $lang));
$smarty->assign("rtl", language_is_rtl($lang));
$smarty->assign("rtl", Language::isRTL($lang));
$smarty->display (get_template_path('headers.tpl'));
$smarty->assign("version", FD_VERSION);
......@@ -180,7 +180,7 @@ if (!(is_dir($smarty->compile_dir) && is_writable($smarty->compile_dir))) {
/* Check for old files in compile directory */
clean_smarty_compile_dir($smarty->compile_dir);
initLanguage();
Language::init();
$smarty->assign ('focusfield', 'username');
......@@ -318,7 +318,7 @@ class Index {
session::global_set('ui', $ui);
/* User might have its own language, re-run initLanguage */
$plistReloaded = initLanguage();
$plistReloaded = Language::init();
/* We need a fully loaded plist and config to test account expiration */
if (!$plistReloaded) {
......
......@@ -98,7 +98,7 @@ if (!session::global_is_set('CurrentMainBase')) {
session::global_set('CurrentMainBase', get_base_from_people($ui->dn));
}
initLanguage();
Language::init();
/* Prepare plugin list */
$plist = load_plist();
......@@ -232,9 +232,9 @@ if (isset($_GET['reset'])) {
/* show web frontend */
$smarty->assign ("date", date("l, dS F Y H:i:s O"));
$lang = session::global_get('lang');
$smarty->assign ("lang", preg_replace('/_.*$/', '', $lang));
$smarty->assign ("rtl", language_is_rtl($lang));
$smarty->assign ("must", '<span class="must">*</span>');
$smarty->assign ('lang', preg_replace('/_.*$/', '', $lang));
$smarty->assign ('rtl', Language::isRTL($lang));
$smarty->assign ('must', '<span class="must">*</span>');
if (isset($plug)) {
$plug = "?plug=$plug";
} else {
......
......@@ -78,12 +78,12 @@ if (isset($_POST['lang_selected']) && $_POST['lang_selected'] != '') {
$lang .= '.UTF-8';
}
} else {
$lang = get_browser_language();
$lang = Language::detect();
}
initLanguage($lang);
Language::init($lang);
$smarty->assign("rtl", language_is_rtl($lang));
$smarty->assign("rtl", Language::isRTL($lang));
$smarty->assign("must", '<span class="must">*</span>');
/* Minimal config */
......@@ -99,7 +99,6 @@ $ui = new fake_userinfo();
$display = "";
require_once("../setup/main.inc");
$smarty->assign("rtl", language_is_rtl($lang));
$smarty->assign("date", date("l, dS F Y H:i:s O"));
$header = $smarty->fetch(get_template_path('headers.tpl'));
......
......@@ -3,7 +3,7 @@
* accept-to-gettext.inc -- convert information in 'Accept-*' headers to
* gettext language identifiers.
* Copyright (c) 2003, Wouter Verhelst <wouter@debian.org>
* Copyright (c) 2012-2016, FusionDirectory
* Copyright (c) 2012-2018, FusionDirectory
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
......@@ -115,7 +115,7 @@ function parse_gettext_lang ($str)
}
}
function al2gt($gettextlangs, $mime)
function al2gt($gettextlangs)
{
/* Check if ACCEPT_LANGUAGE isset */
if (empty($_SERVER["HTTP_ACCEPT_LANGUAGE"])) {
......@@ -177,15 +177,6 @@ function al2gt($gettextlangs, $mime)
return NULL;
}
/* We must re-parse the gettext-string now, since we may have found it
* through a "*" qualifier.*/
list ($lang, $country, $char) = parse_gettext_lang($max_lang);
if (!headers_sent()) {
header("Content-Language: $lang".(empty($country) ? "" : "-$country"));
if (!empty($char)) {
header("Content-Type: $mime; charset=$char");
}
}
return $max_lang;
}
?>
<?php
/*
This code is part of FusionDirectory (http://www.fusiondirectory.org/)
Copyright (C) 2017-2018 FusionDirectory
This program is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation; either version 2 of the License, or
(at your option) any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program; if not, write to the Free Software
Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA.
*/
/*!
* \file class_Language.inc
* Source code for the class Language
*/
/*!
* \brief This class contains all the function needed to manage languages
*/
class Language
{
/*!
* \brief Initialize language configuration
*
* \param string $lang Language locale to use, defaults to self::detect()
*/
public static function init($lang = NULL)
{
global $BASE_DIR;
if ($lang === NULL) {
$lang = static::detect();
}
putenv('LANGUAGE=');
putenv("LANG=$lang");
$langset = setlocale(LC_ALL, $lang);
if ($langset === FALSE) {
trigger_error('Setting locale to '.$lang.' failed');
}
$GLOBALS['t_language'] = $lang;
$GLOBALS['t_gettext_message_dir'] = $BASE_DIR.'/locale/';
static::setHeaders($lang, 'text/html');
/* Set the text domain as 'fusiondirectory' */
$domain = 'fusiondirectory';
bindtextdomain($domain, LOCALE_DIR);
textdomain($domain);
if ($_SERVER['REQUEST_METHOD'] != 'POST') {
@DEBUG (DEBUG_TRACE, __LINE__, __FUNCTION__, __FILE__, $lang, 'Setting language to');
}
$ret = FALSE;
/* Reset plist cache if language changed */
if ((!session::global_is_set('lang')) || (session::global_get('lang') != $lang)) {
$ret = TRUE;
if (session::global_is_set('plist')) {
if ($_SERVER['REQUEST_METHOD'] != 'POST') {
@DEBUG (DEBUG_TRACE, __LINE__, __FUNCTION__, __FILE__, session::global_get('lang'), 'Plist already loaded with language');
}
session::global_un_set('plist');
session::global_set('lang', $lang);
load_plist();
}
}
session::global_set('lang', $lang);
return $ret;
}
/*!
* \brief Determine which language to show to the user
*
* Determines which language should be used to present fusiondirectory content
* to the user. It does so by looking at several possibilites and returning
* the first setting that can be found.
*
* -# Language configured by the user
* -# Global configured language
* -# Language as returned by al2gt (as configured in the browser)
*
* \return string gettext locale string
*/
public static function detect()
{
global $config;
/* Try to use users primary language */
$ui = get_userinfo();
if (isset($ui) && ($ui !== NULL) && ($ui->language != '')) {
return $ui->language.'.UTF-8';
}
/* Check for global language settings in configuration */
if (isset($config) && ($config->get_cfg_value('language') != '')) {
$lang = $config->get_cfg_value('language');
if (!preg_match('/utf/i', $lang)) {
$lang .= '.UTF-8';
}
return $lang;
}
/* Load supported languages */
$languages = static::list();
/* Move supported languages to flat list */
$langs = array();
foreach (array_keys($languages) as $lang) {
$langs[] = $lang.'.UTF-8';
}
/* Return gettext based string */
return al2gt($langs);
}
/*!
* \brief Get the language for the user connecting
*
* \param boolean $languages_in_own_language FALSE
*
* \param boolean $strip_region_tag FALSE
*/
public static function list($languages_in_own_language = FALSE, $strip_region_tag = FALSE)
{
/* locales in english */
$tmp_english = array(
'ar' => 'Arabic',
'ca_ES' => 'Catalan',
'cs_CZ' => 'Czech',
'de_DE' => 'German',
'el_GR' => 'Greek',
'en_US' => 'English',
'es_CO' => 'Colombian Spanish',
'es_ES' => 'Spanish',
'es_VE' => 'Venezuelan',
'fa_IR' => 'Persian',
'fi_FI' => 'Finnish',
'fr_FR' => 'French',
'hu_HU' => 'Hungarian',
'id' => 'Indonesian',
'it_IT' => 'Italian',
'ja' => 'Japanese',
'ko' => 'Korean',
'lv' => 'Latvian',
'nb' => 'Norwegian Bokmål',
'nl_NL' => 'Dutch',
'pl_PL' => 'Polish',
'pt' => 'Portuguese',
'pt_BR' => 'Brazilian',
'ru_RU' => 'Russian',
'tr_TR' => 'Turkish',
'vi_VN' => 'Vietnamese',
'sv_SE' => 'Swedish',
'zh_CN' => 'Chinese',
);
$ret = array();
if ($languages_in_own_language) {
/* locales in their own language */
$tmp_ownlang = array(
'ar' => 'عربية',
'ca_ES' => 'Català',
'cs_CZ' => 'Česky',
'de_DE' => 'Deutsch',
'el_GR' => 'ελληνικά',
'en_US' => 'English',
'es_CO' => 'Español Colombiano',
'es_ES' => 'Español',
'es_VE' => 'Castellano',
'fa_IR' => 'پارسی',
'fi_FI' => 'Suomi',
'fr_FR' => 'Français',
'hu_HU' => 'Magyar',
'id' => 'Bahasa Indonesia',
'it_IT' => 'Italiano',
'ja' => '日本語',
'ko' => '한국어',
'lv' => 'Latviešu valoda',
'nb' => 'Norsk bokmål',
'nl_NL' => 'Nederlands',
'pl_PL' => 'Polski',
'pt' => 'Português',
'pt_BR' => 'Português (Brasil)',
'ru_RU' => 'русский язык',
'tr_TR' => 'Türkçe',
'vi_VN' => 'Tiếng Việt',
'sv_SE' => 'Svenska',
'zh_CN' => '中文, 汉语, 漢語',
);
foreach ($tmp_english as $key => $name) {
$label = _($name)." (".$tmp_ownlang[$key].")";
if ($strip_region_tag) {
$ret[preg_replace("/^([^_]*).*$/", "\\1", $key)] = $label;
} else {
$ret[$key] = $label;
}
}
} else {
foreach ($tmp_english as $key => $name) {
if ($strip_region_tag) {
$ret[preg_replace("/^([^_]*).*/", "\\1", $key)] = _($name);
} else {
$ret[$key] = _($name);
}
}
}
asort($ret);
return $ret;
}
/*!
* \brief Returns TRUE if $lang is a right to left language ($lang should match /.._..(\.UTF-8)?/)
*/
public static function isRTL ($lang)
{
$lang = preg_replace('/\.UTF-8$/', '', $lang);
if (preg_match('/^fa_/', $lang)) {
return TRUE;
}
return FALSE;
}
public static function setHeaders($language, $mime)
{
list ($lang, $country, $char) = parse_gettext_lang($language);
if (!headers_sent()) {
header("Content-Language: $lang".(empty($country) ? '' : "-$country"));
if (!empty($char)) {
header("Content-Type: $mime; charset=$char");
}
} else {
trigger_error('Could not set language '.$lang.' header, headers already sent');
}
}
}
......@@ -419,7 +419,7 @@ class config
timezone::setDefaultTimezoneFromConfig();
initLanguage();
Language::init();
}
/*!
......
......@@ -248,50 +248,6 @@ function DEBUG($level, $line, $function, $file, $data, $info = '')
}
}
/*!
* \brief Determine which language to show to the user
*
* Determines which language should be used to present fusiondirectory content
* to the user. It does so by looking at several possibilites and returning
* the first setting that can be found.
*
* -# Language configured by the user
* -# Global configured language
* -# Language as returned by al2gt (as configured in the browser)
*
* \return string gettext locale string
*/
function get_browser_language()
{
/* Try to use users primary language */
global $config;
$ui = get_userinfo();
if (isset($ui) && ($ui !== NULL) && ($ui->language != '')) {
return $ui->language.'.UTF-8';
}
/* Check for global language settings in configuration */
if (isset($config) && ($config->get_cfg_value('language') != '')) {
$lang = $config->get_cfg_value('language');
if (!preg_match('/utf/i', $lang)) {
$lang .= '.UTF-8';
}
return $lang;
}
/* Load supported languages */
$gosa_languages = get_languages();
/* Move supported languages to flat list */
$langs = array();
foreach (array_keys($gosa_languages) as $lang) {
$langs[] = $lang.'.UTF-8';
}
/* Return gettext based string */
return al2gt($langs, 'text/html');
}
/*!
* \brief Return themed path for specified base file
*
......@@ -2107,116 +2063,6 @@ function check_schema($cfg)
return $checks;
}
/*!
* \brief Get the language for the user connecting
*
* \param boolean $languages_in_own_language FALSE
*
* \param boolean $strip_region_tag FALSE
*/
function get_languages($languages_in_own_language = FALSE, $strip_region_tag = FALSE)
{
/* locales in english */
$tmp_english = array(
"ar" => "Arabic",
"ca_ES" => "Catalan",
"cs_CZ" => "Czech",
"de_DE" => "German",
"el_GR" => "Greek",
"en_US" => "English",
"es_CO" => "Colombian Spanish",
"es_ES" => "Spanish",
"es_VE" => "Venezuelan",
"fa_IR" => "Persian",
"fi_FI" => "Finnish",
"fr_FR" => "French",
"hu_HU" => "Hungarian",
"id" => "Indonesian",
"it_IT" => "Italian",
"ja" => "Japanese",
"ko" => "Korean",
"lv" => "Latvian",
"nb" => "Norwegian Bokmål",
"nl_NL" => "Dutch",
"pl_PL" => "Polish",
"pt" => "Portuguese",
"pt_BR" => "Brazilian",
"ru_RU" => "Russian",
"tr_TR" => "Turkish",
"vi_VN" => "Vietnamese",
"sv_SE" => "Swedish",
"zh_CN" => "Chinese",
);
$ret = array();
if ($languages_in_own_language) {
/* locales in their own language */
$tmp_ownlang = array(
"ar" => "عربية",
"ca_ES" => "Català",
"cs_CZ" => "Česky",
"de_DE" => "Deutsch",
"el_GR" => "ελληνικά",
"en_US" => "English",
"es_CO" => "Español Colombiano",
"es_ES" => "Español",
"es_VE" => "Castellano",
"fa_IR" => "پارسی",
"fi_FI" => "Suomi",
"fr_FR" => "Français",
"hu_HU" => "Magyar",
"id" => "Bahasa Indonesia",
"it_IT" => "Italiano",
"ja" => "日本語",
"ko" => "한국어",
"lv" => "Latviešu valoda",
"nb" => "Norsk bokmål",
"nl_NL" => "Nederlands",
"pl_PL" => "Polski",
"pt" => "Português",
"pt_BR" => "Português (Brasil)",
"ru_RU" => "русский язык",
"tr_TR" => "Türkçe",
"vi_VN" => "Tiếng Việt",
"sv_SE" => "Svenska",
"zh_CN" => "中文, 汉语, 漢語",
);
foreach ($tmp_english as $key => $name) {
$label = _($name)." (".$tmp_ownlang[$key].")";
if ($strip_region_tag) {
$ret[preg_replace("/^([^_]*).*$/", "\\1", $key)] = $label;
} else {
$ret[$key] = $label;
}
}
} else {
foreach ($tmp_english as $key => $name) {
if ($strip_region_tag) {
$ret[preg_replace("/^([^_]*).*/", "\\1", $key)] = _($name);
} else {
$ret[$key] = _($name);
}
}
}
asort($ret);
return $ret;
}
/*!
* \brief Returns TRUE if $lang is a right to left language ($lang should match /.._..(\.UTF-8)?/)
*/
function language_is_rtl ($lang)
{
$lang = preg_replace('/\.UTF-8$/', '', $lang);
if (preg_match('/^fa_/', $lang)) {
return TRUE;
}
return FALSE;
}
/*!
* \brief Returns contents of the given POST variable and check magic quotes settings
......@@ -2567,52 +2413,6 @@ function load_all_classes()
}
}
/*!
* \brief Initialize language configuration
*
* \param string $lang Language locale to use, defaults to get_browser_language
*/
function initLanguage($lang = NULL)
{
global $BASE_DIR;
if ($lang === NULL) {
$lang = get_browser_language();
}
putenv('LANGUAGE=');
putenv("LANG=$lang");
setlocale(LC_ALL, $lang);
$GLOBALS['t_language'] = $lang;
$GLOBALS['t_gettext_message_dir'] = $BASE_DIR.'/locale/';
/* Set the text domain as 'fusiondirectory' */
$domain = 'fusiondirectory';
bindtextdomain($domain, LOCALE_DIR);
textdomain($domain);
if ($_SERVER['REQUEST_METHOD'] != 'POST') {
@DEBUG (DEBUG_TRACE, __LINE__, __FUNCTION__, __FILE__, $lang, 'Setting language to');
}
$ret = FALSE;
/* Reset plist cache if language changed */
if ((!session::global_is_set('lang')) || (session::global_get('lang') != $lang)) {
$ret = TRUE;
if (session::global_is_set('plist')) {
if ($_SERVER['REQUEST_METHOD'] != 'POST') {
@DEBUG (DEBUG_TRACE, __LINE__, __FUNCTION__, __FILE__, session::global_get('lang'), 'Plist already loaded with language');
}
session::global_un_set('plist');
session::global_set('lang', $lang);
load_plist();
}
}
session::global_set('lang', $lang);
return $ret;
}
if (!function_exists('ldap_escape')) {
/* This bloc is for PHP<5.6 */
define('LDAP_ESCAPE_FILTER', 0x01);
......
......@@ -451,7 +451,7 @@ class configInLdap extends simplePlugin
global $config;
$attributesInfo = static::getAttributesInfo();
/* Languages */
$languages = get_languages(TRUE);
$languages = Language::list(TRUE);
$languages = array_merge(array("" => _("Automatic")), $languages);
$attributesInfo['look_n_feel']['attrs'][0]->setChoices(array_keys($languages), array_values($languages));
/* Timezones */
......
......@@ -304,7 +304,7 @@ class user extends simplePlugin
static function getAttributesInfo ()
{
global $config;
$languages = array_merge(array('' => ''), get_languages(TRUE));
$languages = array_merge(array('' => ''), Language::list(TRUE));
$attributesInfo = array(
'perso' => array(
'name' => _('Personal information'),
......
......@@ -50,7 +50,7 @@ class setupStepLanguage extends setupStep
function __construct($parent)
{
parent::__construct($parent);
$this->lang = get_browser_language();
$this->lang = Language::detect();
$this->attributesAccess['lang_selected']->setSize(20);
}
......@@ -64,7 +64,7 @@ class setupStepLanguage extends setupStep
function execute()
{
$languages = get_languages(TRUE);
$languages = Language::list(TRUE);
$languages = array_merge(array("" => _("Automatic")), $languages);
$this->attributesAccess['lang_selected']->setChoices(array_keys($languages), array_values($languages));
return parent::execute();
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment