i18n.php 27 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813
  1. <?php
  2. /**
  3. * SquirrelMail internationalization functions
  4. *
  5. * This file contains variuos functions that are needed to do
  6. * internationalization of SquirrelMail.
  7. *
  8. * Internally the output character set is used. Other characters are
  9. * encoded using Unicode entities according to HTML 4.0.
  10. *
  11. * @copyright &copy; 1999-2006 The SquirrelMail Project Team
  12. * @license http://opensource.org/licenses/gpl-license.php GNU Public License
  13. * @version $Id$
  14. * @package squirrelmail
  15. * @subpackage i18n
  16. */
  17. /** @ignore */
  18. if (! defined('SM_PATH')) define('SM_PATH','../');
  19. /** Everything uses global.php... */
  20. require_once(SM_PATH . 'functions/global.php');
  21. /**
  22. * Gettext bindtextdomain wrapper.
  23. *
  24. * Wrapper solves differences between php versions in order to provide
  25. * ngettext support. Should be used if translation uses ngettext
  26. * functions.
  27. * @since 1.5.1
  28. * @param string $domain gettext domain name
  29. * @param string $dir directory that contains all translations
  30. * @return string path to translation directory
  31. */
  32. function sq_bindtextdomain($domain,$dir) {
  33. global $l10n, $gettext_flags, $sm_notAlias;
  34. if ($gettext_flags==7) {
  35. // gettext extension without ngettext
  36. if (substr($dir, -1) != '/') $dir .= '/';
  37. $mofile=$dir . $sm_notAlias . '/LC_MESSAGES/' . $domain . '.mo';
  38. $input = new FileReader($mofile);
  39. $l10n[$domain] = new gettext_reader($input);
  40. }
  41. $dir=bindtextdomain($domain,$dir);
  42. return $dir;
  43. }
  44. /**
  45. * Gettext textdomain wrapper.
  46. * Makes sure that gettext_domain global is modified.
  47. * @since 1.5.1
  48. * @param string $name gettext domain name
  49. * @return string gettext domain name
  50. */
  51. function sq_textdomain($domain) {
  52. global $gettext_domain;
  53. $gettext_domain=textdomain($domain);
  54. return $gettext_domain;
  55. }
  56. /**
  57. * php setlocale function wrapper
  58. *
  59. * From php 4.3.0 it is possible to use arrays in order to set locale.
  60. * php gettext extension works only when locale is set. This wrapper
  61. * function allows to use more than one locale name.
  62. *
  63. * @param int $category locale category name. Use php named constants
  64. * (LC_ALL, LC_COLLATE, LC_CTYPE, LC_MONETARY, LC_NUMERIC, LC_TIME)
  65. * @param mixed $locale option contains array with possible locales or string with one locale
  66. * @return string name of set locale or false, if all locales fail.
  67. * @since 1.5.1 and 1.4.5
  68. * @see http://www.php.net/setlocale
  69. */
  70. function sq_setlocale($category,$locale) {
  71. // string with only one locale
  72. if (is_string($locale))
  73. return setlocale($category,$locale);
  74. if (! check_php_version(4,3)) {
  75. $ret=false;
  76. $index=0;
  77. while ( ! $ret && $index<count($locale)) {
  78. $ret=setlocale($category,$locale[$index]);
  79. $index++;
  80. }
  81. } else {
  82. // php 4.3.0 or better, use entire array
  83. $ret=setlocale($category,$locale);
  84. }
  85. return $ret;
  86. }
  87. /**
  88. * Converts string from given charset to charset, that can be displayed by user translation.
  89. *
  90. * Function by default returns html encoded strings, if translation uses different encoding.
  91. * If Japanese translation is used - function returns string converted to euc-jp
  92. * If iconv or recode functions are enabled and translation uses utf-8 - function returns utf-8 encoded string.
  93. * If $charset is not supported - function returns unconverted string.
  94. *
  95. * sanitizing of html tags is also done by this function.
  96. *
  97. * @param string $charset
  98. * @param string $string Text to be decoded
  99. * @param boolean $force_decode converts string to html without $charset!=$default_charset check.
  100. * Argument is available since 1.5.1 and 1.4.5.
  101. * @param boolean $save_html disables htmlspecialchars() in order to preserve
  102. * html formating. Use with care. Available since 1.5.1
  103. * @return string decoded string
  104. */
  105. function charset_decode ($charset, $string, $force_decode=false, $save_html=false) {
  106. global $languages, $squirrelmail_language, $default_charset;
  107. global $use_php_recode, $use_php_iconv, $aggressive_decoding;
  108. if (isset($languages[$squirrelmail_language]['XTRA_CODE']) &&
  109. function_exists($languages[$squirrelmail_language]['XTRA_CODE'] . '_decode')) {
  110. $string = call_user_func($languages[$squirrelmail_language]['XTRA_CODE'] . '_decode', $string);
  111. }
  112. $charset = strtolower($charset);
  113. set_my_charset();
  114. // Variables that allow to use functions without function_exist() calls
  115. if (! isset($use_php_recode) || $use_php_recode=="" ) {
  116. $use_php_recode=false; }
  117. if (! isset($use_php_iconv) || $use_php_iconv=="" ) {
  118. $use_php_iconv=false; }
  119. // Don't do conversion if charset is the same.
  120. if ( ! $force_decode && $charset == strtolower($default_charset) )
  121. return ($save_html ? $string : htmlspecialchars($string));
  122. // catch iso-8859-8-i thing
  123. if ( $charset == "iso-8859-8-i" )
  124. $charset = "iso-8859-8";
  125. /*
  126. * Recode converts html special characters automatically if you use
  127. * 'charset..html' decoding. There is no documented way to put -d option
  128. * into php recode function call.
  129. */
  130. if ( $use_php_recode ) {
  131. if ( $default_charset == "utf-8" ) {
  132. // other charsets can be converted to utf-8 without loss.
  133. // and output string is smaller
  134. $string = recode_string($charset . "..utf-8",$string);
  135. return ($save_html ? $string : htmlspecialchars($string));
  136. } else {
  137. $string = recode_string($charset . "..html",$string);
  138. // recode does not convert single quote, htmlspecialchars does.
  139. $string = str_replace("'", '&#039;', $string);
  140. // undo html specialchars
  141. if ($save_html)
  142. $string=str_replace(array('&amp;','&quot;','&lt;','&gt;'),
  143. array('&','"','<','>'),$string);
  144. return $string;
  145. }
  146. }
  147. // iconv functions does not have html target and can be used only with utf-8
  148. if ( $use_php_iconv && $default_charset=='utf-8') {
  149. $string = iconv($charset,$default_charset,$string);
  150. return ($save_html ? $string : htmlspecialchars($string));
  151. }
  152. // If we don't use recode and iconv, we'll do it old way.
  153. /* All HTML special characters are 7 bit and can be replaced first */
  154. if (! $save_html) $string = htmlspecialchars ($string);
  155. /* controls cpu and memory intensive decoding cycles */
  156. if (! isset($aggressive_decoding) || $aggressive_decoding=="" ) {
  157. $aggressive_decoding=false; }
  158. $decode=fixcharset($charset);
  159. $decodefile=SM_PATH . 'functions/decode/' . $decode . '.php';
  160. if (file_exists($decodefile)) {
  161. include_once($decodefile);
  162. // send $save_html argument to decoding function. needed for iso-2022-xx decoding.
  163. $ret = call_user_func('charset_decode_'.$decode, $string, $save_html);
  164. } else {
  165. $ret = $string;
  166. }
  167. return( $ret );
  168. }
  169. /**
  170. * Converts html string to given charset
  171. * @since 1.5.1 and 1.4.4
  172. * @param string $string
  173. * @param string $charset
  174. * @param boolean $htmlencode keep htmlspecialchars encoding
  175. * @param string
  176. */
  177. function charset_encode($string,$charset,$htmlencode=true) {
  178. global $default_charset;
  179. $encode=fixcharset($charset);
  180. $encodefile=SM_PATH . 'functions/encode/' . $encode . '.php';
  181. if (file_exists($encodefile)) {
  182. include_once($encodefile);
  183. $ret = call_user_func('charset_encode_'.$encode, $string);
  184. } elseif(file_exists(SM_PATH . 'functions/encode/us_ascii.php')) {
  185. // function replaces all 8bit html entities with question marks.
  186. // it is used when other encoding functions are unavailable
  187. include_once(SM_PATH . 'functions/encode/us_ascii.php');
  188. $ret = charset_encode_us_ascii($string);
  189. } else {
  190. /**
  191. * fix for yahoo users that remove all us-ascii related things
  192. */
  193. $ret = $string;
  194. }
  195. /**
  196. * Undo html special chars, some places (like compose form) have
  197. * own sanitizing functions and don't need html symbols.
  198. * Undo chars only after encoding in order to prevent conversion of
  199. * html entities in plain text emails.
  200. */
  201. if (! $htmlencode ) {
  202. $ret = str_replace(array('&amp;','&gt;','&lt;','&quot;'),array('&','>','<','"'),$ret);
  203. }
  204. return( $ret );
  205. }
  206. /**
  207. * Combined decoding and encoding functions
  208. *
  209. * If conversion is done to charset different that utf-8, unsupported symbols
  210. * will be replaced with question marks.
  211. * @since 1.5.1 and 1.4.4
  212. * @param string $in_charset initial charset
  213. * @param string $string string that has to be converted
  214. * @param string $out_charset final charset
  215. * @param boolean $htmlencode keep htmlspecialchars encoding
  216. * @return string converted string
  217. */
  218. function charset_convert($in_charset,$string,$out_charset,$htmlencode=true) {
  219. $string=charset_decode($in_charset,$string,true);
  220. $string=charset_encode($string,$out_charset,$htmlencode);
  221. return $string;
  222. }
  223. /**
  224. * Makes charset name suitable for decoding cycles
  225. *
  226. * @since 1.5.0 and 1.4.4
  227. * @param string $charset Name of charset
  228. * @return string $charset Adjusted name of charset
  229. */
  230. function fixcharset($charset) {
  231. /* remove minus and characters that might be used in paths from charset
  232. * name in order to be able to use it in function names and include calls.
  233. */
  234. $charset=preg_replace("/[-:.\/\\\]/",'_',$charset);
  235. // OE ks_c_5601_1987 > cp949
  236. $charset=str_replace('ks_c_5601_1987','cp949',$charset);
  237. // Moz x-euc-tw > euc-tw
  238. $charset=str_replace('x_euc','euc',$charset);
  239. // Moz x-windows-949 > cp949
  240. $charset=str_replace('x_windows_','cp',$charset);
  241. // windows-125x and cp125x charsets
  242. $charset=str_replace('windows_','cp',$charset);
  243. // ibm > cp
  244. $charset=str_replace('ibm','cp',$charset);
  245. // iso-8859-8-i -> iso-8859-8
  246. // use same cycle until I'll find differences
  247. $charset=str_replace('iso_8859_8_i','iso_8859_8',$charset);
  248. return $charset;
  249. }
  250. /**
  251. * Set up the language to be output
  252. * if $do_search is true, then scan the browser information
  253. * for a possible language that we know
  254. *
  255. * Function sets system locale environment (LC_ALL, LANG, LANGUAGE),
  256. * gettext translation bindings and html header information.
  257. *
  258. * Function returns error codes, if there is some fatal error.
  259. * 0 = no error,
  260. * 1 = mbstring support is not present,
  261. * 2 = mbstring support is not present, user's translation reverted to en_US.
  262. *
  263. * @param string $sm_language translation used by user's interface
  264. * @param bool $do_search use browser's preferred language detection functions. Defaults to false.
  265. * @param bool $default set $sm_language to $squirrelmail_default_language if language detection fails or language is not set. Defaults to false.
  266. * @return int function execution error codes.
  267. */
  268. function set_up_language($sm_language, $do_search = false, $default = false) {
  269. static $SetupAlready = 0;
  270. global $use_gettext, $languages,
  271. $squirrelmail_language, $squirrelmail_default_language, $default_charset,
  272. $sm_notAlias, $username, $data_dir;
  273. if ($SetupAlready) {
  274. return;
  275. }
  276. $SetupAlready = TRUE;
  277. sqgetGlobalVar('HTTP_ACCEPT_LANGUAGE', $accept_lang, SQ_SERVER);
  278. /**
  279. * If function is asked to detect preferred language
  280. * OR squirrelmail default language is set to empty string
  281. * AND
  282. * squirrelmail language ($sm_language) is empty string
  283. * (not set in user's prefs and no cookie with language info)
  284. * AND
  285. * browser provides list of preferred languages
  286. * THEN
  287. * get preferred language from HTTP_ACCEPT_LANGUAGE header
  288. */
  289. if (($do_search || empty($squirrelmail_default_language)) &&
  290. ! $sm_language &&
  291. isset($accept_lang)) {
  292. // TODO: use more than one language, if first language is not available
  293. // FIXME: function assumes that string contains two or more characters.
  294. // FIXME: some languages use 5 chars
  295. $sm_language = substr($accept_lang, 0, 2);
  296. }
  297. /**
  298. * If language preference is not set OR script asks to use default language
  299. * AND
  300. * default squirrelmail language is not set to empty string
  301. * THEN
  302. * use default squirrelmail language value from configuration.
  303. */
  304. if ((!$sm_language||$default) &&
  305. ! empty($squirrelmail_default_language)) {
  306. $squirrelmail_language = $squirrelmail_default_language;
  307. $sm_language = $squirrelmail_default_language;
  308. }
  309. /** provide failsafe language when detection fails */
  310. if (! $sm_language) $sm_language='en_US';
  311. $sm_notAlias = $sm_language;
  312. // Catching removed translation
  313. // System reverts to English translation if user prefs contain translation
  314. // that is not available in $languages array
  315. if (!isset($languages[$sm_notAlias])) {
  316. $sm_notAlias="en_US";
  317. }
  318. while (isset($languages[$sm_notAlias]['ALIAS'])) {
  319. $sm_notAlias = $languages[$sm_notAlias]['ALIAS'];
  320. }
  321. if ( isset($sm_language) &&
  322. $use_gettext &&
  323. $sm_language != '' &&
  324. isset($languages[$sm_notAlias]['CHARSET']) ) {
  325. sq_bindtextdomain( 'squirrelmail', SM_PATH . 'locale/' );
  326. sq_textdomain( 'squirrelmail' );
  327. // set codeset in order to avoid gettext charset conversions
  328. if (function_exists('bind_textdomain_codeset')) {
  329. // Japanese translation uses different internal charset
  330. if ($sm_notAlias == 'ja_JP') {
  331. bind_textdomain_codeset ('squirrelmail', 'EUC-JP');
  332. } else {
  333. bind_textdomain_codeset ('squirrelmail', $languages[$sm_notAlias]['CHARSET'] );
  334. }
  335. }
  336. // Use LOCALE key, if it is set.
  337. if (isset($languages[$sm_notAlias]['LOCALE'])){
  338. $longlocale=$languages[$sm_notAlias]['LOCALE'];
  339. } else {
  340. $longlocale=$sm_notAlias;
  341. }
  342. // try setting locale
  343. $retlocale=sq_setlocale(LC_ALL, $longlocale);
  344. // check if locale is set and assign that locale to $longlocale
  345. // in order to use it in putenv calls.
  346. if (! is_bool($retlocale)) {
  347. $longlocale=$retlocale;
  348. } elseif (is_array($longlocale)) {
  349. // setting of all locales failed.
  350. // we need string instead of array used in LOCALE key.
  351. $longlocale=$sm_notAlias;
  352. }
  353. if ( !((bool)ini_get('safe_mode')) &&
  354. getenv( 'LC_ALL' ) != $longlocale ) {
  355. putenv( "LC_ALL=$longlocale" );
  356. putenv( "LANG=$longlocale" );
  357. putenv( "LANGUAGE=$longlocale" );
  358. putenv( "LC_NUMERIC=C" );
  359. if ($sm_notAlias=='tr_TR') putenv( "LC_CTYPE=C" );
  360. }
  361. // Workaround for plugins that use numbers with floating point
  362. // It might be removed if plugins use correct decimal delimiters
  363. // according to locale settings.
  364. setlocale(LC_NUMERIC, 'C');
  365. // Workaround for specific Turkish strtolower/strtoupper rules.
  366. // Many functions expect English conversion rules.
  367. if ($sm_notAlias=='tr_TR') setlocale(LC_CTYPE,'C');
  368. /**
  369. * Set text direction/alignment variables
  370. * When language environment is setup, scripts can use these globals
  371. * without accessing $languages directly and making checks for optional
  372. * array key.
  373. */
  374. global $text_direction, $left_align, $right_align;
  375. if (isset($languages[$sm_notAlias]['DIR']) &&
  376. $languages[$sm_notAlias]['DIR'] == 'rtl') {
  377. /**
  378. * Text direction
  379. * @global string $text_direction
  380. */
  381. $text_direction='rtl';
  382. /**
  383. * Left alignment
  384. * @global string $left_align
  385. */
  386. $left_align='right';
  387. /**
  388. * Right alignment
  389. * @global string $right_align
  390. */
  391. $right_align='left';
  392. } else {
  393. $text_direction='ltr';
  394. $left_align='left';
  395. $right_align='right';
  396. }
  397. $squirrelmail_language = $sm_notAlias;
  398. if ($squirrelmail_language == 'ja_JP') {
  399. header ('Content-Type: text/html; charset=EUC-JP');
  400. if (!function_exists('mb_internal_encoding')) {
  401. // Error messages can't be displayed here
  402. $error = 1;
  403. // Revert to English if possible.
  404. if (function_exists('setPref') && $username!='' && $data_dir!="") {
  405. setPref($data_dir, $username, 'language', "en_US");
  406. $error = 2;
  407. }
  408. // stop further execution in order not to get php errors on mb_internal_encoding().
  409. return $error;
  410. }
  411. if (function_exists('mb_language')) {
  412. mb_language('Japanese');
  413. }
  414. mb_internal_encoding('EUC-JP');
  415. mb_http_output('pass');
  416. } elseif ($squirrelmail_language == 'en_US') {
  417. header( 'Content-Type: text/html; charset=' . $default_charset );
  418. } else {
  419. header( 'Content-Type: text/html; charset=' . $languages[$sm_notAlias]['CHARSET'] );
  420. }
  421. /**
  422. * mbstring.func_overload fix (#929644).
  423. *
  424. * php mbstring extension can replace standard string functions with their multibyte
  425. * equivalents. See http://www.php.net/ref.mbstring#mbstring.overload. This feature
  426. * was added in php v.4.2.0
  427. *
  428. * Some SquirrelMail functions work with 8bit strings in bytes. If interface is forced
  429. * to use mbstring functions and mbstring internal encoding is set to multibyte charset,
  430. * interface can't trust regular string functions. Due to mbstring overloading design
  431. * limits php scripts can't control this setting.
  432. *
  433. * This hack should fix some issues related to 8bit strings in passwords. Correct fix is
  434. * to disable mbstring overloading. Japanese translation uses different internal encoding.
  435. */
  436. if ($squirrelmail_language != 'ja_JP' &&
  437. function_exists('mb_internal_encoding') &&
  438. check_php_version(4,2,0) &&
  439. (int)ini_get('mbstring.func_overload')!=0) {
  440. mb_internal_encoding('pass');
  441. }
  442. }
  443. return 0;
  444. }
  445. /**
  446. * Sets default_charset variable according to the one that is used by user's translations.
  447. *
  448. * Function changes global $default_charset variable in order to be sure, that it
  449. * contains charset used by user's translation. Sanity of $squirrelmail_language
  450. * and $default_charset combination is also tested.
  451. *
  452. * There can be a $default_charset setting in the
  453. * config.php file, but the user may have a different language
  454. * selected for a user interface. This function checks the
  455. * language selected by the user and tags the outgoing messages
  456. * with the appropriate charset corresponding to the language
  457. * selection. This is "more right" (tm), than just stamping the
  458. * message blindly with the system-wide $default_charset.
  459. */
  460. function set_my_charset(){
  461. global $data_dir, $username, $default_charset, $languages, $squirrelmail_language;
  462. $my_language = getPref($data_dir, $username, 'language');
  463. if (!$my_language) {
  464. $my_language = $squirrelmail_language ;
  465. }
  466. // Catch removed translation
  467. if (!isset($languages[$my_language])) {
  468. $my_language="en_US";
  469. }
  470. while (isset($languages[$my_language]['ALIAS'])) {
  471. $my_language = $languages[$my_language]['ALIAS'];
  472. }
  473. $my_charset = $languages[$my_language]['CHARSET'];
  474. if ($my_language!='en_US') {
  475. $default_charset = $my_charset;
  476. }
  477. }
  478. /**
  479. * Replaces non-braking spaces inserted by some browsers with regular space
  480. *
  481. * This function can be used to replace non-braking space symbols
  482. * that are inserted in forms by some browsers instead of normal
  483. * space symbol.
  484. *
  485. * @param string $string Text that needs to be cleaned
  486. * @param string $charset Charset used in text
  487. * @return string Cleaned text
  488. */
  489. function cleanup_nbsp($string,$charset) {
  490. // reduce number of case statements
  491. if (stristr('iso-8859-',substr($charset,0,9))){
  492. $output_charset="iso-8859-x";
  493. }
  494. if (stristr('windows-125',substr($charset,0,11))){
  495. $output_charset="cp125x";
  496. }
  497. if (stristr('koi8',substr($charset,0,4))){
  498. $output_charset="koi8-x";
  499. }
  500. if (! isset($output_charset)){
  501. $output_charset=strtolower($charset);
  502. }
  503. // where is non-braking space symbol
  504. switch($output_charset):
  505. case "iso-8859-x":
  506. case "cp125x":
  507. case "iso-2022-jp":
  508. $nbsp="\xA0";
  509. break;
  510. case "koi8-x":
  511. $nbsp="\x9A";
  512. break;
  513. case "utf-8":
  514. $nbsp="\xC2\xA0";
  515. break;
  516. default:
  517. // don't change string if charset is unmatched
  518. return $string;
  519. endswitch;
  520. // return space instead of non-braking space.
  521. return str_replace($nbsp,' ',$string);
  522. }
  523. /**
  524. * Function informs if it is safe to convert given charset to the one that is used by user.
  525. *
  526. * It is safe to use conversion only if user uses utf-8 encoding and when
  527. * converted charset is similar to the one that is used by user.
  528. *
  529. * @param string $input_charset Charset of text that needs to be converted
  530. * @return bool is it possible to convert to user's charset
  531. */
  532. function is_conversion_safe($input_charset) {
  533. global $languages, $sm_notAlias, $default_charset, $lossy_encoding;
  534. if (isset($lossy_encoding) && $lossy_encoding )
  535. return true;
  536. // convert to lower case
  537. $input_charset = strtolower($input_charset);
  538. // Is user's locale Unicode based ?
  539. if ( $default_charset == "utf-8" ) {
  540. return true;
  541. }
  542. // Charsets that are similar
  543. switch ($default_charset):
  544. case "windows-1251":
  545. if ( $input_charset == "iso-8859-5" ||
  546. $input_charset == "koi8-r" ||
  547. $input_charset == "koi8-u" ) {
  548. return true;
  549. } else {
  550. return false;
  551. }
  552. case "windows-1257":
  553. if ( $input_charset == "iso-8859-13" ||
  554. $input_charset == "iso-8859-4" ) {
  555. return true;
  556. } else {
  557. return false;
  558. }
  559. case "iso-8859-4":
  560. if ( $input_charset == "iso-8859-13" ||
  561. $input_charset == "windows-1257" ) {
  562. return true;
  563. } else {
  564. return false;
  565. }
  566. case "iso-8859-5":
  567. if ( $input_charset == "windows-1251" ||
  568. $input_charset == "koi8-r" ||
  569. $input_charset == "koi8-u" ) {
  570. return true;
  571. } else {
  572. return false;
  573. }
  574. case "iso-8859-13":
  575. if ( $input_charset == "iso-8859-4" ||
  576. $input_charset == "windows-1257" ) {
  577. return true;
  578. } else {
  579. return false;
  580. }
  581. case "koi8-r":
  582. if ( $input_charset == "windows-1251" ||
  583. $input_charset == "iso-8859-5" ||
  584. $input_charset == "koi8-u" ) {
  585. return true;
  586. } else {
  587. return false;
  588. }
  589. case "koi8-u":
  590. if ( $input_charset == "windows-1251" ||
  591. $input_charset == "iso-8859-5" ||
  592. $input_charset == "koi8-r" ) {
  593. return true;
  594. } else {
  595. return false;
  596. }
  597. default:
  598. return false;
  599. endswitch;
  600. }
  601. /* ------------------------------ main --------------------------- */
  602. global $squirrelmail_language, $languages, $use_gettext;
  603. if (! sqgetGlobalVar('squirrelmail_language',$squirrelmail_language,SQ_COOKIE)) {
  604. $squirrelmail_language = '';
  605. }
  606. /**
  607. * Array specifies the available translations.
  608. *
  609. * Structure of array:
  610. * $languages['language']['variable'] = 'value'
  611. *
  612. * Possible 'variable' names:
  613. * NAME - Translation name in English
  614. * CHARSET - Encoding used by translation
  615. * ALIAS - used when 'language' is only short name and 'value' should provide long language name
  616. * ALTNAME - Native translation name. Any 8bit symbols must be html encoded.
  617. * LOCALE - Full locale name (in xx_XX.charset format). It can use array with more than one locale name since 1.4.5 and 1.5.1
  618. * DIR - Text direction. Used to define Right-to-Left languages. Possible values 'rtl' or 'ltr'. If undefined - defaults to 'ltr'
  619. * XTRA_CODE - translation uses special functions. See doc/i18n.txt
  620. *
  621. * Each 'language' definition requires NAME+CHARSET or ALIAS variables.
  622. *
  623. * @name $languages
  624. * @global array $languages
  625. */
  626. $languages['en_US']['NAME'] = 'English';
  627. $languages['en_US']['CHARSET'] = 'iso-8859-1';
  628. $languages['en_US']['LOCALE'] = 'en_US.ISO8859-1';
  629. $languages['en']['ALIAS'] = 'en_US';
  630. /**
  631. * Automatic translation loading from setup.php files.
  632. * Solution for bug. 1240889.
  633. * setup.php file can contain $languages array entries and XTRA_CODE functions.
  634. */
  635. if (is_dir(SM_PATH . 'locale') &&
  636. is_readable(SM_PATH . 'locale')) {
  637. $localedir = dir(SM_PATH . 'locale');
  638. while($lang_dir=$localedir->read()) {
  639. // remove trailing slash, if present
  640. if (substr($lang_dir,-1)=='/') {
  641. $lang_dir = substr($lang_dir,0,-1);
  642. }
  643. if ($lang_dir != '..' && $lang_dir != '.' && $lang_dir != 'CVS' &&
  644. is_dir(SM_PATH.'locale/'.$lang_dir) &&
  645. file_exists(SM_PATH.'locale/'.$lang_dir.'/setup.php')) {
  646. include_once(SM_PATH.'locale/'.$lang_dir.'/setup.php');
  647. }
  648. }
  649. $localedir->close();
  650. }
  651. /* Detect whether gettext is installed. */
  652. $gettext_flags = 0;
  653. if (function_exists('_')) {
  654. $gettext_flags += 1;
  655. }
  656. if (function_exists('bindtextdomain')) {
  657. $gettext_flags += 2;
  658. }
  659. if (function_exists('textdomain')) {
  660. $gettext_flags += 4;
  661. }
  662. if (function_exists('ngettext')) {
  663. $gettext_flags += 8;
  664. }
  665. /* If gettext is fully loaded, cool */
  666. if ($gettext_flags == 15) {
  667. $use_gettext = true;
  668. }
  669. /* If ngettext support is missing, load it */
  670. elseif ($gettext_flags == 7) {
  671. $use_gettext = true;
  672. // load internal ngettext functions
  673. include_once(SM_PATH . 'class/l10n.class.php');
  674. include_once(SM_PATH . 'functions/ngettext.php');
  675. }
  676. /* If we can fake gettext, try that */
  677. elseif ($gettext_flags == 0) {
  678. $use_gettext = true;
  679. include_once(SM_PATH . 'functions/gettext.php');
  680. } else {
  681. /* Uh-ho. A weird install */
  682. if (! $gettext_flags & 1) {
  683. /**
  684. * Function is used as replacement in broken installs
  685. * @ignore
  686. */
  687. function _($str) {
  688. return $str;
  689. }
  690. }
  691. if (! $gettext_flags & 2) {
  692. /**
  693. * Function is used as replacement in broken installs
  694. * @ignore
  695. */
  696. function bindtextdomain() {
  697. return;
  698. }
  699. }
  700. if (! $gettext_flags & 4) {
  701. /**
  702. * Function is used as replacemet in broken installs
  703. * @ignore
  704. */
  705. function textdomain() {
  706. return;
  707. }
  708. }
  709. if (! $gettext_flags & 8) {
  710. /**
  711. * Function is used as replacemet in broken installs
  712. * @ignore
  713. */
  714. function ngettext($str,$str2,$number) {
  715. if ($number>1) {
  716. return $str2;
  717. } else {
  718. return $str;
  719. }
  720. }
  721. }
  722. if (! function_exists('dgettext')) {
  723. /**
  724. * Replacement for broken setups.
  725. * @ignore
  726. */
  727. function dgettext($domain,$str) {
  728. return $str;
  729. }
  730. }
  731. if (! function_exists('dngettext')) {
  732. /**
  733. * Replacement for broken setups
  734. * @ignore
  735. */
  736. function dngettext($domain,$str1,$strn,$number) {
  737. return ($number==1 ? $str1 : $strn);
  738. }
  739. }
  740. }
  741. ?>