$paths) { l10n_debug("load_language($domain): " .$cacti_textdomains[$domain]['path2catalogue']); switch (CACTI_LANGUAGE_HANDLER) { case CACTI_LANGUAGE_HANDLER_PHPGETTEXT: $l10n[$domain] = load_gettext_original($domain); break; case CACTI_LANGUAGE_HANDLER_MOTRANSLATOR: $l10n[$domain] = load_gettext_motranslator($domain); break; case CACTI_LANGUAGE_HANDLER_OSCAROTERO: $l10n[$domain] = load_gettext_oscarotero($domain); break; } if (empty($l10n[$domain])) { die('Invalid language support or corrupt/missing file: ' . $cacti_textdomains[$domain]['path2catalogue'] . PHP_EOF); } } unset($input); } /* load standard wrappers */ define('CACTI_LOCALE', $cacti_locale); define('CACTI_COUNTRY', $cacti_country); define('CACTI_LANGUAGE', $lang2locale[CACTI_LOCALE]['language']); define('CACTI_LANGUAGE_FILE', $catalogue); function load_gettext_original($domain) { global $cacti_textdomains; l10n_debug("load_gettext_original($domain): " .$cacti_textdomains[$domain]['path2catalogue']); $input = new FileReader($cacti_textdomains[$domain]['path2catalogue']); if ($input == false) { die('Unable to read file: ' . $cacti_textdomains[$domain]['path2catalogue'] . PHP_EOF); } $l10n_domain = new gettext_reader($input); if ($l10n_domain == false) { die('Invalid language file: ' . $cacti_textdomains[$domain]['path2catalogue'] . PHP_EOF); } return $l10n_domain; } function load_gettext_motranslator($domain) { global $cacti_textdomains; l10n_debug("load_gettext_mostranslator($domain): " .$cacti_textdomains[$domain]['path2catalogue']); $input = new PhpMyAdmin\MoTranslator\Translator($cacti_textdomains[$domain]['path2catalogue']); if ($input == false) { die('Unable to read file: ' . $cacti_textdomains[$domain]['path2catalogue'] . PHP_EOF); } return $input; } function load_gettext_oscarotero($domain) { global $cacti_textdomains; l10n_debug("load_gettext_oscarotero($domain): " .$cacti_textdomains[$domain]['path2catalogue']); $input = Gettext\Translations::fromMoFile($cacti_textdomains[$domain]['path2catalogue']); if ($input == false) { die('Unable to read file: ' . $cacti_textdomains[$domain]['path2catalogue'] . PHP_EOF); } $l10n_domain = new Gettext\Translator(); $l10n_domain->loadTranslations($input); if ($l10n_domain == false) { die('Invalid language file: ' . $cacti_textdomains[$domain]['path2catalogue'] . PHP_EOF); } return $l10n_domain; } function apply_locale($language) { global $cacti_locale, $cacti_country, $lang2locale; $locale_set = false; if ($language != '') { $language = repair_locale($language); $locale_set = isset($lang2locale[$language]); } // If the users has not elected a language and autodetect is on if (!$locale_set && (isset($_SERVER['HTTP_ACCEPT_LANGUAGE']) && (read_config_option('i18n_auto_detection') == '' || read_config_option('i18n_auto_detection') == '1'))) { /* detect browser settings if auto detection is enabled */ $accepted = explode(',', $_SERVER['HTTP_ACCEPT_LANGUAGE']); $accepted = $accepted[0]; $language = repair_locale($accepted); $locale_set = isset($lang2locale[$language]); } if (!$locale_set) { $language = repair_locale(read_config_option('i18n_default_language')); if ($language == false || $language == '') { $language = repair_locale(read_default_config_option('i18n_default_language')); } $locale_set = isset($lang2locale[$language]); } if ($locale_set) { $cacti_locale = $language; $cacti_country = $lang2locale[$cacti_locale]['country']; return $cacti_locale; } return false; } /* best effort function to repair locale */ function repair_locale($language) { global $lang2locale; /* Repair legacy language support */ $found_locale = ''; $locale = str_replace('_','-', $language); if (array_key_exists($locale, $lang2locale)) { $language = $locale; } else { $wanted_locale = substr($language, 0, 2); $language = ''; foreach ($lang2locale as $locale => $data) { if (substr($locale, 0, 2) == $wanted_locale) { $language = $locale; break; } } } return $language; } /** * 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; /* reset variables */ $_SESSION['sess_user_language'] = ''; $cacti_textdomains = array(); define('CACTI_LOCALE', 'en-US'); define('CACTI_COUNTRY', 'us'); define('CACTI_LANGUAGE', 'English'); define('CACTI_LANGUAGE_FILE', 'english_usa'); define('CACTI_LANGUAGE_HANDLER', CACTI_LANGUAGE_HANDLER_NONE); } function __gettext($text, $domain = 'cacti') { global $l10n; // Assume translation fails or is not defined if (isset($l10n[$domain])) { switch (CACTI_LANGUAGE_HANDLER) { case CACTI_LANGUAGE_HANDLER_PHPGETTEXT: $translated = $l10n[$domain]->translate($text); break; case CACTI_LANGUAGE_HANDLER_OSCAROTERO: case CACTI_LANGUAGE_HANDLER_MOTRANSLATOR: $translated = $l10n[$domain]->gettext($text); break; } } if (!isset($translated)) { $translated = $text; } else { l10n_debug("__gettext($domain):\n Original: $text\n Translated: $translated", FILE_APPEND); } return __uf($translated); } function __n($singular, $plural, $number, $domain = 'cacti') { global $l10n; if (isset($l10n[$domain])) { return __uf($l10n[$domain]->ngettext($singular, $plural, $number)); } else { return ($number == 1) ? __uf($singular) : __uf($plural); } } function __uf($text) { return str_replace('%%', '%', $text); } 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]]) && $args[1] != 'cacti') { 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 */ if (isset($l10n[$args[$num-1]]) && $args[$num-1] != 'cacti') { $args[0] = __gettext($args[0], $args[$num-1]); } else { $args[0] = __gettext($args[0]); } /* process return string against input arguments */ return __uf(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 ) ? __uf($singular) : __uf($msgstr); } else { return ( $msgstr == $xplural ) ? __uf($plural) : __uf($msgstr); } } function __x() { global $l10n; $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 == 1) { /* 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]]) && $args[$num-1] != 'cacti' ? __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 __uf(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 __uf($date); } /** * 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-AL' => array('language' => 'Albanian', 'direction' => 'ltr', 'country' => 'al', 'filename' => 'albanian_albania'), 'ar-SA' => array('language' => 'Arabic', 'direction' => 'rtl', 'country' => 'sa', 'filename' => 'arabic_saudi_arabia'), 'hy-AM' => array('language' => 'Armenian', 'direction' => 'ltr', 'country' => 'am', 'filename' => 'armenian_armenia'), 'be-BY' => array('language' => 'Belarusian', 'direction' => 'ltr', 'country' => 'by', 'filename' => 'belarusian_belarus'), 'bg-BG' => array('language' => 'Bulgarian', 'direction' => 'ltr', 'country' => 'bg', 'filename' => 'bulgarian_bulgaria'), 'zh-CN' => array('language' => 'Chinese (China)', 'direction' => 'ltr', 'country' => 'cn', 'filename' => 'chinese_china_simplified'), 'zh-HK' => array('language' => 'Chinese (Hong Kong)', 'direction' => 'ltr', 'country' => 'hk', 'filename' => 'chinese_hong_kong'), 'zh-SG' => array('language' => 'Chinese (Singapore)', 'direction' => 'ltr', 'country' => 'sg', 'filename' => 'chinese_singapore'), 'zh-TW' => array('language' => 'Chinese (Taiwan)', 'direction' => 'ltr', 'country' => 'tw', 'filename' => 'chinese_taiwan'), 'hr-HR' => array('language' => 'Croatian', 'direction' => 'ltr', 'country' => 'hr', 'filename' => 'croatian_croatia'), 'cs-GZ' => array('language' => 'Czech', 'direction' => 'ltr', 'country' => 'cz', 'filename' => 'czech_czech_republic'), 'da-DK' => array('language' => 'Danish', 'direction' => 'ltr', 'country' => 'dk', 'filename' => 'danish_denmark'), 'nl-NL' => array('language' => 'Dutch', 'direction' => 'ltr', 'country' => 'nl', 'filename' => 'dutch_netherlands'), 'en-US' => array('language' => 'English', 'direction' => 'ltr', 'country' => 'us', 'filename' => 'english_usa'), 'en-GB' => array('language' => 'English (Britain)', 'direction' => 'ltr', 'country' => 'gb', 'filename' => 'english_gb'), 'et-EE' => array('language' => 'Estonian', 'direction' => 'ltr', 'country' => 'ee', 'filename' => 'estonian_estonia'), 'fi-FI' => array('language' => 'Finnish', 'direction' => 'ltr', 'country' => 'fi', 'filename' => 'finnish_finland'), 'fr-FR' => array('language' => 'French', 'direction' => 'ltr', 'country' => 'fr', 'filename' => 'french_france'), 'de-DE' => array('language' => 'German', 'direction' => 'ltr', 'country' => 'de', 'filename' => 'german_germany'), 'el-GR' => array('language' => 'Greek', 'direction' => 'ltr', 'country' => 'gr', 'filename' => 'greek_greece'), 'he-IL' => array('language' => 'Hebrew', 'direction' => 'rtl', 'country' => 'il', 'filename' => 'hebrew_israel'), 'hi-IN' => array('language' => 'Hindi', 'direction' => 'ltr', 'country' => 'in', 'filename' => 'hindi_india'), 'hu-HU' => array('language' => 'Hungarian', 'direction' => 'ltr', 'country' => 'hu', 'filename' => 'hungarian_hungary'), 'is-IS' => array('language' => 'Icelandic', 'direction' => 'ltr', 'country' => 'is', 'filename' => 'icelandic_iceland'), 'id-ID' => array('language' => 'Indonesian', 'direction' => 'ltr', 'country' => 'id', 'filename' => 'indonesian_indonesia'), 'ga-IE' => array('language' => 'Irish', 'direction' => 'ltr', 'country' => 'ie', 'filename' => 'irish_ireland'), 'it-IT' => array('language' => 'Italian', 'direction' => 'ltr', 'country' => 'it', 'filename' => 'italian_italy'), 'ja-JP' => array('language' => 'Japanese', 'direction' => 'ltr', 'country' => 'jp', 'filename' => 'japanese_japan'), 'ko-KR' => array('language' => 'Korean', 'direction' => 'ltr', 'country' => 'kr', 'filename' => 'korean_korea'), 'lv-LV' => array('language' => 'Lativan', 'direction' => 'ltr', 'country' => 'lv', 'filename' => 'latvian_latvia'), 'lt-LT' => array('language' => 'Lithuanian', 'direction' => 'ltr', 'country' => 'lt', 'filename' => 'lithuanian_lithuania'), 'mk-MK' => array('language' => 'Macedonian', 'direction' => 'ltr', 'country' => 'mk', 'filename' => 'macedonian_macedonia'), 'ms-MY' => array('language' => 'Malay', 'direction' => 'ltr', 'country' => 'my', 'filename' => 'malay_malaysia'), 'mt-LT' => array('language' => 'Maltese', 'direction' => 'ltr', 'country' => 'lt', 'filename' => 'maltese_malta'), 'no-NO' => array('language' => 'Norwegian', 'direction' => 'ltr', 'country' => 'no', 'filename' => 'norwegian_norway'), 'pl-PL' => array('language' => 'Polish', 'direction' => 'ltr', 'country' => 'pl', 'filename' => 'polish_poland'), 'pt-PT' => array('language' => 'Portuguese', 'direction' => 'ltr', 'country' => 'pt', 'filename' => 'portuguese_portugal'), 'pt-BR' => array('language' => 'Portuguese (Brazil)', 'direction' => 'ltr', 'country' => 'br', 'filename' => 'portuguese_brazil'), 'ro-RO' => array('language' => 'Romanian', 'direction' => 'ltr', 'country' => 'ro', 'filename' => 'romanian_romania'), 'ru-RU' => array('language' => 'Russian', 'direction' => 'ltr', 'country' => 'ru', 'filename' => 'russian_russia'), 'sr-RS' => array('language' => 'Serbian', 'direction' => 'ltr', 'country' => 'rs', 'filename' => 'serbian_serbia'), 'sk-SK' => array('language' => 'Slovak', 'direction' => 'ltr', 'country' => 'sk', 'filename' => 'slovak_slovakia'), 'sl-SI' => array('language' => 'Slovenian', 'direction' => 'ltr', 'country' => 'si', 'filename' => 'slovenian_slovenia'), 'es-ES' => array('language' => 'Spanish', 'direction' => 'ltr', 'country' => 'es', 'filename' => 'spanish_spain'), 'sv-SE' => array('language' => 'Swedish', 'direction' => 'ltr', 'country' => 'se', 'filename' => 'swedish_sweden'), 'th-TH' => array('language' => 'Thai', 'direction' => 'ltr', 'country' => 'th', 'filename' => 'thai_thailand'), 'tr-TR' => array('language' => 'Turkish', 'direction' => 'ltr', 'country' => 'tr', 'filename' => 'turkish_turkey'), 'vi-VN' => array('language' => 'Vietnamese', 'direction' => 'ltr', '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-US'] = $lang2locale['en-US']['language']; foreach ($lang2locale as $locale => $properties) { $locations[$properties['filename'] . '.mo'] = array( 'locale' => $locale, 'language' => $properties['language'] ); $locations[$locale . '.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))) { if (isset($locations[$filename]['language'])) { $supported_languages[$locations[$filename]['locale']] = $locations[$filename]['language']; } } } asort($supported_languages); 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']; } elseif ((read_config_option('auth_method') == 0)) { if (isset($_SESSION['sess_config_array'])) { $config_array = $_SESSION['sess_config_array']; } elseif (isset($config['config_options_array'])) { $config_array = $config['config_options_array']; } if (!isset($config_array[$config_name])) { $effective_uid = db_fetch_cell_prepared('SELECT id FROM user_auth WHERE id = ?', array(get_guest_account())); } if ($effective_uid == '') { $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 = null, $baseu = 1024) { global $cacti_locale, $cacti_country; $country = strtoupper($cacti_country); if (function_exists('numfmt_create')) { $fmt_key = $cacti_locale . '_'. $country; $fmt = numfmt_create($fmt_key, NumberFormatter::DECIMAL); if ($fmt !== false && $fmt !== null) { numfmt_set_attribute($fmt, NumberFormatter::MAX_FRACTION_DIGITS, $decimals); return numfmt_format($fmt, $number); } cacti_log('DEBUG: Number format \'' . $fmt_key .'\' was unavailable, using older methods',false,'i18n',POLLER_VERBOSITY_HIGH); } $origlocales = explode(';', setlocale(LC_ALL, 0)); setlocale(LC_ALL, $cacti_locale); $locale = localeconv(); if (!isset($locale['decimal_point']) || $locale['decimal_point'] == '') { $locale['decimal_point'] = '.'; } if (!isset($locale['thousands_sep']) || $locale['thousands_sep'] == '') { $locale['thousands_sep'] = ','; } if ($decimals == -1 || $decimals == null) { $number = number_format($number, null, $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; } function get_new_user_default_language() { $accepted = repair_locale(read_config_option('i18n_default_language')); if ($accepted == '') { $accepted = repair_locale(read_default_config_option('i18n_default_language')); } return $accepted; } function l10n_debug($text, $mode = FILE_APPEND, $eol = PHP_EOL) { if (is_dir('/share/') && is_writeable('/share/i18n.log')) { file_put_contents('/share/i18n.log', $text . $eol, $mode); } elseif (file_exists('/tmp/i18n.log') && is_writeable('/tmp/i18n.log')) { file_put_contents('/tmp/i18n.log', $text . $eol, $mode); } }