Files
cacti/include/global_languages.php
T
Browniebraun f158bcc875 Referring to issue #335
Add universal wrapper function to escape translations before being inserted into the final output as HTML attribute.
Languages like French are making use of many quotation marks. In this case the HTML syntax will become invalid.
2017-03-01 12:17:09 +01:00

625 lines
22 KiB
PHP

<?php
/*
+-------------------------------------------------------------------------+
| Copyright (C) 2004-2017 The Cacti Group |
| |
| 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. |
+-------------------------------------------------------------------------+
| Cacti: The Complete RRDTool-based Graphing Solution |
+-------------------------------------------------------------------------+
| This code is designed, written, and maintained by the Cacti Group. See |
| about.php and/or the AUTHORS file for specific developer information. |
+-------------------------------------------------------------------------+
| http://www.cacti.net/ |
+-------------------------------------------------------------------------+
*/
/* default localization of Cacti */
$cacti_locale = 'en';
$cacti_country = 'us';
/* an array that will contains all textdomains being in use. */
$cacti_textdomains = array();
/* get a list of locale settings */
$lang2locale = get_list_of_locales();
/* use a fallback if i18n is disabled (default) */
if (!read_config_option('i18n_language_support') && read_config_option('i18n_language_support') != '')
{
load_fallback_procedure();
return;
}
/* determine whether or not we can support the language */
if (isset($_REQUEST['language']) && isset($lang2locale[$_REQUEST['language']]))
/* user requests another language */
{
$cacti_locale = $_REQUEST['language'];
$cacti_country = $lang2locale[$_REQUEST['language']]['country'];
$_SESSION['sess_user_language'] = $cacti_locale;
unset($_SESSION['sess_current_date1']);
unset($_SESSION['sess_current_date2']);
/* save customized language setting (authenticated users only) */
set_user_config_option('language', $cacti_locale);
}
/* language definition stored in the SESSION */
elseif (isset($_SESSION['sess_user_language']) && isset($lang2locale[$_SESSION['sess_user_language']]))
{
$cacti_locale = $_SESSION['sess_user_language'];
$cacti_country = $lang2locale[$_SESSION['sess_user_language']]['country'];
}
elseif ($user_locale = read_user_i18n_setting('user_language'))
/* look up for user customized language setting stored in Cacti DB */
{
if (isset($lang2locale[$user_locale]))
{
$cacti_locale = $user_locale;
$cacti_country = $lang2locale[$cacti_locale]['country'];
$_SESSION['sess_user_language'] = $cacti_locale;
}
}
elseif ( isset($_SERVER['HTTP_ACCEPT_LANGUAGE']) && ( read_config_option('i18n_auto_detection') | read_config_option('i18n_auto_detection') == '' ) )
/* detect browser settings if auto detection is enabled */
{
$accepted = $_SERVER['HTTP_ACCEPT_LANGUAGE'];
$accepted = strtolower(str_replace(strstr($accepted, ','), '', $accepted));
$accepted = (isset($lang2locale[$accepted])) ? $accepted : str_replace(strstr($accepted, '-'), '', $accepted);
if (isset($lang2locale[$accepted]))
{
$cacti_locale = $accepted;
$cacti_country = $lang2locale[$accepted]['country'];
}
}
else
/* use the default language defined under 'general' */
{
$accepted = read_config_option('i18n_default_language');
if ($accepted == '')
{
$accepted = read_default_config_option('i18n_default_language');
}
if (isset($lang2locale[$accepted]))
{
$cacti_locale = $accepted;
$cacti_country = $lang2locale[$accepted]['country'];
}
}
/* define the path to the language file */
$path2catalogue = $config['base_path'] . '/locales/LC_MESSAGES/' . $lang2locale[$cacti_locale]['filename'] . '.mo';
/* define the path to the language file of the DHTML calendar */
$path2calendar = $config['include_path'] . '/js/LC_MESSAGES/jquery.ui.datepicker-' . $lang2locale[$cacti_locale]['filename'] . '.js';
/* use fallback procedure if requested language is not available */
if (file_exists($path2catalogue) & file_exists($path2calendar))
{
$cacti_textdomains['cacti']['path2locales'] = $config['base_path'] . '/locales';
$cacti_textdomains['cacti']['path2catalogue'] = $path2catalogue;
}
else
{
load_fallback_procedure();
return;
}
/* search the correct textdomains for all plugins being installed */
$plugins = db_fetch_assoc('SELECT `directory` FROM `plugin_config` ORDER BY id');
if ($plugins && sizeof($plugins) > 0)
{
foreach($plugins as $plugin)
{
$plugin = $plugin['directory'];
$path2catalogue = $config['base_path'] . '/plugins/' . $plugin . '/locales/LC_MESSAGES/' . $lang2locale[$cacti_locale]['filename'] . '.mo';
if (file_exists($path2catalogue))
{
$cacti_textdomains[$plugin]['path2locales'] = $config['base_path'] . '/plugins/' . $plugin . '/locales';
$cacti_textdomains[$plugin]['path2catalogue'] = $path2catalogue;
}
}
/* if i18n support is set to strict mode then check if all plugins support the requested language */
if (read_config_option('i18n_language_support') == 2)
{
if(sizeof($plugins) != (sizeof($cacti_textdomains) - 1))
{
load_fallback_procedure();
return;
}
}
}
/* load php-gettext class */
require($config['include_path'] . '/phpgettext/streams.php');
require($config['include_path'] . '/phpgettext/gettext.php');
/* prefetch all language files to work in memory only,
die if one of the language files is corrupted */
$l10n = array();
foreach($cacti_textdomains as $domain => $paths) {
$input = new FileReader($cacti_textdomains[$domain]['path2catalogue']);
if($input == false) {
die('Unable to read file: ' . $cacti_textdomains[$domain]['path2catalogue']);
}
$l10n[$domain] = new gettext_reader($input);
if($l10n[$domain] == false) {
die('Invalid language file: ' . $cacti_textdomains[$domain]['path2catalogue']);
}
}
unset($input);
/* load standard wrappers */
load_i18n_gettext_wrappers();
define('CACTI_LOCALE', $cacti_locale);
define('CACTI_COUNTRY', $cacti_country);
define('CACTI_LANGUAGE', $lang2locale[CACTI_LOCALE]['language']);
define('CACTI_LANGUAGE_FILE', $lang2locale[CACTI_LOCALE]['filename']);
/**
* Universal escaping wrappers
*/
function __esc() {
return htmlspecialchars( call_user_func_array('__', func_get_args()), ENT_QUOTES);
}
function __esc_n() {
return htmlspecialchars( call_user_func_array('__n', func_get_args()), ENT_QUOTES);
}
function __esc_x() {
return htmlspecialchars( call_user_func_array('__x', func_get_args()), ENT_QUOTES);
}
function __esc_xn() {
return htmlspecialchars( call_user_func_array('__xn', func_get_args()), ENT_QUOTES);
}
/**
* load_fallback_procedure - loads wrapper package if native language (English) has to be used
*
* @return
*/
function load_fallback_procedure(){
global $cacti_textdomains, $cacti_locale, $cacti_country, $lang2locale;
/* load wrappers if native gettext is not available */
load_i18n_fallback_wrappers();
/* reset variables */
$_SESSION['sess_user_language'] = '';
$cacti_textdomains = array();
define('CACTI_LOCALE', 'en');
define('CACTI_COUNTRY', 'us');
define('CACTI_LANGUAGE', 'English');
define('CACTI_LANGUAGE_FILE', 'english_usa');
}
/**
* load_i18n_gettext_wrappers - creates all wrappers to translate strings by using php-gettext
*
* @return
*/
function load_i18n_gettext_wrappers(){
function __gettext($text, $domain = 'cacti') {
global $l10n;
if (isset($l10n[$domain])) {
return $l10n[$domain]->translate($text);
}else {
return $text;
}
}
function __n($singular, $plural, $number, $domain = 'cacti'){
global $l10n;
if (isset($l10n[$domain])) {
return $l10n[$domain]->ngettext($singular, $plural, $number);
}else {
return ($number == 1) ? $singular : $plural;
}
}
function __() {
global $l10n;
$args = func_get_args();
$num = func_num_args();
/* this should not happen */
if ($num < 1) {
return false;
/* convert pure text strings */
}elseif ($num == 1) {
return __gettext($args[0]);
/* convert pure text strings by using a different textdomain */
}elseif ($num == 2 && isset($l10n[$args[1]])) {
return __gettext($args[0], $args[1]);
/* convert stings including one or more placeholders */
}else {
/* only the last argument is allowed to initiate
the use of a different textdomain */
/* get gettext string */
$args[0] = isset($l10n[$args[$num-1]]) ? __gettext($args[0], $args[$num-1])
: __gettext($args[0]);
/* process return string against input arguments */
return call_user_func_array('sprintf', $args);
}
}
function __xn($context, $singular, $plural, $number, $domain = 'cacti'){
$xsingular = $context . chr(4) . $singular;
$xplural = $context . chr(4) . $plural;
$msgstr = __n($xsingular, $xplural, $number, $domain);
if($number == 1 ) {
return ( $msgstr == $xsingular ) ? $singular : $msgstr;
}else {
return ( $msgstr == $xplural ) ? $plural : $msgstr;
}
}
function __x(){
$args = func_get_args();
$num = func_num_args();
/* this should never happen */
if ($num < 2) {
return false;
}else {
$context = array_shift($args);
$num--;
$msgid = reset($args);
$xmsgid = $context . chr(4) . $msgid;
$args[0] = $xmsgid;
if($num == 2) {
/* pure text string without placeholders and a change of the default textdomain */
$msgstr = __gettext($args[0]);
}else {
/* get gettext string */
$msgstr = isset($l10n[$args[$num-1]]) ? __gettext($args[0], $args[$num-1])
: __gettext($args[0]);
}
/* use the raw message id if language catalogue does not contain a context specific message string */
$args[0] = ( $msgstr == $xmsgid ) ? $msgid : $msgstr;
/* process return string against input arguments */
return call_user_func_array('sprintf', $args);
}
}
function __date($format, $timestamp = false, $domain = 'cacti') {
global $i18n_date_placeholders;
if (!$timestamp) {
$timestamp = time();
}
/* placeholders will allow to fill in the translated weekdays, month and so on.. */
$i18n_date_placeholders = array(
'#1' => __(date('D', $timestamp), $domain),
'#2' => __(date('M', $timestamp), $domain),
'#3' => __(date('F', $timestamp), $domain),
'#4' => __(date('l', $timestamp), $domain)
);
/* if defined exchange the format string for the configured locale */
$format = __gettext($format, $domain);
/* replace special date chars by placeholders */
$format = str_replace(array('D', 'M', 'F', 'l'), array('#1', '#2', '#3', '#4'), $format);
/* get date string included placeholders */
$date = date($format, $timestamp);
/* fill in specific translations */
$date = str_replace(array_keys($i18n_date_placeholders), array_values($i18n_date_placeholders), $date);
return $date;
}
}
/**
* load_i18n_fallback_wrappers - creates special wrappers to leave the native language untouched
*
* @return
*/
function load_i18n_fallback_wrappers(){
function __gettext($text, $domain = 'cacti') {
return $text;
}
function __n($singular, $plural, $number, $domain = 'cacti') {
return ($number == 1) ? $singular : $plural;
}
function __() {
$args = func_get_args();
$num = func_num_args();
/* this should not happen */
if ($num < 1) {
return false;
/* convert pure text strings */
}elseif ($num == 1) {
return $args[0];
/* convert pure text strings by using a different textdomain */
}elseif ($num == 2 && isset($l10n[$args[1]])) {
return $args[0];
/* convert stings including one or more placeholders */
}else {
/* only the last argument is allowed to initiate
the use of a different textdomain */
/* process return string against input arguments */
return call_user_func_array('sprintf', $args);
}
}
function __xn($context, $singular, $plural, $number, $domain = 'cacti'){
return __n($singular, $plural, $number, $domain);
}
function __x(){
$args = func_get_args();
$num = func_num_args();
/* this should never happen */
if ($num < 2) {
return false;
}else {
$context = array_shift($args);
return call_user_func_array('__', $args);
}
}
function __date($format, $timestamp = false, $domain = 'cacti') {
if (!$timestamp) {$timestamp = time();}
return date($format, $timestamp);
}
}
/**
* get_list_of_locales - returns the default settings being used for l10n
*
* @return - a multi-dimensional array with the locale code as main key
*/
function get_list_of_locales () {
$lang2locale = array(
'sq' => array('language' => 'Albanian', 'country' => 'al', 'filename' => 'albanian_albania'),
'ar' => array('language' => 'Arabic', 'country' => 'sa', 'filename' => 'arabic_saudi_arabia'),
'hy' => array('language' => 'Armenian', 'country' => 'am', 'filename' => 'armenian_armenia'),
'be' => array('language' => 'Belarusian', 'country' => 'by', 'filename' => 'belarusian_belarus'),
'bg' => array('language' => 'Bulgarian', 'country' => 'bg', 'filename' => 'bulgarian_bulgaria'),
'zh' => array('language' => 'Chinese', 'country' => 'cn', 'filename' => 'chinese_china'),
'zh-cn'=> array('language' => 'Chinese (China)', 'country' => 'cn', 'filename' => 'chinese_china_simplified'),
'zh-hk'=> array('language' => 'Chinese (Hong Kong)', 'country' => 'hk', 'filename' => 'chinese_hong_kong'),
'zh-sg'=> array('language' => 'Chinese (Singapore)', 'country' => 'sg', 'filename' => 'chinese_singapore'),
'zh-tw'=> array('language' => 'Chinese (Taiwan)', 'country' => 'tw', 'filename' => 'chinese_taiwan'),
'hr' => array('language' => 'Croatian', 'country' => 'hr', 'filename' => 'croatian_croatia'),
'cs' => array('language' => 'Czech', 'country' => 'cz', 'filename' => 'czech_czech_republic'),
'da' => array('language' => 'Danish', 'country' => 'dk', 'filename' => 'danish_denmark'),
'nl' => array('language' => 'Dutch', 'country' => 'nl', 'filename' => 'dutch_netherlands'),
'en' => array('language' => 'English', 'country' => 'us', 'filename' => 'english_usa'),
'et' => array('language' => 'Estonian', 'country' => 'ee', 'filename' => 'estonian_estonia'),
'fi' => array('language' => 'Finnish', 'country' => 'fi', 'filename' => 'finnish_finland'),
'fr' => array('language' => 'French', 'country' => 'fr', 'filename' => 'french_france'),
'de' => array('language' => 'German', 'country' => 'de', 'filename' => 'german_germany'),
'el' => array('language' => 'Greek', 'country' => 'gr', 'filename' => 'greek_greece'),
'iw' => array('language' => 'Hebrew', 'country' => 'il', 'filename' => 'hebrew_israel'),
'hi' => array('language' => 'Hindi', 'country' => 'in', 'filename' => 'hindi_india'),
'hu' => array('language' => 'Hungarian', 'country' => 'hu', 'filename' => 'hungarian_hungary'),
'is' => array('language' => 'Icelandic', 'country' => 'is', 'filename' => 'icelandic_iceland'),
'id' => array('language' => 'Indonesian', 'country' => 'id', 'filename' => 'indonesian_indonesia'),
'ga' => array('language' => 'Irish', 'country' => 'ie', 'filename' => 'irish_ireland'),
'it' => array('language' => 'Italian', 'country' => 'it', 'filename' => 'italian_italy'),
'ja' => array('language' => 'Japanese', 'country' => 'jp', 'filename' => 'japanese_japan'),
'ko' => array('language' => 'Korean', 'country' => 'kr', 'filename' => 'korean_korea'),
'lv' => array('language' => 'Lativan', 'country' => 'lv', 'filename' => 'latvian_latvia'),
'lt' => array('language' => 'Lithuanian', 'country' => 'lt', 'filename' => 'lithuanian_lithuania'),
'mk' => array('language' => 'Macedonian', 'country' => 'mk', 'filename' => 'macedonian_macedonia'),
'ms' => array('language' => 'Malay', 'country' => 'my', 'filename' => 'malay_malaysia'),
'mt' => array('language' => 'Maltese', 'country' => 'lt', 'filename' => 'maltese_malta'),
'no' => array('language' => 'Norwegian', 'country' => 'no', 'filename' => 'norwegian_norway'),
'pl' => array('language' => 'Polish', 'country' => 'pl', 'filename' => 'polish_poland'),
'pt' => array('language' => 'Portuguese', 'country' => 'pt', 'filename' => 'portuguese_portugal'),
'pt-br'=> array('language' => 'Portuguese (Brazil)', 'country' => 'br', 'filename' => 'portuguese_brazil'),
'ro' => array('language' => 'Romanian', 'country' => 'ro', 'filename' => 'romanian_romania'),
'ru' => array('language' => 'Russian', 'country' => 'ru', 'filename' => 'russian_russia'),
'sr' => array('language' => 'Serbian', 'country' => 'rs', 'filename' => 'serbian_serbia'),
'sk' => array('language' => 'Slovak', 'country' => 'sk', 'filename' => 'slovak_slovakia'),
'sl' => array('language' => 'Slovenian', 'country' => 'si', 'filename' => 'slovenian_slovenia'),
'es' => array('language' => 'Spanish', 'country' => 'es', 'filename' => 'spanish_spain'),
'sv' => array('language' => 'Swedish', 'country' => 'se', 'filename' => 'swedish_sweden'),
'th' => array('language' => 'Thai', 'country' => 'th', 'filename' => 'thai_thailand'),
'tr' => array('language' => 'Turkish', 'country' => 'tr', 'filename' => 'turkish_turkey'),
'vi' => array('language' => 'Vietnamese', 'country' => 'vn', 'filename' => 'vietnamese_vietnam')
);
return $lang2locale;
}
/**
* get_installed_locales - finds all installed locales
*
* @return - an associative array of all installed locales (e.g. 'en' => 'English')
*/
function get_installed_locales(){
global $config, $lang2locale;
$locations = array();
$supported_languages['en'] = $lang2locale['en']['language'];
foreach($lang2locale as $locale => $properties) {
$locations[$properties['filename'] . '.mo'] = array('locale' => $locale, 'language' => $properties['language']);
}
/* create a list of all languages this Cacti system supports ... */
$dhandle = opendir($config['base_path'] . '/locales/LC_MESSAGES');
if(is_resource($dhandle)) {
while (false !== ($filename = readdir($dhandle))) {
/* check if language file for DHTML calendar is also available */
$path2calendar = $config['include_path'] . '/js/LC_MESSAGES/jquery.ui.datepicker-' . str_replace('.mo', '.js', $filename);
if(isset($locations[$filename]) & file_exists($path2calendar)) {
$supported_languages[$locations[$filename]['locale']] = $locations[$filename]['language'];
}
}
}
return $supported_languages;
}
/* read_user_i18n_setting - finds the current value of a i18n configuration setting
@arg $config_name - the name of the configuration setting as specified $settings_user array
in 'include/global_settings.php'
@returns - the current value of the i18n configuration option or the system default value */
function read_user_i18n_setting($config_name) {
global $config;
/* users must have cacti user auth turned on to use this, or the guest account must be active */
if (isset($_SESSION['sess_user_id'])) {
$effective_uid = $_SESSION['sess_user_id'];
}else if (isset($config['config_options_array']['export_user_id'])) {
$effective_uid = $config['config_options_array']['export_user_id'];
}else if ((read_config_option('auth_method') == 0)) {
if (isset($_SESSION['sess_config_array'])) {
$config_array = $_SESSION['sess_config_array'];
}else if (isset($config['config_options_array'])) {
$config_array = $config['config_options_array'];
}
if (!isset($config_array[$config_name])) {
$effective_uid = db_fetch_cell("SELECT user_auth.id
FROM settings
INNER JOIN user_auth
ON user_auth.username = settings.value
WHERE settings.name = 'guest_user'");
}
if (strlen($effective_uid) == 0) {
$effective_uid = 0;
}
}else{
$effective_uid = 0;
}
if (db_table_exists('settings_user')) {
$db_setting = db_fetch_row_prepared('SELECT value
FROM settings_user
WHERE name = ?
AND user_id = ?',
array($config_name, $effective_uid));
}
if (isset($db_setting['value'])) {
return $db_setting['value'];
}else{
return false;
}
}
/**
* number_format_i18n - local specific number format wrapper
*
* @return - formatted numer in the correct locale
*/
function number_format_i18n($number, $decimals = 2, $baseu = 1024) {
global $cacti_locale, $cacti_country;
$country = strtoupper($cacti_country);
if (function_exists('numfmt_create')) {
$fmt = numfmt_create($cacti_locale . '_' . $country, NumberFormatter::DECIMAL);
numfmt_set_attribute($fmt, NumberFormatter::MAX_FRACTION_DIGITS, $decimals);
return numfmt_format($fmt, $number);
}else{
$origlocales = explode(';', setlocale(LC_ALL, 0));
setlocale(LC_ALL, $cacti_locale . '_' . $country);
$locale = localeconv();
if ($decimals == -1) {
$number = number_format($number, $decimals, $locale['decimal_point'], $locale['thousands_sep']);
}elseif ($number>=pow($baseu, 4)) {
$number = number_format($number/pow($baseu, 4), $decimals, $locale['decimal_point'], $locale['thousands_sep']) . __(' T');
} elseif($number>=pow($baseu, 3)) {
$number = number_format($number/pow($baseu, 3), $decimals, $locale['decimal_point'], $locale['thousands_sep']) . __(' G');
} elseif($number>=pow($baseu, 2)) {
$number = number_format($number/pow($baseu, 2), $decimals, $locale['decimal_point'], $locale['thousands_sep']) . __(' M');
} elseif($number>=$baseu) {
$number = number_format($number/$baseu, $decimals, $locale['decimal_point'], $locale['thousands_sep']) . __(' K');
} else {
$number = number_format($number, $decimals, $locale['decimal_point'], $locale['thousands_sep']);
}
foreach ($origlocales as $locale_setting) {
if (strpos($locale_setting, '=') !== false) {
list($category, $locale) = explode('=', $locale_setting);
} else {
$category = LC_ALL;
$locale = $locale_setting;
}
switch($category) {
case 'LC_ALL':
case 'LC_COLLATE':
case 'LC_CTYPE':
case 'LC_MONETARY':
case 'LC_NUMERIC':
case 'LC_TIME':
if (defined($category)) {
setlocale(constant($category), $locale);
}
}
}
return $number;
}
}