/**
  * @return null|string
  */
 public function getLazySuggestionBox()
 {
     $this->mustBeKnownMessage();
     if (!$this->handle->getCode()) {
         return null;
     }
     $url = SpecialPage::getTitleFor('Translate', 'editpage')->getLocalUrl(array('suggestions' => 'only', 'page' => $this->handle->getTitle()->getPrefixedDbKey(), 'loadgroup' => $this->group->getId()));
     $url = Xml::encodeJsVar($url);
     $id = Sanitizer::escapeId('tm-lazysug-' . $this->dialogID());
     $target = self::jQueryPathId($id);
     $script = Html::inlineScript("jQuery({$target}).load({$url})");
     $spinner = Html::element('div', array('class' => 'mw-ajax-loader'));
     return Html::rawElement('div', array('id' => $id), $script . $spinner);
 }
	public function testGetId() {
		$this->assertEquals(
			$this->groupConfiguration['BASIC']['id'],
			$this->group->getId(),
			"id comes from config."
		);
	}
 protected function groupSelector()
 {
     $activeId = false;
     if ($this->group) {
         $activeId = $this->group->getId();
     }
     $groups = MessageGroups::getAllGroups();
     $dynamic = MessageGroups::getDynamicGroups();
     $groups = array_keys(array_merge($groups, $dynamic));
     $selected = $this->options['group'];
     $selector = new XmlSelect('group', 'group');
     $selector->setDefault($selected);
     foreach ($groups as $id) {
         if ($id === $activeId) {
             $activeId = false;
         }
         $group = MessageGroups::getGroup($id);
         $hide = MessageGroups::getPriority($group) === 'discouraged';
         if (!$group->exists() || $hide) {
             continue;
         }
         $selector->addOption($group->getLabel(), $id);
     }
     if ($activeId) {
         $selector->addOption($this->group->getLabel(), $activeId);
     }
     return $selector->getHTML();
 }
 public static function getState(MessageGroup $group, $code)
 {
     $dbw = wfGetDB(DB_MASTER);
     $table = 'translate_groupreviews';
     $field = 'tgr_state';
     $conds = array('tgr_group' => $group->getId(), 'tgr_lang' => $code);
     return $dbw->selectField($table, $field, $conds, __METHOD__);
 }
 public function contents()
 {
     $optional = $this->context->msg('translate-optional')->escaped();
     $this->doLinkBatch();
     $sourceLang = Language::factory($this->group->getSourceLanguage());
     $targetLang = Language::factory($this->collection->getLanguage());
     $titleMap = $this->collection->keys();
     $output = '';
     $this->collection->initMessages();
     // Just to be sure
     /**
      * @var TMessage $m
      */
     foreach ($this->collection as $key => $m) {
         $tools = array();
         /**
          * @var Title $title
          */
         $title = $titleMap[$key];
         $original = $m->definition();
         $translation = $m->translation();
         $hasTranslation = $translation !== null;
         if ($hasTranslation) {
             $message = $translation;
             $extraAttribs = self::getLanguageAttributes($targetLang);
         } else {
             $message = $original;
             $extraAttribs = self::getLanguageAttributes($sourceLang);
         }
         Hooks::run('TranslateFormatMessageBeforeTable', array(&$message, $m, $this->group, $targetLang, &$extraAttribs));
         // Using Html::element( a ) because Linker::link is memory hog.
         // It takes about 20 KiB per call, and that times 5000 is quite
         // a lot of memory.
         $niceTitle = htmlspecialchars($this->context->getLanguage()->truncate($title->getPrefixedText(), -35));
         $linkAttribs = array('href' => $title->getLocalUrl(array('action' => 'edit')));
         $linkAttribs += TranslationEditPage::jsEdit($title, $this->group->getId());
         $tools['edit'] = Html::element('a', $linkAttribs, $niceTitle);
         $anchor = 'msg_' . $key;
         $anchor = Xml::element('a', array('id' => $anchor, 'href' => "#{$anchor}"), "↓");
         $extra = '';
         if ($m->hasTag('optional')) {
             $extra = '<br />' . $optional;
         }
         $tqeData = $extraAttribs + array('data-title' => $title->getPrefixedText(), 'data-group' => $this->group->getId(), 'id' => 'tqe-anchor-' . substr(sha1($title->getPrefixedText()), 0, 12), 'class' => 'tqe-inlineeditable ' . ($hasTranslation ? 'translated' : 'untranslated'));
         $button = $this->getReviewButton($m);
         $status = $this->getReviewStatus($m);
         $leftColumn = $button . $anchor . $tools['edit'] . $extra . $status;
         if ($this->reviewMode) {
             $output .= Xml::tags('tr', array('class' => 'orig'), Xml::tags('td', array('rowspan' => '2'), $leftColumn) . Xml::tags('td', self::getLanguageAttributes($sourceLang), TranslateUtils::convertWhiteSpaceToHTML($original)));
             $output .= Xml::tags('tr', null, Xml::tags('td', $tqeData, TranslateUtils::convertWhiteSpaceToHTML($message)));
         } else {
             $output .= Xml::tags('tr', array('class' => 'def'), Xml::tags('td', null, $leftColumn) . Xml::tags('td', $tqeData, TranslateUtils::convertWhiteSpaceToHTML($message)));
         }
         $output .= "\n";
     }
     return $output;
 }
 /**
  * Keeps track of recently used message groups per user.
  */
 public static function trackGroup(MessageGroup $group, User $user)
 {
     if ($user->isAnon()) {
         return true;
     }
     $groups = $user->getOption('translate-recent-groups', '');
     if ($groups === '') {
         $groups = array();
     } else {
         $groups = explode('|', $groups);
     }
     if (isset($groups[0]) && $groups[0] === $group->getId()) {
         return true;
     }
     array_unshift($groups, $group->getId());
     $groups = array_unique($groups);
     $groups = array_slice($groups, 0, 5);
     $user->setOption('translate-recent-groups', implode('|', $groups));
     // Promise to persist the data post-send
     DeferredUpdates::addCallableUpdate(function () use($user) {
         $user->saveSettings();
     });
     return true;
 }
 public function getDefinitionBox()
 {
     $this->mustHaveDefinition();
     $en = $this->getDefinition();
     $title = Linker::link(SpecialPage::getTitleFor('Translate'), htmlspecialchars($this->group->getLabel()), array(), array('group' => $this->group->getId(), 'language' => $this->handle->getCode()));
     $label = wfMessage('translate-edit-definition')->text() . wfMessage('word-separator')->text() . wfMessage('parentheses', $title)->text();
     // Source language object
     $sl = Language::factory($this->group->getSourceLanguage());
     $dialogID = $this->dialogID();
     $id = Sanitizer::escapeId("def-{$dialogID}");
     $msg = $this->adder($id, $sl) . "\n" . Html::rawElement('div', array('class' => 'mw-translate-edit-deftext', 'dir' => $sl->getDir(), 'lang' => $sl->getCode()), TranslateUtils::convertWhiteSpaceToHTML($en));
     $msg .= $this->wrapInsert($id, $en);
     $class = array('class' => 'mw-sp-translate-edit-definition mw-translate-edit-definition');
     return TranslateUtils::fieldset($label, $msg, $class);
 }
 /**
  * Actually creates the table for single message group, unless it
  * is blacklisted or hidden by filters.
  * @param MessageGroup $group
  * @param array $cache
  * @param MessageGroup $parent
  * @return string
  */
 protected function makeGroupRow(MessageGroup $group, array $cache, MessageGroup $parent = null)
 {
     $groupId = $group->getId();
     if ($this->table->isBlacklisted($groupId, $this->target) !== null) {
         return '';
     }
     $stats = $cache[$groupId];
     $total = $stats[MessageGroupStats::TOTAL];
     $translated = $stats[MessageGroupStats::TRANSLATED];
     $fuzzy = $stats[MessageGroupStats::FUZZY];
     // Quick checks to see whether filters apply
     if ($this->noComplete && $fuzzy === 0 && $translated === $total) {
         return '';
     }
     if ($this->noEmpty && $translated === 0 && $fuzzy === 0) {
         return '';
     }
     // Calculation of summary row values
     if (!$group instanceof AggregateMessageGroup) {
         if (!isset($this->statsCounted[$groupId])) {
             $this->totals = MessageGroupStats::multiAdd($this->totals, $stats);
             $this->statsCounted[$groupId] = true;
         }
     }
     $state = $this->getWorkflowStateValue($groupId);
     $params = $stats;
     $params[] = $state;
     $params[] = $groupId;
     $params[] = $this->getLanguage()->getCode();
     $params[] = $this->target;
     $cachekey = wfMemcKey(__METHOD__, implode('-', $params));
     $cacheval = wfGetCache(CACHE_ANYTHING)->get($cachekey);
     if (!$this->purge && is_string($cacheval)) {
         return $cacheval;
     }
     $extra = array();
     if ($total === null) {
         $this->incomplete = true;
     } elseif ($translated === $total) {
         $extra = array('action' => 'proofread');
     }
     $rowParams = array();
     $rowParams['data-groupid'] = $groupId;
     $rowParams['class'] = get_class($group);
     if ($parent) {
         $rowParams['data-parentgroup'] = $parent->getId();
     }
     $out = "\t" . Html::openElement('tr', $rowParams);
     $out .= "\n\t\t" . Html::rawElement('td', array(), $this->table->makeGroupLink($group, $this->target, $extra));
     $out .= $this->table->makeNumberColumns($stats);
     $out .= $this->getWorkflowStateCell($groupId, $state);
     $out .= "\n\t" . Html::closeElement('tr') . "\n";
     wfGetCache(CACHE_ANYTHING)->set($cachekey, $out, 3600 * 24);
     return $out;
 }
Exemple #9
0
 /**
  * Returns the message groups this message group is part of.
  * @since 2011-12-25
  * @return array
  */
 public static function getParentGroups(MessageGroup $group)
 {
     // Take the first message, get a handle for it and check
     // if that message belongs to other groups. Those are the
     // parent aggregate groups. Ideally we loop over all keys,
     // but this should be enough.
     $keys = array_keys($group->getDefinitions());
     $title = Title::makeTitle($group->getNamespace(), $keys[0]);
     $handle = new MessageHandle($title);
     $ids = $handle->getGroupIds();
     foreach ($ids as $index => $id) {
         if ($id === $group->getId()) {
             unset($ids[$index]);
         }
     }
     return $ids;
 }
	public function __construct( MessageCollection $collection, MessageGroup $group ) {
		$this->collection = $collection;
		$this->group = $group;
		$this->setHeaderText( 'table', $group->getLabel() );
		$this->appendEditLinkParams( 'loadgroup', $group->getId() );
	}
 protected function setup($parameters)
 {
     $request = $this->getRequest();
     $isBeta = self::isBeta($request);
     $defaults = array('taction' => 'translate', 'task' => $isBeta ? 'custom' : 'untranslated', 'language' => $this->getLanguage()->getCode(), 'group' => $isBeta ? '!additions' : '', 'offset' => '', 'limit' => $isBeta ? 0 : 100, 'optional' => '0');
     // Dump everything here
     $nondefaults = array();
     $parameters = array_map('trim', explode(';', $parameters));
     $pars = array();
     foreach ($parameters as $_) {
         if ($_ === '') {
             continue;
         }
         if (strpos($_, '=') !== false) {
             list($key, $value) = array_map('trim', explode('=', $_, 2));
         } else {
             $key = 'group';
             $value = $_;
         }
         $pars[$key] = $value;
     }
     foreach ($defaults as $v => $t) {
         if (is_bool($t)) {
             $r = isset($pars[$v]) ? (bool) $pars[$v] : $defaults[$v];
             $r = $request->getBool($v, $r);
         } elseif (is_int($t)) {
             $r = isset($pars[$v]) ? (int) $pars[$v] : $defaults[$v];
             $r = $request->getInt($v, $r);
         } elseif (is_string($t)) {
             $r = isset($pars[$v]) ? (string) $pars[$v] : $defaults[$v];
             $r = $request->getText($v, $r);
         }
         if (!isset($r)) {
             throw new MWException('$r was not set');
         }
         wfAppendToArrayIfNotDefault($v, $r, $defaults, $nondefaults);
     }
     // Fix defaults based on what we got
     if (isset($nondefaults['taction'])) {
         if ($nondefaults['taction'] === 'proofread') {
             if ($this->getUser()->isAllowed('translate-messagereview')) {
                 $defaults['task'] = 'acceptqueue';
             } else {
                 $defaults['task'] = 'reviewall';
             }
         } elseif ($nondefaults['taction'] === 'export') {
             $defaults['task'] = '';
         }
     }
     if ($isBeta) {
         /* @todo fix all the places in Translate to create correct links.
          * The least effort way is to change them once we totally drop the
          * old UI. The penalty is only http redirect in some cases. More
          * effort would be to create utilities like makeTranslationLink
          * and makeProofreadLink.
          */
         $this->rewriteLegacyUrls($nondefaults);
     }
     $this->defaults = $defaults;
     $this->nondefaults = $nondefaults;
     Hooks::run('TranslateGetSpecialTranslateOptions', array(&$defaults, &$nondefaults));
     $this->options = $nondefaults + $defaults;
     $this->group = MessageGroups::getGroup($this->options['group']);
     if ($this->group) {
         $this->options['group'] = $this->group->getId();
     }
     $this->task = TranslateTasks::getTask($this->options['task']);
     if ($this->group && MessageGroups::isDynamic($this->group)) {
         $this->group->setLanguage($this->options['language']);
     }
 }
 /**
  * @param MessageGroup $group
  * @param string $code
  * @param string $type
  * @param array $params
  * @param int $limit
  * @return string HTML
  */
 protected function formatChange(MessageGroup $group, $code, $type, $params, &$limit)
 {
     $key = $params['key'];
     $title = Title::makeTitleSafe($group->getNamespace(), "{$key}/{$code}");
     $id = self::changeId($group->getId(), $code, $type, $key);
     if ($title && $title->exists() && $type === 'addition') {
         // The message has for some reason dropped out from cache
         // or perhaps it is being reused. In any case treat it
         // as a change for display, so the admin can see if
         // action is needed and let the message be processed.
         // Otherwise it will end up in the postponed category
         // forever and will prevent rebuilding the cache, which
         // leads to many other annoying problems.
         $type = 'change';
     } elseif ($title && !$title->exists() && ($type === 'deletion' || $type === 'change')) {
         return '';
     }
     $text = '';
     if ($type === 'deletion') {
         $wiki = ContentHandler::getContentText(Revision::newFromTitle($title)->getContent());
         $oldContent = ContentHandler::makeContent($wiki, $title);
         $newContent = ContentHandler::makeContent('', $title);
         $this->diff->setContent($oldContent, $newContent);
         $text = $this->diff->getDiff(Linker::link($title), '');
     } elseif ($type === 'addition') {
         $oldContent = ContentHandler::makeContent('', $title);
         $newContent = ContentHandler::makeContent($params['content'], $title);
         $this->diff->setContent($oldContent, $newContent);
         $text = $this->diff->getDiff('', Linker::link($title));
     } elseif ($type === 'change') {
         $wiki = ContentHandler::getContentText(Revision::newFromTitle($title)->getContent());
         $handle = new MessageHandle($title);
         if ($handle->isFuzzy()) {
             $wiki = '!!FUZZY!!' . str_replace(TRANSLATE_FUZZY, '', $wiki);
         }
         $label = $this->msg('translate-manage-action-ignore')->text();
         $actions = Xml::checkLabel($label, "i/{$id}", "i/{$id}");
         $limit--;
         if ($group->getSourceLanguage() === $code) {
             $label = $this->msg('translate-manage-action-fuzzy')->text();
             $actions .= ' ' . Xml::checkLabel($label, "f/{$id}", "f/{$id}", true);
             $limit--;
         }
         $oldContent = ContentHandler::makeContent($wiki, $title);
         $newContent = ContentHandler::makeContent($params['content'], $title);
         $this->diff->setContent($oldContent, $newContent);
         $text .= $this->diff->getDiff(Linker::link($title), $actions);
     }
     $hidden = Html::hidden($id, 1);
     $limit--;
     $text .= $hidden;
     $classes = "mw-translate-smg-change smg-change-{$type}";
     if ($limit < 0) {
         // Don't add if one of the fields might get dropped of at submission
         return '';
     }
     return Html::rawElement('div', array('class' => $classes), $text);
 }
 protected function exportGroup(MessageGroup $group, $config)
 {
     $server = TTMServer::factory($config);
     $server->setLogger($this);
     $id = $group->getId();
     $sourceLanguage = $group->getSourceLanguage();
     $stats = MessageGroupStats::forGroup($id);
     $collection = $group->initCollection($sourceLanguage);
     $collection->filter('ignored');
     $collection->initMessages();
     $server->beginBatch();
     $inserts = array();
     foreach ($collection->keys() as $mkey => $title) {
         $handle = new MessageHandle($title);
         $inserts[] = array($handle, $sourceLanguage, $collection[$mkey]->definition());
     }
     while ($inserts !== array()) {
         $batch = array_splice($inserts, 0, $this->mBatchSize);
         $server->batchInsertDefinitions($batch);
     }
     $inserts = array();
     foreach ($stats as $targetLanguage => $numbers) {
         if ($targetLanguage === $sourceLanguage) {
             continue;
         }
         if ($numbers[MessageGroupStats::TRANSLATED] === 0) {
             continue;
         }
         $collection->resetForNewLanguage($targetLanguage);
         $collection->filter('ignored');
         $collection->filter('translated', false);
         $collection->loadTranslations();
         foreach ($collection->keys() as $mkey => $title) {
             $handle = new MessageHandle($title);
             $inserts[] = array($handle, $sourceLanguage, $collection[$mkey]->translation());
         }
         while (count($inserts) >= $this->mBatchSize) {
             $batch = array_splice($inserts, 0, $this->mBatchSize);
             $server->batchInsertTranslations($batch);
         }
     }
     while ($inserts !== array()) {
         $batch = array_splice($inserts, 0, $this->mBatchSize);
         $server->batchInsertTranslations($batch);
     }
     $server->endBatch();
 }
 /**
  * Returns full path the the cache file.
  * @return string
  */
 protected function getCacheFileName()
 {
     return TranslateUtils::cacheFile("translate_groupcache-{$this->group->getId()}-{$this->code}.cdb");
 }
	protected static function expandAggregates( MessageGroup $group ) {
		$flattened = array( $group->getId() );
		if ( $group instanceof AggregateMessageGroup ) {
			foreach ( $group->getGroups() as $subgroup ) {
				$flattened = array_merge( $flattened, self::expandAggregates( $subgroup ) );
			}
		}
		return $flattened;
	}
 /**
  * Returns full path to the old cache file location.
  * @return string
  */
 protected function getOldCacheFileName()
 {
     $cacheFileName = "translate_groupcache-{$this->group->getId()}-{$this->code}.cdb";
     return TranslateUtils::cacheFile($cacheFileName);
 }
 /**
  * @param array[] $stats
  * @param MessageGroup $group
  * @param string $code Language code
  *
  * @return null[]|int[]
  */
 protected static function forItemInternal(&$stats, $group, $code)
 {
     $id = $group->getId();
     if (self::$timeStart !== null && microtime(true) - self::$timeStart > self::$limit) {
         return $stats[$id][$code] = self::getUnknownStats();
     }
     if ($group instanceof AggregateMessageGroup) {
         $aggregates = self::getEmptyStats();
         $expanded = self::expandAggregates($group);
         if ($expanded === array()) {
             return $aggregates;
         }
         $res = self::selectRowsIdLang(array_keys($expanded), $code);
         $stats = self::extractResults($res, $stats);
         foreach ($expanded as $sid => $subgroup) {
             # Discouraged groups may belong to another group, usually if there
             # is an aggregate group for all translatable pages. In that case
             # calculate and store the statistics, but don't count them as part of
             # the aggregate group, so that the numbers in Special:LanguageStats
             # add up. The statistics for discouraged groups can still be viewed
             # through Special:MessageGroupStats.
             if (!isset($stats[$sid][$code])) {
                 $stats[$sid][$code] = self::forItemInternal($stats, $subgroup, $code);
             }
             $include = Hooks::run('Translate:MessageGroupStats:isIncluded', array($sid, $code));
             if ($include) {
                 $aggregates = self::multiAdd($aggregates, $stats[$sid][$code]);
             }
         }
         $stats[$id][$code] = $aggregates;
     } else {
         $aggregates = self::calculateGroup($group, $code);
     }
     // Don't add nulls to the database, causes annoying warnings
     if ($aggregates[self::TOTAL] === null) {
         return $aggregates;
     }
     self::$updates[] = array('tgs_group' => $id, 'tgs_lang' => $code, 'tgs_total' => $aggregates[self::TOTAL], 'tgs_translated' => $aggregates[self::TRANSLATED], 'tgs_fuzzy' => $aggregates[self::FUZZY], 'tgs_proofread' => $aggregates[self::PROOFREAD]);
     return $aggregates;
 }
 protected function exportGroup(MessageGroup $group, $multi = false)
 {
     // Make sure all existing connections are dead,
     // we can't use them in forked children.
     LBFactory::destroyInstance();
     $server = TTMServer::primary();
     $id = $group->getId();
     $sourceLanguage = $group->getSourceLanguage();
     if ($multi) {
         $stats = MessageGroupStats::forGroup($id);
         $this->statusLine("Loaded stats for {$id}\n");
     } else {
         $this->statusLine("Loading stats... ", 4);
         $stats = MessageGroupStats::forGroup($id);
         $this->output("done!", 4);
         $this->statusLine("Inserting sources: ", 5);
     }
     $collection = $group->initCollection($sourceLanguage);
     $collection->filter('ignored');
     $collection->filter('optional');
     $collection->initMessages();
     $sids = array();
     $counter = 0;
     foreach ($collection->keys() as $mkey => $title) {
         $def = $collection[$mkey]->definition();
         $sids[$mkey] = $server->insertSource($title, $sourceLanguage, $def);
         if (++$counter % $this->mBatchSize === 0 && !$multi) {
             wfWaitForSlaves(10);
             $this->output('.', 5);
         }
     }
     $total = count($sids);
     if ($multi) {
         $this->statusLine("Inserted {$total} source entries for {$id}\n");
     } else {
         $this->output("{$total} entries", 5);
         $this->statusLine("Inserting translations...", 6);
     }
     $dbw = $server->getDB(DB_MASTER);
     foreach ($stats as $targetLanguage => $numbers) {
         if ($targetLanguage === $sourceLanguage) {
             continue;
         }
         if ($numbers[MessageGroupStats::TRANSLATED] === 0) {
             continue;
         }
         if (!$multi) {
             $this->output(sprintf("%19s  ", $targetLanguage), $targetLanguage);
         }
         $collection->resetForNewLanguage($targetLanguage);
         $collection->filter('ignored');
         $collection->filter('optional');
         $collection->filter('translated', false);
         $collection->loadTranslations();
         $inserts = array();
         foreach ($collection->keys() as $mkey => $title) {
             $inserts[] = array('tmt_sid' => $sids[$mkey], 'tmt_lang' => $targetLanguage, 'tmt_text' => $collection[$mkey]->translation());
         }
         do {
             $batch = array_splice($inserts, 0, $this->mBatchSize);
             $dbw->insert('translate_tmt', $batch, __METHOD__);
             if (!$multi) {
                 $this->output('.', $targetLanguage);
             }
             wfWaitForSlaves(10);
         } while (count($inserts));
     }
     if ($multi) {
         $this->statusLine("Inserted translations for {$id}\n");
     }
 }
 /**
  * @param MessageGroup $group
  * @param string $prefix
  * @return string
  */
 protected function htmlIdForGroup(MessageGroup $group, $prefix = '')
 {
     $id = sha1($group->getId());
     $id = substr($id, 5, 8);
     return $prefix . $id;
 }
	/**
	 * Gets the description of a group. This is a bit slow thing to do for
	 * thousand+ groups, so some caching is involved.
	 * @param $group MessageGroup
	 * @return string Plain text
	 */
	public function getGroupDescription( MessageGroup $group ) {
		$code = $this->lang->getCode();

		$cache = wfGetCache( CACHE_ANYTHING );
		$key = wfMemckey( "translate-groupdesc-$code-" . $group->getId() );
		$desc = $cache->get( $key );
		if ( is_string( $desc ) ) {
			return $desc;
		}

		$realFunction = array( 'MessageCache', 'singleton' );
		if ( is_callable( $realFunction ) ) {
			$mc = MessageCache::singleton();
		} else {
			global $wgMessageCache;
			$mc = $wgMessageCache;
		}
		$desc = $mc->transform( $group->getDescription(), true, $this->lang );
		$cache->set( $key, $desc );
		return $desc;
	}