1<?php 2/* 3 +-------------------------------------------------------------------------+ 4 | Copyright (C) 2004-2021 The Cacti Group | 5 | | 6 | This program is free software; you can redistribute it and/or | 7 | modify it under the terms of the GNU General Public License | 8 | as published by the Free Software Foundation; either version 2 | 9 | of the License, or (at your option) any later version. | 10 | | 11 | This program is distributed in the hope that it will be useful, | 12 | but WITHOUT ANY WARRANTY; without even the implied warranty of | 13 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | 14 | GNU General Public License for more details. | 15 +-------------------------------------------------------------------------+ 16 | Cacti: The Complete RRDtool-based Graphing Solution | 17 +-------------------------------------------------------------------------+ 18 | This code is designed, written, and maintained by the Cacti Group. See | 19 | about.php and/or the AUTHORS file for specific developer information. | 20 +-------------------------------------------------------------------------+ 21 | http://www.cacti.net/ | 22 +-------------------------------------------------------------------------+ 23*/ 24 25/* default localization of Cacti */ 26$cacti_locale = 'en-US'; 27$cacti_country = 'us'; 28 29/* an array that will contains all textdomains being in use. */ 30$cacti_textdomains = array(); 31 32global $path2calendar, $path2timepicker, $path2colorpicker; 33 34/* get a list of locale settings */ 35$lang2locale = get_list_of_locales(); 36 37/* use a fallback if i18n is disabled (default) */ 38if (!read_config_option('i18n_language_support') && read_config_option('i18n_language_support') != '') { 39 l10n_debug("load_fallback_procedure(1)"); 40 load_fallback_procedure(); 41 return; 42} 43 44/* Repair legacy language support */ 45if (isset($_REQUEST['language'])) { 46 $_REQUEST['language'] = repair_locale($_REQUEST['language']); 47} 48 49/* determine whether or not we can support the language */ 50$user_locale = ''; 51if (isset($_REQUEST['language']) && isset($lang2locale[$_REQUEST['language']])) { 52 /* user requests another language */ 53 $user_locale = apply_locale($_REQUEST['language']); 54 unset($_SESSION['sess_current_date1']); 55 unset($_SESSION['sess_current_date2']); 56 57 /* save customized language setting (authenticated users only) */ 58 set_user_setting('language', $user_locale); 59} elseif (isset($_SESSION['sess_user_language']) && isset($lang2locale[$_SESSION['sess_user_language']])) { 60 /* language definition stored in the SESSION */ 61 $user_locale = apply_locale($_SESSION['sess_user_language']); 62} else { 63 /* look up for user customized language setting stored in Cacti DB */ 64 $user_locale = apply_locale(read_user_i18n_setting('user_language')); 65} 66 67/* allow RRDtool to display i18n */ 68setlocale(LC_CTYPE, str_replace('-', '_', $user_locale) . '.UTF-8'); 69 70if ($user_locale !== false && $user_locale !== '') { 71 $_SESSION['sess_user_language'] = $user_locale; 72} 73 74/* define the path to the language file */ 75l10n_debug("search(1): " . $config['base_path'] . '/locales/LC_MESSAGES/' . $cacti_locale . '.mo'); 76l10n_debug("search(2): " . $config['base_path'] . '/locales/LC_MESSAGES/' . $lang2locale[$cacti_locale]['filename'] . '.mo'); 77 78if (file_exists($config['base_path'] . '/locales/LC_MESSAGES/' . $cacti_locale . '.mo')) { 79 $path2catalogue = $config['base_path'] . '/locales/LC_MESSAGES/' . $cacti_locale . '.mo'; 80} elseif (file_exists($config['base_path'] . '/locales/LC_MESSAGES/' . $lang2locale[$cacti_locale]['filename'] . '.mo')) { 81 $path2catalogue = $config['base_path'] . '/locales/LC_MESSAGES/' . $lang2locale[$cacti_locale]['filename'] . '.mo'; 82} else { 83 $path2catalogue = ''; 84} 85 86$catalogue = $path2catalogue; 87 88/* define the path to the language file of the DHTML calendar */ 89if ($cacti_locale != '') { 90 $lang_parts = explode('-', $cacti_locale); 91 92 // Detect the calendar path 93 if (file_exists($config['include_path'] . '/js/LC_MESSAGES/jquery-ui-datepicker-' . $cacti_locale . '.js')) { 94 $path2calendar = $config['include_path'] . '/js/LC_MESSAGES/jquery-ui-datepicker-' . $cacti_locale . '.js'; 95 } elseif (file_exists($config['include_path'] . '/js/LC_MESSAGES/jquery-ui-datepicker-' . $lang_parts[0] . '.js')) { 96 $path2calendar = $config['include_path'] . '/js/LC_MESSAGES/jquery-ui-datepicker-' . $lang_parts[0] . '.js'; 97 } else { 98 $path2calendar = ''; 99 } 100 101 // Detect the timepicker path 102 if (file_exists($config['include_path'] . '/js/LC_MESSAGES/jquery-ui-timepicker-' . $cacti_locale . '.js')) { 103 $path2timepicker = $config['include_path'] . '/js/LC_MESSAGES/jquery-ui-timepicker-' . $cacti_locale . '.js'; 104 } elseif (file_exists($config['include_path'] . '/js/LC_MESSAGES/jquery-ui-timepicker-' . $lang_parts[0] . '.js')) { 105 $path2timepicker = $config['include_path'] . '/js/LC_MESSAGES/jquery-ui-timepicker-' . $lang_parts[0] . '.js'; 106 } else { 107 $path2timepicker = ''; 108 } 109 110 // Detect the colorpicker path 111 if (file_exists($config['include_path'] . '/js/LC_MESSAGES/jquery.ui.colorpicker-' . $cacti_locale . '.js')) { 112 $path2colorpicker = $config['include_path'] . '/js/LC_MESSAGES/jquery.ui.colorpicker-' . $cacti_locale . '.js'; 113 } elseif (file_exists($config['include_path'] . '/js/LC_MESSAGES/jquery.ui.colorpicker-' . $lang_parts[0] . '.js')) { 114 $path2colorpicker = $config['include_path'] . '/js/LC_MESSAGES/jquery.ui.colorpicker-' . $lang_parts[0] . '.js'; 115 } else { 116 $path2colorpicker = ''; 117 } 118} else { 119 $path2timepicker = ''; 120 $path2calendar = ''; 121 $path2colorpicker = ''; 122} 123 124/* use fallback procedure if requested language is not available */ 125if (file_exists($path2catalogue)) { 126 $cacti_textdomains['cacti']['path2catalogue'] = $path2catalogue; 127} else { 128 l10n_debug("load_fallback_procedure(2): " . $path2catalogue); 129 load_fallback_procedure(); 130 return; 131} 132 133/* search the correct textdomains for all plugins being installed */ 134$plugins = db_fetch_assoc('SELECT `directory` 135 FROM `plugin_config` 136 ORDER BY id'); 137 138if ($plugins && cacti_sizeof($plugins)) { 139 foreach ($plugins as $plugin) { 140 $plugin = $plugin['directory']; 141 142 if (file_exists($config['base_path'] . '/plugins/' . $plugin . '/locales/LC_MESSAGES/' . $cacti_locale . '.mo')) { 143 $path2catalogue = $config['base_path'] . '/plugins/' . $plugin . '/locales/LC_MESSAGES/' . $cacti_locale . '.mo'; 144 } elseif (file_exists($config['base_path'] . '/plugins/' . $plugin . '/locales/LC_MESSAGES/' . $lang2locale[$cacti_locale]['filename'] . '.mo')) { 145 $path2catalogue = $config['base_path'] . '/plugins/' . $plugin . '/locales/LC_MESSAGES/' . $lang2locale[$cacti_locale]['filename'] . '.mo'; 146 } 147 148 if (file_exists($path2catalogue)) { 149 $cacti_textdomains[$plugin]['path2catalogue'] = $path2catalogue; 150 } 151 } 152 153 /* if i18n support is set to strict mode then check if all plugins support the requested language */ 154 if (read_config_option('i18n_language_support') == 2) { 155 if (cacti_sizeof($plugins) != (cacti_sizeof($cacti_textdomains) - 1)) { 156 l10n_debug("load_fallback_procedure(3)"); 157 load_fallback_procedure(); 158 return; 159 } 160 } 161} 162 163l10n_debug("require(1)"); 164 165/* load php-gettext class if present */ 166$l10n = array(); 167 168// Is the handler defined in the db? 169$l10n_handler = read_config_option('l10n_language_handler'); 170 171// Is the handler defined in the config but not the db? 172if (empty($l10n_handler) && !empty($config['l10n_language_handler'])) { 173 l10n_debug('Handler: not specified in settings'); 174 $l10n_handler = $config['l10n_language_handler']; 175} 176 177if (empty($l10n_handler)) { 178 l10n_debug('Handler: not specified in config, autodetection is now in progress'); 179 if (file_exists($config['include_path'] . '/vendor/gettext/src/Translator.php')) { 180 $l10n_handler = CACTI_LANGUAGE_HANDLER_OSCAROTERO; 181 } elseif (file_exists($config['include_path'] . '/vendor/phpgettext/streams.php')) { 182 $l10n_handler = CACTI_LANGUAGE_HANDLER_PHPGETTEXT; 183 } elseif (file_exists($config['include_path'] . '/vendor/motranslator/src/Translator.php')) { 184 $l10n_handler = CACTI_LANGUAGE_HANDLER_MOTRANSLATOR; 185 } 186} 187 188l10n_debug("require(1): Handler $l10n_handler"); 189switch ($l10n_handler) { 190 case CACTI_LANGUAGE_HANDLER_OSCAROTERO: 191 //require($config['include_path'] . '/vendor/gettext/oscarotero.php'); 192 require_once($config['include_path'] . '/vendor/gettext/src/autoloader.php'); 193 require_once($config['include_path'] . '/vendor/cldr-to-gettext-plural-rules/src/autoloader.php'); 194 break; 195 196 case CACTI_LANGUAGE_HANDLER_PHPGETTEXT: 197 require_once($config['include_path'] . '/vendor/phpgettext/streams.php'); 198 require_once($config['include_path'] . '/vendor/phpgettext/gettext.php'); 199 break; 200 201 case CACTI_LANGUAGE_HANDLER_MOTRANSLATOR: 202 require_once($config['include_path'] . '/vendor/motranslator/src/Translator.php'); 203 require_once($config['include_path'] . '/vendor/motranslator/src/StringReader.php'); 204 break; 205 206 default: 207 $l10n_handler = CACTI_LANGUAGE_HANDLER_NONE; 208 break; 209} 210 211define('CACTI_LANGUAGE_HANDLER', $l10n_handler); 212l10n_debug("require(2): Handler " . CACTI_LANGUAGE_HANDLER); 213 214if (CACTI_LANGUAGE_HANDLER != CACTI_LANGUAGE_HANDLER_NONE) { 215 /* prefetch all language files to work in memory only, 216 die if one of the language files is corrupted */ 217 218 foreach ($cacti_textdomains as $domain => $paths) { 219 l10n_debug("load_language($domain): " .$cacti_textdomains[$domain]['path2catalogue']); 220 switch (CACTI_LANGUAGE_HANDLER) { 221 case CACTI_LANGUAGE_HANDLER_PHPGETTEXT: 222 $l10n[$domain] = load_gettext_original($domain); 223 break; 224 225 case CACTI_LANGUAGE_HANDLER_MOTRANSLATOR: 226 $l10n[$domain] = load_gettext_motranslator($domain); 227 break; 228 229 case CACTI_LANGUAGE_HANDLER_OSCAROTERO: 230 $l10n[$domain] = load_gettext_oscarotero($domain); 231 break; 232 } 233 234 if (empty($l10n[$domain])) { 235 die('Invalid language support or corrupt/missing file: ' . $cacti_textdomains[$domain]['path2catalogue'] . PHP_EOF); 236 } 237 } 238 unset($input); 239} 240 241/* load standard wrappers */ 242define('CACTI_LOCALE', $cacti_locale); 243define('CACTI_COUNTRY', $cacti_country); 244define('CACTI_LANGUAGE', $lang2locale[CACTI_LOCALE]['language']); 245define('CACTI_LANGUAGE_FILE', $catalogue); 246 247function load_gettext_original($domain) { 248 global $cacti_textdomains; 249 250 l10n_debug("load_gettext_original($domain): " .$cacti_textdomains[$domain]['path2catalogue']); 251 $input = new FileReader($cacti_textdomains[$domain]['path2catalogue']); 252 if ($input == false) { 253 die('Unable to read file: ' . $cacti_textdomains[$domain]['path2catalogue'] . PHP_EOF); 254 } 255 256 $l10n_domain = new gettext_reader($input); 257 if ($l10n_domain == false) { 258 die('Invalid language file: ' . $cacti_textdomains[$domain]['path2catalogue'] . PHP_EOF); 259 } 260 return $l10n_domain; 261} 262 263function load_gettext_motranslator($domain) { 264 global $cacti_textdomains; 265 266 l10n_debug("load_gettext_mostranslator($domain): " .$cacti_textdomains[$domain]['path2catalogue']); 267 $input = new PhpMyAdmin\MoTranslator\Translator($cacti_textdomains[$domain]['path2catalogue']); 268 if ($input == false) { 269 die('Unable to read file: ' . $cacti_textdomains[$domain]['path2catalogue'] . PHP_EOF); 270 } 271 return $input; 272} 273 274function load_gettext_oscarotero($domain) { 275 global $cacti_textdomains; 276 277 l10n_debug("load_gettext_oscarotero($domain): " .$cacti_textdomains[$domain]['path2catalogue']); 278 $input = Gettext\Translations::fromMoFile($cacti_textdomains[$domain]['path2catalogue']); 279 if ($input == false) { 280 die('Unable to read file: ' . $cacti_textdomains[$domain]['path2catalogue'] . PHP_EOF); 281 } 282 283 $l10n_domain = new Gettext\Translator(); 284 $l10n_domain->loadTranslations($input); 285 if ($l10n_domain == false) { 286 die('Invalid language file: ' . $cacti_textdomains[$domain]['path2catalogue'] . PHP_EOF); 287 } 288 return $l10n_domain; 289} 290 291function apply_locale($language) { 292 global $cacti_locale, $cacti_country, $lang2locale; 293 294 $locale_set = false; 295 if ($language != '') { 296 $language = repair_locale($language); 297 $locale_set = isset($lang2locale[$language]); 298 } 299 300 // If the users has not elected a language and autodetect is on 301 if (!$locale_set && (isset($_SERVER['HTTP_ACCEPT_LANGUAGE']) && (read_config_option('i18n_auto_detection') == '' || read_config_option('i18n_auto_detection') == '1'))) { 302 /* detect browser settings if auto detection is enabled */ 303 $accepted = explode(',', $_SERVER['HTTP_ACCEPT_LANGUAGE']); 304 $accepted = $accepted[0]; 305 306 $language = repair_locale($accepted); 307 $locale_set = isset($lang2locale[$language]); 308 } 309 310 if (!$locale_set) { 311 $language = repair_locale(read_config_option('i18n_default_language')); 312 if ($language == false || $language == '') { 313 $language = repair_locale(read_default_config_option('i18n_default_language')); 314 } 315 316 $locale_set = isset($lang2locale[$language]); 317 } 318 319 if ($locale_set) { 320 $cacti_locale = $language; 321 $cacti_country = $lang2locale[$cacti_locale]['country']; 322 return $cacti_locale; 323 } 324 325 return false; 326} 327 328/* best effort function to repair locale */ 329function repair_locale($language) { 330 global $lang2locale; 331 332 /* Repair legacy language support */ 333 $found_locale = ''; 334 $locale = str_replace('_','-', $language); 335 if (array_key_exists($locale, $lang2locale)) { 336 $language = $locale; 337 } else { 338 $wanted_locale = substr($language, 0, 2); 339 $language = ''; 340 foreach ($lang2locale as $locale => $data) { 341 if (substr($locale, 0, 2) == $wanted_locale) { 342 $language = $locale; 343 break; 344 } 345 } 346 } 347 348 return $language; 349} 350 351/** 352 * Universal escaping wrappers 353 */ 354function __esc() { 355 return htmlspecialchars( call_user_func_array('__', func_get_args()), ENT_QUOTES); 356} 357 358function __esc_n() { 359 return htmlspecialchars( call_user_func_array('__n', func_get_args()), ENT_QUOTES); 360} 361 362function __esc_x() { 363 return htmlspecialchars( call_user_func_array('__x', func_get_args()), ENT_QUOTES); 364} 365 366function __esc_xn() { 367 return htmlspecialchars( call_user_func_array('__xn', func_get_args()), ENT_QUOTES); 368} 369 370/** 371 * load_fallback_procedure - loads wrapper package if native language (English) has to be used 372 * 373 * @return 374 */ 375function load_fallback_procedure(){ 376 global $cacti_textdomains, $cacti_locale, $cacti_country, $lang2locale; 377 378 /* reset variables */ 379 $_SESSION['sess_user_language'] = ''; 380 381 $cacti_textdomains = array(); 382 define('CACTI_LOCALE', 'en-US'); 383 define('CACTI_COUNTRY', 'us'); 384 define('CACTI_LANGUAGE', 'English'); 385 define('CACTI_LANGUAGE_FILE', 'english_usa'); 386 define('CACTI_LANGUAGE_HANDLER', CACTI_LANGUAGE_HANDLER_NONE); 387} 388 389function __gettext($text, $domain = 'cacti') { 390 global $l10n; 391 392 // Assume translation fails or is not defined 393 if (isset($l10n[$domain])) { 394 switch (CACTI_LANGUAGE_HANDLER) { 395 case CACTI_LANGUAGE_HANDLER_PHPGETTEXT: 396 $translated = $l10n[$domain]->translate($text); 397 break; 398 399 case CACTI_LANGUAGE_HANDLER_OSCAROTERO: 400 case CACTI_LANGUAGE_HANDLER_MOTRANSLATOR: 401 $translated = $l10n[$domain]->gettext($text); 402 break; 403 } 404 } 405 406 if (!isset($translated)) { 407 $translated = $text; 408 } else { 409 l10n_debug("__gettext($domain):\n Original: $text\n Translated: $translated", FILE_APPEND); 410 } 411 412 return __uf($translated); 413} 414 415function __n($singular, $plural, $number, $domain = 'cacti') { 416 global $l10n; 417 if (isset($l10n[$domain])) { 418 return __uf($l10n[$domain]->ngettext($singular, $plural, $number)); 419 } else { 420 return ($number == 1) ? __uf($singular) : __uf($plural); 421 } 422} 423 424function __uf($text) { 425 return str_replace('%%', '%', $text); 426} 427 428function __() { 429 global $l10n; 430 431 $args = func_get_args(); 432 $num = func_num_args(); 433 434 /* this should not happen */ 435 if ($num < 1) { 436 return false; 437 438 /* convert pure text strings */ 439 } elseif ($num == 1) { 440 return __gettext($args[0]); 441 442 /* convert pure text strings by using a different textdomain */ 443 } elseif ($num == 2 && isset($l10n[$args[1]]) && $args[1] != 'cacti') { 444 return __gettext($args[0], $args[1]); 445 446 /* convert stings including one or more placeholders */ 447 } else { 448 /* only the last argument is allowed to initiate 449 the use of a different textdomain */ 450 451 /* get gettext string */ 452 if (isset($l10n[$args[$num-1]]) && $args[$num-1] != 'cacti') { 453 $args[0] = __gettext($args[0], $args[$num-1]); 454 } else { 455 $args[0] = __gettext($args[0]); 456 } 457 458 /* process return string against input arguments */ 459 return __uf(call_user_func_array('sprintf', $args)); 460 } 461} 462 463function __xn($context, $singular, $plural, $number, $domain = 'cacti') { 464 $xsingular = $context . chr(4) . $singular; 465 $xplural = $context . chr(4) . $plural; 466 467 $msgstr = __n($xsingular, $xplural, $number, $domain); 468 469 if ($number == 1 ) { 470 return ( $msgstr == $xsingular ) ? __uf($singular) : __uf($msgstr); 471 } else { 472 return ( $msgstr == $xplural ) ? __uf($plural) : __uf($msgstr); 473 } 474} 475 476function __x() { 477 global $l10n; 478 479 $args = func_get_args(); 480 $num = func_num_args(); 481 482 /* this should never happen */ 483 if ($num < 2) { 484 return false; 485 } else { 486 $context = array_shift($args); 487 $num--; 488 489 $msgid = reset($args); 490 $xmsgid = $context . chr(4) . $msgid; 491 492 $args[0] = $xmsgid; 493 494 if ($num == 1) { 495 /* pure text string without placeholders and a change of the default textdomain */ 496 $msgstr = __gettext($args[0]); 497 } else { 498 /* get gettext string */ 499 $msgstr = isset($l10n[$args[$num-1]]) && $args[$num-1] != 'cacti' ? 500 __gettext($args[0], $args[$num-1]) : __gettext($args[0]); 501 } 502 503 /* use the raw message id if language catalogue does not contain a context specific message string */ 504 $args[0] = ( $msgstr == $xmsgid ) ? $msgid : $msgstr; 505 506 /* process return string against input arguments */ 507 return __uf(call_user_func_array('sprintf', $args)); 508 } 509} 510 511function __date($format, $timestamp = false, $domain = 'cacti') { 512 global $i18n_date_placeholders; 513 514 if (!$timestamp) { 515 $timestamp = time(); 516 } 517 518 /* placeholders will allow to fill in the translated weekdays, month and so on.. */ 519 $i18n_date_placeholders = array( 520 '#1' => __(date('D', $timestamp), $domain), 521 '#2' => __(date('M', $timestamp), $domain), 522 '#3' => __(date('F', $timestamp), $domain), 523 '#4' => __(date('l', $timestamp), $domain) 524 ); 525 526 /* if defined exchange the format string for the configured locale */ 527 $format = __gettext($format, $domain); 528 529 /* replace special date chars by placeholders */ 530 $format = str_replace(array('D', 'M', 'F', 'l'), array('#1', '#2', '#3', '#4'), $format); 531 532 /* get date string included placeholders */ 533 $date = date($format, $timestamp); 534 535 /* fill in specific translations */ 536 $date = str_replace(array_keys($i18n_date_placeholders), array_values($i18n_date_placeholders), $date); 537 538 return __uf($date); 539} 540 541/** 542 * get_list_of_locales - returns the default settings being used for l10n 543 * 544 * @return - a multi-dimensional array with the locale code as main key 545 */ 546function get_list_of_locales() { 547 $lang2locale = array( 548 'sq-AL' => array('language' => 'Albanian', 'direction' => 'ltr', 'country' => 'al', 'filename' => 'albanian_albania'), 549 'ar-SA' => array('language' => 'Arabic', 'direction' => 'rtl', 'country' => 'sa', 'filename' => 'arabic_saudi_arabia'), 550 'hy-AM' => array('language' => 'Armenian', 'direction' => 'ltr', 'country' => 'am', 'filename' => 'armenian_armenia'), 551 'be-BY' => array('language' => 'Belarusian', 'direction' => 'ltr', 'country' => 'by', 'filename' => 'belarusian_belarus'), 552 'bg-BG' => array('language' => 'Bulgarian', 'direction' => 'ltr', 'country' => 'bg', 'filename' => 'bulgarian_bulgaria'), 553 'zh-CN' => array('language' => 'Chinese (China)', 'direction' => 'ltr', 'country' => 'cn', 'filename' => 'chinese_china_simplified'), 554 'zh-HK' => array('language' => 'Chinese (Hong Kong)', 'direction' => 'ltr', 'country' => 'hk', 'filename' => 'chinese_hong_kong'), 555 'zh-SG' => array('language' => 'Chinese (Singapore)', 'direction' => 'ltr', 'country' => 'sg', 'filename' => 'chinese_singapore'), 556 'zh-TW' => array('language' => 'Chinese (Taiwan)', 'direction' => 'ltr', 'country' => 'tw', 'filename' => 'chinese_taiwan'), 557 'hr-HR' => array('language' => 'Croatian', 'direction' => 'ltr', 'country' => 'hr', 'filename' => 'croatian_croatia'), 558 'cs-GZ' => array('language' => 'Czech', 'direction' => 'ltr', 'country' => 'cz', 'filename' => 'czech_czech_republic'), 559 'da-DK' => array('language' => 'Danish', 'direction' => 'ltr', 'country' => 'dk', 'filename' => 'danish_denmark'), 560 'nl-NL' => array('language' => 'Dutch', 'direction' => 'ltr', 'country' => 'nl', 'filename' => 'dutch_netherlands'), 561 'en-US' => array('language' => 'English', 'direction' => 'ltr', 'country' => 'us', 'filename' => 'english_usa'), 562 'en-GB' => array('language' => 'English (Britain)', 'direction' => 'ltr', 'country' => 'gb', 'filename' => 'english_gb'), 563 'et-EE' => array('language' => 'Estonian', 'direction' => 'ltr', 'country' => 'ee', 'filename' => 'estonian_estonia'), 564 'fi-FI' => array('language' => 'Finnish', 'direction' => 'ltr', 'country' => 'fi', 'filename' => 'finnish_finland'), 565 'fr-FR' => array('language' => 'French', 'direction' => 'ltr', 'country' => 'fr', 'filename' => 'french_france'), 566 'de-DE' => array('language' => 'German', 'direction' => 'ltr', 'country' => 'de', 'filename' => 'german_germany'), 567 'el-GR' => array('language' => 'Greek', 'direction' => 'ltr', 'country' => 'gr', 'filename' => 'greek_greece'), 568 'he-IL' => array('language' => 'Hebrew', 'direction' => 'rtl', 'country' => 'il', 'filename' => 'hebrew_israel'), 569 'hi-IN' => array('language' => 'Hindi', 'direction' => 'ltr', 'country' => 'in', 'filename' => 'hindi_india'), 570 'hu-HU' => array('language' => 'Hungarian', 'direction' => 'ltr', 'country' => 'hu', 'filename' => 'hungarian_hungary'), 571 'is-IS' => array('language' => 'Icelandic', 'direction' => 'ltr', 'country' => 'is', 'filename' => 'icelandic_iceland'), 572 'id-ID' => array('language' => 'Indonesian', 'direction' => 'ltr', 'country' => 'id', 'filename' => 'indonesian_indonesia'), 573 'ga-IE' => array('language' => 'Irish', 'direction' => 'ltr', 'country' => 'ie', 'filename' => 'irish_ireland'), 574 'it-IT' => array('language' => 'Italian', 'direction' => 'ltr', 'country' => 'it', 'filename' => 'italian_italy'), 575 'ja-JP' => array('language' => 'Japanese', 'direction' => 'ltr', 'country' => 'jp', 'filename' => 'japanese_japan'), 576 'ko-KR' => array('language' => 'Korean', 'direction' => 'ltr', 'country' => 'kr', 'filename' => 'korean_korea'), 577 'lv-LV' => array('language' => 'Lativan', 'direction' => 'ltr', 'country' => 'lv', 'filename' => 'latvian_latvia'), 578 'lt-LT' => array('language' => 'Lithuanian', 'direction' => 'ltr', 'country' => 'lt', 'filename' => 'lithuanian_lithuania'), 579 'mk-MK' => array('language' => 'Macedonian', 'direction' => 'ltr', 'country' => 'mk', 'filename' => 'macedonian_macedonia'), 580 'ms-MY' => array('language' => 'Malay', 'direction' => 'ltr', 'country' => 'my', 'filename' => 'malay_malaysia'), 581 'mt-LT' => array('language' => 'Maltese', 'direction' => 'ltr', 'country' => 'lt', 'filename' => 'maltese_malta'), 582 'no-NO' => array('language' => 'Norwegian', 'direction' => 'ltr', 'country' => 'no', 'filename' => 'norwegian_norway'), 583 'pl-PL' => array('language' => 'Polish', 'direction' => 'ltr', 'country' => 'pl', 'filename' => 'polish_poland'), 584 'pt-PT' => array('language' => 'Portuguese', 'direction' => 'ltr', 'country' => 'pt', 'filename' => 'portuguese_portugal'), 585 'pt-BR' => array('language' => 'Portuguese (Brazil)', 'direction' => 'ltr', 'country' => 'br', 'filename' => 'portuguese_brazil'), 586 'ro-RO' => array('language' => 'Romanian', 'direction' => 'ltr', 'country' => 'ro', 'filename' => 'romanian_romania'), 587 'ru-RU' => array('language' => 'Russian', 'direction' => 'ltr', 'country' => 'ru', 'filename' => 'russian_russia'), 588 'sr-RS' => array('language' => 'Serbian', 'direction' => 'ltr', 'country' => 'rs', 'filename' => 'serbian_serbia'), 589 'sk-SK' => array('language' => 'Slovak', 'direction' => 'ltr', 'country' => 'sk', 'filename' => 'slovak_slovakia'), 590 'sl-SI' => array('language' => 'Slovenian', 'direction' => 'ltr', 'country' => 'si', 'filename' => 'slovenian_slovenia'), 591 'es-ES' => array('language' => 'Spanish', 'direction' => 'ltr', 'country' => 'es', 'filename' => 'spanish_spain'), 592 'sv-SE' => array('language' => 'Swedish', 'direction' => 'ltr', 'country' => 'se', 'filename' => 'swedish_sweden'), 593 'th-TH' => array('language' => 'Thai', 'direction' => 'ltr', 'country' => 'th', 'filename' => 'thai_thailand'), 594 'tr-TR' => array('language' => 'Turkish', 'direction' => 'ltr', 'country' => 'tr', 'filename' => 'turkish_turkey'), 595 'vi-VN' => array('language' => 'Vietnamese', 'direction' => 'ltr', 'country' => 'vn', 'filename' => 'vietnamese_vietnam') 596 ); 597 598 return $lang2locale; 599} 600 601/** 602 * get_installed_locales - finds all installed locales 603 * 604 * @return - an associative array of all installed locales (e.g. 'en' => 'English') 605 */ 606function get_installed_locales() { 607 global $config, $lang2locale; 608 609 $locations = array(); 610 $supported_languages['en-US'] = $lang2locale['en-US']['language']; 611 foreach ($lang2locale as $locale => $properties) { 612 $locations[$properties['filename'] . '.mo'] = array( 613 'locale' => $locale, 614 'language' => $properties['language'] 615 ); 616 $locations[$locale . '.mo'] = array( 617 'locale' => $locale, 618 'language' => $properties['language'] 619 ); 620 } 621 622 /* create a list of all languages this Cacti system supports ... */ 623 $dhandle = opendir($config['base_path'] . '/locales/LC_MESSAGES'); 624 if (is_resource($dhandle)) { 625 while (false !== ($filename = readdir($dhandle))) { 626 if (isset($locations[$filename]['language'])) { 627 $supported_languages[$locations[$filename]['locale']] = $locations[$filename]['language']; 628 } 629 } 630 } 631 632 asort($supported_languages); 633 634 return $supported_languages; 635} 636 637/* read_user_i18n_setting - finds the current value of a i18n configuration setting 638 @arg $config_name - the name of the configuration setting as specified $settings_user array 639 in 'include/global_settings.php' 640 @returns - the current value of the i18n configuration option or the system default value */ 641function read_user_i18n_setting($config_name) { 642 global $config; 643 644 /* users must have cacti user auth turned on to use this, or the guest account must be active */ 645 if (isset($_SESSION['sess_user_id'])) { 646 $effective_uid = $_SESSION['sess_user_id']; 647 } elseif ((read_config_option('auth_method') == 0)) { 648 if (isset($_SESSION['sess_config_array'])) { 649 $config_array = $_SESSION['sess_config_array']; 650 } elseif (isset($config['config_options_array'])) { 651 $config_array = $config['config_options_array']; 652 } 653 654 if (!isset($config_array[$config_name])) { 655 $effective_uid = db_fetch_cell_prepared('SELECT id 656 FROM user_auth 657 WHERE id = ?', 658 array(get_guest_account())); 659 } 660 661 if ($effective_uid == '') { 662 $effective_uid = 0; 663 } 664 } else { 665 $effective_uid = 0; 666 } 667 668 if (db_table_exists('settings_user')) { 669 $db_setting = db_fetch_row_prepared('SELECT value 670 FROM settings_user 671 WHERE name = ? 672 AND user_id = ?', 673 array($config_name, $effective_uid)); 674 } 675 676 if (isset($db_setting['value'])) { 677 return $db_setting['value']; 678 } else { 679 return false; 680 } 681} 682 683/** 684 * number_format_i18n - local specific number format wrapper 685 * 686 * @return - formatted numer in the correct locale 687 */ 688function number_format_i18n($number, $decimals = null, $baseu = 1024) { 689 global $cacti_locale, $cacti_country; 690 691 $country = strtoupper($cacti_country); 692 693 if (function_exists('numfmt_create')) { 694 $fmt_key = $cacti_locale . '_'. $country; 695 $fmt = numfmt_create($fmt_key, NumberFormatter::DECIMAL); 696 if ($fmt !== false && $fmt !== null) { 697 numfmt_set_attribute($fmt, NumberFormatter::MAX_FRACTION_DIGITS, $decimals); 698 699 return numfmt_format($fmt, $number); 700 } 701 cacti_log('DEBUG: Number format \'' . $fmt_key .'\' was unavailable, using older methods',false,'i18n',POLLER_VERBOSITY_HIGH); 702 } 703 704 $origlocales = explode(';', setlocale(LC_ALL, 0)); 705 setlocale(LC_ALL, $cacti_locale); 706 $locale = localeconv(); 707 708 if (!isset($locale['decimal_point']) || $locale['decimal_point'] == '') { 709 $locale['decimal_point'] = '.'; 710 } 711 712 if (!isset($locale['thousands_sep']) || $locale['thousands_sep'] == '') { 713 $locale['thousands_sep'] = ','; 714 } 715 716 if ($decimals == -1 || $decimals == null) { 717 $number = number_format($number, null, $locale['decimal_point'], $locale['thousands_sep']); 718 } elseif ($number>=pow($baseu, 4)) { 719 $number = number_format($number/pow($baseu, 4), $decimals, $locale['decimal_point'], $locale['thousands_sep']) . __(' T'); 720 } elseif ($number>=pow($baseu, 3)) { 721 $number = number_format($number/pow($baseu, 3), $decimals, $locale['decimal_point'], $locale['thousands_sep']) . __(' G'); 722 } elseif ($number>=pow($baseu, 2)) { 723 $number = number_format($number/pow($baseu, 2), $decimals, $locale['decimal_point'], $locale['thousands_sep']) . __(' M'); 724 } elseif ($number>=$baseu) { 725 $number = number_format($number/$baseu, $decimals, $locale['decimal_point'], $locale['thousands_sep']) . __(' K'); 726 } else { 727 $number = number_format($number, $decimals, $locale['decimal_point'], $locale['thousands_sep']); 728 } 729 730 foreach ($origlocales as $locale_setting) { 731 if (strpos($locale_setting, '=') !== false) { 732 list($category, $locale) = explode('=', $locale_setting); 733 } else { 734 $category = LC_ALL; 735 $locale = $locale_setting; 736 } 737 738 switch($category) { 739 case 'LC_ALL': 740 case 'LC_COLLATE': 741 case 'LC_CTYPE': 742 case 'LC_MONETARY': 743 case 'LC_NUMERIC': 744 case 'LC_TIME': 745 if (defined($category)) { 746 setlocale(constant($category), $locale); 747 } 748 } 749 } 750 751 return $number; 752} 753 754function get_new_user_default_language() { 755 $accepted = repair_locale(read_config_option('i18n_default_language')); 756 if ($accepted == '') { 757 $accepted = repair_locale(read_default_config_option('i18n_default_language')); 758 } 759 return $accepted; 760} 761 762function l10n_debug($text, $mode = FILE_APPEND, $eol = PHP_EOL) { 763 if (is_dir('/share/') && is_writeable('/share/i18n.log')) { 764 file_put_contents('/share/i18n.log', $text . $eol, $mode); 765 } elseif (file_exists('/tmp/i18n.log') && is_writeable('/tmp/i18n.log')) { 766 file_put_contents('/tmp/i18n.log', $text . $eol, $mode); 767 } 768} 769