1<?php 2/* 3** Zabbix 4** Copyright (C) 2001-2021 Zabbix SIA 5** 6** This program is free software; you can redistribute it and/or modify 7** it under the terms of the GNU General Public License as published by 8** the Free Software Foundation; either version 2 of the License, or 9** (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** You should have received a copy of the GNU General Public License 17** along with this program; if not, write to the Free Software 18** Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. 19**/ 20 21 22/** 23 * In case gettext functions do not exist, just replacing them with our own, 24 * so user can see at least English translation. 25 */ 26if (!function_exists('_')) { 27 /** 28 * Stub gettext function in case gettext is not available. 29 * 30 * @param string $string 31 * 32 * @return string 33 */ 34 function _($string) { 35 return $string; 36 } 37} 38 39if (!function_exists('ngettext')) { 40 /** 41 * Stub gettext function in case gettext is not available. Do not use directly, use _n() instead. 42 * 43 * @see _n 44 * 45 * @param string $string1 46 * @param string $string2 47 * @param string $n 48 * 49 * @return string 50 */ 51 function ngettext($string1, $string2, $n) { 52 return ($n == 1) ? $string1 : $string2; 53 } 54} 55 56/** 57 * Translates the string with respect to the given context. 58 * 59 * @see _x 60 * 61 * @param string $context 62 * @param string $msgId 63 * 64 * @return string 65 */ 66function pgettext($context, $msgId) { 67 $contextString = $context."\004".$msgId; 68 $translation = _($contextString); 69 70 return ($translation == $contextString) ? $msgId : $translation; 71} 72 73/** 74 * Translates the string with respect to the given context and plural forms. 75 * 76 * @see _xn 77 * 78 * @param string $context 79 * @param string $msgId 80 * @param string $msgIdPlural 81 * @param string $num 82 * 83 * @return string 84 */ 85function npgettext($context, $msgId, $msgIdPlural, $num) { 86 $contextString = $context."\004".$msgId; 87 $contextStringp = $context."\004".$msgIdPlural; 88 return ngettext($contextString, $contextStringp, $num); 89} 90 91/** 92 * Translates the string and substitutes the placeholders with the given parameters. 93 * Placeholders must be defined as %1$s, %2$s etc. 94 * 95 * @param string $string String optionally containing placeholders to substitute. 96 * @param string $param,... Unlimited number of optional parameters to replace sequential placeholders. 97 * 98 * @return string 99 */ 100function _s($string) { 101 $arguments = array_slice(func_get_args(), 1); 102 103 return _params(_($string), $arguments); 104} 105 106/** 107 * Translates the string in the correct form with respect to the given numeric parameter. According to gettext 108 * standards the numeric parameter must be passed last. 109 * Supports unlimited parameters; placeholders must be defined as %1$s, %2$s etc. 110 * 111 * Examples: 112 * _n('%2$s item on host %1$s', '%2$s items on host %1$s', 'Zabbix server', 1) // 1 item on host Zabbix server 113 * _n('%2$s item on host %1$s', '%2$s items on host %1$s', 'Zabbix server', 2) // 2 items on host Zabbix server 114 * 115 * @param string $string1 singular string 116 * @param string $string2 plural string 117 * @param string $param parameter to replace the first placeholder 118 * @param string $param,... unlimited number of optional parameters 119 * 120 * @return string 121 */ 122function _n($string1, $string2) { 123 $arguments = array_slice(func_get_args(), 2); 124 125 return _params(ngettext($string1, $string2, end($arguments)), $arguments); 126} 127 128/** 129 * Translates the string with respect to the given context. 130 * If no translation is found, the original string will be used. 131 * 132 * Example: _x('Message', 'context'); 133 * returns: 'Message' 134 * 135 * @param string $message string to translate 136 * @param string $context context of the string 137 * 138 * @return string 139 */ 140function _x($message, $context) { 141 return ($context == '') 142 ? _($message) 143 : pgettext($context, $message); 144} 145 146/** 147 * Translates the string with respect to the given context and replaces placeholders with supplied arguments. 148 * If no translation is found, the original string will be used. Unlimited number of parameters supplied. 149 * Parameter placeholders must be defined as %1$s, %2$s etc. 150 * 151 * Example: _xs('Message for arg1 "%1$s" and arg2 "%2$s"', 'context', 'arg1Value', 'arg2Value'); 152 * returns: 'Message for arg1 "arg1Value" and arg2 "arg2Value"' 153 * 154 * @param string $message String to translate. 155 * @param string $context Context of the string. 156 * @param string $param,... Unlimited number of optional parameters to replace sequential placeholders. 157 * 158 * @return string 159 */ 160function _xs($message, $context) { 161 $arguments = array_slice(func_get_args(), 2); 162 163 return ($context == '') 164 ? _params($message, $arguments) 165 : _params(pgettext($context, $message), $arguments); 166} 167 168/** 169 * Translates the string with respect to the given context and plural forms, also replaces placeholders with supplied 170 * arguments. If no translation is found, the original string will be used. Unlimited number of parameters supplied. 171 * 172 * Parameter placeholders must be defined as %1$s, %2$s etc. 173 * 174 * Example: _xn('%1$s message for arg1 "%2$s"', '%1$s messages for arg1 "%2$s"', 3, 'context', 'arg1Value'); 175 * returns: '3 messages for arg1 "arg1Value"' 176 * 177 * @param string $message String to translate. 178 * @param string $messagePlural String to translate for plural form. 179 * @param int $num Number to determine usage of plural form, also is used as first replace argument. 180 * @param string $context Context of the string. 181 * @param string $param,... Unlimited number of optional parameters to replace sequential placeholders. 182 * 183 * @return string 184 */ 185function _xn($message, $messagePlural, $num, $context) { 186 $arguments = array_slice(func_get_args(), 4); 187 array_unshift($arguments, $num); 188 189 return _params(pgettext($context, ngettext($message, $messagePlural, $num)), $arguments); 190} 191 192/** 193 * Returns a formatted string. 194 * 195 * @param string $format receives already stranlated string with format 196 * @param array $arguments arguments to replace according to given format 197 * 198 * @return string 199 */ 200function _params($format, array $arguments) { 201 return vsprintf($format, $arguments); 202} 203 204/** 205 * Initialize locale environment and gettext translations depending on language selected by user. 206 * 207 * Note: should be called before including file includes/translateDefines.inc.php. 208 * 209 * @param string $language Locale language prefix like en_US, ru_RU etc. 210 * @param string $error Message on failure. 211 * 212 * @return bool Whether locale could be switched; always true for en_GB. 213 */ 214function setupLocale(string $language, ?string &$error = ''): bool { 215 $numeric_locales = [ 216 'C', 'POSIX', 'en', 'en_US', 'en_US.UTF-8', 'English_United States.1252', 'en_GB', 'en_GB.UTF-8' 217 ]; 218 $locale_variants = zbx_locale_variants($language); 219 $locale_set = false; 220 $error = ''; 221 222 init_mbstrings(); 223 224 // Since LC_MESSAGES may be unavailable on some systems, try to set all of the locales and then make adjustments. 225 foreach ($locale_variants as $locale) { 226 putenv('LC_ALL='.$locale); 227 putenv('LANG='.$locale); 228 putenv('LANGUAGE='.$locale); 229 230 if (setlocale(LC_ALL, $locale)) { 231 $locale_set = true; 232 break; 233 } 234 } 235 236 // Force PHP to always use a point instead of a comma for decimal numbers. 237 setlocale(LC_NUMERIC, $numeric_locales); 238 239 if (function_exists('bindtextdomain')) { 240 bindtextdomain('frontend', 'locale'); 241 bind_textdomain_codeset('frontend', 'UTF-8'); 242 textdomain('frontend'); 243 } 244 245 if (!$locale_set && strtolower($language) !== 'en_gb') { 246 setlocale(LC_ALL, $numeric_locales); 247 248 $language = htmlspecialchars($language, ENT_QUOTES, 'UTF-8'); 249 $locale_variants = array_map(function ($locale) { 250 return htmlspecialchars($locale, ENT_QUOTES, 'UTF-8'); 251 }, $locale_variants); 252 253 $error = 'Locale for language "'.$language.'" is not found on the web server. Tried to set: '. 254 implode(', ', $locale_variants).'. Unable to translate Zabbix interface.'; 255 } 256 257 return ($error === ''); 258} 259