i18n.php 34 KB

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