public function execute() { $params = $this->extractRequestParams(); $title = Title::newFromText($params['title']); if (!$title) { $this->dieUsage('Invalid title', 'invalidtitle'); } $handle = new MessageHandle($title); if (!$handle->isValid()) { $this->dieUsage('Title does not correspond to a translatable message', 'nomessagefortitle'); } if (strval($params['group']) !== '') { $group = MessageGroups::getGroup($params['group']); } else { $group = $handle->getGroup(); } if (!$group) { $this->dieUsage('Invalid group', 'invalidgroup'); } $data = array(); $times = array(); $props = $params['prop']; $aggregator = new QueryAggregator(); // Figure out the intersection of supported and requested aids $types = $group->getTranslationAids(); $props = array_intersect($props, array_keys($types)); $result = $this->getResult(); // Create list of aids, populate web services queries $aids = array(); foreach ($props as $type) { $class = $types[$type]; $obj = new $class($group, $handle, $this); if ($obj instanceof QueryAggregatorAware) { $obj->setQueryAggregator($aggregator); $obj->populateQueries(); } $aids[$type] = $obj; } // Execute all web service queries asynchronously to save time $start = microtime(true); $aggregator->run(); $times['query_aggregator'] = round(microtime(true) - $start, 3); // Construct the result data structure foreach ($aids as $type => $obj) { $start = microtime(true); try { $aid = $obj->getData(); } catch (TranslationHelperException $e) { $aid = array('error' => $e->getMessage()); } if (isset($aid['**'])) { $result->setIndexedTagName($aid, $aid['**']); unset($aid['**']); } $data[$type] = $aid; $times[$type] = round(microtime(true) - $start, 3); } $result->addValue(null, 'helpers', $data); $result->addValue(null, 'times', $times); }
public function testParsing() { $title = Title::newFromText('MediaWiki:Ugakey/nl'); $page = WikiPage::factory($title); $content = ContentHandler::makeContent('$1 van $2', $title); $status = $page->doEditContent($content, __METHOD__); $value = $status->getValue(); /** * @var Revision $rev */ $rev = $value['revision']; $revision = $rev->getId(); $dbw = wfGetDB(DB_MASTER); $conds = array('rt_page' => $title->getArticleID(), 'rt_type' => RevTag::getType('fuzzy'), 'rt_revision' => $revision); $index = array_keys($conds); $dbw->replace('revtag', array($index), $conds, __METHOD__); $handle = new MessageHandle($title); $this->assertTrue($handle->isValid(), 'Message is known'); $this->assertTrue($handle->isFuzzy(), 'Message is fuzzy after database fuzzying'); // Update the translation without the fuzzy string $content = ContentHandler::makeContent('$1 van $2', $title); $page->doEditContent($content, __METHOD__); $this->assertFalse($handle->isFuzzy(), 'Message is unfuzzy after edit'); $content = ContentHandler::makeContent('!!FUZZY!!$1 van $2', $title); $page->doEditContent($content, __METHOD__); $this->assertTrue($handle->isFuzzy(), 'Message is fuzzy after manual fuzzying'); // Update the translation without the fuzzy string $content = ContentHandler::makeContent('$1 van $2', $title); $page->doEditContent($content, __METHOD__); $this->assertFalse($handle->isFuzzy(), 'Message is unfuzzy after edit'); }
public function execute() { global $wgUser; if ( !$wgUser->isallowed( self::$right ) ) { $this->dieUsage( 'Permission denied', 'permissiondenied' ); } $params = $this->extractRequestParams(); $revision = Revision::newFromId( $params['revision'] ); if ( !$revision ) { $this->dieUsage( 'Invalid revision', 'invalidrevision' ); } $title = $revision->getTitle(); $handle = new MessageHandle( $title ); if ( !$handle->isValid() ) { $this->dieUsage( 'Unknown message', 'unknownmessage' ); } if ( $handle->isFuzzy() ) { $this->dieUsage( 'Cannot review fuzzy translations', 'fuzzymessage' ); } if ( $revision->getUser() == $wgUser->getId() ) { $this->dieUsage( 'Cannot review own translations', 'owntranslation' ); } $dbw = wfGetDB( DB_MASTER ); $table = 'translate_reviews'; $row = array( 'trr_user' => $wgUser->getId(), 'trr_page' => $revision->getPage(), 'trr_revision' => $revision->getId(), ); $options = array( 'IGNORE' ); $res = $dbw->insert( $table, $row, __METHOD__, $options ); if ( !$dbw->affectedRows() ) { $this->setWarning( 'Already marked as reviewed by you' ); } else { $logger = new LogPage( 'translationreview' ); $params = array( $revision->getId() ); $logger->addEntry( 'message', $title, null, $params, $wgUser ); } $output = array( 'review' => array( 'title' => $title->getPrefixedText(), 'pageid' => $revision->getPage(), 'revision' => $revision->getId() ) ); $this->getResult()->addValue( null, $this->getModuleName(), $output ); }
/** * 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; }
protected function formatTranslation(StashedTranslation $translation) { $title = $translation->getTitle(); $handle = new MessageHandle($title); // Prepare for the worst $definition = ''; $comparison = ''; if ($handle->isValid()) { $groupId = MessageIndex::getPrimaryGroupId($handle); $group = MessageGroups::getGroup($groupId); $key = $handle->getKey(); $definition = $group->getMessage($key, $group->getSourceLanguage()); $comparison = $group->getMessage($key, $handle->getCode()); } return array('title' => $title->getPrefixedText(), 'definition' => $definition, 'translation' => $translation->getValue(), 'comparison' => $comparison, 'metadata' => $translation->getMetadata()); }
protected function extractMessages($resultset, $offset, $limit) { $messages = $documents = $ret = array(); $language = $this->params['language']; foreach ($resultset->getResults() as $document) { $data = $document->getData(); if (!$this->server->isLocalSuggestion($data)) { continue; } $title = Title::newFromText($data['localid']); if (!$title) { continue; } $handle = new MessageHandle($title); if (!$handle->isValid()) { continue; } $key = $title->getNamespace() . ':' . $title->getDBKey(); $messages[$key] = $data['content']; } $definitions = new MessageDefinitions($messages); $collection = MessageCollection::newFromDefinitions($definitions, $language); $filter = $this->params['filter']; if ($filter === 'untranslated') { $collection->filter('hastranslation', true); } elseif (in_array($filter, $this->getAvailableFilters())) { $collection->filter($filter, false); } $total = count($collection); $offset = $collection->slice($offset, $limit); $left = count($collection); $offsets = array('start' => $offset[2], 'left' => $left, 'total' => $total); if ($filter === 'translated' || $filter === 'fuzzy') { $collection->loadTranslations(); } foreach ($collection->keys() as $mkey => $title) { $documents[$mkey]['content'] = $messages[$mkey]; if ($filter === 'translated' || $filter === 'fuzzy') { $documents[$mkey]['content'] = $collection[$mkey]->translation(); } $handle = new MessageHandle($title); $documents[$mkey]['localid'] = $handle->getTitleForBase()->getPrefixedText(); $documents[$mkey]['language'] = $language; $ret[] = $documents[$mkey]; } return array($ret, $offsets); }
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'); }
public function execute() { $params = $this->extractRequestParams(); $title = Title::newFromText($params['title']); if (!$title) { $this->dieUsage('Invalid title', 'invalidtitle'); } $handle = new MessageHandle($title); if (!$handle->isValid()) { $this->dieUsage('Title does not correspond to a translatable message', 'nomessagefortitle'); } $namespace = $title->getNamespace(); $pageInfo = self::getTranslations($handle); $result = $this->getResult(); $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]); if (defined('ApiResult::META_CONTENT')) { ApiResult::setContentValue($data, 'translation', $translation); } else { ApiResult::setContent($data, $translation); } $fit = $result->addValue(array('query', $this->getModuleName()), null, $data); if (!$fit) { $this->setContinueEnumParameter('offset', $count); break; } } if (defined('ApiResult::META_CONTENT')) { $result->addIndexedTagName(array('query', $this->getModuleName()), 'message'); } else { $result->setIndexedTagName_internal(array('query', $this->getModuleName()), 'message'); } }
public function run() { $title = $this->title; $handle = new MessageHandle($title); $code = $handle->getCode(); if (!$handle->isValid() && !$code) { return true; } $groups = self::getGroupsWithTransitions($handle); foreach ($groups as $id => $transitions) { $group = MessageGroups::getGroup($id); $stats = MessageGroupStats::forItem($id, $code); $state = self::getNewState($stats, $transitions); if ($state) { ApiGroupReview::changeState($group, $code, $state, FuzzyBot::getUser()); } } return true; }
public function update(MessageHandle $handle, $targetText) { if (!$handle->isValid() || $handle->getCode() === '') { return false; } $mkey = $handle->getKey(); $group = $handle->getGroup(); $targetLanguage = $handle->getCode(); $sourceLanguage = $group->getSourceLanguage(); // 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; } $context = Title::makeTitle($handle->getTitle()->getNamespace(), $mkey); $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' => $context->getPrefixedText(), 'tms_text' => $definition); $sid = $dbw->selectField('translate_tms', 'tms_sid', $conds, __METHOD__); if ($sid === false) { $sid = $this->insertSource($context, $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 if ($targetText !== null) { $row = $deleteConds + array('tmt_text' => $targetText); $dbw->insert('translate_tmt', $row, __METHOD__); } return true; }
/** * Hook to update source and destination translation pages on moving translation units * Hook: TitleMoveComplete * @since 2014.08 */ public static function onMoveTranslationUnits(Title &$ot, Title &$nt, User &$user, $oldid, $newid, $reason) { // Do the update only once. In case running by job queue, the update is not done here if (self::$jobQueueRunning) { return; } $groupLast = null; foreach (array($ot, $nt) as $title) { $handle = new MessageHandle($title); if (!$handle->isValid()) { continue; } // Documentation pages are never translation pages if ($handle->isDoc()) { continue; } $group = $handle->getGroup(); if (!$group instanceof WikiPageMessageGroup) { continue; } $language = $handle->getCode(); // Ignore pages such as Translations:Page/unit without language code if (strval($code) === '') { continue; } // Update the page only once if source and destination units // belong to the same page if ($group !== $groupLast) { $groupLast = $group; $page = TranslatablePage::newFromTitle($group->getTitle()); self::updateTranslationPage($page, $language, $user, 0, $reason); } } }
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; }
/** * Validates review action by checking permissions and other things. * @param User $user * @param Revision $revision * @return string Error key or empty string if review is allowed. * @since 2012-09-24 */ public static function getReviewBlockers(User $user, Revision $revision) { if (!$user->isAllowed(self::$right)) { return 'permissiondenied'; } if ($user->isBlocked()) { return 'blocked'; } $title = $revision->getTitle(); $handle = new MessageHandle($title); if (!$handle->isValid()) { return 'unknownmessage'; } if ($revision->getUser() == $user->getId()) { return 'owntranslation'; } if ($handle->isFuzzy()) { return 'fuzzymessage'; } return ''; }
/** * Hook: ArticleContentOnDiff */ public static function displayOnDiff(DifferenceEngine $de, OutputPage $out) { $title = $de->getTitle(); $handle = new MessageHandle($title); if (!$handle->isValid()) { return true; } $th = new TranslationHelpers($title, false); $th->setEditMode(false); $de->loadNewText(); if ($de->mNewContent instanceof TextContent) { $th->setTranslation($de->mNewContent->getNativeData()); } else { // Screw you, not interested. return true; } TranslationHelpers::addModules($out); $boxes = array(); $boxes[] = $th->callBox('documentation', array($th, 'getDocumentationBox')); $boxes[] = $th->callBox('definition', array($th, 'getDefinitionBox')); $boxes[] = $th->callBox('translation', array($th, 'getTranslationDisplayBox')); $output = implode("\n", $boxes); $output = Html::rawElement('div', array('class' => 'mw-sp-translate-edit-fields'), $output); $out->addHtml($output); return true; }
/** * 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())]); }
public function execute($par) { global $wgLanguageCode; $this->setHeaders(); $this->checkPermissions(); $server = TTMServer::primary(); if (!$server instanceof SearchableTTMServer) { throw new ErrorPageError('tux-sst-nosolr-title', 'tux-sst-nosolr-body'); } $out = $this->getOutput(); $out->addModuleStyles('jquery.uls.grid'); $out->addModuleStyles('ext.translate.special.searchtranslations.styles'); $out->addModuleStyles('ext.translate.special.translate.styles'); $out->addModules('ext.translate.special.searchtranslations'); $out->addModules('ext.translate.special.searchtranslations.operatorsuggest'); TranslateUtils::addSpecialHelpLink($out, 'Help:Extension:Translate#searching'); $this->opts = $opts = new FormOptions(); $opts->add('query', ''); $opts->add('sourcelanguage', $wgLanguageCode); $opts->add('language', ''); $opts->add('group', ''); $opts->add('grouppath', ''); $opts->add('filter', ''); $opts->add('match', ''); $opts->add('case', ''); $opts->add('limit', $this->limit); $opts->add('offset', 0); $opts->fetchValuesFromRequest($this->getRequest()); $queryString = $opts->getValue('query'); if ($queryString === '') { $this->showEmptySearch(); return; } $params = $opts->getAllValues(); $filter = $opts->getValue('filter'); try { $translationSearch = new CrossLanguageTranslationSearchQuery($params, $server); if (in_array($filter, $translationSearch->getAvailableFilters())) { if ($opts->getValue('language') === '') { $params['language'] = $this->getLanguage()->getCode(); $opts->setValue('language', $params['language']); } $documents = $translationSearch->getDocuments(); $total = $translationSearch->getTotalHits(); $resultset = $translationSearch->getResultSet(); } else { $resultset = $server->search($queryString, $params, $this->hl); $documents = $server->getDocuments($resultset); $total = $server->getTotalHits($resultset); } } catch (TTMServerException $e) { error_log('Translation search server unavailable:' . $e->getMessage()); throw new ErrorPageError('tux-sst-solr-offline-title', 'tux-sst-solr-offline-body'); } // Part 1: facets $facets = $server->getFacets($resultset); $facetHtml = ''; if (count($facets['language']) > 0) { if ($filter !== '') { $facets['language'] = array_merge($facets['language'], array($opts->getValue('language') => $total)); } $facetHtml = Html::element('div', array('class' => 'row facet languages', 'data-facets' => FormatJson::encode($this->getLanguages($facets['language'])), 'data-language' => $opts->getValue('language')), $this->msg('tux-sst-facet-language')); } if (count($facets['group']) > 0) { $facetHtml .= Html::element('div', array('class' => 'row facet groups', 'data-facets' => FormatJson::encode($this->getGroups($facets['group'])), 'data-group' => $opts->getValue('group')), $this->msg('tux-sst-facet-group')); } // Part 2: results $resultsHtml = ''; $title = Title::newFromText($queryString); if ($title && !in_array($filter, $translationSearch->getAvailableFilters())) { $handle = new MessageHandle($title); $code = $handle->getCode(); $language = $opts->getValue('language'); if ($handle->isValid() && $code !== '' && $code !== $language) { $groupId = $handle->getGroup()->getId(); $helpers = new TranslationHelpers($title, $groupId); $document['wiki'] = wfWikiId(); $document['localid'] = $handle->getTitleForBase()->getPrefixedText(); $document['content'] = $helpers->getTranslation(); $document['language'] = $handle->getCode(); array_unshift($documents, $document); $total++; } } foreach ($documents as $document) { $text = $document['content']; $text = TranslateUtils::convertWhiteSpaceToHTML($text); list($pre, $post) = $this->hl; $text = str_replace($pre, '<strong class="tux-search-highlight">', $text); $text = str_replace($post, '</strong>', $text); $title = Title::newFromText($document['localid'] . '/' . $document['language']); if (!$title) { // Should not ever happen but who knows... continue; } $resultAttribs = array('class' => 'row tux-message', 'data-title' => $title->getPrefixedText(), 'data-language' => $document['language']); $handle = new MessageHandle($title); if ($handle->isValid()) { $groupId = $handle->getGroup()->getId(); $helpers = new TranslationHelpers($title, $groupId); $resultAttribs['data-definition'] = $helpers->getDefinition(); $resultAttribs['data-translation'] = $helpers->getTranslation(); $resultAttribs['data-group'] = $groupId; $uri = $title->getLocalUrl(array('action' => 'edit')); $link = Html::element('a', array('href' => $uri), $this->msg('tux-sst-edit')->text()); } else { $url = wfParseUrl($document['uri']); $domain = $url['host']; $link = Html::element('a', array('href' => $document['uri']), $this->msg('tux-sst-view-foreign', $domain)->text()); } $access = Html::rawElement('div', array('class' => 'row tux-edit tux-message-item'), $link); $titleText = $title->getPrefixedText(); $titleAttribs = array('class' => 'row tux-title', 'dir' => 'ltr'); $textAttribs = array('class' => 'row tux-text', 'lang' => wfBCP47($document['language']), 'dir' => Language::factory($document['language'])->getDir()); $resultsHtml = $resultsHtml . Html::openElement('div', $resultAttribs) . Html::rawElement('div', $textAttribs, $text) . Html::element('div', $titleAttribs, $titleText) . $access . Html::closeElement('div'); } $resultsHtml .= Html::rawElement('hr', array('class' => 'tux-pagination-line')); $prev = $next = ''; $offset = $this->opts->getValue('offset'); $params = $this->opts->getChangedValues(); if ($total - $offset > $this->limit) { $newParams = array('offset' => $offset + $this->limit) + $params; $attribs = array('class' => 'mw-ui-button pager-next', 'href' => $this->getPageTitle()->getLocalUrl($newParams)); $next = Html::element('a', $attribs, $this->msg('tux-sst-next')->text()); } if ($offset) { $newParams = array('offset' => max(0, $offset - $this->limit)) + $params; $attribs = array('class' => 'mw-ui-button pager-prev', 'href' => $this->getPageTitle()->getLocalUrl($newParams)); $prev = Html::element('a', $attribs, $this->msg('tux-sst-prev')->text()); } $resultsHtml .= Html::rawElement('div', array('class' => 'tux-pagination-links'), "{$prev} {$next}"); $search = $this->getSearchInput($queryString); $count = $this->msg('tux-sst-count')->numParams($total); $this->showSearch($search, $count, $facetHtml, $resultsHtml, $total); }
public function getDefinitions() { if (!$this->language) { throw new MWException("Language not set"); } $db = wfGetDB(DB_SLAVE); $tables = 'recentchanges'; $fields = array('rc_namespace', 'rc_title'); $conds = $this->getQueryConditions(); $options = array('ORDER BY' => 'rc_id DESC', 'LIMIT' => 5000); $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() || !$this->matchingMessage($handle)) { continue; } $messageKey = $handle->getKey(); $fullKey = $row->rc_namespace . ':' . $messageKey; /* Note: due to bugs, getMessage might return null even for * known messages. These negatives are not cached, but that * should be rare enough case to not affect performance. */ if (!isset($defs[$fullKey])) { $group = $handle->getGroup(); $msg = $group->getMessage($messageKey, $group->getSourceLanguage()); if ($msg !== null) { $defs[$fullKey] = $msg; } } } return $defs; }
/** * Hook: ArticleContentOnDiff */ public static function displayOnDiff( DifferenceEngine $de, OutputPage $out ) { $title = $de->getTitle(); $handle = new MessageHandle( $title ); if ( !$handle->isValid() ) { return true; } $de->loadNewText(); $out->setRevisionId( $de->mNewRev->getId() ); $th = new TranslationHelpers( $title, /*group*/false ); $th->setEditMode( false ); $th->setTranslation( $de->mNewtext ); TranslationHelpers::addModules( $out ); $boxes = array(); $boxes[] = $th->getDocumentationBox(); $boxes[] = $th->getDefinitionBox(); $boxes[] = $th->getTranslationDisplayBox(); $output = Html::rawElement( 'div', array( 'class' => 'mw-sp-translate-edit-fields' ), implode( "\n\n", $boxes ) ); $out->addHtml( $output ); return false; }
/** * Prevent editing of unknown pages in Translations namespace. * Hook: getUserPermissionsErrorsExpensive */ public static function preventUnknownTranslations(Title $title, User $user, $action, &$result) { $handle = new MessageHandle($title); if ($handle->isPageTranslation() && $action === 'edit' && !$handle->isValid()) { $result = array('tpt-unknown-page'); return false; } return true; }
/** * Parser function hook */ public static function translationDialogMagicWord( Parser $parser, $title = '', $linktext = '' ) { $title = Title::newFromText( $title ); if ( !$title ) return ''; $handle = new MessageHandle( $title ); if ( !$handle->isValid() ) return ''; $group = $handle->getGroup(); $callParams = array( $title->getPrefixedText(), $group->getId() ); $call = Xml::encodeJsCall( 'mw.translate.openDialog', $callParams ); $js = <<<JAVASCRIPT mw.loader.using( 'ext.translate.quickedit', function() { $call; } ); return false; JAVASCRIPT; $a = array( 'href' => $title->getFullUrl( array( 'action' => 'edit' ) ), 'onclick' => $js, ); if ( $linktext === '' ) { $linktext = wfMessage( 'translate-edit-jsopen' )->text(); } $output = Html::element( 'a', $a, $linktext ); return $parser->insertStripItem( $output, $parser->mStripState ); }
/** * 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 = " <sup>" . $this->msg('translate-translations-history-short')->escaped() . "</sup> "; $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)); }
public function update(MessageHandle $handle, $targetText) { if ($handle->getCode() === '') { return false; } /* There are various different cases here: * [new or updated] [fuzzy|non-fuzzy] [translation|definition] * 1) We don't distinguish between new or updated here. * 2) Delete old translation, but not definition * 3) Insert new translation or definition, if non-fuzzy * The definition should never be fuzzied anyway. * * These only apply to known messages. */ $update = $this->client->createUpdate(); $title = $handle->getTitle(); $doDelete = true; $sourceLanguage = ''; if ($handle->isValid()) { $sourceLanguage = $handle->getGroup()->getSourceLanguage(); if ($handle->getCode() === $sourceLanguage) { $doDelete = false; } } if ($doDelete) { $base = Title::makeTitle($title->getNamespace(), $handle->getKey()); $conds = array('wiki' => wfWikiId(), 'language' => $handle->getCode(), 'messageid' => $base->getPrefixedText()); foreach ($conds as $key => &$value) { $value = "{$key}:" . $update->getHelper()->escapePhrase($value); } $update->addDeleteQuery(implode(' AND ', $conds)); } if ($targetText !== null) { if ($handle->isValid()) { // Of the message definition page $targetTitle = $handle->getTitle(); $sourceTitle = Title::makeTitle($targetTitle->getNamespace(), $handle->getKey() . '/' . $sourceLanguage); $revId = intval($sourceTitle->getLatestRevID()); /* Note: in some cases the source page might not exist, in this case * we use 0 as message version identifier, to differentiate them from * orphan messages */ } else { $revId = 'orphan'; } $doc = $this->createDocument($handle, $targetText, $revId); // Add document and commit within X seconds. $update->addDocument($doc, null, self::COMMIT_WITHIN); } try { $this->client->update($update); } catch (Solarium_Exception $e) { error_log("SolrTTMServer update-write failed"); return false; } return true; }
protected function parseQueryString($queryString, array $opts) { $fields = $highlights = array(); $terms = preg_split('/\\s+/', $queryString); $match = $opts['match']; $case = $opts['case']; // Map each word in the query string with its corresponding field foreach ($terms as $term) { $prefix = strstr($term, '*', true); if ($prefix) { // For wildcard search $fields['content.prefix_complete'][] = $prefix; } elseif ($case === '1') { // For case sensitive search $fields['content.case_sensitive'][] = $term; } else { $fields['content'][] = $term; } } // Allow searching either by message content or message id (page name // without language subpage) with exact match only. $searchQuery = new \Elastica\Query\Bool(); foreach ($fields as $analyzer => $words) { foreach ($words as $word) { $boolQuery = new \Elastica\Query\Bool(); $contentQuery = new \Elastica\Query\Match(); $contentQuery->setFieldQuery($analyzer, $word); $boolQuery->addShould($contentQuery); $messageQuery = new \Elastica\Query\Term(); $messageQuery->setTerm('localid', $word); $boolQuery->addShould($messageQuery); if ($match === 'all') { $searchQuery->addMust($boolQuery); } else { $searchQuery->addShould($boolQuery); } // Fields for highlighting $highlights[$analyzer] = array('number_of_fragments' => 0); // Allow searching by exact message title (page name with // language subpage). $title = Title::newFromText($word); if (!$title) { continue; } $handle = new MessageHandle($title); if ($handle->isValid() && $handle->getCode() !== '') { $localid = $handle->getTitleForBase()->getPrefixedText(); $boolQuery = new \Elastica\Query\Bool(); $messageId = new \Elastica\Query\Term(); $messageId->setTerm('localid', $localid); $boolQuery->addMust($messageId); $searchQuery->addShould($boolQuery); } } } return array($searchQuery, $highlights); }