Example #1
0
 /**
  * The UI to translate content.
  *
  * @return tempcode		The UI
  */
 function interface_content()
 {
     $title = get_page_title('TRANSLATE_CONTENT');
     if (!multi_lang()) {
         warn_exit(do_lang_tempcode('MULTILANG_OFF'));
     }
     $max = get_param_integer('max', 100);
     $lang = choose_language($title);
     if (is_object($lang)) {
         return $lang;
     }
     // Fiddle around in order to find what we haven't translated. Subqueries and self joins don't work well enough across different db's
     if (!db_has_subqueries($GLOBALS['SITE_DB']->connection_read)) {
         $_done_id_list = collapse_2d_complexity('id', 'text_original', $GLOBALS['SITE_DB']->query_select('translate', array('id', 'text_original'), array('language' => $lang, 'broken' => 0)));
         $done_id_list = '';
         foreach (array_keys($_done_id_list) as $done_id) {
             if ($done_id_list != '') {
                 $done_id_list .= ',';
             }
             $done_id_list .= strval($done_id);
         }
         $and_clause = $done_id_list == '' ? '' : 'AND id NOT IN (' . $done_id_list . ')';
         $query = 'FROM ' . get_table_prefix() . 'translate WHERE ' . db_string_not_equal_to('language', $lang) . ' ' . $and_clause . ' AND ' . db_string_not_equal_to('text_original', '') . ' ORDER BY importance_level';
         $to_translate = $GLOBALS['SITE_DB']->query('SELECT * ' . $query, $max);
     } else {
         $query = 'FROM ' . get_table_prefix() . 'translate a LEFT JOIN ' . get_table_prefix() . 'translate b ON a.id=b.id AND b.broken=0 AND ' . db_string_equal_to('b.language', $lang) . ' WHERE b.id IS NULL AND ' . db_string_not_equal_to('a.language', $lang) . ' AND ' . db_string_not_equal_to('a.text_original', '');
         $to_translate = $GLOBALS['SITE_DB']->query('SELECT a.* ' . $query . (can_arbitrary_groupby() ? ' GROUP BY a.id' : '') . ' ORDER BY a.importance_level', $max);
     }
     $total = $GLOBALS['SITE_DB']->query_value_null_ok_full('SELECT COUNT(*) ' . $query);
     if (count($to_translate) == 0) {
         inform_exit(do_lang_tempcode('NOTHING_TO_TRANSLATE'));
     }
     require_all_lang($lang, true);
     require_all_open_lang_files($lang);
     // Make our translation page
     require_code('lang2');
     $lines = '';
     $intertrans = $this->get_intertran_conv($lang);
     $actions = make_string_tempcode(' ');
     $last_level = NULL;
     $too_many = count($to_translate) == $max;
     $ids_to_lookup = array();
     foreach ($to_translate as $it) {
         $ids_to_lookup[] = $it['id'];
     }
     $names = find_lang_content_names($ids_to_lookup);
     foreach ($to_translate as $i => $it) {
         if ($it['importance_level'] == 0) {
             continue;
         }
         // Corrupt data
         $id = $it['id'];
         $old = $it['text_original'];
         $current = $this->find_lang_matches($old, $lang);
         $priority = $last_level === $it['importance_level'] ? NULL : do_lang('PRIORITY_' . strval($it['importance_level']));
         $name = $names[$id];
         if (is_null($name)) {
             continue;
         }
         // Orphaned string
         if ($intertrans != '') {
             $actions = do_template('TRANSLATE_ACTION', array('_GUID' => 'f625cf15c9db5e5af30fc772a7f0d5ff', 'LANG_FROM' => $it['language'], 'LANG_TO' => $lang, 'NAME' => 'trans_' . strval($id), 'OLD' => $old));
         }
         $line = do_template('TRANSLATE_LINE_CONTENT', array('_GUID' => '87a0f5298ce9532839f3206cd0e06051', 'NAME' => $name, 'ID' => strval($id), 'OLD' => $old, 'CURRENT' => $current, 'ACTIONS' => $actions, 'PRIORITY' => $priority));
         $lines .= $line->evaluate();
         /*XHTMLXHTML*/
         $last_level = $it['importance_level'];
     }
     $url = build_url(array('page' => '_SELF', 'type' => '_content', 'lang' => $lang), '_SELF');
     require_code('lang2');
     return do_template('TRANSLATE_SCREEN_CONTENT_SCREEN', array('_GUID' => 'af732c5e595816db1c6f025c4b8fa6a2', 'MAX' => integer_format($max), 'TOTAL' => integer_format($total - $max), 'LANG_ORIGINAL_NAME' => get_site_default_lang(), 'LANG_NICE_ORIGINAL_NAME' => lookup_language_full_name(get_site_default_lang()), 'LANG_NICE_NAME' => lookup_language_full_name($lang), 'TOO_MANY' => $too_many, 'INTERTRANS' => $intertrans, 'LANG' => $lang, 'LINES' => $lines, 'TITLE' => $title, 'URL' => $url));
 }
Example #2
0
 /**
  * Get the human-readable form of a language id, or a language entry from a language INI file.
  *
  * @param  ID_TEXT		The language id
  * @param  ?mixed			The first token [string or tempcode] (replaces {1}) (NULL: none)
  * @param  ?mixed			The second token [string or tempcode] (replaces {2}) (NULL: none)
  * @param  ?mixed			The third token (replaces {3}). May be an array of [of string], to allow any number of additional args (NULL: none)
  * @param  ?LANGUAGE_NAME The language to use (NULL: users language)
  * @param  boolean		Whether to cause ocPortal to exit if the lookup does not succeed
  * @return ?mixed			The human-readable content (NULL: not found). String normally. Tempcode if tempcode parameters.
  */
 function _do_lang($codename, $token1 = NULL, $token2 = NULL, $token3 = NULL, $lang = NULL, $require_result = true)
 {
     $pos = strpos($codename, ':');
     if ($pos !== false) {
         require_lang(substr($codename, 0, $pos));
         $codename = substr($codename, $pos + 1);
     }
     global $LANGUAGE, $USER_LANG_CACHED, $RECORD_LANG_STRINGS, $XSS_DETECT, $PAGE_CACHE_FILE, $PAGE_CACHE_LANG_LOADED;
     if ($RECORD_LANG_STRINGS) {
         global $RECORDED_LANG_STRINGS;
         $RECORDED_LANG_STRINGS[$codename] = 1;
     }
     if ($lang === NULL) {
         $lang = $USER_LANG_CACHED === NULL ? user_lang() : $USER_LANG_CACHED;
     }
     if (!isset($LANGUAGE[$lang][$codename]) && (!array_key_exists($lang, $LANGUAGE) || !array_key_exists($codename, $LANGUAGE[$lang]))) {
         global $PAGE_CACHE_LAZY_LOAD, $PAGE_CACHE_LANGS_REQUESTED, $LANG_REQUESTED_LANG;
         if ($PAGE_CACHE_LAZY_LOAD) {
             $PAGE_CACHE_LAZY_LOAD = false;
             // We can't be lazy any more, but we will keep growing our pool so hopefully CAN be lazy the next time
             foreach ($PAGE_CACHE_LANGS_REQUESTED as $request) {
                 list($that_codename, $that_lang) = $request;
                 unset($LANG_REQUESTED_LANG[$that_lang][$that_codename]);
                 require_lang($that_codename, $that_lang, NULL, true);
             }
             $ret = _do_lang($codename, $token1, $token2, $token3, $lang, $require_result);
             if ($ret === NULL) {
                 $PAGE_CACHE_LANG_LOADED[$lang][$codename] = NULL;
                 if ($GLOBALS['MEM_CACHE'] !== NULL) {
                     persistant_cache_set($PAGE_CACHE_FILE, $PAGE_CACHE_LANG_LOADED);
                 } else {
                     @rewind($PAGE_CACHE_FILE);
                     @ftruncate($PAGE_CACHE_FILE, 0);
                     @fwrite($PAGE_CACHE_FILE, serialize($PAGE_CACHE_LANG_LOADED));
                 }
             }
             return $ret;
         }
         require_all_open_lang_files($lang);
     }
     if ($lang == 'xxx') {
         return 'xxx';
     }
     // Helpful for testing language compliancy. We don't expect to see non x's if we're running this language
     if (!isset($LANGUAGE[$lang][$codename]) && (!array_key_exists($lang, $LANGUAGE) || !array_key_exists($codename, $LANGUAGE[$lang]))) {
         if ($lang != fallback_lang()) {
             $ret = do_lang($codename, $token1, $token2, $token3, fallback_lang(), $require_result);
             if ($codename == 'charset') {
                 switch (strtolower($lang)) {
                     case 'ar':
                     case 'bg':
                     case 'zh-CN':
                     case 'zh-TW':
                     case 'hr':
                     case 'cs':
                     case 'da':
                     case 'nl':
                     case 'fi':
                     case 'fr':
                     case 'de':
                     case 'el':
                     case 'hi':
                     case 'it':
                     case 'ja':
                     case 'ko':
                     case 'pl':
                     case 'pt':
                     case 'ro':
                     case 'ru':
                     case 'es':
                     case 'sv':
                         $ret = 'utf-8';
                         break;
                 }
             } elseif (substr($codename, 0, 3) == 'FC_') {
                 $ret = ocp_mb_substr(trim(do_lang(substr($codename, 3), $token1, $token2, $token3, $lang)), 0, 1);
             } elseif ($codename == 'locale') {
                 $ret = strtolower($lang) . '_' . strtoupper($lang);
             } else {
                 $ret2 = strtolower($codename) != $codename ? google_translate($ret, $lang) : $ret;
                 if ($ret2 != $ret) {
                     $ret = $ret2;
                 }
             }
             if ($PAGE_CACHE_FILE !== NULL) {
                 if (!isset($PAGE_CACHE_LANG_LOADED[$lang][$codename]) && isset($PAGE_CACHE_LANG_LOADED[fallback_lang()][$codename])) {
                     $PAGE_CACHE_LANG_LOADED[$lang][$codename] = $ret;
                     // Will have been cached into fallback_lang() from the nested do_lang call, we need to copy it into our cache bucket for this language
                     if ($GLOBALS['MEM_CACHE'] !== NULL) {
                         persistant_cache_set($PAGE_CACHE_FILE, $PAGE_CACHE_LANG_LOADED);
                     } else {
                         @rewind($PAGE_CACHE_FILE);
                         @ftruncate($PAGE_CACHE_FILE, 0);
                         @fwrite($PAGE_CACHE_FILE, serialize($PAGE_CACHE_LANG_LOADED));
                     }
                 }
             }
             return $ret;
         } else {
             if ($require_result) {
                 global $USER_LANG_LOOP, $REQUIRE_LANG_LOOP;
                 //print_r(debug_backtrace());
                 if ($USER_LANG_LOOP == 1) {
                     critical_error('RELAY', 'Missing language code: ' . escape_html($codename) . '. This language code is required to produce error messages, and thus a critical error was prompted by the non-ability to show less-critical error messages. It is likely the source language files (lang/' . fallback_lang() . '/*.ini) for ocPortal on this website have been corrupted.');
                 }
                 if ($REQUIRE_LANG_LOOP >= 2) {
                     return '';
                 }
                 // Probably failing to load global.ini, so just output with some text missing
                 require_code('view_modes');
                 erase_cached_language();
                 fatal_exit(do_lang_tempcode('MISSING_LANG_ENTRY', escape_html($codename)));
             } else {
                 return NULL;
             }
         }
     }
     if ($PAGE_CACHE_FILE !== NULL) {
         if (!isset($PAGE_CACHE_LANG_LOADED[$lang][$codename])) {
             $PAGE_CACHE_LANG_LOADED[$lang][$codename] = $LANGUAGE[$lang][$codename];
             if ($GLOBALS['MEM_CACHE'] !== NULL) {
                 persistant_cache_set($PAGE_CACHE_FILE, $PAGE_CACHE_LANG_LOADED);
             } else {
                 @rewind($PAGE_CACHE_FILE);
                 @ftruncate($PAGE_CACHE_FILE, 0);
                 @fwrite($PAGE_CACHE_FILE, serialize($PAGE_CACHE_LANG_LOADED));
             }
         }
     }
     // Put in parameters
     static $non_plural_non_vowel = array('1', 'b', 'c', 'd', 'f', 'g', 'h', 'j', 'k', 'l', 'm', 'n', 'p', 'q', 'r', 's', 't', 'v', 'w', 'x', 'y', 'z');
     $looked_up = $LANGUAGE[$lang][$codename];
     if ($looked_up === NULL) {
         return NULL;
     }
     // Learning cache pool has told us this string definitely does not exist
     $out = str_replace('\\n', "\n", $looked_up);
     $plural_or_vowel_check = strpos($out, '|') !== false;
     if ($XSS_DETECT) {
         ocp_mark_as_escaped($out);
     }
     if ($token1 !== NULL) {
         if (is_object($token1) && $token2 === NULL || $token2 !== NULL && is_object($token2)) {
             $bits = preg_split('#\\{\\d[^\\}]*\\}#', $out, 2, PREG_SPLIT_OFFSET_CAPTURE);
             $ret = new ocp_tempcode();
             foreach ($bits as $bit) {
                 if ($XSS_DETECT) {
                     ocp_mark_as_escaped($bit[0]);
                 }
                 $at = $bit[1];
                 if ($at != 0) {
                     if ($out[$at - 2] == '1') {
                         $ret->attach($token1);
                     } elseif ($out[$at - 2] == '2') {
                         $ret->attach($token2);
                     } elseif ($plural_or_vowel_check && substr($out[$at - 2], 0, 2) == '1|') {
                         $exploded = explode('|', $out[$at - 2]);
                         $_token = $token1->evaluate();
                         $_token_denum = str_replace(',', '', $_token);
                         $ret->attach(in_array(is_numeric($_token_denum) ? $_token_denum : strtolower(substr($_token, 0, 1)), $non_plural_non_vowel) ? $exploded[1] : $exploded[2]);
                     } elseif ($plural_or_vowel_check && substr($out[$at - 2], 0, 2) == '2|') {
                         $exploded = explode('|', $out[$at - 2]);
                         $_token = $token2->evaluate();
                         $_token_denum = str_replace(',', '', $_token);
                         $ret->attach(in_array(is_numeric($_token_denum) ? $_token_denum : strtolower(substr($_token, 0, 1)), $non_plural_non_vowel) ? $exploded[1] : $exploded[2]);
                     }
                 }
                 $ret->attach($bit[0]);
             }
             return $ret;
         } elseif ($token1 !== NULL) {
             $out = str_replace('{1}', $token1, $out);
             if ($plural_or_vowel_check) {
                 $_token_denum = str_replace(',', '', $token1);
                 $out = preg_replace('#\\{1\\|(.*)\\|(.*)\\}#U', in_array(is_numeric($_token_denum) ? $_token_denum : strtolower(substr($token1, 0, 1)), $non_plural_non_vowel) ? '\\1' : '\\2', $out);
             }
             if ($XSS_DETECT && ocp_is_escaped($token1)) {
                 ocp_mark_as_escaped($out);
             }
         }
         if ($token2 !== NULL) {
             if ($XSS_DETECT) {
                 $escaped = ocp_is_escaped($out);
             }
             $out = str_replace('{2}', $token2, $out);
             if ($plural_or_vowel_check) {
                 $_token_denum = str_replace(',', '', $token1);
                 $out = preg_replace('#\\{2\\|(.*)\\|(.*)\\}#U', in_array(is_numeric($_token_denum) ? $_token_denum : strtolower(substr($token2, 0, 1)), $non_plural_non_vowel) ? '\\1' : '\\2', $out);
             }
             if ($XSS_DETECT && ocp_is_escaped($token2) && $escaped) {
                 ocp_mark_as_escaped($out);
             }
             if ($token3 !== NULL) {
                 $i = 3;
                 if (!is_array($token3)) {
                     $token3 = array($token3);
                 }
                 foreach ($token3 as $token) {
                     if ($XSS_DETECT) {
                         $escaped = ocp_is_escaped($out);
                     }
                     $out = str_replace('{' . strval($i) . '}', $token, $out);
                     if ($plural_or_vowel_check) {
                         $_token_denum = str_replace(',', '', $token);
                         $out = preg_replace('#\\{' . strval($i) . '\\|(.*)\\|(.*)\\}#U', in_array(is_numeric($_token_denum) ? $_token_denum : strtolower(substr($token, 0, 1)), $non_plural_non_vowel) ? '\\1' : '\\2', $out);
                     }
                     if ($XSS_DETECT && ocp_is_escaped($token) && $escaped) {
                         ocp_mark_as_escaped($out);
                     }
                     $i++;
                 }
             }
         }
     }
     return $out;
 }
Example #3
0
/**
 * Get the human-readable form of a language id, or a language entry from a language INI file.
 *
 * @param  ID_TEXT		The language id
 * @param  ?mixed			The first token [string or tempcode] (replaces {1}) (NULL: none)
 * @param  ?mixed			The second token [string or tempcode] (replaces {2}) (NULL: none)
 * @param  ?mixed			The third token (replaces {3}). May be an array of [of string], to allow any number of additional args (NULL: none)
 * @param  ?LANGUAGE_NAME The language to use (NULL: users language)
 * @param  boolean		Whether to cause ocPortal to exit if the lookup does not succeed
 * @return ?mixed			The human-readable content (NULL: not found). String normally. Tempcode if tempcode parameters.
 */
function _do_lang($codename, $token1 = NULL, $token2 = NULL, $token3 = NULL, $lang = NULL, $require_result = true)
{
    global $LANGUAGE, $USER_LANG_CACHED, $RECORD_LANG_STRINGS, $XSS_DETECT, $PAGE_CACHE_FILE, $PAGE_CACHE_LANG_LOADED;
    if ($lang === NULL) {
        $lang = $USER_LANG_CACHED === NULL ? user_lang() : $USER_LANG_CACHED;
    }
    if ($GLOBALS['SEMI_DEBUG_MODE']) {
        $pos = strpos($codename, '=');
        if ($pos !== false) {
            // Find loaded file with smallest levenstein distance to current page
            $best = mixed();
            $best_for = NULL;
            global $LANGS_REQUESTED;
            foreach (array_keys($LANGS_REQUESTED) as $possible) {
                $dist = levenshtein(get_page_name(), $possible);
                if (is_null($best) || $best > $dist) {
                    $best = $dist;
                    $best_for = $possible;
                }
            }
            $save_path = get_file_base() . '/lang/' . fallback_lang() . '/' . $best_for . '.ini';
            if (!is_file($save_path)) {
                $save_path = get_file_base() . '/lang_custom/' . fallback_lang() . '/' . $best_for . '.ini';
            }
            // Tack language strings onto this file
            list($codename, $value) = explode('=', $codename, 2);
            $myfile = fopen($save_path, 'at');
            fwrite($myfile, "\n" . $codename . '=' . $value);
            fclose($myfile);
            // Fake-load the string
            $LANGUAGE[$lang][$codename] = $value;
            // Go through all required files, doing a string replace if needed
            $included_files = get_included_files();
            foreach ($included_files as $inc) {
                $orig_contents = file_get_contents($inc);
                $contents = str_replace("'" . $codename . '=' . $value . "'", "'" . $codename . "'", $orig_contents);
                if ($orig_contents != $contents) {
                    $myfile = fopen($inc, 'wt');
                    fwrite($myfile, $contents);
                    fclose($myfile);
                }
            }
        }
    }
    $there = isset($LANGUAGE[$lang][$codename]);
    if (!$there) {
        $pos = strpos($codename, ':');
        if ($pos !== false) {
            require_lang(substr($codename, 0, $pos), NULL, NULL, !$require_result);
            $codename = substr($codename, $pos + 1);
        }
        $there = isset($LANGUAGE[$lang][$codename]);
    }
    if ($RECORD_LANG_STRINGS) {
        global $RECORDED_LANG_STRINGS;
        $RECORDED_LANG_STRINGS[$codename] = 1;
    }
    if (!$there && (!isset($LANGUAGE[$lang]) || !array_key_exists($codename, $LANGUAGE[$lang]))) {
        global $PAGE_CACHE_LAZY_LOAD, $PAGE_CACHE_LANGS_REQUESTED, $LANG_REQUESTED_LANG;
        if ($PAGE_CACHE_LAZY_LOAD) {
            $PAGE_CACHE_LAZY_LOAD = false;
            // We can't be lazy any more, but we will keep growing our pool so hopefully CAN be lazy the next time
            foreach ($PAGE_CACHE_LANGS_REQUESTED as $request) {
                list($that_codename, $that_lang) = $request;
                unset($LANG_REQUESTED_LANG[$that_lang][$that_codename]);
                require_lang($that_codename, $that_lang, NULL, true);
            }
            $ret = _do_lang($codename, $token1, $token2, $token3, $lang, $require_result);
            if ($ret === NULL) {
                $PAGE_CACHE_LANG_LOADED[$lang][$codename] = NULL;
                if ($GLOBALS['MEM_CACHE'] !== NULL) {
                    persistant_cache_set($PAGE_CACHE_FILE, $PAGE_CACHE_LANG_LOADED);
                } else {
                    open_page_cache_file();
                    @rewind($PAGE_CACHE_FILE);
                    @flock($PAGE_CACHE_FILE, LOCK_EX);
                    @ftruncate($PAGE_CACHE_FILE, 0);
                    @fwrite($PAGE_CACHE_FILE, serialize($PAGE_CACHE_LANG_LOADED));
                    @flock($PAGE_CACHE_FILE, LOCK_UN);
                }
            }
            return $ret;
        }
        require_all_open_lang_files($lang);
    }
    if ($lang == 'xxx') {
        return 'xxx';
    }
    // Helpful for testing language compliancy. We don't expect to see non x's if we're running this language
    if (!isset($LANGUAGE[$lang][$codename]) && ($require_result || !isset($LANGUAGE[$lang]) || !array_key_exists($codename, $LANGUAGE[$lang]))) {
        if ($lang != fallback_lang()) {
            $ret = do_lang($codename, $token1, $token2, $token3, fallback_lang(), $require_result);
            if ($PAGE_CACHE_FILE !== NULL) {
                if (!isset($PAGE_CACHE_LANG_LOADED[$lang][$codename]) && isset($PAGE_CACHE_LANG_LOADED[fallback_lang()][$codename])) {
                    $PAGE_CACHE_LANG_LOADED[$lang][$codename] = $PAGE_CACHE_LANG_LOADED[fallback_lang()][$codename];
                    // Will have been cached into fallback_lang() from the nested do_lang call, we need to copy it into our cache bucket for this language
                    if ($GLOBALS['MEM_CACHE'] !== NULL) {
                        persistant_cache_set($PAGE_CACHE_FILE, $PAGE_CACHE_LANG_LOADED);
                    } else {
                        open_page_cache_file();
                        @rewind($PAGE_CACHE_FILE);
                        @flock($PAGE_CACHE_FILE, LOCK_EX);
                        @ftruncate($PAGE_CACHE_FILE, 0);
                        @fwrite($PAGE_CACHE_FILE, serialize($PAGE_CACHE_LANG_LOADED));
                        @flock($PAGE_CACHE_FILE, LOCK_UN);
                    }
                }
            }
            return $ret;
        } else {
            if ($require_result) {
                global $USER_LANG_LOOP, $REQUIRE_LANG_LOOP;
                //print_r(debug_backtrace());
                if ($USER_LANG_LOOP == 1) {
                    critical_error('RELAY', 'Missing language code: ' . escape_html($codename) . '. This language code is required to produce error messages, and thus a critical error was prompted by the non-ability to show less-critical error messages. It is likely the source language files (lang/' . fallback_lang() . '/*.ini) for ocPortal on this website have been corrupted.');
                }
                if ($REQUIRE_LANG_LOOP >= 2) {
                    return '';
                }
                // Probably failing to load global.ini, so just output with some text missing
                require_code('view_modes');
                erase_cached_language();
                require_code('site');
                attach_message(do_lang_tempcode('MISSING_LANG_ENTRY', escape_html($codename)), 'warn');
                return '';
            } else {
                return NULL;
            }
        }
    }
    if ($PAGE_CACHE_FILE !== NULL) {
        if (!isset($PAGE_CACHE_LANG_LOADED[$lang][$codename]) && (!isset($PAGE_CACHE_LANG_LOADED[$lang]) || !array_key_exists($codename, $PAGE_CACHE_LANG_LOADED[$lang]))) {
            $PAGE_CACHE_LANG_LOADED[$lang][$codename] = $LANGUAGE[$lang][$codename];
            if ($GLOBALS['MEM_CACHE'] !== NULL) {
                persistant_cache_set($PAGE_CACHE_FILE, $PAGE_CACHE_LANG_LOADED);
            } else {
                open_page_cache_file();
                @rewind($PAGE_CACHE_FILE);
                @flock($PAGE_CACHE_FILE, LOCK_EX);
                @ftruncate($PAGE_CACHE_FILE, 0);
                @fwrite($PAGE_CACHE_FILE, serialize($PAGE_CACHE_LANG_LOADED));
                @flock($PAGE_CACHE_FILE, LOCK_UN);
            }
        }
    }
    // Put in parameters
    static $non_plural_non_vowel = array('1', 'b', 'c', 'd', 'f', 'g', 'h', 'j', 'k', 'l', 'm', 'n', 'p', 'q', 'r', 's', 't', 'v', 'w', 'x', 'y', 'z', '{');
    $looked_up = $LANGUAGE[$lang][$codename];
    if ($looked_up === NULL) {
        return NULL;
        // Learning cache pool has told us this string definitely does not exist
    }
    $out = str_replace('\\n', "\n", $looked_up);
    $plural_or_vowel_check = strpos($out, '|') !== false;
    if ($XSS_DETECT) {
        ocp_mark_as_escaped($out);
    }
    if ($token1 !== NULL) {
        if (is_object($token1) && $token2 === NULL || $token2 !== NULL && is_object($token2)) {
            $bits = preg_split('#\\{\\d[^\\}]*\\}#', $out, 2, PREG_SPLIT_OFFSET_CAPTURE);
            $ret = new ocp_tempcode();
            foreach ($bits as $bit) {
                if ($XSS_DETECT) {
                    ocp_mark_as_escaped($bit[0]);
                }
                $at = $bit[1];
                if ($at != 0) {
                    if ($out[$at - 2] == '1') {
                        $ret->attach($token1);
                    } elseif ($out[$at - 2] == '2') {
                        $ret->attach($token2);
                    } elseif ($plural_or_vowel_check && substr($out[$at - 2], 0, 2) == '1|') {
                        $exploded = explode('|', $out[$at - 2]);
                        $_token = $token1->evaluate();
                        $_token_denum = str_replace(',', '', $_token);
                        $ret->attach(in_array(is_numeric($_token_denum) ? $_token_denum : ocp_mb_strtolower(ocp_mb_substr($_token, 0, 1)), $non_plural_non_vowel) ? $exploded[1] : $exploded[2]);
                    } elseif ($plural_or_vowel_check && substr($out[$at - 2], 0, 2) == '2|') {
                        $exploded = explode('|', $out[$at - 2]);
                        $_token = $token2->evaluate();
                        $_token_denum = str_replace(',', '', $_token);
                        $ret->attach(in_array(is_numeric($_token_denum) ? $_token_denum : ocp_mb_strtolower(ocp_mb_substr($_token, 0, 1)), $non_plural_non_vowel) ? $exploded[1] : $exploded[2]);
                    }
                }
                $ret->attach($bit[0]);
            }
            return $ret;
        } elseif ($token1 !== NULL) {
            $out = str_replace('{1}', $token1, $out);
            if ($plural_or_vowel_check) {
                $_token_denum = str_replace(',', '', $token1);
                $out = preg_replace('#\\{1\\|(.*)\\|(.*)\\}#U', in_array(is_numeric($_token_denum) ? $_token_denum : ocp_mb_strtolower(ocp_mb_substr($token1, 0, 1)), $non_plural_non_vowel) ? '\\1' : '\\2', $out);
            }
            if ($XSS_DETECT && ocp_is_escaped($token1)) {
                ocp_mark_as_escaped($out);
            }
        }
        if ($token2 !== NULL) {
            if ($XSS_DETECT) {
                $escaped = ocp_is_escaped($out);
            }
            $out = str_replace('{2}', $token2, $out);
            if ($plural_or_vowel_check) {
                $_token_denum = str_replace(',', '', $token1);
                $out = preg_replace('#\\{2\\|(.*)\\|(.*)\\}#U', in_array(is_numeric($_token_denum) ? $_token_denum : ocp_mb_strtolower(ocp_mb_substr($token2, 0, 1)), $non_plural_non_vowel) ? '\\1' : '\\2', $out);
            }
            if ($XSS_DETECT && ocp_is_escaped($token2) && $escaped) {
                ocp_mark_as_escaped($out);
            }
            if ($token3 !== NULL) {
                $i = 3;
                if (!is_array($token3)) {
                    $token3 = array($token3);
                }
                foreach ($token3 as $token) {
                    if ($XSS_DETECT) {
                        $escaped = ocp_is_escaped($out);
                    }
                    $out = str_replace('{' . strval($i) . '}', $token, $out);
                    if ($plural_or_vowel_check) {
                        $_token_denum = str_replace(',', '', $token);
                        $out = preg_replace('#\\{' . strval($i) . '\\|(.*)\\|(.*)\\}#U', in_array(is_numeric($_token_denum) ? $_token_denum : ocp_mb_strtolower(ocp_mb_substr($token, 0, 1)), $non_plural_non_vowel) ? '\\1' : '\\2', $out);
                    }
                    if ($XSS_DETECT && ocp_is_escaped($token) && $escaped) {
                        ocp_mark_as_escaped($out);
                    }
                    $i++;
                }
            }
        }
    }
    return $out;
}