Update COPYING with new address of the FSF.
[squirrelmail.git] / functions / i18n.php
index 676f272060252ab5dfee9cf49b6a0b8a8ddca990..554ab4427c189a458c62a67b43618ae68b733f5c 100644 (file)
@@ -70,7 +70,7 @@ function sq_textdomain($domain) {
  *     (LC_ALL, LC_COLLATE, LC_CTYPE, LC_MONETARY, LC_NUMERIC, LC_TIME)
  * @param mixed $locale option contains array with possible locales or string with one locale
  * @return string name of set locale or false, if all locales fail.
- * @since 1.5.1
+ * @since 1.5.1 and 1.4.5
  * @see http://www.php.net/setlocale
  */
 function sq_setlocale($category,$locale) {
@@ -104,9 +104,11 @@ function sq_setlocale($category,$locale) {
  *
  * @param string $charset
  * @param string $string Text to be decoded
+ * @param boolean $force_decode converts string to html without $charset!=$default_charset check.
+ * Argument is available since 1.5.1 and 1.4.5.
  * @return string decoded string
  */
-function charset_decode ($charset, $string) {
+function charset_decode ($charset, $string, $force_decode=false) {
     global $languages, $squirrelmail_language, $default_charset;
     global $use_php_recode, $use_php_iconv, $aggressive_decoding;
 
@@ -126,7 +128,7 @@ function charset_decode ($charset, $string) {
         $use_php_iconv=false; }
 
     // Don't do conversion if charset is the same.
-    if ( $charset == strtolower($default_charset) )
+    if ( ! $force_decode && $charset == strtolower($default_charset) )
         return htmlspecialchars($string);
 
     // catch iso-8859-8-i thing
@@ -181,7 +183,7 @@ function charset_decode ($charset, $string) {
 
 /**
  * Converts html string to given charset
- * @since 1.5.1
+ * @since 1.5.1 and 1.4.4
  * @param string $string
  * @param string $charset
  * @param boolean $htmlencode keep htmlspecialchars encoding
@@ -217,7 +219,7 @@ function charset_encode($string,$charset,$htmlencode=true) {
  *
  * If conversion is done to charset different that utf-8, unsupported symbols
  * will be replaced with question marks.
- * @since 1.5.1
+ * @since 1.5.1 and 1.4.4
  * @param string $in_charset initial charset
  * @param string $string string that has to be converted
  * @param string $out_charset final charset
@@ -225,7 +227,7 @@ function charset_encode($string,$charset,$htmlencode=true) {
  * @return string converted string
  */
 function charset_convert($in_charset,$string,$out_charset,$htmlencode=true) {
-    $string=charset_decode($in_charset,$string);
+    $string=charset_decode($in_charset,$string,true);
     $string=charset_encode($string,$out_charset,$htmlencode);
     return $string;
 }
@@ -233,7 +235,7 @@ function charset_convert($in_charset,$string,$out_charset,$htmlencode=true) {
 /**
  * Makes charset name suitable for decoding cycles
  *
- * @since 1.5.0
+ * @since 1.5.0 and 1.4.4
  * @param string $charset Name of charset
  * @return string $charset Adjusted name of charset
  */
@@ -288,14 +290,42 @@ function set_up_language($sm_language, $do_search = false, $default = false) {
     $SetupAlready = TRUE;
     sqgetGlobalVar('HTTP_ACCEPT_LANGUAGE',  $accept_lang, SQ_SERVER);
 
-    if ($do_search && ! $sm_language && isset($accept_lang)) {
+    /**
+     * If function is asked to detect preferred language
+     *  OR squirrelmail default language is set to empty string
+     *    AND
+     * squirrelmail language ($sm_language) is empty string
+     * (not set in user's prefs and no cookie with language info)
+     *    AND
+     * browser provides list of preferred languages
+     *  THEN
+     * get preferred language from HTTP_ACCEPT_LANGUAGE header
+     */
+    if (($do_search || empty($squirrelmail_default_language)) &&
+        ! $sm_language &&
+        isset($accept_lang)) {
+        // TODO: use more than one language, if first language is not available
+        // FIXME: function assumes that string contains two or more characters.
+        // FIXME: some languages use 5 chars
         $sm_language = substr($accept_lang, 0, 2);
     }
 
-    if ((!$sm_language||$default) && isset($squirrelmail_default_language)) {
+    /**
+     * If language preference is not set OR script asks to use default language
+     *  AND
+     * default squirrelmail language is not set to empty string
+     *  THEN
+     * use default squirrelmail language value from configuration.
+     */
+    if ((!$sm_language||$default) &&
+        ! empty($squirrelmail_default_language)) {
         $squirrelmail_language = $squirrelmail_default_language;
         $sm_language = $squirrelmail_default_language;
     }
+
+    /** provide failsafe language when detection fails */
+    if (! $sm_language) $sm_language='en_US';
+
     $sm_notAlias = $sm_language;
 
     // Catching removed translation
@@ -411,6 +441,27 @@ function set_up_language($sm_language, $do_search = false, $default = false) {
         } else {
             header( 'Content-Type: text/html; charset=' . $languages[$sm_notAlias]['CHARSET'] );
         }
+        /**
+         * mbstring.func_overload fix (#929644).
+         *
+         * php mbstring extension can replace standard string functions with their multibyte
+         * equivalents. See http://www.php.net/ref.mbstring#mbstring.overload. This feature 
+         * was added in php v.4.2.0
+         *
+         * Some SquirrelMail functions work with 8bit strings in bytes. If interface is forced
+         * to use mbstring functions and mbstring internal encoding is set to multibyte charset,
+         * interface can't trust regular string functions. Due to mbstring overloading design
+         * limits php scripts can't control this setting.
+         *
+         * This hack should fix some issues related to 8bit strings in passwords. Correct fix is
+         * to disable mbstring overloading. Japanese translation uses different internal encoding.
+         */
+        if ($squirrelmail_language != 'ja_JP' &&
+            function_exists('mb_internal_encoding') &&
+            check_php_version(4,2,0) &&
+            (int)ini_get('mbstring.func_overload')!=0) {
+            mb_internal_encoding('pass');
+        }
     }
     return 0;
 }
@@ -419,8 +470,8 @@ function set_up_language($sm_language, $do_search = false, $default = false) {
  * Sets default_charset variable according to the one that is used by user's translations.
  *
  * Function changes global $default_charset variable in order to be sure, that it
- * contains charset used by user's translation. Sanity of $squirrelmail_default_language
- * and $default_charset combination provided in SquirrelMail config is also tested.
+ * contains charset used by user's translation. Sanity of $squirrelmail_language
+ * and $default_charset combination is also tested.
  *
  * There can be a $default_charset setting in the
  * config.php file, but the user may have a different language
@@ -431,11 +482,11 @@ function set_up_language($sm_language, $do_search = false, $default = false) {
  * message blindly with the system-wide $default_charset.
  */
 function set_my_charset(){
-    global $data_dir, $username, $default_charset, $languages, $squirrelmail_default_language;
+    global $data_dir, $username, $default_charset, $languages, $squirrelmail_language;
 
     $my_language = getPref($data_dir, $username, 'language');
     if (!$my_language) {
-        $my_language = $squirrelmail_default_language ;
+        $my_language = $squirrelmail_language ;
     }
     // Catch removed translation
     if (!isset($languages[$my_language])) {
@@ -848,7 +899,7 @@ endswitch;
 
 global $squirrelmail_language, $languages, $use_gettext;
 
-if (! isset($squirrelmail_language)) {
+if (! sqgetGlobalVar('squirrelmail_language',$squirrelmail_language,SQ_COOKIE)) {
     $squirrelmail_language = '';
 }
 
@@ -863,12 +914,13 @@ if (! isset($squirrelmail_language)) {
  *  CHARSET   - Encoding used by translation
  *  ALIAS     - used when 'language' is only short name and 'value' should provide long language name
  *  ALTNAME   - Native translation name. Any 8bit symbols must be html encoded.
- *  LOCALE    - Full locale name (in xx_XX.charset format)
+ *  LOCALE    - Full locale name (in xx_XX.charset format). It can use array with several locale names since 1.4.5 and 1.5.1
  *  DIR       - Text direction. Used to define Right-to-Left languages. Possible values 'rtl' or 'ltr'. If undefined - defaults to 'ltr'
  *  XTRA_CODE - translation uses special functions. See doc/i18n.txt
  *
  * Each 'language' definition requires NAME+CHARSET or ALIAS variables.
  *
+ * @todo TODO: make language loading modular (similar to plugins, with locale/xx_XX/setup.php files)
  * @name $languages
  * @global array $languages
  */