/**
  * Get the message definition. Cached for performance.
  *
  * @return string
  */
 public function getDefinition()
 {
     static $cache = array();
     $key = $this->handle->getTitle()->getPrefixedText();
     if (array_key_exists($key, $cache)) {
         return $cache[$key];
     }
     if (method_exists($this->group, 'getMessageContent')) {
         $cache[$key] = $this->group->getMessageContent($this->handle);
     } else {
         $cache[$key] = $this->group->getMessage($this->handle->getKey(), $this->group->getSourceLanguage());
     }
     return $cache[$key];
 }
	/**
	 * Shovels the new translation into translation memory.
	 * Hook: Translate:newTranslation
	 *
	 * @param $handle MessageHandle
	 * @param $revision
	 * @param $text string
	 * @param $user User
	 *
	 * @return bool
	 */
	public static function update( MessageHandle $handle, $revision, $text, User $user ) {
		global $wgContLang;

		$dbw = self::getDatabaseHandle();
		// Not in use or misconfigured
		if ( $dbw === null ) {
			return true;
		}

		// Skip definitions to not slow down mass imports etc.
		// These will be added when first translation is made
		if ( $handle->getCode() === 'en' ) {
			return true;
		}

		$group = $handle->getGroup();
		$key = $handle->getKey();
		$code = $handle->getCode();
		$ns_text = $wgContLang->getNsText( $group->getNamespace() );
		$definition = $group->getMessage( $key, 'en' );
		if ( !is_string( $definition ) || !strlen( $definition ) ) {
			wfDebugLog( 'tmserver', "Unable to get definition for $ns_text:$key/$code" );
			return true;
		}

		$tmDefinition = array(
			'text' => $definition,
			'context' => "$ns_text:$key",
			'length' => strlen( $definition ),
			'lang' => 'en'
		);

		// Check that the definition exists, add it if not
		$source_id = $dbw->selectField( '`sources`', 'sid', $tmDefinition, __METHOD__ );
		if ( $source_id === false ) {
			$dbw->insert( '`sources`', $tmDefinition, __METHOD__ );
			$source_id = $dbw->insertId();
			wfDebugLog( 'tmserver', "Inserted new tm-definition for $ns_text:$key:\n$definition\n----------" );
		}

		$delete = array(
			'sid' => $source_id,
			'lang' => $code,
		);

		$insert = $delete + array(
			'text' => $text,
			'time' => wfTimestamp(),
		);

		// Purge old translations for this message
		$dbw->delete( '`targets`', $delete, __METHOD__ );
		// We only do SQlite which does not need to know unique indexes
		$dbw->replace( '`targets`', null, $insert, __METHOD__ );
		wfDebugLog( 'tmserver', "Inserted new tm-translation for $ns_text:$key/$code" );

		return true;
	}
예제 #3
0
 /**
  * @since 2012-01-04
  * @return array
  */
 public static function getGroupIds(MessageHandle $handle)
 {
     $namespace = $handle->getTitle()->getNamespace();
     $key = $handle->getKey();
     $normkey = strtr(strtolower("{$namespace}:{$key}"), " ", "_");
     $index = self::singleton()->retrieve();
     if (isset($index[$normkey])) {
         return (array) $index[$normkey];
     } else {
         return array();
     }
 }
 /**
  * Retrieves a list of groups given MessageHandle belongs to.
  * @since 2012-01-04
  * @param MessageHandle $handle
  * @return array
  */
 public static function getGroupIds(MessageHandle $handle)
 {
     $namespace = $handle->getTitle()->getNamespace();
     $key = $handle->getKey();
     $normkey = TranslateUtils::normaliseKey($namespace, $key);
     $value = self::singleton()->get($normkey);
     if ($value !== null) {
         return (array) $value;
     } else {
         return array();
     }
 }
	protected function getTranslationPageDiff() {

		global $wgEnablePageTranslation;

		if ( !$wgEnablePageTranslation ) {
			return null;
		}

		$this->mustBeKnownMessage();
		if ( !$this->group instanceof WikiPageMessageGroup ) {
			return null;
		}

		// Shortcuts
		$code = $this->handle->getCode();
		$key = $this->handle->getKey();

		// TODO: encapsulate somewhere
		$page = TranslatablePage::newFromTitle( $this->group->getTitle() );
		$rev = $page->getTransRev( "$key/$code" );
		$latest = $page->getMarkedTag();
		if ( $rev === $latest ) {
			return null;
		}

		$oldpage = TranslatablePage::newFromRevision( $this->group->getTitle(), $rev );
		$oldtext = $newtext = null;
		foreach ( $oldpage->getParse()->getSectionsForSave() as $section ) {
			if ( $this->group->getTitle()->getPrefixedDBKey() . '/' . $section->id === $key ) {
				$oldtext = $section->getTextForTrans();
			}
		}

		foreach ( $page->getParse()->getSectionsForSave() as $section ) {
			if ( $this->group->getTitle()->getPrefixedDBKey() . '/' . $section->id === $key ) {
				$newtext = $section->getTextForTrans();
			}
		}

		if ( $oldtext === $newtext ) {
			return null;
		}

		$diff = new DifferenceEngine;
		if ( method_exists( 'DifferenceEngine', 'setTextLanguage' ) ) {
			$diff->setTextLanguage( $this->group->getSourceLanguage() );
		}
		$diff->setText( $oldtext, $newtext );
		$diff->setReducedLineNumbers();
		$diff->showDiffStyle();

		return $diff->getDiff( wfMsgHtml( 'tpt-diff-old' ), wfMsgHtml( 'tpt-diff-new' ) );
	}
 /**
  * Adds link in toolbox to Special:Prefixindex to show all other
  * available translations for a message. Only shown when it
  * actually is a translatable/translated message.
  *
  * @param $quickTemplate QuickTemplate
  *
  * @return bool
  */
 static function toolboxAllTranslations(&$quickTemplate)
 {
     $title = $quickTemplate->getSkin()->getTitle();
     $handle = new MessageHandle($title);
     if ($handle->isValid()) {
         $message = $title->getNsText() . ':' . $handle->getKey();
         $desc = wfMessage('translate-sidebar-alltrans')->escaped();
         $url = htmlspecialchars(SpecialPage::getTitleFor('Translations')->getLocalURL(array('message' => $message)));
         // Add the actual toolbox entry.
         // Add newlines and tabs for nicer HTML output.
         echo "\n\t\t\t\t<li id=\"t-alltrans\"><a href=\"{$url}\">{$desc}</a></li>\n";
     }
     return true;
 }
 /**
  * Returns all translations of a given message.
  * @param MessageHandle $handle Language code is ignored.
  * @return array[]
  * @since 2012-12-18
  */
 public static function getTranslations(MessageHandle $handle)
 {
     $namespace = $handle->getTitle()->getNamespace();
     $base = $handle->getKey();
     $dbr = wfGetDB(DB_SLAVE);
     $res = $dbr->select('page', array('page_namespace', 'page_title'), array('page_namespace' => $namespace, 'page_title ' . $dbr->buildLike("{$base}/", $dbr->anyString())), __METHOD__, array('ORDER BY' => 'page_title', 'USE INDEX' => 'name_title'));
     $titles = array();
     foreach ($res as $row) {
         $titles[] = $row->page_title;
     }
     if ($titles === array()) {
         return array();
     }
     $pageInfo = TranslateUtils::getContents($titles, $namespace);
     return $pageInfo;
 }
 public function execute()
 {
     $params = $this->extractRequestParams();
     $title = Title::newFromText($params['title']);
     if (!$title) {
         $this->dieUsage('Invalid title');
     }
     $handle = new MessageHandle($title);
     if (!$handle->isValid()) {
         $this->dieUsage('Title does not correspond to a translatable message');
     }
     $base = Title::makeTitle($title->getNamespace(), $handle->getKey());
     $namespace = $base->getNamespace();
     $message = $base->getDBKey();
     $dbr = wfGetDB(DB_SLAVE);
     $res = $dbr->select('page', array('page_namespace', 'page_title'), array('page_namespace' => $namespace, 'page_title ' . $dbr->buildLike("{$message}/", $dbr->anyString())), __METHOD__, array('ORDER BY' => 'page_title', 'USE INDEX' => 'name_title'));
     $titles = array();
     foreach ($res as $row) {
         $titles[] = $row->page_title;
     }
     $pageInfo = TranslateUtils::getContents($titles, $namespace);
     $result = $this->getResult();
     $pages = array();
     $count = 0;
     foreach ($pageInfo as $key => $info) {
         if (++$count <= $params['offset']) {
             continue;
         }
         $tTitle = Title::makeTitle($namespace, $key);
         $tHandle = new MessageHandle($tTitle);
         $data = array('title' => $tTitle->getPrefixedText(), 'language' => $tHandle->getCode(), 'lasttranslator' => $info[1]);
         $fuzzy = MessageHandle::hasFuzzyString($info[0]) || $tHandle->isFuzzy();
         if ($fuzzy) {
             $data['fuzzy'] = 'fuzzy';
         }
         $translation = str_replace(TRANSLATE_FUZZY, '', $info[0]);
         $result->setContent($data, $translation);
         $fit = $result->addValue(array('query', $this->getModuleName()), null, $data);
         if (!$fit) {
             $this->setContinueEnumParameter('offset', $count);
             break;
         }
     }
     $result->setIndexedTagName_internal(array('query', $this->getModuleName()), 'message');
 }
 protected function getPageDiff()
 {
     $this->mustBeKnownMessage();
     $title = $this->handle->getTitle();
     $key = $this->handle->getKey();
     if (!$title->exists()) {
         return null;
     }
     $definitionTitle = Title::makeTitleSafe($title->getNamespace(), "{$key}/en");
     if (!$definitionTitle || !$definitionTitle->exists()) {
         return null;
     }
     $db = wfGetDB(DB_MASTER);
     $conds = array('rt_page' => $title->getArticleID(), 'rt_type' => RevTag::getType('tp:transver'));
     $options = array('ORDER BY' => 'rt_revision DESC');
     $latestRevision = $definitionTitle->getLatestRevID();
     $translationRevision = $db->selectField('revtag', 'rt_value', $conds, __METHOD__, $options);
     if ($translationRevision === false) {
         return null;
     }
     // Using newFromId instead of newFromTitle, because the page might have been renamed
     $oldrev = Revision::newFromId($translationRevision);
     if (!$oldrev) {
         // And someone might still have deleted it
         return null;
     }
     $oldtext = ContentHandler::getContentText($oldrev->getContent());
     $newContent = Revision::newFromTitle($definitionTitle, $latestRevision)->getContent();
     $newtext = ContentHandler::getContentText($newContent);
     if ($oldtext === $newtext) {
         return null;
     }
     $diff = new DifferenceEngine();
     if (method_exists('DifferenceEngine', 'setTextLanguage')) {
         $diff->setTextLanguage($this->group->getSourceLanguage());
     }
     $oldContent = ContentHandler::makeContent($oldtext, $diff->getTitle());
     $newContent = ContentHandler::makeContent($newtext, $diff->getTitle());
     $diff->setContent($oldContent, $newContent);
     $diff->setReducedLineNumbers();
     $diff->showDiffStyle();
     return $diff->getDiff(wfMessage('tpt-diff-old')->escaped(), wfMessage('tpt-diff-new')->escaped());
 }
예제 #10
0
 public function update(MessageHandle $handle, $targetText)
 {
     global $wgContLang;
     if (!$handle->isValid() || $handle->getCode() === '') {
         return false;
     }
     $mkey = $handle->getKey();
     $group = $handle->getGroup();
     $targetLanguage = $handle->getCode();
     $sourceLanguage = $group->getSourceLanguage();
     $title = $handle->getTitle();
     // Skip definitions to not slow down mass imports etc.
     // These will be added when the first translation is made
     if ($targetLanguage === $sourceLanguage) {
         return false;
     }
     $definition = $group->getMessage($mkey, $sourceLanguage);
     if (!is_string($definition) || !strlen(trim($definition))) {
         return false;
     }
     $dbw = $this->getDB(DB_MASTER);
     /* Check that the definition exists and fetch the sid. If not, add
      * the definition and retrieve the sid. If the definition changes,
      * we will create a new entry - otherwise we could at some point
      * get suggestions which do not match the original definition any
      * longer. The old translations are still kept until purged by
      * rerunning the bootstrap script. */
     $conds = array('tms_context' => $title->getPrefixedText(), 'tms_text' => $definition);
     $sid = $dbw->selectField('translate_tms', 'tms_sid', $conds, __METHOD__);
     if ($sid === false) {
         $sid = $this->insertSource($title, $sourceLanguage, $definition);
     }
     // Delete old translations for this message if any. Could also use replace
     $deleteConds = array('tmt_sid' => $sid, 'tmt_lang' => $targetLanguage);
     $dbw->delete('translate_tmt', $deleteConds, __METHOD__);
     // Insert the new translation
     $row = $deleteConds + array('tmt_text' => $targetText);
     $dbw->insert('translate_tmt', $row, __METHOD__);
     return true;
 }
 function run()
 {
     global $wgTranslateDocumentationLanguageCode;
     $title = $this->title;
     $params = $this->params;
     $user = FuzzyBot::getUser();
     $flags = EDIT_DEFER_UPDATES | EDIT_FORCE_BOT;
     $wikiPage = WikiPage::factory($title);
     $summary = wfMessage('translate-manage-import-summary')->inContentLanguage()->plain();
     $content = ContentHandler::makeContent($params['content'], $title);
     $wikiPage->doEditContent($content, $summary, $flags, false, $user);
     // NOTE: message documentation is excluded from fuzzying!
     if ($params['fuzzy']) {
         $handle = new MessageHandle($title);
         $key = $handle->getKey();
         $languages = TranslateUtils::getLanguageNames('en');
         unset($languages[$wgTranslateDocumentationLanguageCode]);
         $languages = array_keys($languages);
         $dbw = wfGetDB(DB_MASTER);
         $fields = array('page_id', 'page_latest');
         $conds = array('page_namespace' => $title->getNamespace());
         $pages = array();
         foreach ($languages as $code) {
             $otherTitle = Title::makeTitleSafe($title->getNamespace(), "{$key}/{$code}");
             $pages[$otherTitle->getDBKey()] = true;
         }
         unset($pages[$title->getDBKey()]);
         if (count($pages) === 0) {
             return true;
         }
         $conds['page_title'] = array_keys($pages);
         $res = $dbw->select('page', $fields, $conds, __METHOD__);
         $inserts = array();
         foreach ($res as $row) {
             $inserts[] = array('rt_type' => RevTag::getType('fuzzy'), 'rt_page' => $row->page_id, 'rt_revision' => $row->page_latest);
         }
         $dbw->replace('revtag', array(array('rt_type', 'rt_page', 'rt_revision')), $inserts, __METHOD__);
     }
     return true;
 }
 public function getDefinitions()
 {
     global $wgTranslateSandboxSuggestions, $wgTranslateSandboxLimit;
     // This will contain the list of messages shown to the user
     $list = array();
     // Ugly
     $store = new TranslationStashStorage(wfGetDB(DB_MASTER));
     $user = RequestContext::getMain()->getUser();
     $translations = $store->getTranslations($user);
     // Add messages the user has already translated first, so he
     // can go back and correct them.
     foreach ($translations as $translation) {
         $title = $translation->getTitle();
         $handle = new MessageHandle($title);
         $index = $title->getNamespace() . ':' . $handle->getKey();
         $list[$index] = '';
     }
     // Always add the regular suggestions
     foreach ($wgTranslateSandboxSuggestions as $titleText) {
         $title = Title::newFromText($titleText);
         if (!$title) {
             wfWarn("Invalid title in \$wgTranslateSandboxSuggestions: {$titleText}");
             continue;
         }
         $index = $title->getNamespace() . ':' . $handle->getKey();
         // This index might already exist, but that is okay
         $list[$index] = '';
     }
     // Message index of all known messages
     $mi = MessageIndex::singleton();
     // Get some random keys
     $all = array_keys($mi->retrieve());
     // In case there aren't any messages
     if ($all === array()) {
         return $list;
     }
     $min = 0;
     $max = count($all) - 1;
     // Indexes are zero-based
     // Get some message. Will be filtered to less below.
     for ($i = count($list); $i < 100; $i++) {
         $list[$all[rand($min, $max)]] = '';
     }
     // Fetch definitions, slowly, one by one
     $count = 0;
     // Provide twice the number of messages than the limit
     // to have a buffer in case the user skips some messages
     $messagesToProvide = $wgTranslateSandboxLimit * 2;
     foreach ($list as $index => &$translation) {
         list($ns, $page) = explode(':', $index, 2);
         $title = Title::makeTitle($ns, "{$page}/{$this->language}");
         $handle = new MessageHandle($title);
         if (MessageGroups::isTranslatableMessage($handle)) {
             // Modified by reference
             $translation = $this->getMessageContent($handle);
             if ($translation === null) {
                 // Something is not in sync or badly broken. Handle gracefully.
                 unset($list[$index]);
                 wfWarn("No message definition for {$index} while preparing the sandbox");
                 continue;
             }
         } else {
             // This might include messages that the user has already translated
             // or messages given in $wgTranslateSandboxSuggestions or just dated
             // message index.
             unset($list[$index]);
             continue;
         }
         $count++;
         if ($count === $messagesToProvide) {
             break;
         }
     }
     // Remove the extra entries
     $list = array_slice($list, 0, $messagesToProvide);
     return $list;
 }
 /**
  * Filters out messages that should not be translated under normal
  * conditions.
  *
  * @param MessageHandle $handle Handle for the translation target.
  * @return boolean
  * @since 2013.10
  */
 public static function isTranslatableMessage(MessageHandle $handle)
 {
     static $cache = array();
     if (!$handle->isValid()) {
         return false;
     }
     $group = $handle->getGroup();
     $groupId = $group->getId();
     $language = $handle->getCode();
     $cacheKey = "{$groupId}:{$language}";
     if (!isset($cache[$cacheKey])) {
         $allowed = true;
         $discouraged = false;
         $whitelist = $group->getTranslatableLanguages();
         if (is_array($whitelist) && !isset($whitelist[$language])) {
             $allowed = false;
         }
         if (self::getPriority($group) === 'discouraged') {
             $discouraged = true;
         } else {
             $priorityLanguages = TranslateMetadata::get($groupId, 'prioritylangs');
             if ($priorityLanguages) {
                 $map = array_flip(explode(',', $priorityLanguages));
                 if (!isset($map[$language])) {
                     $discouraged = true;
                 }
             }
         }
         $cache[$cacheKey] = array('relevant' => $allowed && !$discouraged, 'tags' => array());
         $groupTags = $group->getTags();
         foreach (array('ignored', 'optional') as $tag) {
             if (isset($groupTags[$tag])) {
                 foreach ($groupTags[$tag] as $key) {
                     // TODO: ucfirst should not be here
                     $cache[$cacheKey]['tags'][ucfirst($key)] = true;
                 }
             }
         }
     }
     return $cache[$cacheKey]['relevant'] && !isset($cache[$cacheKey]['tags'][ucfirst($handle->getKey())]);
 }
예제 #14
0
 public function getDefinitions()
 {
     global $wgTranslateMessageNamespaces;
     $db = wfGetDB(DB_SLAVE);
     $tables = 'recentchanges';
     $fields = array('rc_namespace', 'rc_title');
     $conds = array('rc_title ' . $db->buildLike($db->anyString(), '/' . $this->language), 'rc_namespace' => $wgTranslateMessageNamespaces, 'rc_type != ' . RC_LOG, 'rc_id > ' . $this->getRCCutoff());
     $options = array('ORDER BY' => 'rc_id DESC', 'LIMIT' => 1000);
     $res = $db->select($tables, $fields, $conds, __METHOD__, $options);
     $defs = array();
     foreach ($res as $row) {
         $title = Title::makeTitle($row->rc_namespace, $row->rc_title);
         $handle = new MessageHandle($title);
         if (!$handle->isValid()) {
             continue;
         }
         $mkey = $row->rc_namespace . ':' . $handle->getKey();
         if (!isset($defs[$mkey])) {
             $group = $handle->getGroup();
             $defs[$mkey] = $group->getMessage($handle->getKey(), $this->getSourceLanguage());
         }
     }
     return $defs;
 }
 public function batchInsertDefinitions(array $batch)
 {
     foreach ($batch as $key => $item) {
         list($title, $language, $text) = $item;
         $handle = new MessageHandle($title);
         $context = Title::makeTitle($handle->getTitle()->getNamespace(), $handle->getKey());
         $this->sids[$key] = $this->insertSource($context, $language, $text);
     }
     wfWaitForSlaves(10);
 }
 /**
  * Builds a table with all translations of $title.
  *
  * @param Title $title (default: null)
  */
 function showTranslations(Title $title)
 {
     $handle = new MessageHandle($title);
     $namespace = $title->getNamespace();
     $message = $handle->getKey();
     if (!$handle->isValid()) {
         $this->getOutput()->addWikiMsg('translate-translations-no-message', $title->getPrefixedText());
         return;
     }
     $dbr = wfGetDB(DB_SLAVE);
     $res = $dbr->select('page', array('page_namespace', 'page_title'), array('page_namespace' => $namespace, 'page_title ' . $dbr->buildLike("{$message}/", $dbr->anyString())), __METHOD__, array('ORDER BY' => 'page_title', 'USE INDEX' => 'name_title'));
     if (!$res->numRows()) {
         $this->getOutput()->addWikiMsg('translate-translations-no-message', $title->getPrefixedText());
         return;
     } else {
         $this->getOutput()->addWikiMsg('translate-translations-count', $this->getLanguage()->formatNum($res->numRows()));
     }
     // Normal output.
     $titles = array();
     foreach ($res as $s) {
         $titles[] = $s->page_title;
     }
     $pageInfo = TranslateUtils::getContents($titles, $namespace);
     $tableheader = Xml::openElement('table', array('class' => 'mw-sp-translate-table sortable'));
     $tableheader .= Xml::openElement('tr');
     $tableheader .= Xml::element('th', null, $this->msg('allmessagesname')->text());
     $tableheader .= Xml::element('th', null, $this->msg('allmessagescurrent')->text());
     $tableheader .= Xml::closeElement('tr');
     // Adapted version of TranslateUtils:makeListing() by Nikerabbit.
     $out = $tableheader;
     $canTranslate = $this->getUser()->isAllowed('translate');
     $ajaxPageList = array();
     $historyText = "&#160;<sup>" . $this->msg('translate-translations-history-short')->escaped() . "</sup>&#160;";
     $separator = $this->msg('word-separator')->plain();
     foreach ($res as $s) {
         $key = $s->page_title;
         $tTitle = Title::makeTitle($s->page_namespace, $key);
         $ajaxPageList[] = $tTitle->getPrefixedDBkey();
         $tHandle = new MessageHandle($tTitle);
         $code = $tHandle->getCode();
         $text = TranslateUtils::getLanguageName($code, $this->getLanguage()->getCode());
         $text .= $separator;
         $text .= $this->msg('parentheses')->params($code)->plain();
         $text = htmlspecialchars($text);
         if ($canTranslate) {
             $tools['edit'] = TranslationHelpers::ajaxEditLink($tTitle, $text);
         } else {
             $tools['edit'] = Linker::link($tTitle, $text);
         }
         $tools['history'] = Linker::link($tTitle, $historyText, array('action', 'title' => $this->msg('history-title', $tTitle->getPrefixedDBkey())->text()), array('action' => 'history'));
         if (MessageHandle::hasFuzzyString($pageInfo[$key][0]) || $tHandle->isFuzzy()) {
             $class = 'orig';
         } else {
             $class = 'def';
         }
         $leftColumn = $tools['history'] . $tools['edit'];
         $out .= Xml::tags('tr', array('class' => $class), Xml::tags('td', null, $leftColumn) . Xml::tags('td', array('lang' => $code, 'dir' => Language::factory($code)->getDir()), TranslateUtils::convertWhiteSpaceToHTML($pageInfo[$key][0])));
     }
     $out .= Xml::closeElement('table');
     $this->getOutput()->addHTML($out);
     $vars = array('trlKeys' => $ajaxPageList);
     $this->getOutput()->addScript(Skin::makeVariablesScript($vars));
 }
 /**
  * @see schema.xml
  */
 protected function createDocument(MessageHandle $handle, $text, $revId)
 {
     $language = $handle->getCode();
     $translationTitle = $handle->getTitle();
     $title = Title::makeTitle($handle->getTitle()->getNamespace(), $handle->getKey());
     $wiki = wfWikiId();
     $messageid = $title->getPrefixedText();
     $globalid = "{$wiki}-{$messageid}-{$revId}/{$language}";
     $doc = new Solarium_Document_ReadWrite();
     $doc->wiki = $wiki;
     $doc->uri = $translationTitle->getCanonicalUrl();
     $doc->messageid = $messageid;
     $doc->globalid = $globalid;
     $doc->language = $language;
     $doc->content = $text;
     $doc->setField('group', $handle->getGroupIds());
     return $doc;
 }
 /**
  * Adds tag which identifies the revision of source message at that time.
  * This is used to show diff against current version of source message
  * when updating a translation.
  * Hook: Translate:newTranslation
  * @param MessageHandle $handle
  * @param int $revision
  * @param string $text
  * @param User $user
  * @return bool
  */
 public static function updateTransverTag(MessageHandle $handle, $revision, $text, User $user)
 {
     if ($user->isAllowed('bot')) {
         return false;
     }
     $group = $handle->getGroup();
     $title = $handle->getTitle();
     $name = $handle->getKey() . '/' . $group->getSourceLanguage();
     $definitionTitle = Title::makeTitleSafe($title->getNamespace(), $name);
     if (!$definitionTitle || !$definitionTitle->exists()) {
         return true;
     }
     $definitionRevision = $definitionTitle->getLatestRevID();
     $dbw = wfGetDB(DB_MASTER);
     $conds = array('rt_page' => $title->getArticleID(), 'rt_type' => RevTag::getType('tp:transver'), 'rt_revision' => $revision, 'rt_value' => $definitionRevision);
     $index = array('rt_type', 'rt_page', 'rt_revision');
     $dbw->replace('revtag', array($index), $conds, __METHOD__);
     return true;
 }
 /**
  * @param Title $title
  * @return bool|TranslatablePage
  */
 public static function isTranslationPage(Title $title)
 {
     $handle = new MessageHandle($title);
     $key = $handle->getKey();
     $code = $handle->getCode();
     if ($key === '' || $code === '') {
         return false;
     }
     $codes = Language::fetchLanguageNames();
     global $wgTranslateDocumentationLanguageCode;
     unset($codes[$wgTranslateDocumentationLanguageCode]);
     if (!isset($codes[$code])) {
         return false;
     }
     $newtitle = self::changeTitleText($title, $key);
     if (!$newtitle) {
         return false;
     }
     $page = TranslatablePage::newFromTitle($newtitle);
     if ($page->getMarkedTag() === false) {
         return false;
     }
     return $page;
 }
 /**
  * @param Title $title
  * @param $message
  * @param $comment
  * @param $user
  * @param int $editFlags
  * @return array|String
  */
 public static function doFuzzy($title, $message, $comment, $user, $editFlags = 0)
 {
     $context = RequestContext::getMain();
     if (!$context->getUser()->isAllowed('translate-manage')) {
         return $context->msg('badaccess-group0')->text();
     }
     $dbw = wfGetDB(DB_MASTER);
     // Work on all subpages of base title.
     $handle = new MessageHandle($title);
     $titleText = $handle->getKey();
     $conds = array('page_namespace' => $title->getNamespace(), 'page_latest=rev_id', 'rev_text_id=old_id', 'page_title' . $dbw->buildLike("{$titleText}/", $dbw->anyString()));
     $rows = $dbw->select(array('page', 'revision', 'text'), array('page_title', 'page_namespace', 'old_text', 'old_flags'), $conds, __METHOD__);
     // Edit with fuzzybot if there is no user.
     if (!$user) {
         $user = FuzzyBot::getUser();
     }
     // Process all rows.
     $changed = array();
     foreach ($rows as $row) {
         global $wgTranslateDocumentationLanguageCode;
         $ttitle = Title::makeTitle($row->page_namespace, $row->page_title);
         // No fuzzy for English original or documentation language code.
         if ($ttitle->getSubpageText() === 'en' || $ttitle->getSubpageText() === $wgTranslateDocumentationLanguageCode) {
             // Use imported text, not database text.
             $text = $message;
         } else {
             $text = Revision::getRevisionText($row);
             $text = self::makeTextFuzzy($text);
         }
         // Do actual import
         $changed[] = self::doImport($ttitle, $text, $comment, $user, $editFlags);
     }
     // Format return text
     $text = '';
     foreach ($changed as $c) {
         $key = array_shift($c);
         $text .= "* " . $context->msg($key, $c)->plain() . "\n";
     }
     return array('translate-manage-import-fuzzy', "\n" . $text);
 }