i18n.php 27 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808
  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. // Set text direction/alignment variables
  369. // These don't appear to be used... are they safe to remove?
  370. if (isset($languages[$sm_notAlias]['DIR']) &&
  371. $languages[$sm_notAlias]['DIR'] == 'rtl') {
  372. /**
  373. * Text direction
  374. * @global string $text_direction
  375. */
  376. $text_direction='rtl';
  377. /**
  378. * Left alignment
  379. * @global string $left_align
  380. */
  381. $left_align='right';
  382. /**
  383. * Right alignment
  384. * @global string $right_align
  385. */
  386. $right_align='left';
  387. } else {
  388. $text_direction='ltr';
  389. $left_align='left';
  390. $right_align='right';
  391. }
  392. $squirrelmail_language = $sm_notAlias;
  393. if ($squirrelmail_language == 'ja_JP') {
  394. header ('Content-Type: text/html; charset=EUC-JP');
  395. if (!function_exists('mb_internal_encoding')) {
  396. // Error messages can't be displayed here
  397. $error = 1;
  398. // Revert to English if possible.
  399. if (function_exists('setPref') && $username!='' && $data_dir!="") {
  400. setPref($data_dir, $username, 'language', "en_US");
  401. $error = 2;
  402. }
  403. // stop further execution in order not to get php errors on mb_internal_encoding().
  404. return $error;
  405. }
  406. if (function_exists('mb_language')) {
  407. mb_language('Japanese');
  408. }
  409. mb_internal_encoding('EUC-JP');
  410. mb_http_output('pass');
  411. } elseif ($squirrelmail_language == 'en_US') {
  412. header( 'Content-Type: text/html; charset=' . $default_charset );
  413. } else {
  414. header( 'Content-Type: text/html; charset=' . $languages[$sm_notAlias]['CHARSET'] );
  415. }
  416. /**
  417. * mbstring.func_overload fix (#929644).
  418. *
  419. * php mbstring extension can replace standard string functions with their multibyte
  420. * equivalents. See http://www.php.net/ref.mbstring#mbstring.overload. This feature
  421. * was added in php v.4.2.0
  422. *
  423. * Some SquirrelMail functions work with 8bit strings in bytes. If interface is forced
  424. * to use mbstring functions and mbstring internal encoding is set to multibyte charset,
  425. * interface can't trust regular string functions. Due to mbstring overloading design
  426. * limits php scripts can't control this setting.
  427. *
  428. * This hack should fix some issues related to 8bit strings in passwords. Correct fix is
  429. * to disable mbstring overloading. Japanese translation uses different internal encoding.
  430. */
  431. if ($squirrelmail_language != 'ja_JP' &&
  432. function_exists('mb_internal_encoding') &&
  433. check_php_version(4,2,0) &&
  434. (int)ini_get('mbstring.func_overload')!=0) {
  435. mb_internal_encoding('pass');
  436. }
  437. }
  438. return 0;
  439. }
  440. /**
  441. * Sets default_charset variable according to the one that is used by user's translations.
  442. *
  443. * Function changes global $default_charset variable in order to be sure, that it
  444. * contains charset used by user's translation. Sanity of $squirrelmail_language
  445. * and $default_charset combination is also tested.
  446. *
  447. * There can be a $default_charset setting in the
  448. * config.php file, but the user may have a different language
  449. * selected for a user interface. This function checks the
  450. * language selected by the user and tags the outgoing messages
  451. * with the appropriate charset corresponding to the language
  452. * selection. This is "more right" (tm), than just stamping the
  453. * message blindly with the system-wide $default_charset.
  454. */
  455. function set_my_charset(){
  456. global $data_dir, $username, $default_charset, $languages, $squirrelmail_language;
  457. $my_language = getPref($data_dir, $username, 'language');
  458. if (!$my_language) {
  459. $my_language = $squirrelmail_language ;
  460. }
  461. // Catch removed translation
  462. if (!isset($languages[$my_language])) {
  463. $my_language="en_US";
  464. }
  465. while (isset($languages[$my_language]['ALIAS'])) {
  466. $my_language = $languages[$my_language]['ALIAS'];
  467. }
  468. $my_charset = $languages[$my_language]['CHARSET'];
  469. if ($my_language!='en_US') {
  470. $default_charset = $my_charset;
  471. }
  472. }
  473. /**
  474. * Replaces non-braking spaces inserted by some browsers with regular space
  475. *
  476. * This function can be used to replace non-braking space symbols
  477. * that are inserted in forms by some browsers instead of normal
  478. * space symbol.
  479. *
  480. * @param string $string Text that needs to be cleaned
  481. * @param string $charset Charset used in text
  482. * @return string Cleaned text
  483. */
  484. function cleanup_nbsp($string,$charset) {
  485. // reduce number of case statements
  486. if (stristr('iso-8859-',substr($charset,0,9))){
  487. $output_charset="iso-8859-x";
  488. }
  489. if (stristr('windows-125',substr($charset,0,11))){
  490. $output_charset="cp125x";
  491. }
  492. if (stristr('koi8',substr($charset,0,4))){
  493. $output_charset="koi8-x";
  494. }
  495. if (! isset($output_charset)){
  496. $output_charset=strtolower($charset);
  497. }
  498. // where is non-braking space symbol
  499. switch($output_charset):
  500. case "iso-8859-x":
  501. case "cp125x":
  502. case "iso-2022-jp":
  503. $nbsp="\xA0";
  504. break;
  505. case "koi8-x":
  506. $nbsp="\x9A";
  507. break;
  508. case "utf-8":
  509. $nbsp="\xC2\xA0";
  510. break;
  511. default:
  512. // don't change string if charset is unmatched
  513. return $string;
  514. endswitch;
  515. // return space instead of non-braking space.
  516. return str_replace($nbsp,' ',$string);
  517. }
  518. /**
  519. * Function informs if it is safe to convert given charset to the one that is used by user.
  520. *
  521. * It is safe to use conversion only if user uses utf-8 encoding and when
  522. * converted charset is similar to the one that is used by user.
  523. *
  524. * @param string $input_charset Charset of text that needs to be converted
  525. * @return bool is it possible to convert to user's charset
  526. */
  527. function is_conversion_safe($input_charset) {
  528. global $languages, $sm_notAlias, $default_charset, $lossy_encoding;
  529. if (isset($lossy_encoding) && $lossy_encoding )
  530. return true;
  531. // convert to lower case
  532. $input_charset = strtolower($input_charset);
  533. // Is user's locale Unicode based ?
  534. if ( $default_charset == "utf-8" ) {
  535. return true;
  536. }
  537. // Charsets that are similar
  538. switch ($default_charset):
  539. case "windows-1251":
  540. if ( $input_charset == "iso-8859-5" ||
  541. $input_charset == "koi8-r" ||
  542. $input_charset == "koi8-u" ) {
  543. return true;
  544. } else {
  545. return false;
  546. }
  547. case "windows-1257":
  548. if ( $input_charset == "iso-8859-13" ||
  549. $input_charset == "iso-8859-4" ) {
  550. return true;
  551. } else {
  552. return false;
  553. }
  554. case "iso-8859-4":
  555. if ( $input_charset == "iso-8859-13" ||
  556. $input_charset == "windows-1257" ) {
  557. return true;
  558. } else {
  559. return false;
  560. }
  561. case "iso-8859-5":
  562. if ( $input_charset == "windows-1251" ||
  563. $input_charset == "koi8-r" ||
  564. $input_charset == "koi8-u" ) {
  565. return true;
  566. } else {
  567. return false;
  568. }
  569. case "iso-8859-13":
  570. if ( $input_charset == "iso-8859-4" ||
  571. $input_charset == "windows-1257" ) {
  572. return true;
  573. } else {
  574. return false;
  575. }
  576. case "koi8-r":
  577. if ( $input_charset == "windows-1251" ||
  578. $input_charset == "iso-8859-5" ||
  579. $input_charset == "koi8-u" ) {
  580. return true;
  581. } else {
  582. return false;
  583. }
  584. case "koi8-u":
  585. if ( $input_charset == "windows-1251" ||
  586. $input_charset == "iso-8859-5" ||
  587. $input_charset == "koi8-r" ) {
  588. return true;
  589. } else {
  590. return false;
  591. }
  592. default:
  593. return false;
  594. endswitch;
  595. }
  596. /* ------------------------------ main --------------------------- */
  597. global $squirrelmail_language, $languages, $use_gettext;
  598. if (! sqgetGlobalVar('squirrelmail_language',$squirrelmail_language,SQ_COOKIE)) {
  599. $squirrelmail_language = '';
  600. }
  601. /**
  602. * Array specifies the available translations.
  603. *
  604. * Structure of array:
  605. * $languages['language']['variable'] = 'value'
  606. *
  607. * Possible 'variable' names:
  608. * NAME - Translation name in English
  609. * CHARSET - Encoding used by translation
  610. * ALIAS - used when 'language' is only short name and 'value' should provide long language name
  611. * ALTNAME - Native translation name. Any 8bit symbols must be html encoded.
  612. * 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
  613. * DIR - Text direction. Used to define Right-to-Left languages. Possible values 'rtl' or 'ltr'. If undefined - defaults to 'ltr'
  614. * XTRA_CODE - translation uses special functions. See doc/i18n.txt
  615. *
  616. * Each 'language' definition requires NAME+CHARSET or ALIAS variables.
  617. *
  618. * @name $languages
  619. * @global array $languages
  620. */
  621. $languages['en_US']['NAME'] = 'English';
  622. $languages['en_US']['CHARSET'] = 'iso-8859-1';
  623. $languages['en_US']['LOCALE'] = 'en_US.ISO8859-1';
  624. $languages['en']['ALIAS'] = 'en_US';
  625. /**
  626. * Automatic translation loading from setup.php files.
  627. * Solution for bug. 1240889.
  628. * setup.php file can contain $languages array entries and XTRA_CODE functions.
  629. */
  630. if (is_dir(SM_PATH . 'locale') &&
  631. is_readable(SM_PATH . 'locale')) {
  632. $localedir = dir(SM_PATH . 'locale');
  633. while($lang_dir=$localedir->read()) {
  634. // remove trailing slash, if present
  635. if (substr($lang_dir,-1)=='/') {
  636. $lang_dir = substr($lang_dir,0,-1);
  637. }
  638. if ($lang_dir != '..' && $lang_dir != '.' && $lang_dir != 'CVS' &&
  639. is_dir(SM_PATH.'locale/'.$lang_dir) &&
  640. file_exists(SM_PATH.'locale/'.$lang_dir.'/setup.php')) {
  641. include_once(SM_PATH.'locale/'.$lang_dir.'/setup.php');
  642. }
  643. }
  644. $localedir->close();
  645. }
  646. /* Detect whether gettext is installed. */
  647. $gettext_flags = 0;
  648. if (function_exists('_')) {
  649. $gettext_flags += 1;
  650. }
  651. if (function_exists('bindtextdomain')) {
  652. $gettext_flags += 2;
  653. }
  654. if (function_exists('textdomain')) {
  655. $gettext_flags += 4;
  656. }
  657. if (function_exists('ngettext')) {
  658. $gettext_flags += 8;
  659. }
  660. /* If gettext is fully loaded, cool */
  661. if ($gettext_flags == 15) {
  662. $use_gettext = true;
  663. }
  664. /* If ngettext support is missing, load it */
  665. elseif ($gettext_flags == 7) {
  666. $use_gettext = true;
  667. // load internal ngettext functions
  668. include_once(SM_PATH . 'class/l10n.class.php');
  669. include_once(SM_PATH . 'functions/ngettext.php');
  670. }
  671. /* If we can fake gettext, try that */
  672. elseif ($gettext_flags == 0) {
  673. $use_gettext = true;
  674. include_once(SM_PATH . 'functions/gettext.php');
  675. } else {
  676. /* Uh-ho. A weird install */
  677. if (! $gettext_flags & 1) {
  678. /**
  679. * Function is used as replacement in broken installs
  680. * @ignore
  681. */
  682. function _($str) {
  683. return $str;
  684. }
  685. }
  686. if (! $gettext_flags & 2) {
  687. /**
  688. * Function is used as replacement in broken installs
  689. * @ignore
  690. */
  691. function bindtextdomain() {
  692. return;
  693. }
  694. }
  695. if (! $gettext_flags & 4) {
  696. /**
  697. * Function is used as replacemet in broken installs
  698. * @ignore
  699. */
  700. function textdomain() {
  701. return;
  702. }
  703. }
  704. if (! $gettext_flags & 8) {
  705. /**
  706. * Function is used as replacemet in broken installs
  707. * @ignore
  708. */
  709. function ngettext($str,$str2,$number) {
  710. if ($number>1) {
  711. return $str2;
  712. } else {
  713. return $str;
  714. }
  715. }
  716. }
  717. if (! function_exists('dgettext')) {
  718. /**
  719. * Replacement for broken setups.
  720. * @ignore
  721. */
  722. function dgettext($domain,$str) {
  723. return $str;
  724. }
  725. }
  726. if (! function_exists('dngettext')) {
  727. /**
  728. * Replacement for broken setups
  729. * @ignore
  730. */
  731. function dngettext($domain,$str1,$strn,$number) {
  732. return ($number==1 ? $str1 : $strn);
  733. }
  734. }
  735. }
  736. ?>