Application->isAdmin && (EDITING_MODE == EDITING_MODE_CONTENT)) { // front-end viewed in content mode $this->_editExisting = $this->_editMissing = true; $this->_simpleEditingMode = !$this->Application->isDebugMode(); $this->_translateHtmlTag = 'span'; } $this->_editLinkMask = $this->getRawEditLink('#LABEL#'); if (defined('DEBUG_MODE') && DEBUG_MODE && !$this->Application->GetVar('admin')) { // admin and front-end while not viewed using content mode (via admin) $this->_editMissing = defined('DBG_PHRASES') && DBG_PHRASES; if (!$this->Application->isAdmin) { $this->_phraseEditTemplate = 'phrases_edit'; $url_params = Array ( 'm_opener' => 'd', 'phrases_label' => '#LABEL#', 'phrases_event' => 'OnPreparePhrase', 'next_template' => 'external:' . $_SERVER['REQUEST_URI'], 'pass' => 'm,phrases' ); $this->_phraseEscapeStrategy = kUtil::ESCAPE_URL; $this->_editLinkMask = $this->Application->HREF($this->_phraseEditTemplate, '', $url_params); } } } /** * Returns raw link for given phrase editing. * * @param string $label Phrase label. * * @return string */ protected function getRawEditLink($label) { $function_params = array( $label, $this->_phraseEditTemplate, array('event' => 'OnPreparePhrase', 'simple_mode' => $this->_simpleEditingMode), ); return 'javascript:translate_phrase(' . implode(',', array_map('json_encode', $function_params)) . ');'; } /** * Returns final link (using mask) for given phrase editing. * * @param string $label Phrase label. * * @return string */ protected function getEditLink($label) { $escaped_label = kUtil::escape($label, $this->_phraseEscapeStrategy); return str_replace('#LABEL#', $escaped_label, $this->_editLinkMask); } /** * Returns HTML code for label editing. * * @param string $url Phrase editing url. * @param string $text Link text to show (usually label in upper case). * @param string $alt Text to display when hovered over the link. * * @return string */ protected function getEditHtmlCode($url, $text, $alt) { $url = kUtil::escape($url, kUtil::ESCAPE_HTML); $ret = '<' . $this->_translateHtmlTag . ' href="' . $url . '" name="cms-translate-phrase" title="' . $alt . '">' . $text . '_translateHtmlTag . '>'; return $this->fromTag ? $this->escapeTagReserved($ret) : $ret; } /** * Loads phrases from current language * Method is called manually (not from kFactory class) too * * @param string $prefix * @param string $special * @param int $language_id * @param Array $phrase_ids */ public function Init($prefix, $special = '', $language_id = null, $phrase_ids = null) { parent::Init($prefix, $special); if (kUtil::constOn('IS_INSTALL')) { $this->LanguageId = 1; } else { if ( !isset($language_id) ) { if ($this->Application->isAdmin) { $language_id = $this->Application->Session->GetField('Language'); $this->AdminLanguageId = $language_id; // same languages, when used from Admin Console } else { $language_id = $this->Application->GetVar('m_lang'); } } $this->LanguageId = $language_id; if (!$this->Application->isAdmin && $this->Application->GetVar('admin')) { /** @var Session $admin_session */ $admin_session = $this->Application->recallObject('Session.admin'); $this->AdminLanguageId = $admin_session->GetField('Language'); } } $this->LoadPhrases($phrase_ids); } function LoadPhrases($ids) { if ( !is_array($ids) || !implode('', $ids) ) { return ; } $sql = 'SELECT l' . $this->LanguageId . '_Translation AS Translation, l' . $this->LanguageId . '_HintTranslation AS HintTranslation, l' . $this->LanguageId . '_ColumnTranslation AS ColumnTranslation, PhraseKey FROM ' . TABLE_PREFIX . 'LanguageLabels WHERE PhraseId IN (' . implode(',', $ids) . ') AND l' . $this->LanguageId . '_Translation IS NOT NULL'; $this->Phrases = $this->Conn->Query($sql, 'PhraseKey'); $this->Ids = $this->OriginalIds = $ids; } function AddCachedPhrase($label, $value, $allow_editing = true) { // uppercase phrase name for cases, when this method is called outside this class $cache_key = ($allow_editing ? '' : 'NE:') . mb_strtoupper($label); $this->Phrases[$cache_key] = Array ('Translation' => $value, 'HintTranslation' => $value, 'ColumnTranslation' => $value); } function NeedsCacheUpdate() { return is_array($this->Ids) && count($this->Ids) > 0 && $this->Ids != $this->OriginalIds; } /** * Returns translation of given label * * @param string $label * @param bool $allow_editing return translation link, when translation is missing on current language * @param bool $use_admin use current Admin Console language to translate phrase * @return string * @access public */ public function GetPhrase($label, $allow_editing = true, $use_admin = false) { if ( !isset($this->LanguageId) ) { //actually possible when custom field contains references to language labels and its being rebuilt in OnAfterConfigRead //which is triggered by Sections rebuild, which in turn read all the configs and all of that happens BEFORE seeting the language... return 'impossible case'; } // cut exclamation marks - deprecated form of passing phrase name from templates $label = preg_replace('/^!(.*)!$/', '\\1', $label); if ( strlen($label) == 0 ) { return ''; } $original_label = $label; list ($field_prefix, $label) = $this->parseLabel($label); $translation_field = mb_convert_case($field_prefix, MB_CASE_TITLE) . 'Translation'; $uppercase_label = mb_strtoupper($label); $cache_key = ($allow_editing ? '' : 'NE:') . $uppercase_label; if ( isset($this->Phrases[$cache_key]) ) { $translated_label = $this->Phrases[$cache_key][$translation_field]; if ($this->_editExisting && $allow_editing && !array_key_exists($uppercase_label, $this->_missingPhrases)) { // option to change translation for Labels $edit_link = $this->getRawEditLink($label); $translated_label = $this->getEditHtmlCode($edit_link, $translated_label, 'Edit translation'); } return $translated_label; } $this->LoadPhraseByLabel($uppercase_label, $original_label, $allow_editing, $use_admin); return $this->GetPhrase($original_label, $allow_editing); } function LoadPhraseByLabel($uppercase_label, $original_label, $allow_editing = true, $use_admin = false) { if ( !$allow_editing && !$use_admin && !isset($this->_missingPhrases[$uppercase_label]) && isset($this->Phrases[$uppercase_label]) ) { // label is already translated, but it's version without on the fly translation code is requested $this->Phrases['NE:' . $uppercase_label] = $this->Phrases[$uppercase_label]; return true; } $language_id = $use_admin ? $this->AdminLanguageId : $this->LanguageId; $sql = 'SELECT PhraseId, l' . $language_id . '_Translation AS Translation, l' . $language_id . '_HintTranslation AS HintTranslation, l' . $language_id . '_ColumnTranslation AS ColumnTranslation FROM ' . TABLE_PREFIX . 'LanguageLabels WHERE (PhraseKey = ' . $this->Conn->qstr($uppercase_label) . ') AND (l' . $language_id . '_Translation IS NOT NULL)'; $res = $this->Conn->GetRow($sql); if ($res === false || count($res) == 0) { $translation = '!' . $uppercase_label . '!'; if ($this->_editMissing && $allow_editing) { list (, $original_label) = $this->parseLabel($original_label); $edit_url = $this->getEditLink($original_label); $translation = $this->getEditHtmlCode($edit_url, $translation, 'Translate'); $this->_missingPhrases[$uppercase_label] = true; // add as key for faster accessing } // add it as already cached, as long as we don't need to cache not found phrase $this->AddCachedPhrase($uppercase_label, $translation, $allow_editing); return false; } $cache_key = ($allow_editing ? '' : 'NE:') . $uppercase_label; $this->Phrases[$cache_key] = $res; array_push($this->Ids, $res['PhraseId']); $this->Ids = array_unique($this->Ids); // just to make sure return true; } /** * Parse label into translation field prefix and actual label. * * @param string $label Phrase label. * * @return array */ protected function parseLabel($label) { if ( strpos($label, ':') === false || preg_match('/^(HINT|COLUMN):(.*)$/i', $label, $regs) == 0 ) { return array('', $label); } return array($regs[1], $regs[2]); } /** * Sort params by name and then by length * * @param string $a * @param string $b * @return int * @access private */ function CmpParams($a, $b) { $a_len = mb_strlen($a); $b_len = mb_strlen($b); if ($a_len == $b_len) return 0; return $a_len > $b_len ? -1 : 1; } /** * Replace language tags in exclamation marks found in text * * @param string $text * @param bool|null $force_escaping force escaping, not escaping of resulting string * @return mixed * @access public */ public function ReplaceLanguageTags($text, $force_escaping = null) { $this->fromTag = true; if( isset($force_escaping) ) { $this->fromTag = $force_escaping; } preg_match_all("(!(la|lu|lc)[^!]+!)", $text, $res, PREG_PATTERN_ORDER); $language_tags = $res[0]; uasort($language_tags, Array(&$this, 'CmpParams')); $i = 0; $values = Array(); foreach ($language_tags as $label) { array_push($values, $this->GetPhrase($label) ); //array_push($values, $this->Application->Phrase($label) ); $language_tags[$i] = '/' . $language_tags[$i] . '/'; $i++; } $this->fromTag = false; return preg_replace($language_tags, $values, $text); } /** * Escape chars in phrase translation, that could harm parser to process tag * * @param string $text * @return string * @access private */ function escapeTagReserved($text) { $reserved = Array('"', "'"); // = $replacement = Array('\"', "\'"); // \= return str_replace($reserved, $replacement, $text); } }