i18n.php 32 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891892893894895896897898899900901902903904905906907908909910911912913914915916917918919920921922923924925926927928929930
  1. <?php
  2. /**
  3. * functions/i18n.php
  4. *
  5. * Copyright (c) 1999-2004 The SquirrelMail Project Team
  6. * Licensed under the GNU GPL. For full terms see the file COPYING.
  7. *
  8. * This file contains variuos functions that are needed to do
  9. * internationalization of SquirrelMail.
  10. *
  11. * Internally the output character set is used. Other characters are
  12. * encoded using Unicode entities according to HTML 4.0.
  13. *
  14. * @version $Id$
  15. * @package squirrelmail
  16. * @subpackage i18n
  17. */
  18. /** Everything uses global.php... */
  19. require_once(SM_PATH . 'functions/global.php');
  20. /**
  21. * Converts string from given charset to charset, that can be displayed by user translation.
  22. *
  23. * Function by default returns html encoded strings, if translation uses different encoding.
  24. * If Japanese translation is used - function returns string converted to euc-jp
  25. * If iconv or recode functions are enabled and translation uses utf-8 - function returns utf-8 encoded string.
  26. * If $charset is not supported - function returns unconverted string.
  27. *
  28. * sanitizing of html tags is also done by this function.
  29. *
  30. * @param string $charset
  31. * @param string $string Text to be decoded
  32. * @return string decoded string
  33. */
  34. function charset_decode ($charset, $string) {
  35. global $languages, $squirrelmail_language, $default_charset;
  36. global $use_php_recode, $use_php_iconv, $agresive_decoding;
  37. if (isset($languages[$squirrelmail_language]['XTRA_CODE']) &&
  38. function_exists($languages[$squirrelmail_language]['XTRA_CODE'])) {
  39. $string = $languages[$squirrelmail_language]['XTRA_CODE']('decode', $string);
  40. }
  41. $charset = strtolower($charset);
  42. set_my_charset();
  43. // Variables that allow to use functions without function_exist() calls
  44. if (! isset($use_php_recode) || $use_php_recode=="" ) {
  45. $use_php_recode=false; }
  46. if (! isset($use_php_iconv) || $use_php_iconv=="" ) {
  47. $use_php_iconv=false; }
  48. // Don't do conversion if charset is the same.
  49. if ( $charset == strtolower($default_charset) )
  50. return htmlspecialchars($string);
  51. // catch iso-8859-8-i thing
  52. if ( $charset == "iso-8859-8-i" )
  53. $charset = "iso-8859-8";
  54. /*
  55. * Recode converts html special characters automatically if you use
  56. * 'charset..html' decoding. There is no documented way to put -d option
  57. * into php recode function call.
  58. */
  59. if ( $use_php_recode ) {
  60. if ( $default_charset == "utf-8" ) {
  61. // other charsets can be converted to utf-8 without loss.
  62. // and output string is smaller
  63. $string = recode_string($charset . "..utf-8",$string);
  64. return htmlspecialchars($string);
  65. } else {
  66. $string = recode_string($charset . "..html",$string);
  67. // recode does not convert single quote, htmlspecialchars does.
  68. $string = str_replace("'", '&#039;', $string);
  69. return $string;
  70. }
  71. }
  72. // iconv functions does not have html target and can be used only with utf-8
  73. if ( $use_php_iconv && $default_charset=='utf-8') {
  74. $string = iconv($charset,$default_charset,$string);
  75. return htmlspecialchars($string);
  76. }
  77. // If we don't use recode and iconv, we'll do it old way.
  78. /* All HTML special characters are 7 bit and can be replaced first */
  79. $string = htmlspecialchars ($string);
  80. /* controls cpu and memory intensive decoding cycles */
  81. if (! isset($agresive_decoding) || $agresive_decoding=="" ) {
  82. $agresive_decoding=false; }
  83. $decode=fixcharset($charset);
  84. $decodefile=SM_PATH . 'functions/decode/' . $decode . '.php';
  85. if (file_exists($decodefile)) {
  86. include_once($decodefile);
  87. $ret = call_user_func('charset_decode_'.$decode, $string);
  88. } else {
  89. $ret = $string;
  90. }
  91. return( $ret );
  92. }
  93. /**
  94. * Makes charset name suitable for decoding cycles
  95. *
  96. * @param string $charset Name of charset
  97. * @return string $charset Adjusted name of charset
  98. */
  99. function fixcharset($charset) {
  100. // minus removed from function names
  101. $charset=str_replace('-','_',$charset);
  102. // windows-125x and cp125x charsets
  103. $charset=str_replace('windows_','cp',$charset);
  104. // ibm > cp
  105. $charset=str_replace('ibm','cp',$charset);
  106. // iso-8859-8-i -> iso-8859-8
  107. // use same cycle until I'll find differences
  108. $charset=str_replace('iso_8859_8_i','iso_8859_8',$charset);
  109. return $charset;
  110. }
  111. /**
  112. * Set up the language to be output
  113. * if $do_search is true, then scan the browser information
  114. * for a possible language that we know
  115. *
  116. * Function sets system locale environment (LC_ALL, LANG, LANGUAGE),
  117. * gettext translation bindings and html header information.
  118. *
  119. * Function returns error codes, if there is some fatal error.
  120. * 0 = no error,
  121. * 1 = mbstring support is not present,
  122. * 2 = mbstring support is not present, user's translation reverted to en_US.
  123. *
  124. * @param string $sm_language translation used by user's interface
  125. * @param bool $do_search use browser's preferred language detection functions. Defaults to false.
  126. * @param bool $default set $sm_language to $squirrelmail_default_language if language detection fails or language is not set. Defaults to false.
  127. * @return int function execution error codes.
  128. */
  129. function set_up_language($sm_language, $do_search = false, $default = false) {
  130. static $SetupAlready = 0;
  131. global $use_gettext, $languages,
  132. $squirrelmail_language, $squirrelmail_default_language,
  133. $sm_notAlias, $username, $data_dir;
  134. if ($SetupAlready) {
  135. return;
  136. }
  137. $SetupAlready = TRUE;
  138. sqgetGlobalVar('HTTP_ACCEPT_LANGUAGE', $accept_lang, SQ_SERVER);
  139. if ($do_search && ! $sm_language && isset($accept_lang)) {
  140. $sm_language = substr($accept_lang, 0, 2);
  141. }
  142. if ((!$sm_language||$default) && isset($squirrelmail_default_language)) {
  143. $squirrelmail_language = $squirrelmail_default_language;
  144. $sm_language = $squirrelmail_default_language;
  145. }
  146. $sm_notAlias = $sm_language;
  147. // Catching removed translation
  148. // System reverts to English translation if user prefs contain translation
  149. // that is not available in $languages array
  150. if (!isset($languages[$sm_notAlias])) {
  151. $sm_notAlias="en_US";
  152. }
  153. while (isset($languages[$sm_notAlias]['ALIAS'])) {
  154. $sm_notAlias = $languages[$sm_notAlias]['ALIAS'];
  155. }
  156. if ( isset($sm_language) &&
  157. $use_gettext &&
  158. $sm_language != '' &&
  159. isset($languages[$sm_notAlias]['CHARSET']) ) {
  160. bindtextdomain( 'squirrelmail', SM_PATH . 'locale/' );
  161. textdomain( 'squirrelmail' );
  162. if (function_exists('bind_textdomain_codeset')) {
  163. if ($sm_notAlias == 'ja_JP') {
  164. bind_textdomain_codeset ("squirrelmail", 'EUC-JP');
  165. } else {
  166. bind_textdomain_codeset ("squirrelmail", $languages[$sm_notAlias]['CHARSET'] );
  167. }
  168. }
  169. if (isset($languages[$sm_notAlias]['LOCALE'])){
  170. $longlocale=$languages[$sm_notAlias]['LOCALE'];
  171. } else {
  172. $longlocale=$sm_notAlias;
  173. }
  174. if ( !ini_get('safe_mode') &&
  175. getenv( 'LC_ALL' ) != $longlocale ) {
  176. putenv( "LC_ALL=$longlocale" );
  177. putenv( "LANG=$longlocale" );
  178. putenv( "LANGUAGE=$longlocale" );
  179. }
  180. setlocale(LC_ALL, $longlocale);
  181. // Set text direction/alignment variables
  182. if (isset($languages[$sm_notAlias]['DIR']) &&
  183. $languages[$sm_notAlias]['DIR'] == 'rtl') {
  184. /**
  185. * Text direction
  186. * @global string $text_direction
  187. */
  188. $text_direction='rtl';
  189. /**
  190. * Left alignment
  191. * @global string $left_align
  192. */
  193. $left_align='right';
  194. /**
  195. * Right alignment
  196. * @global string $right_align
  197. */
  198. $right_align='left';
  199. } else {
  200. $text_direction='ltr';
  201. $left_align='left';
  202. $right_align='right';
  203. }
  204. $squirrelmail_language = $sm_notAlias;
  205. if ($squirrelmail_language == 'ja_JP') {
  206. header ('Content-Type: text/html; charset=EUC-JP');
  207. if (!function_exists('mb_internal_encoding')) {
  208. // Error messages can't be displayed here
  209. $error = 1;
  210. // Revert to English if possible.
  211. if (function_exists('setPref') && $username!='' && $data_dir!="") {
  212. setPref($data_dir, $username, 'language', "en_US");
  213. $error = 2;
  214. }
  215. // stop further execution in order not to get php errors on mb_internal_encoding().
  216. return $error;
  217. }
  218. if (function_exists('mb_language')) {
  219. mb_language('Japanese');
  220. }
  221. mb_internal_encoding('EUC-JP');
  222. mb_http_output('pass');
  223. } else {
  224. header( 'Content-Type: text/html; charset=' . $languages[$sm_notAlias]['CHARSET'] );
  225. }
  226. }
  227. return 0;
  228. }
  229. /**
  230. * Sets default_charset variable according to the one that is used by user's translations.
  231. *
  232. * Function changes global $default_charset variable in order to be sure, that it
  233. * contains charset used by user's translation. Sanity of $squirrelmail_default_language
  234. * and $default_charset combination provided in SquirrelMail config is also tested.
  235. *
  236. * There can be a $default_charset setting in the
  237. * config.php file, but the user may have a different language
  238. * selected for a user interface. This function checks the
  239. * language selected by the user and tags the outgoing messages
  240. * with the appropriate charset corresponding to the language
  241. * selection. This is "more right" (tm), than just stamping the
  242. * message blindly with the system-wide $default_charset.
  243. */
  244. function set_my_charset(){
  245. global $data_dir, $username, $default_charset, $languages, $squirrelmail_default_language;
  246. $my_language = getPref($data_dir, $username, 'language');
  247. if (!$my_language) {
  248. $my_language = $squirrelmail_default_language ;
  249. }
  250. // Catch removed translation
  251. if (!isset($languages[$my_language])) {
  252. $my_language="en_US";
  253. }
  254. while (isset($languages[$my_language]['ALIAS'])) {
  255. $my_language = $languages[$my_language]['ALIAS'];
  256. }
  257. $my_charset = $languages[$my_language]['CHARSET'];
  258. if ($my_charset) {
  259. $default_charset = $my_charset;
  260. }
  261. }
  262. /* ------------------------------ main --------------------------- */
  263. global $squirrelmail_language, $languages, $use_gettext;
  264. if (! isset($squirrelmail_language)) {
  265. $squirrelmail_language = '';
  266. }
  267. /**
  268. * Array specifies the available translations.
  269. *
  270. * Structure of array:
  271. * $languages['language']['variable'] = 'value'
  272. *
  273. * Possible 'variable' names:
  274. * NAME - Translation name in English
  275. * CHARSET - Encoding used by translation
  276. * ALIAS - used when 'language' is only short name and 'value' should provide long language name
  277. * ALTNAME - Native translation name. Any 8bit symbols must be html encoded.
  278. * LOCALE - Full locale name (in xx_XX.charset format)
  279. * DIR - Text direction. Used to define Right-to-Left languages. Possible values 'rtl' or 'ltr'. If undefined - defaults to 'ltr'
  280. * XTRA_CODE - translation uses special functions. 'value' provides name of that extra function
  281. *
  282. * Each 'language' definition requires NAME+CHARSET or ALIAS variables.
  283. *
  284. * @name $languages
  285. * @global array $languages
  286. */
  287. $languages['bg_BG']['NAME'] = 'Bulgarian';
  288. $languages['bg_BG']['ALTNAME'] = '&#1041;&#1098;&#1083;&#1075;&#1072;&#1088;&#1089;&#1082;&#1080;';
  289. $languages['bg_BG']['CHARSET'] = 'windows-1251';
  290. $languages['bg_BG']['LOCALE'] = 'bg_BG.CP1251';
  291. $languages['bg']['ALIAS'] = 'bg_BG';
  292. $languages['ca_ES']['NAME'] = 'Catalan';
  293. $languages['ca_ES']['CHARSET'] = 'iso-8859-1';
  294. $languages['ca_ES']['LOCALE'] = 'ca_ES.ISO8859-1';
  295. $languages['ca']['ALIAS'] = 'ca_ES';
  296. $languages['cs_CZ']['NAME'] = 'Czech';
  297. $languages['cs_CZ']['ALTNAME'] = '&#268;e&scaron;tina';
  298. $languages['cs_CZ']['CHARSET'] = 'iso-8859-2';
  299. $languages['cs_CZ']['LOCALE'] = 'cs_CZ.ISO8859-2';
  300. $languages['cs']['ALIAS'] = 'cs_CZ';
  301. $languages['cy_GB']['NAME'] = 'Welsh';
  302. $languages['cy_GB']['ALTNAME'] = 'Cymraeg';
  303. $languages['cy_GB']['CHARSET'] = 'iso-8859-1';
  304. $languages['cy_GB']['LOCALE'] = 'cy_GB.ISO8859-1';
  305. $languages['cy']['ALIAS'] = 'cy_GB';
  306. // Danish locale is da_DK.
  307. $languages['da_DK']['NAME'] = 'Danish';
  308. $languages['da_DK']['ALTNAME'] = 'Dansk';
  309. $languages['da_DK']['CHARSET'] = 'iso-8859-1';
  310. $languages['da_DK']['LOCALE'] = 'da_DK.ISO8859-1';
  311. $languages['da']['ALIAS'] = 'da_DK';
  312. $languages['de_DE']['NAME'] = 'German';
  313. $languages['de_DE']['ALTNAME'] = 'Deutsch';
  314. $languages['de_DE']['CHARSET'] = 'iso-8859-1';
  315. $languages['de_DE']['LOCALE'] = 'de_DE.ISO8859-1';
  316. $languages['de']['ALIAS'] = 'de_DE';
  317. $languages['el_GR']['NAME'] = 'Greek';
  318. $languages['el_GR']['ALTNAME'] = '&Epsilon;&lambda;&lambda;&eta;&nu;&iota;&kappa;&#940;';
  319. $languages['el_GR']['CHARSET'] = 'iso-8859-7';
  320. $languages['el_GR']['LOCALE'] = 'el_GR.ISO8859-7';
  321. $languages['el']['ALIAS'] = 'el_GR';
  322. $languages['en_GB']['NAME'] = 'British';
  323. $languages['en_GB']['CHARSET'] = 'iso-8859-15';
  324. $languages['en_GB']['LOCALE'] = 'en_GB.ISO8859-15';
  325. $languages['en_US']['NAME'] = 'English';
  326. $languages['en_US']['CHARSET'] = 'iso-8859-1';
  327. $languages['en_US']['LOCALE'] = 'en_US.ISO8859-1';
  328. $languages['en']['ALIAS'] = 'en_US';
  329. $languages['es_ES']['NAME'] = 'Spanish';
  330. $languages['es_ES']['ALTNAME'] = 'Espa&ntilde;ol';
  331. $languages['es_ES']['CHARSET'] = 'iso-8859-1';
  332. $languages['es_ES']['LOCALE'] = 'es_ES.ISO8859-1';
  333. $languages['es']['ALIAS'] = 'es_ES';
  334. $languages['et_EE']['NAME'] = 'Estonian';
  335. $languages['et_EE']['CHARSET'] = 'iso-8859-15';
  336. $languages['et_EE']['LOCALE'] = 'et_EE.ISO8859-15';
  337. $languages['et']['ALIAS'] = 'et_EE';
  338. $languages['fo_FO']['NAME'] = 'Faroese';
  339. $languages['fo_FO']['CHARSET'] = 'iso-8859-1';
  340. $languages['fo_FO']['LOCALE'] = 'fo_FO.ISO8859-1';
  341. $languages['fo']['ALIAS'] = 'fo_FO';
  342. $languages['fi_FI']['NAME'] = 'Finnish';
  343. $languages['fi_FI']['ALTNAME'] = 'Suomi';
  344. $languages['fi_FI']['CHARSET'] = 'iso-8859-1';
  345. $languages['fi_FI']['LOCALE'] = 'fi_FI.ISO8859-1';
  346. $languages['fi']['ALIAS'] = 'fi_FI';
  347. $languages['fr_FR']['NAME'] = 'French';
  348. $languages['fr_FR']['ALTNAME'] = 'Fran&#231;ais';
  349. $languages['fr_FR']['CHARSET'] = 'iso-8859-1';
  350. $languages['fr_FR']['LOCALE'] = 'fr_FR.ISO8859-1';
  351. $languages['fr']['ALIAS'] = 'fr_FR';
  352. $languages['hr_HR']['NAME'] = 'Croatian';
  353. $languages['hr_HR']['CHARSET'] = 'iso-8859-2';
  354. $languages['hr_HR']['LOCALE'] = 'hr_HR.ISO8859-2';
  355. $languages['hr']['ALIAS'] = 'hr_HR';
  356. $languages['hu_HU']['NAME'] = 'Hungarian';
  357. $languages['hu_HU']['ALTNAME'] = 'Magyar';
  358. $languages['hu_HU']['CHARSET'] = 'iso-8859-2';
  359. $languages['hu_HU']['LOCALE'] = 'hu_HU.ISO8859-2';
  360. $languages['hu']['ALIAS'] = 'hu_HU';
  361. $languages['id_ID']['NAME'] = 'Indonesian';
  362. $languages['id_ID']['ALTNAME'] = 'Bahasa Indonesia';
  363. $languages['id_ID']['CHARSET'] = 'iso-8859-1';
  364. $languages['id_ID']['LOCALE'] = 'id_ID.ISO8859-1';
  365. $languages['id']['ALIAS'] = 'id_ID';
  366. $languages['is_IS']['NAME'] = 'Icelandic';
  367. $languages['is_IS']['ALTNAME'] = '&Iacute;slenska';
  368. $languages['is_IS']['CHARSET'] = 'iso-8859-1';
  369. $languages['is_IS']['LOCALE'] = 'is_IS.ISO8859-1';
  370. $languages['is']['ALIAS'] = 'is_IS';
  371. $languages['it_IT']['NAME'] = 'Italian';
  372. $languages['it_IT']['CHARSET'] = 'iso-8859-1';
  373. $languages['it_IT']['LOCALE'] = 'it_IT.ISO8859-1';
  374. $languages['it']['ALIAS'] = 'it_IT';
  375. $languages['ja_JP']['NAME'] = 'Japanese';
  376. $languages['ja_JP']['ALTNAME'] = '&#26085;&#26412;&#35486;';
  377. $languages['ja_JP']['CHARSET'] = 'iso-2022-jp';
  378. $languages['ja_JP']['LOCALE'] = 'ja_JP.EUC-JP';
  379. $languages['ja_JP']['XTRA_CODE'] = 'japanese_charset_xtra';
  380. $languages['ja']['ALIAS'] = 'ja_JP';
  381. $languages['ko_KR']['NAME'] = 'Korean';
  382. $languages['ko_KR']['CHARSET'] = 'euc-KR';
  383. $languages['ko_KR']['LOCALE'] = 'ko_KR.EUC-KR';
  384. $languages['ko_KR']['XTRA_CODE'] = 'korean_charset_xtra';
  385. $languages['ko']['ALIAS'] = 'ko_KR';
  386. $languages['lt_LT']['NAME'] = 'Lithuanian';
  387. $languages['lt_LT']['ALTNAME'] = 'Lietuvi&#371;';
  388. $languages['lt_LT']['CHARSET'] = 'utf-8';
  389. $languages['lt_LT']['LOCALE'] = 'lt_LT.UTF-8';
  390. $languages['lt']['ALIAS'] = 'lt_LT';
  391. $languages['nl_NL']['NAME'] = 'Dutch';
  392. $languages['nl_NL']['ALTNAME'] = 'Nederlands';
  393. $languages['nl_NL']['CHARSET'] = 'iso-8859-1';
  394. $languages['nl_NL']['LOCALE'] = 'nl_NL.ISO8859-1';
  395. $languages['nl']['ALIAS'] = 'nl_NL';
  396. $languages['ms_MY']['NAME'] = 'Malay';
  397. $languages['ms_MY']['ALTNAME'] = 'Bahasa Melayu';
  398. $languages['ms_MY']['CHARSET'] = 'iso-8859-1';
  399. $languages['ms_MY']['LOCALE'] = 'ms_MY.ISO8859-1';
  400. $languages['my']['ALIAS'] = 'ms_MY';
  401. $languages['nb_NO']['NAME'] = 'Norwegian (Bokm&aring;l)';
  402. $languages['nb_NO']['ALTNAME'] = 'Norsk (Bokm&aring;l)';
  403. $languages['nb_NO']['CHARSET'] = 'iso-8859-1';
  404. $languages['nb_NO']['LOCALE'] = 'nb_NO.ISO8859-1';
  405. $languages['nb']['ALIAS'] = 'nb_NO';
  406. $languages['nn_NO']['NAME'] = 'Norwegian (Nynorsk)';
  407. $languages['nn_NO']['ALTNAME'] = 'Norsk (Nynorsk)';
  408. $languages['nn_NO']['CHARSET'] = 'iso-8859-1';
  409. $languages['nn_NO']['LOCALE'] = 'nn_NO.ISO8859-1';
  410. $languages['pl_PL']['NAME'] = 'Polish';
  411. $languages['pl_PL']['ALTNAME'] = 'Polski';
  412. $languages['pl_PL']['CHARSET'] = 'iso-8859-2';
  413. $languages['pl_PL']['LOCALE'] = 'pl_PL.ISO8859-2';
  414. $languages['pl']['ALIAS'] = 'pl_PL';
  415. $languages['pt_PT']['NAME'] = 'Portuguese (Portugal)';
  416. $languages['pt_PT']['CHARSET'] = 'iso-8859-1';
  417. $languages['pt_PT']['LOCALE'] = 'pt_PT.ISO8859-1';
  418. $languages['pt']['ALIAS'] = 'pt_PT';
  419. $languages['pt_BR']['NAME'] = 'Portuguese (Brazil)';
  420. $languages['pt_BR']['ALTNAME'] = 'Portugu&ecirc;s do Brasil';
  421. $languages['pt_BR']['CHARSET'] = 'iso-8859-1';
  422. $languages['pt_BR']['LOCALE'] = 'pt_BR.ISO8859-1';
  423. $languages['ro_RO']['NAME'] = 'Romanian';
  424. $languages['ro_RO']['ALTNAME'] = 'Rom&acirc;n&#259;';
  425. $languages['ro_RO']['CHARSET'] = 'iso-8859-2';
  426. $languages['ro_RO']['LOCALE'] = 'ro_RO.ISO8859-2';
  427. $languages['ro']['ALIAS'] = 'ro_RO';
  428. $languages['ru_RU']['NAME'] = 'Russian';
  429. $languages['ru_RU']['ALTNAME'] = '&#1056;&#1091;&#1089;&#1089;&#1082;&#1080;&#1081;';
  430. $languages['ru_RU']['CHARSET'] = 'utf-8';
  431. $languages['ru_RU']['LOCALE'] = 'ru_RU.UTF-8';
  432. $languages['ru']['ALIAS'] = 'ru_RU';
  433. $languages['sk_SK']['NAME'] = 'Slovak';
  434. $languages['sk_SK']['CHARSET'] = 'iso-8859-2';
  435. $languages['sk_SK']['LOCALE'] = 'sk_SK.ISO8859-2';
  436. $languages['sk']['ALIAS'] = 'sk_SK';
  437. $languages['sl_SI']['NAME'] = 'Slovenian';
  438. $languages['sl_SI']['ALTNAME'] = 'Sloven&scaron;&#269;ina';
  439. $languages['sl_SI']['CHARSET'] = 'iso-8859-2';
  440. $languages['sl_SI']['LOCALE'] = 'sl_SI.ISO8859-2';
  441. $languages['sl']['ALIAS'] = 'sl_SI';
  442. $languages['sr_YU']['NAME'] = 'Serbian';
  443. $languages['sr_YU']['ALTNAME'] = 'Srpski';
  444. $languages['sr_YU']['CHARSET'] = 'iso-8859-2';
  445. $languages['sr_YU']['LOCALE'] = 'sr_YU.ISO8859-2';
  446. $languages['sr']['ALIAS'] = 'sr_YU';
  447. $languages['sv_SE']['NAME'] = 'Swedish';
  448. $languages['sv_SE']['ALTNAME'] = 'Svenska';
  449. $languages['sv_SE']['CHARSET'] = 'iso-8859-1';
  450. $languages['sv_SE']['LOCALE'] = 'sv_SE.ISO8859-1';
  451. $languages['sv']['ALIAS'] = 'sv_SE';
  452. $languages['th_TH']['NAME'] = 'Thai';
  453. $languages['th_TH']['CHARSET'] = 'tis-620';
  454. $languages['th_TH']['LOCALE'] = 'th_TH.TIS-620';
  455. $languages['th']['ALIAS'] = 'th_TH';
  456. $languages['tl_PH']['NAME'] = 'Tagalog';
  457. $languages['tl_PH']['CHARSET'] = 'iso-8859-1';
  458. $languages['tl_PH']['LOCALE'] = 'tl_PH.ISO8859-1';
  459. $languages['tl']['ALIAS'] = 'tl_PH';
  460. $languages['tr_TR']['NAME'] = 'Turkish';
  461. $languages['tr_TR']['CHARSET'] = 'iso-8859-9';
  462. $languages['tr_TR']['LOCALE'] = 'tr_TR.ISO8859-9';
  463. $languages['tr']['ALIAS'] = 'tr_TR';
  464. $languages['zh_TW']['NAME'] = 'Chinese Trad';
  465. $languages['zh_TW']['CHARSET'] = 'big5';
  466. $languages['zh_TW']['LOCALE'] = 'zh_TW.BIG5';
  467. $languages['tw']['ALIAS'] = 'zh_TW';
  468. $languages['zh_CN']['NAME'] = 'Chinese Simp';
  469. $languages['zh_CN']['CHARSET'] = 'gb2312';
  470. $languages['zh_CN']['LOCALE'] = 'zh_CN.GB2312';
  471. $languages['cn']['ALIAS'] = 'zh_CN';
  472. $languages['uk_UA']['NAME'] = 'Ukrainian';
  473. $languages['uk_UA']['CHARSET'] = 'koi8-u';
  474. $languages['uk_UA']['LOCALE'] = 'uk_UA.KOI8-U';
  475. $languages['uk']['ALIAS'] = 'uk_UA';
  476. $languages['ru_UA']['NAME'] = 'Russian (Ukrainian)';
  477. $languages['ru_UA']['CHARSET'] = 'koi8-r';
  478. $languages['ru_UA']['LOCALE'] = 'ru_UA.KOI8-R';
  479. /*
  480. $languages['vi_VN']['NAME'] = 'Vietnamese';
  481. $languages['vi_VN']['CHARSET'] = 'utf-8';
  482. $languages['vi']['ALIAS'] = 'vi_VN';
  483. */
  484. // Right to left languages
  485. $languages['ar']['NAME'] = 'Arabic';
  486. $languages['ar']['CHARSET'] = 'windows-1256';
  487. $languages['ar']['DIR'] = 'rtl';
  488. $languages['fa_IR']['NAME'] = 'Farsi';
  489. $languages['fa_IR']['CHARSET'] = 'utf-8';
  490. $languages['fa_IR']['DIR'] = 'rtl';
  491. $languages['fa_IR']['LOCALE'] = 'fa_IR.UTF-8';
  492. $languages['fa']['ALIAS'] = 'fa_IR';
  493. $languages['he_IL']['NAME'] = 'Hebrew';
  494. $languages['he_IL']['CHARSET'] = 'windows-1255';
  495. $languages['he_IL']['LOCALE'] = 'he_IL.CP1255';
  496. $languages['he_IL']['DIR'] = 'rtl';
  497. $languages['he']['ALIAS'] = 'he_IL';
  498. /* Detect whether gettext is installed. */
  499. $gettext_flags = 0;
  500. if (function_exists('_')) {
  501. $gettext_flags += 1;
  502. }
  503. if (function_exists('bindtextdomain')) {
  504. $gettext_flags += 2;
  505. }
  506. if (function_exists('textdomain')) {
  507. $gettext_flags += 4;
  508. }
  509. /* If gettext is fully loaded, cool */
  510. if ($gettext_flags == 7) {
  511. $use_gettext = true;
  512. }
  513. /* If we can fake gettext, try that */
  514. elseif ($gettext_flags == 0) {
  515. $use_gettext = true;
  516. include_once(SM_PATH . 'functions/gettext.php');
  517. } else {
  518. /* Uh-ho. A weird install */
  519. if (! $gettext_flags & 1) {
  520. function _($str) {
  521. return $str;
  522. }
  523. }
  524. if (! $gettext_flags & 2) {
  525. function bindtextdomain() {
  526. return;
  527. }
  528. }
  529. if (! $gettext_flags & 4) {
  530. function textdomain() {
  531. return;
  532. }
  533. }
  534. }
  535. /**
  536. * Japanese charset extra function
  537. *
  538. * Action performed by function is defined by first argument.
  539. * Default return value is defined by second argument.
  540. * Use of third argument depends on action.
  541. *
  542. * @param string $action action performed by this function.
  543. * possible values:
  544. * decode - convert returned string to euc-jp. third argument unused
  545. * encode - convert returned string to jis. third argument unused
  546. * strimwidth - third argument=$width. trims string to $width symbols.
  547. * encodeheader - create base64 encoded header in iso-2022-jp. third argument unused
  548. * decodeheader - return human readable string from mime header. string is returned in euc-jp. third argument unused
  549. * downloadfilename - third argument $useragent. Arguments provide browser info. Returns shift-jis or euc-jp encoded file name
  550. * wordwrap - third argument=$wrap. wraps text at $wrap symbols
  551. * utf7-imap_encode - returns string converted from euc-jp to utf7-imap. third argument unused
  552. * utf7-imap_decode - returns string converted from utf7-imap to euc-jp. third argument unused
  553. * @param string $ret default return value
  554. */
  555. function japanese_charset_xtra() {
  556. $ret = func_get_arg(1); /* default return value */
  557. if (function_exists('mb_detect_encoding')) {
  558. switch (func_get_arg(0)) { /* action */
  559. case 'decode':
  560. $detect_encoding = @mb_detect_encoding($ret);
  561. if ($detect_encoding == 'JIS' ||
  562. $detect_encoding == 'EUC-JP' ||
  563. $detect_encoding == 'SJIS' ||
  564. $detect_encoding == 'UTF-8') {
  565. $ret = mb_convert_kana(mb_convert_encoding($ret, 'EUC-JP', 'AUTO'), "KV");
  566. }
  567. break;
  568. case 'encode':
  569. $detect_encoding = @mb_detect_encoding($ret);
  570. if ($detect_encoding == 'JIS' ||
  571. $detect_encoding == 'EUC-JP' ||
  572. $detect_encoding == 'SJIS' ||
  573. $detect_encoding == 'UTF-8') {
  574. $ret = mb_convert_encoding(mb_convert_kana($ret, "KV"), 'JIS', 'AUTO');
  575. }
  576. break;
  577. case 'strimwidth':
  578. $width = func_get_arg(2);
  579. $ret = mb_strimwidth($ret, 0, $width, '...');
  580. break;
  581. case 'encodeheader':
  582. $result = '';
  583. if (strlen($ret) > 0) {
  584. $tmpstr = mb_substr($ret, 0, 1);
  585. $prevcsize = strlen($tmpstr);
  586. for ($i = 1; $i < mb_strlen($ret); $i++) {
  587. $tmp = mb_substr($ret, $i, 1);
  588. if (strlen($tmp) == $prevcsize) {
  589. $tmpstr .= $tmp;
  590. } else {
  591. if ($prevcsize == 1) {
  592. $result .= $tmpstr;
  593. } else {
  594. $result .= str_replace(' ', '',
  595. mb_encode_mimeheader($tmpstr,'iso-2022-jp','B',''));
  596. }
  597. $tmpstr = $tmp;
  598. $prevcsize = strlen($tmp);
  599. }
  600. }
  601. if (strlen($tmpstr)) {
  602. if (strlen(mb_substr($tmpstr, 0, 1)) == 1)
  603. $result .= $tmpstr;
  604. else
  605. $result .= str_replace(' ', '',
  606. mb_encode_mimeheader($tmpstr,'iso-2022-jp','B',''));
  607. }
  608. }
  609. $ret = $result;
  610. break;
  611. case 'decodeheader':
  612. $ret = str_replace("\t", "", $ret);
  613. if (eregi('=\\?([^?]+)\\?(q|b)\\?([^?]+)\\?=', $ret))
  614. $ret = @mb_decode_mimeheader($ret);
  615. $ret = @mb_convert_encoding($ret, 'EUC-JP', 'AUTO');
  616. break;
  617. case 'downloadfilename':
  618. $useragent = func_get_arg(2);
  619. if (strstr($useragent, 'Windows') !== false ||
  620. strstr($useragent, 'Mac_') !== false) {
  621. $ret = mb_convert_encoding($ret, 'SJIS', 'AUTO');
  622. } else {
  623. $ret = mb_convert_encoding($ret, 'EUC-JP', 'AUTO');
  624. }
  625. break;
  626. case 'wordwrap':
  627. $no_begin = "\x21\x25\x29\x2c\x2e\x3a\x3b\x3f\x5d\x7d\xa1\xf1\xa1\xeb\xa1" .
  628. "\xc7\xa1\xc9\xa2\xf3\xa1\xec\xa1\xed\xa1\xee\xa1\xa2\xa1\xa3\xa1\xb9" .
  629. "\xa1\xd3\xa1\xd5\xa1\xd7\xa1\xd9\xa1\xdb\xa1\xcd\xa4\xa1\xa4\xa3\xa4" .
  630. "\xa5\xa4\xa7\xa4\xa9\xa4\xc3\xa4\xe3\xa4\xe5\xa4\xe7\xa4\xee\xa1\xab" .
  631. "\xa1\xac\xa1\xb5\xa1\xb6\xa5\xa1\xa5\xa3\xa5\xa5\xa5\xa7\xa5\xa9\xa5" .
  632. "\xc3\xa5\xe3\xa5\xe5\xa5\xe7\xa5\xee\xa5\xf5\xa5\xf6\xa1\xa6\xa1\xbc" .
  633. "\xa1\xb3\xa1\xb4\xa1\xaa\xa1\xf3\xa1\xcb\xa1\xa4\xa1\xa5\xa1\xa7\xa1" .
  634. "\xa8\xa1\xa9\xa1\xcf\xa1\xd1";
  635. $no_end = "\x5c\x24\x28\x5b\x7b\xa1\xf2\x5c\xa1\xc6\xa1\xc8\xa1\xd2\xa1" .
  636. "\xd4\xa1\xd6\xa1\xd8\xa1\xda\xa1\xcc\xa1\xf0\xa1\xca\xa1\xce\xa1\xd0\xa1\xef";
  637. $wrap = func_get_arg(2);
  638. if (strlen($ret) >= $wrap &&
  639. substr($ret, 0, 1) != '>' &&
  640. strpos($ret, 'http://') === FALSE &&
  641. strpos($ret, 'https://') === FALSE &&
  642. strpos($ret, 'ftp://') === FALSE) {
  643. $ret = mb_convert_kana($ret, "KV");
  644. $line_new = '';
  645. $ptr = 0;
  646. while ($ptr < strlen($ret) - 1) {
  647. $l = mb_strcut($ret, $ptr, $wrap);
  648. $ptr += strlen($l);
  649. $tmp = $l;
  650. $l = mb_strcut($ret, $ptr, 2);
  651. while (strlen($l) != 0 && mb_strpos($no_begin, $l) !== FALSE ) {
  652. $tmp .= $l;
  653. $ptr += strlen($l);
  654. $l = mb_strcut($ret, $ptr, 1);
  655. }
  656. $line_new .= $tmp;
  657. if ($ptr < strlen($ret) - 1)
  658. $line_new .= "\n";
  659. }
  660. $ret = $line_new;
  661. }
  662. break;
  663. case 'utf7-imap_encode':
  664. $ret = mb_convert_encoding($ret, 'UTF7-IMAP', 'EUC-JP');
  665. break;
  666. case 'utf7-imap_decode':
  667. $ret = mb_convert_encoding($ret, 'EUC-JP', 'UTF7-IMAP');
  668. break;
  669. }
  670. }
  671. return $ret;
  672. }
  673. /**
  674. * Korean charset extra functions
  675. *
  676. * Action performed by function is defined by first argument.
  677. * Default return value is defined by second argument.
  678. *
  679. * @param string action performed by this function.
  680. * possible values:
  681. * downloadfilename - Hangul(Korean Character) Attached File Name Fix.
  682. * @param string default return value
  683. */
  684. function korean_charset_xtra() {
  685. $ret = func_get_arg(1); /* default return value */
  686. if (func_get_arg(0) == 'downloadfilename') { /* action */
  687. $ret = str_replace("\x0D\x0A", '', $ret); /* Hanmail's CR/LF Clear */
  688. for ($i=0;$i<strlen($ret);$i++) {
  689. if ($ret[$i] >= "\xA1" && $ret[$i] <= "\xFE") { /* 0xA1 - 0XFE are Valid */
  690. $i++;
  691. continue;
  692. } else if (($ret[$i] >= 'a' && $ret[$i] <= 'z') || /* From Original ereg_replace in download.php */
  693. ($ret[$i] >= 'A' && $ret[$i] <= 'Z') ||
  694. ($ret[$i] == '.') || ($ret[$i] == '-')) {
  695. continue;
  696. } else {
  697. $ret[$i] = '_';
  698. }
  699. }
  700. }
  701. return $ret;
  702. }
  703. /**
  704. * Replaces non-braking spaces inserted by some browsers with regular space
  705. *
  706. * This function can be used to replace non-braking space symbols
  707. * that are inserted in forms by some browsers instead of normal
  708. * space symbol.
  709. *
  710. * @param string $string Text that needs to be cleaned
  711. * @param string $charset Charset used in text
  712. * @return string Cleaned text
  713. */
  714. function cleanup_nbsp($string,$charset) {
  715. // reduce number of case statements
  716. if (stristr('iso-8859-',substr($charset,0,9))){
  717. $output_charset="iso-8859-x";
  718. }
  719. if (stristr('windows-125',substr($charset,0,11))){
  720. $output_charset="cp125x";
  721. }
  722. if (stristr('koi8',substr($charset,0,4))){
  723. $output_charset="koi8-x";
  724. }
  725. if (! isset($output_charset)){
  726. $output_charset=strtolower($charset);
  727. }
  728. // where is non-braking space symbol
  729. switch($output_charset):
  730. case "iso-8859-x":
  731. case "cp125x":
  732. case "iso-2022-jp":
  733. $nbsp="\xA0";
  734. break;
  735. case "koi8-x":
  736. $nbsp="\x9A";
  737. break;
  738. case "utf-8":
  739. $nbsp="\xC2\xA0";
  740. break;
  741. default:
  742. // don't change string if charset is unmatched
  743. return $string;
  744. endswitch;
  745. // return space instead of non-braking space.
  746. return str_replace($nbsp,' ',$string);
  747. }
  748. /**
  749. * Function informs if it is safe to convert given charset to the one that is used by user.
  750. *
  751. * It is safe to use conversion only if user uses utf-8 encoding and when
  752. * converted charset is similar to the one that is used by user.
  753. *
  754. * @param string $input_charset Charset of text that needs to be converted
  755. * @return bool is it possible to convert to user's charset
  756. */
  757. function is_conversion_safe($input_charset) {
  758. global $languages, $sm_notAlias, $default_charset;
  759. // convert to lower case
  760. $input_charset = strtolower($input_charset);
  761. // Is user's locale Unicode based ?
  762. if ( $default_charset == "utf-8" ) {
  763. return true;
  764. }
  765. // Charsets that are similar
  766. switch ($default_charset):
  767. case "windows-1251":
  768. if ( $input_charset == "iso-8859-5" ||
  769. $input_charset == "koi8-r" ||
  770. $input_charset == "koi8-u" ) {
  771. return true;
  772. } else {
  773. return false;
  774. }
  775. case "windows-1257":
  776. if ( $input_charset == "iso-8859-13" ||
  777. $input_charset == "iso-8859-4" ) {
  778. return true;
  779. } else {
  780. return false;
  781. }
  782. case "iso-8859-4":
  783. if ( $input_charset == "iso-8859-13" ||
  784. $input_charset == "windows-1257" ) {
  785. return true;
  786. } else {
  787. return false;
  788. }
  789. case "iso-8859-5":
  790. if ( $input_charset == "windows-1251" ||
  791. $input_charset == "koi8-r" ||
  792. $input_charset == "koi8-u" ) {
  793. return true;
  794. } else {
  795. return false;
  796. }
  797. case "iso-8859-13":
  798. if ( $input_charset == "iso-8859-4" ||
  799. $input_charset == "windows-1257" ) {
  800. return true;
  801. } else {
  802. return false;
  803. }
  804. case "koi8-r":
  805. if ( $input_charset == "windows-1251" ||
  806. $input_charset == "iso-8859-5" ||
  807. $input_charset == "koi8-u" ) {
  808. return true;
  809. } else {
  810. return false;
  811. }
  812. case "koi8-u":
  813. if ( $input_charset == "windows-1251" ||
  814. $input_charset == "iso-8859-5" ||
  815. $input_charset == "koi8-r" ) {
  816. return true;
  817. } else {
  818. return false;
  819. }
  820. default:
  821. return false;
  822. endswitch;
  823. }
  824. ?>