protected function getData()
 {
     $params = $this->extractRequestParams();
     $group = MessageGroups::getGroup($params['group']);
     if (!$group) {
         $this->dieUsageMsg(array('missingparam', 'mcgroup'));
     } elseif (MessageGroups::isDynamic($group)) {
         $this->dieUsage('Dynamic message groups are not supported here', 'invalidparam');
     }
     return MessageGroupStats::forGroup($group->getId());
 }
 /**
  * @param string $group
  * @param string $language
  * @param array[]|null $stats
  *
  * @return self
  */
 public static function getNew($group, $language, array $stats = null)
 {
     $self = new self();
     $self->group = $group;
     $self->language = $language;
     if (is_array($stats)) {
         $self->stats = $stats;
     } else {
         $self->stats = MessageGroupStats::forItem($group, $language);
     }
     return $self;
 }
 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 execute()
 {
     $params = $this->extractRequestParams();
     MessageGroupStats::setTimeLimit($params['timelimit']);
     $cache = $this->getData();
     $result = $this->getResult();
     foreach ($cache as $item => $stats) {
         if ($item < $params['offset']) {
             continue;
         }
         if ($stats[MessageGroupStats::TOTAL] === null) {
             $this->setContinueEnumParameter('offset', $item);
             break;
         }
         $data = $this->makeItem($item, $stats);
         $result->addValue(array('query', $this->getModuleName()), null, $data);
     }
     if (defined('ApiResult::META_CONTENT')) {
         $result->addIndexedTagName(array('query', $this->getModuleName()), 'stats');
     } else {
         $result->setIndexedTagName_internal(array('query', $this->getModuleName()), 'stats');
     }
 }
 public function execute()
 {
     $params = $this->extractRequestParams();
     $group = MessageGroups::getGroup($params['group']);
     if (!$group) {
         $this->dieUsageMsg(array('missingparam', 'mcgroup'));
     }
     MessageGroupStats::setTimeLimit($params['timelimit']);
     $cache = MessageGroupStats::forGroup($group->getId());
     $result = $this->getResult();
     foreach ($cache as $code => $stats) {
         if ($code < $params['offset']) {
             continue;
         }
         list($total, $translated, $fuzzy) = $stats;
         if ($total === null) {
             $this->setContinueEnumParameter('offset', $code);
             break;
         }
         $data = array('code' => $code, 'total' => $total, 'translated' => $translated, 'fuzzy' => $fuzzy);
         $result->addValue(array('query', $this->getModuleName()), null, $data);
     }
     $result->setIndexedTagName_internal(array('query', $this->getModuleName()), 'messagegroupstats');
 }
 protected function getData()
 {
     $params = $this->extractRequestParams();
     return MessageGroupStats::forLanguage($params['language']);
 }
Ejemplo n.º 7
0
    // Add matching groups to groups array.
    foreach ($allGroups as $groupId => $messageGroup) {
        if (strpos($groupId, $options['groupprefix']) === 0 && !$messageGroup->isMeta()) {
            $groups[$groupId] = $messageGroup;
        }
    }
}
foreach ($groups as $groupId => $group) {
    if (!$group instanceof MessageGroup) {
        STDERR("Invalid group: " . $groupId);
        exit(1);
    }
    STDERR('Exporting ' . $groupId);
    $langs = $reqLangs;
    if ($threshold) {
        $stats = MessageGroupStats::forGroup($groupId);
        foreach ($langs as $index => $code) {
            if (!isset($stats[$code])) {
                unset($langs[$index]);
            }
            list($total, $translated, ) = $stats[$code];
            if ($translated / $total * 100 < $threshold) {
                unset($langs[$index]);
            }
        }
    }
    if ($group instanceof FileBasedMessageGroup) {
        $ffs = $group->getFFS();
        $ffs->setWritePath($options['target']);
        $collection = $group->initCollection('en');
        $definitionFile = false;
 public function execute()
 {
     $output = $this->getOption('output', 'default');
     // Select an output engine
     switch ($output) {
         case 'wiki':
             $out = new WikiStatsOutput();
             break;
         case 'text':
             $out = new TextStatsOutput();
             break;
         case 'csv':
             $out = new CsvStatsOutput();
             break;
         default:
             $out = new TranslateStatsOutput();
     }
     $skipLanguages = array();
     if ($this->hasOption('skiplanguages')) {
         $skipLanguages = array_map('trim', explode(',', $this->getOption('skiplanguages')));
     }
     $reportScore = false;
     // Check if score should be reported and prepare weights
     $most = $this->getOption('most');
     $weights = array();
     if ($most && isset($this->localisedWeights[$most])) {
         $reportScore = true;
         foreach ($this->localisedWeights[$most] as $weight) {
             $weights[] = $weight;
         }
     }
     // check if l10n should be done
     $l10n = false;
     if (($output === 'wiki' || $output === 'default') && !$this->hasOption('nol10n')) {
         $l10n = true;
     }
     $wmfscore = $this->hasOption('wmfscore');
     // Get groups from input
     $groups = array();
     if ($reportScore) {
         $reqGroups = array_keys($this->localisedWeights[$most]);
     } elseif ($wmfscore) {
         $reqGroups = array_keys($this->localisedWeights['wikimedia']);
     } else {
         $reqGroups = array_map('trim', explode(',', $this->getOption('groups')));
     }
     // List of all groups
     $allGroups = MessageGroups::singleton()->getGroups();
     // Get list of valid groups
     foreach ($reqGroups as $id) {
         // Page translation group ids use spaces which are not nice on command line
         $id = str_replace('_', ' ', $id);
         if (isset($allGroups[$id])) {
             $groups[$id] = $allGroups[$id];
         } else {
             $this->output("Unknown group: {$id}");
         }
     }
     if ($wmfscore) {
         // Override/set parameters
         $out = new CsvStatsOutput();
         $reportScore = true;
         $weights = array();
         foreach ($this->localisedWeights['wikimedia'] as $weight) {
             $weights[] = $weight;
         }
         $wmfscores = array();
     }
     if (!count($groups)) {
         $this->error('No groups given', true);
     }
     // List of all languages.
     $languages = Language::fetchLanguageNames(false);
     // Default sorting order by language code, users can sort wiki output.
     ksort($languages);
     if ($this->hasOption('legenddetail')) {
         $out->addFreeText("{{" . $this->getOption('legenddetail') . "}}\n");
     }
     $totalWeight = 0;
     if ($reportScore) {
         if ($wmfscore) {
             foreach ($this->localisedWeights['wikimedia'] as $weight) {
                 $totalWeight += $weight;
             }
         } else {
             foreach ($this->localisedWeights[$most] as $weight) {
                 $totalWeight += $weight;
             }
         }
     }
     $showContinent = $this->getOption('continent');
     if (!$wmfscore) {
         // Output headers
         $out->heading();
         $out->blockstart();
         if ($most) {
             $out->element($l10n ? "{{int:translate-gs-pos}}" : 'Pos.', true);
         }
         $out->element($l10n ? "{{int:translate-gs-code}}" : 'Code', true);
         $out->element($l10n ? "{{int:translate-page-language}}" : 'Language', true);
         if ($showContinent) {
             $out->element($l10n ? "{{int:translate-gs-continent}}" : 'Continent', true);
         }
         if ($most && $this->hasOption('speakers')) {
             $out->element($l10n ? "{{int:translate-gs-speakers}}" : 'Speakers', true);
         }
         if ($reportScore) {
             $out->element(($l10n ? "{{int:translate-gs-score}}" : 'Score') . ' (' . $totalWeight . ')', true);
         }
         /**
          * @var $g MessageGroup
          */
         foreach ($groups as $g) {
             // Add unprocessed description of group as heading
             if ($reportScore) {
                 $gid = $g->getId();
                 $heading = $g->getLabel() . " (" . $this->localisedWeights[$most][$gid] . ")";
             } else {
                 $heading = $g->getLabel();
             }
             $out->element($heading, true);
             if (!$reportScore && $this->hasOption('fuzzy')) {
                 $out->element($l10n ? "{{int:translate-percentage-fuzzy}}" : 'Fuzzy', true);
             }
         }
         $out->blockend();
     }
     $rows = array();
     foreach ($languages as $code => $name) {
         // Skip list
         if (in_array($code, $skipLanguages)) {
             continue;
         }
         $rows[$code] = array();
     }
     foreach ($groups as $groupName => $g) {
         $stats = MessageGroupStats::forGroup($groupName);
         // Perform the statistic calculations on every language
         foreach ($languages as $code => $name) {
             // Skip list
             if (!$most && in_array($code, $skipLanguages)) {
                 continue;
             }
             // Do not calculate if we do not need it for anything.
             if ($wmfscore && isset($this->wikimediaCodeMap[$code]) && $this->wikimediaCodeMap[$code] == '') {
                 continue;
             }
             // If --most is set, skip all other
             if ($most && !isset($this->mostSpokenLanguages[$code])) {
                 continue;
             }
             $total = $stats[$code][MessageGroupStats::TOTAL];
             $translated = $stats[$code][MessageGroupStats::TRANSLATED];
             $fuzzy = $stats[$code][MessageGroupStats::FUZZY];
             $rows[$code][] = array(false, $translated, $total);
             if ($this->hasOption('fuzzy')) {
                 $rows[$code][] = array(true, $fuzzy, $total);
             }
         }
         unset($collection);
     }
     // init summary array
     $summarise = false;
     if ($this->hasOption('summary')) {
         $summarise = true;
         $summary = array();
     }
     foreach ($languages as $code => $name) {
         // Skip list
         if (!$most && in_array($code, $skipLanguages)) {
             continue;
         }
         // Skip unneeded
         if ($wmfscore && isset($this->wikimediaCodeMap[$code]) && $this->wikimediaCodeMap[$code] == '') {
             continue;
         }
         // If --most is set, skip all other
         if ($most && !isset($this->mostSpokenLanguages[$code])) {
             continue;
         }
         $columns = $rows[$code];
         $allZero = true;
         foreach ($columns as $fields) {
             if (intval($fields[1]) !== 0) {
                 $allZero = false;
             }
         }
         // Skip dummy languages if requested
         if ($allZero && $this->hasOption('skipzero')) {
             continue;
         }
         // Output the the row
         if (!$wmfscore) {
             $out->blockstart();
         }
         // Fill language position field
         if ($most) {
             $out->element($this->mostSpokenLanguages[$code][0]);
         }
         // Fill language name field
         if (!$wmfscore) {
             // Fill language code field
             $out->element($code);
             if ($l10n && function_exists('efI18nTagsInit')) {
                 $out->element("{{#languagename:" . $code . "}}");
             } else {
                 $out->element($name);
             }
         }
         // Fill continent field
         if ($showContinent) {
             if ($this->mostSpokenLanguages[$code][2] == 'multiple') {
                 $continent = $l10n ? "{{int:translate-gs-multiple}}" : 'Multiple';
             } else {
                 $continent = $l10n ? "{{int:timezoneregion-" . $this->mostSpokenLanguages[$code][2] . "}}" : ucfirst($this->mostSpokenLanguages[$code][2]);
             }
             $out->element($continent);
         }
         // Fill speakers field
         if ($most && $this->hasOption('speakers')) {
             $out->element(number_format($this->mostSpokenLanguages[$code][1]));
         }
         // Fill the score field
         if ($reportScore) {
             // Keep count
             $i = 0;
             // Start with 0 points
             $score = 0;
             foreach ($columns as $fields) {
                 list(, $upper, $total) = $fields;
                 // Weigh the score and add it to the current score
                 $score += $weights[$i] * $upper / $total;
                 $i++;
             }
             // Report a round numbers
             $score = number_format($score, 0);
             if ($summarise) {
                 $continent = $this->mostSpokenLanguages[$code][2];
                 if (isset($summary[$continent])) {
                     $newcount = $summary[$continent][0] + 1;
                     $newscore = $summary[$continent][1] + (int) $score;
                 } else {
                     $newcount = 1;
                     $newscore = $score;
                 }
                 $summary[$continent] = array($newcount, $newscore);
             }
             if ($wmfscore) {
                 // Multiple variants can be used for the same wiki.
                 // Store the scores in an array and output them later
                 // when they can be averaged.
                 if (isset($this->wikimediaCodeMap[$code])) {
                     $wmfcode = $this->wikimediaCodeMap[$code];
                 } else {
                     $codeparts = explode('-', $code);
                     $wmfcode = $codeparts[0];
                 }
                 if (isset($wmfscores[$wmfcode])) {
                     $count = $wmfscores[$wmfcode]['count'] + 1;
                     $tmpWmfScore = (int) $wmfscores[$wmfcode]['score'];
                     $tmpWmfCount = (int) $wmfscores[$wmfcode]['count'];
                     $score = ($tmpWmfCount * $tmpWmfScore + (int) $score) / $count;
                     $wmfscores[$wmfcode] = array('score' => $score, 'count' => $count);
                 } else {
                     $wmfscores[$wmfcode] = array('score' => $score, 'count' => 1);
                 }
             } else {
                 $out->element($score);
             }
         }
         // Fill fields for groups
         if (!$wmfscore) {
             foreach ($columns as $fields) {
                 list($invert, $upper, $total) = $fields;
                 $c = $out->formatPercent($upper, $total, $invert);
                 $out->element($c);
             }
             $out->blockend();
         }
     }
     $out->footer();
     if ($reportScore && $this->hasOption('summary')) {
         if ($reportScore && $this->hasOption('legendsummary')) {
             $out->addFreeText("{{" . $this->getOption('legendsummary') . "}}\n");
         }
         $out->summaryheading();
         $out->blockstart();
         $out->element($l10n ? "{{int:translate-gs-continent}}" : 'Continent', true);
         $out->element($l10n ? "{{int:translate-gs-count}}" : 'Count', true);
         $out->element($l10n ? "{{int:translate-gs-avgscore}}" : 'Avg. score', true);
         $out->blockend();
         ksort($summary);
         $totals = array(0, 0);
         foreach ($summary as $key => $values) {
             $out->blockstart();
             if ($key == 'multiple') {
                 $out->element($l10n ? "{{int:translate-gs-multiple}}" : 'Multiple');
             } else {
                 $out->element($l10n ? "{{int:timezoneregion-" . $key . "}}" : ucfirst($key));
             }
             $out->element($values[0]);
             $out->element(number_format($values[1] / $values[0]));
             $out->blockend();
             $totals[0] += $values[0];
             $totals[1] += $values[1];
         }
         $out->blockstart();
         $out->element($l10n ? "{{int:translate-gs-total}}" : 'Total');
         $out->element($totals[0]);
         $out->element(number_format($totals[1] / $totals[0]));
         $out->blockend();
         $out->footer();
     }
     // Custom output
     if ($wmfscore) {
         ksort($wmfscores);
         foreach ($wmfscores as $code => $stats) {
             echo $code . ';' . number_format($stats['score']) . ";\n";
         }
     }
 }
	/**
	 * @param $group
	 * @param $cache
	 * @param $parent bool
	 * @return string
	 */
	protected function makeGroupRow( $group, $cache, $parent = false ) {
		$groupId = $group->getId();

		if ( $this->table->isBlacklisted( $groupId, $this->target ) !== null ) {
			return '';
		}

		# These are hidden, and the code in MessageGroupStats makes sure that
		# these are not counted in the aggregate groups they may belong.
		if ( MessageGroups::getPriority( $group ) === 'discouraged' ) {
			return '';
		}

		$stats = $cache[$groupId];

		list( $total, $translated, $fuzzy ) = $stats;
		if ( $total === null ) {
			$this->incomplete = true;
			$extra = array();
		} else {
			if ( $this->noComplete && $fuzzy === 0 && $translated === $total ) {
				return '';
			}

			if ( $this->noEmpty && $translated === 0 && $fuzzy === 0 ) {
				return '';
			}

			if ( $translated === $total ) {
				$extra = array( 'task' => 'reviewall' );
			} else {
				$extra = array();
			}
		}

		if ( !$group instanceof AggregateMessageGroup ) {
			$this->totals = MessageGroupStats::multiAdd( $this->totals, $stats );
		}

		$rowParams = array();
		$rowParams['data-groupid'] = $groupId;
		if ( is_string( $parent ) ) {
			$rowParams['data-parentgroups'] = $parent;
		} elseif ( $parent === true ) {
			$rowParams['data-ismeta'] = '1';
		}

		$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( $fuzzy, $translated, $total );
		$out .= $this->getWorkflowStateCell( $groupId );

		$out .= "\n\t" . Html::closeElement( 'tr' ) . "\n";
		return $out;
	}
 /**
  *
  * @return array
  */
 public function getTranslationPercentages()
 {
     // Calculate percentages for the available translations
     $group = $this->getMessageGroup();
     if (!$group instanceof WikiPageMessageGroup) {
         return array();
     }
     $titles = $this->getTranslationPages();
     $temp = MessageGroupStats::forGroup($this->getMessageGroupId());
     $stats = array();
     foreach ($titles as $t) {
         $handle = new MessageHandle($t);
         $code = $handle->getCode();
         // Sometimes we want to display 0.00 for pages for which translation
         // hasn't started yet.
         $stats[$code] = 0.0;
         if (isset($temp[$code]) && $temp[$code][MessageGroupStats::TOTAL] > 0) {
             $total = $temp[$code][MessageGroupStats::TOTAL];
             $translated = $temp[$code][MessageGroupStats::TRANSLATED];
             $percentage = $translated / $total;
             $stats[$code] = sprintf('%.2f', $percentage);
         }
     }
     // Content language is always up-to-date
     $stats[$this->getSourceLanguageCode()] = 1.0;
     return $stats;
 }
 /**
  * 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;
 }
			$out->element( ( $l10n ? "{{int:translate-percentage-fuzzy}}" : 'Fuzzy' ), true );
		}
	}

	$out->blockend();
}

$rows = array();
foreach ( $languages as $code => $name ) {
	// Skip list
	if ( in_array( $code, $skipLanguages ) ) continue;
	$rows[$code] = array();
}

foreach ( $groups as $groupName => $g ) {
	$stats = MessageGroupStats::forGroup( $groupName );

	// Perform the statistic calculations on every language
	foreach ( $languages as $code => $name ) {
		// Skip list
		if ( !isset( $options['most'] ) && in_array( $code, $skipLanguages ) ) {
			continue;
		}

		// Do not calculate if we do not need it for anything.
		if ( $wmfscore && isset( $wikimediaCodeMap[$code] ) && $wikimediaCodeMap[$code] == '' ) {
			continue;
		}

		// If --most is set, skip all other
		if ( isset( $options['most'] ) && !isset( $mostSpokenLanguages[$code] ) ) {
	/**
	 * Runs message checks, adds tp:transver tags and updates statistics.
	 * Hook: ArticleSaveComplete
	 */
	public static function onSave( $article, $user, $text, $summary,
			$minor, $_, $_, $flags, $revision
	) {
		$title = $article->getTitle();
		$handle = new MessageHandle( $title );

		if ( !$handle->isValid() ) {
			return true;
		}

		// Update it.
		if ( $revision === null ) {
			$rev = $article->getTitle()->getLatestRevId();
		} else {
			$rev = $revision->getID();
		}

		$fuzzy = self::checkNeedsFuzzy( $handle, $text );
		self::updateFuzzyTag( $title, $rev, $fuzzy );
		MessageGroupStats::clear( $handle );

		if ( $fuzzy === false ) {
			wfRunHooks( 'Translate:newTranslation', array( $handle, $rev, $text, $user ) );
		}

		return true;
	}
	/**
	 * Set the maximum time statistics are calculated.
	 * If the time limit is exceeded, the missing
	 * entries will be null.
	 * @param $limit float time in seconds
	 */
	public static function setTimeLimit( $limit ) {
		self::$timeStart = microtime( true );
		self::$limit = $limit;
	}
Ejemplo n.º 15
0
 /**
  * Purge message group stats when set of keys have changed.
  * @param $old array
  * @param $new array
  */
 protected function clearMessageGroupStats(array $old, array $new)
 {
     $changes = array();
     foreach (array_diff_assoc($new, $old) as $groups) {
         foreach ((array) $groups as $group) {
             $changes[$group] = true;
         }
     }
     foreach (array_diff_assoc($old, $new) as $groups) {
         foreach ((array) $groups as $group) {
             $changes[$group] = true;
         }
     }
     MessageGroupStats::clearGroup(array_keys($changes));
 }
 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();
 }
 public function execute($parameters)
 {
     $this->setHeaders();
     $user = $this->getUser();
     $request = $this->getRequest();
     $target = $request->getText('target', $parameters);
     $revision = $request->getInt('revision', 0);
     $action = $request->getVal('do');
     $out = $this->getOutput();
     TranslateUtils::addSpecialHelpLink($out, 'Help:Extension:Translate/Page_translation_example');
     // No specific page or invalid input
     $title = Title::newFromText($target);
     if (!$title) {
         if ($target !== '') {
             $out->addWikiMsg('tpt-badtitle');
         } else {
             $this->listPages();
         }
         return;
     }
     // Check permissions
     if (!$user->isAllowed('pagetranslation')) {
         throw new PermissionsError('pagetranslation');
     }
     // Check permissions
     if ($request->wasPosted() && !$user->matchEditToken($request->getText('token'))) {
         throw new PermissionsError('pagetranslation');
     }
     // We are processing some specific page
     if (!$title->exists()) {
         $out->addWikiMsg('tpt-nosuchpage', $title->getPrefixedText());
         return;
     }
     if ($action === 'discourage' || $action === 'encourage') {
         $id = TranslatablePage::getMessageGroupIdFromTitle($title);
         $current = MessageGroups::getPriority($id);
         if ($action === 'encourage') {
             $new = '';
         } else {
             $new = 'discouraged';
         }
         if ($new !== $current) {
             MessageGroups::setPriority($id, $new);
             $entry = new ManualLogEntry('pagetranslation', $action);
             $entry->setPerformer($user);
             $entry->setTarget($title);
             $logid = $entry->insert();
             $entry->publish($logid);
         }
         $this->listPages();
         $group = MessageGroups::getGroup($id);
         $parents = MessageGroups::getSharedGroups($group);
         MessageGroupStats::clearGroup($parents);
         return;
     }
     if ($action === 'unlink') {
         if (!$request->wasPosted()) {
             $this->showUnlinkConfirmation($title);
             return;
         } else {
             $page = TranslatablePage::newFromTitle($title);
             $content = ContentHandler::makeContent(self::getStrippedSourcePageText($page->getParse()), $title);
             $status = WikiPage::factory($title)->doEditContent($content, $this->msg('tpt-unlink-summary')->inContentLanguage()->text(), EDIT_FORCE_BOT | EDIT_UPDATE);
             if (!$status->isOK()) {
                 $out->wrapWikiMsg('<div class="errorbox">$1</div>', array('tpt-edit-failed', $status->getWikiText()));
                 return;
             }
             $page = TranslatablePage::newFromTitle($title);
             $this->unmarkPage($page, $user);
             $out->wrapWikiMsg('<div class="successbox">$1</div>', array('tpt-unmarked', $title->getPrefixedText()));
             $this->listPages();
             return;
         }
     }
     if ($action === 'unmark') {
         $page = TranslatablePage::newFromTitle($title);
         $this->unmarkPage($page, $user);
         $out->wrapWikiMsg('<div class="successbox">$1</div>', array('tpt-unmarked', $title->getPrefixedText()));
         $this->listPages();
         return;
     }
     if ($revision === 0) {
         // Get the latest revision
         $revision = intval($title->getLatestRevID());
     }
     $page = TranslatablePage::newFromRevision($title, $revision);
     if (!$page instanceof TranslatablePage) {
         $out->wrapWikiMsg('<div class="errorbox">$1</div>', array('tpt-notsuitable', $title->getPrefixedText(), $revision));
         return;
     }
     if ($revision !== intval($title->getLatestRevID())) {
         // We do want to notify the reviewer if the underlying page changes during review
         $target = $title->getFullUrl(array('oldid' => $revision));
         $link = "<span class='plainlinks'>[{$target} {$revision}]</span>";
         $out->wrapWikiMsg('<div class="warningbox">$1</div>', array('tpt-oldrevision', $title->getPrefixedText(), $link));
         $this->listPages();
         return;
     }
     $lastrev = $page->getMarkedTag();
     if ($lastrev !== false && $lastrev === $revision) {
         $out->wrapWikiMsg('<div class="warningbox">$1</div>', array('tpt-already-marked'));
         $this->listPages();
         return;
     }
     // This will modify the sections to include name property
     $error = false;
     $sections = $this->checkInput($page, $error);
     // Non-fatal error which prevents saving
     if ($error === false && $request->wasPosted()) {
         // Check if user wants to translate title
         // If not, remove it from the list of sections
         if (!$request->getCheck('translatetitle')) {
             $sections = array_filter($sections, function ($s) {
                 return $s->id !== 'Page display title';
             });
         }
         $err = $this->markForTranslation($page, $sections);
         if ($err) {
             call_user_func_array(array($out, 'addWikiMsg'), $err);
         } else {
             $this->showSuccess($page);
             $this->listPages();
         }
         return;
     }
     $this->showPage($page, $sections);
 }
 /**
  * @param $code
  * @param $cache
  * @return string
  */
 protected function makeRow($code, $cache)
 {
     $stats = $cache[$code];
     $total = $stats[MessageGroupStats::TOTAL];
     $translated = $stats[MessageGroupStats::TRANSLATED];
     $fuzzy = $stats[MessageGroupStats::FUZZY];
     if ($total === null) {
         $this->incomplete = true;
         $extra = array();
     } else {
         if ($this->noComplete && $fuzzy === 0 && $translated === $total) {
             return '';
         }
         if ($this->noEmpty && $translated === 0 && $fuzzy === 0) {
             return '';
         }
         // Skip below 2% if "don't show without translations" is checked.
         if ($this->noEmpty && $translated / $total < 0.02) {
             return '';
         }
         if ($translated === $total) {
             $extra = array('action' => 'proofread');
         } else {
             $extra = array();
         }
     }
     $this->totals = MessageGroupStats::multiAdd($this->totals, $stats);
     $out = "\t" . Html::openElement('tr');
     $out .= "\n\t\t" . $this->getMainColumnCell($code, $extra);
     $out .= $this->table->makeNumberColumns($stats);
     $state = $this->getWorkflowStateValue($code);
     $out .= $this->getWorkflowStateCell($code, $state);
     $out .= "\n\t" . Html::closeElement('tr') . "\n";
     return $out;
 }
Ejemplo n.º 19
0
 /**
  * @param $code
  * @param $cache
  * @return string
  */
 protected function makeRow($code, $cache)
 {
     $stats = $cache[$code];
     list($total, $translated, $fuzzy) = $stats;
     if ($total === null) {
         $this->incomplete = true;
         $extra = array();
     } else {
         if ($this->noComplete && $fuzzy === 0 && $translated === $total) {
             return '';
         }
         if ($this->noEmpty && $translated === 0 && $fuzzy === 0) {
             return '';
         }
         if ($translated === $total) {
             $extra = array('task' => 'reviewall');
         } else {
             $extra = array();
         }
     }
     $this->totals = MessageGroupStats::multiAdd($this->totals, $stats);
     $out = "\t" . Html::openElement('tr');
     $out .= "\n\t\t" . $this->getMainColumnCell($code, $extra);
     $out .= $this->table->makeNumberColumns($fuzzy, $translated, $total);
     $out .= $this->getWorkflowStateCell($code);
     $out .= "\n\t" . Html::closeElement('tr') . "\n";
     return $out;
 }
Ejemplo n.º 20
0
 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");
     }
 }
 /**
  * Purge message group stats when set of keys have changed.
  * @param array $old
  * @param array $new
  */
 protected function clearMessageGroupStats(array $old, array $new)
 {
     $changes = array();
     foreach ($new as $key => $groups) {
         // Using != here on purpose to ignore order of items
         if (!isset($old[$key])) {
             $changes[$key] = array(array(), (array) $groups);
         } elseif ($groups != $old[$key]) {
             $changes[$key] = array((array) $old[$key], (array) $groups);
         }
     }
     foreach ($old as $key => $groups) {
         if (!isset($new[$key])) {
             $changes[$key] = array((array) $groups, array());
         }
         // We already checked for diffs above
     }
     $changedGroups = array();
     foreach ($changes as $data) {
         foreach ($data[0] as $group) {
             $changedGroups[$group] = true;
         }
         foreach ($data[1] as $group) {
             $changedGroups[$group] = true;
         }
     }
     MessageGroupStats::clearGroup(array_keys($changedGroups));
     foreach ($changes as $key => $data) {
         list($ns, $pagename) = explode(':', $key, 2);
         $title = Title::makeTitle($ns, $pagename);
         $handle = new MessageHandle($title);
         list($oldGroups, $newGroups) = $data;
         Hooks::run('TranslateEventMessageMembershipChange', array($handle, $oldGroups, $newGroups));
     }
 }
 public function execute()
 {
     $target = $this->getOption('target');
     if (!is_writable($target)) {
         $this->error("Target directory is not writable ({$target}).", 1);
     }
     $threshold = $this->getOption('threshold');
     $noFuzzy = $this->hasOption('no-fuzzy');
     $noLocation = '';
     if ($this->hasOption('no-location')) {
         $noLocation = '--no-location ';
     }
     $skip = array();
     if ($this->hasOption('skip')) {
         $skip = array_map('trim', explode(',', $this->getOption('skip')));
     }
     $reqLangs = TranslateUtils::parseLanguageCodes($this->getOption('lang'));
     $reqLangs = array_flip($reqLangs);
     foreach ($skip as $skipLang) {
         unset($reqLangs[$skipLang]);
     }
     $reqLangs = array_flip($reqLangs);
     $codemapOnly = $this->hasOption('codemaponly');
     $groupIds = explode(',', trim($this->getOption('group')));
     $groupIds = MessageGroups::expandWildcards($groupIds);
     $groups = MessageGroups::getGroupsById($groupIds);
     /** @var FileBasedMessageGroup $group */
     foreach ($groups as $groupId => $group) {
         if ($group->isMeta()) {
             $this->output("Skipping meta message group {$groupId}.\n");
             unset($groups[$groupId]);
             continue;
         }
         if (!$group instanceof FileBasedMessageGroup) {
             $this->output("EE2: Unexportable message group {$groupId}.\n");
             unset($groups[$groupId]);
             continue;
         }
     }
     if (!count($groups)) {
         $this->error("EE1: No valid message groups identified.", 1);
     }
     $changeFilter = false;
     $hours = $this->getOption('hours');
     if ($hours) {
         $namespaces = array();
         /** @var FileBasedMessageGroup $group */
         foreach ($groups as $group) {
             $namespaces[$group->getNamespace()] = true;
         }
         $namespaces = array_keys($namespaces);
         $bots = true;
         $changeFilter = array();
         $rows = TranslateUtils::translationChanges($hours, $bots, $namespaces);
         foreach ($rows as $row) {
             $title = Title::makeTitle($row->rc_namespace, $row->rc_title);
             $handle = new MessageHandle($title);
             $code = $handle->getCode();
             if (!$code) {
                 continue;
             }
             $groupIds = $handle->getGroupIds();
             foreach ($groupIds as $groupId) {
                 $changeFilter[$groupId][$code] = true;
             }
         }
     }
     $skipGroups = array();
     if ($this->hasOption('skipgroup')) {
         $skipGroups = array_map('trim', explode(',', $this->getOption('skipgroup')));
     }
     foreach ($groups as $groupId => $group) {
         if (in_array($groupId, $skipGroups)) {
             $this->output("Group {$groupId} is in skipgroup.\n");
             continue;
         }
         // No changes to this group at all
         if (is_array($changeFilter) && !isset($changeFilter[$groupId])) {
             $this->output("No recent changes to {$groupId}.\n");
             continue;
         }
         $langs = $reqLangs;
         if ($codemapOnly) {
             foreach ($langs as $index => $code) {
                 if ($group->mapCode($code) === $code) {
                     unset($langs[$index]);
                 }
             }
         }
         if ($threshold) {
             $stats = MessageGroupStats::forGroup($groupId);
             foreach ($langs as $index => $code) {
                 if (!isset($stats[$code])) {
                     unset($langs[$index]);
                     continue;
                 }
                 $total = $stats[$code][MessageGroupStats::TOTAL];
                 $translated = $stats[$code][MessageGroupStats::TRANSLATED];
                 if ($translated / $total * 100 < $threshold) {
                     unset($langs[$index]);
                 }
             }
         }
         // Filter out unchanged languages from requested languages
         if (is_array($changeFilter)) {
             $langs = array_intersect($langs, array_keys($changeFilter[$groupId]));
         }
         if (!count($langs)) {
             continue;
         }
         $this->output("Exporting {$groupId}...\n");
         $ffs = $group->getFFS();
         $ffs->setWritePath($target);
         $sourceLanguage = $group->getSourceLanguage();
         $collection = $group->initCollection($sourceLanguage);
         $definitionFile = false;
         if ($this->hasOption('ppgettext') && $ffs instanceof GettextFFS) {
             global $wgMaxShellMemory, $wgTranslateGroupRoot;
             // Need more shell memory for msgmerge.
             $wgMaxShellMemory = 402400;
             $path = $group->getSourceFilePath($sourceLanguage);
             $definitionFile = str_replace($wgTranslateGroupRoot, $this->getOption('ppgettext'), $path);
         }
         $whitelist = $group->getTranslatableLanguages();
         foreach ($langs as $lang) {
             // Do not export languges that are blacklisted (or not whitelisted).
             // Also check that whitelist is not null, which means that all
             // languages are allowed for translation and export.
             if (is_array($whitelist) && !isset($whitelist[$lang])) {
                 continue;
             }
             $collection->resetForNewLanguage($lang);
             $collection->loadTranslations();
             // Don't export ignored, unless it is the source language
             // or message documentation
             global $wgTranslateDocumentationLanguageCode;
             if ($lang !== $wgTranslateDocumentationLanguageCode && $lang !== $sourceLanguage) {
                 $collection->filter('ignored');
             }
             if ($noFuzzy) {
                 $collection->filter('fuzzy');
             }
             $ffs->write($collection);
             // Do post processing if requested.
             if ($definitionFile) {
                 if (is_file($definitionFile)) {
                     $targetFileName = $ffs->getWritePath() . "/" . $group->getTargetFilename($collection->code);
                     $cmd = "msgmerge --quiet " . $noLocation . "--output-file=" . $targetFileName . ' ' . $targetFileName . ' ' . $definitionFile;
                     wfShellExec($cmd, $ret);
                     // Report on errors.
                     if ($ret) {
                         $this->error("ERROR: {$ret}");
                     }
                 } else {
                     $this->error("{$definitionFile} does not exist.", 1);
                 }
             }
         }
     }
 }
	public function execute( $parameters ) {
		$this->setHeaders();

		global $wgRequest, $wgOut, $wgUser;
		$this->user = $wgUser;
		$request = $wgRequest;

		$target = $wgRequest->getText( 'target', $parameters );
		$revision = $wgRequest->getInt( 'revision', 0 );
		$action = $request->getVal( 'do' );

		// No specific page or invalid input
		$title = Title::newFromText( $target );
		if ( !$title ) {
			if ( $target !== '' ) {
				$wgOut->addWikiMsg( 'tpt-badtitle' );
			} else {
				$this->listPages();
			}

			return;
		}

		// Check permissions
		if ( !$this->user->isAllowed( 'pagetranslation' ) ) {
			$wgOut->permissionRequired( 'pagetranslation' );
			return;
		}

		// Check permissions
		if ( $wgRequest->wasPosted() && !$this->user->matchEditToken( $wgRequest->getText( 'token' ) ) ) {
			self::superDebug( __METHOD__, "token failure", $this->user );
			$wgOut->permissionRequired( 'pagetranslation' );
			return;
		}

		// We are processing some specific page
		if ( !$title->exists() ) {
			$wgOut->addWikiMsg( 'tpt-nosuchpage', $title->getPrefixedText() );
			return;
		}

		if ( $action === 'discourage' || $action === 'encourage' ) {
			$id = TranslatablePage::getMessageGroupIdFromTitle( $title );
			$dbw = wfGetDB( DB_MASTER );
			$table = 'translate_groupreviews';
			$row = array(
				'tgr_group' => $id,
				'tgr_lang' => '*priority',
				'tgr_state' => 'discouraged',
			);
			if ( $action === 'encourage' ) {
				$dbw->delete( $table, $row, __METHOD__ );
			} else {
				$index = array( 'tgr_group', 'tgr_lang' );
				$dbw->replace( $table, array( $index ), $row, __METHOD__ );
			}
			$this->listPages();

			$group = MessageGroups::getGroup( $id );
			$parents = MessageGroups::getParentGroups( $group );
			MessageGroupStats::clearGroup( $parents );

			return;
		}

		if ( $action === 'unmark' ) {
			$page = TranslatablePage::newFromTitle( $title );
			$page->removeTags();
			$page->getTitle()->invalidateCache();

			$logger = new LogPage( 'pagetranslation' );
			$params = array( 'user' => $wgUser->getName() );
			$logger->addEntry( 'unmark', $page->getTitle(), null, array( serialize( $params ) ) );
			$wgOut->addWikiMsg( 'tpt-unmarked', $title->getPrefixedText() );
			self::superDebug( __METHOD__, "unmarked page", $this->user, $title );
			return;
		}

		if ( $revision === 0 ) {
			// Get the latest revision
			$revision = intval( $title->getLatestRevID() );
		}

		$page = TranslatablePage::newFromRevision( $title, $revision );
		if ( !$page instanceof TranslatablePage ) {
			$wgOut->addWikiMsg( 'tpt-notsuitable', $title->getPrefixedText(), $revision );

			return;
		}

		if ( $revision !== intval( $title->getLatestRevID() ) ) {
			// We do want to notify the reviewer if the underlying page changes during review
			$target = $title->getFullUrl( array( 'oldid' => $revision ) );
			$link = "<span class='plainlinks'>[$target $revision]</span>";
			$wgOut->addWikiMsg( 'tpt-oldrevision', $title->getPrefixedText(), $link );
			self::superDebug( __METHOD__, "revision mismatch while marking", $this->user, $title, $revision, intval( $title->getLatestRevID() ) );
			return;
		}

		$lastrev = $page->getMarkedTag();
		if ( $lastrev !== false && $lastrev === $revision ) {
			$wgOut->addWikiMsg( 'tpt-already-marked' );
			$this->listPages();

			return;
		}

		// This will modify the sections to include name property
		$error = false;
		$sections = $this->checkInput( $page, $error );

		// Non-fatal error which prevents saving
		if ( $error === false && $wgRequest->wasPosted() ) {
			$err = $this->markForTranslation( $page, $sections );
			if ( $err ) {
				call_user_func_array( array( $wgOut, 'addWikiMsg' ), $err );
			} else {
				$this->showSuccess( $page );
				$this->listPages();
			}

			return;
		}

		self::superDebug( __METHOD__, "marking page", $this->user, $title, $revision );
		$this->showPage( $page, $sections );
	}