public function execute() { $groupIds = explode(',', trim($this->getOption('group'))); $groupIds = MessageGroups::expandWildcards($groupIds); $groups = MessageGroups::getGroupsById($groupIds); if (!count($groups)) { $this->error("ESG2: No valid message groups identified.", 1); } $start = $this->getOption('start') ? strtotime($this->getOption('start')) : false; $end = $this->getOption('end') ? strtotime($this->getOption('end')) : false; $this->output("Conflict times: " . wfTimestamp(TS_ISO_8601, $start) . " - " . wfTimestamp(TS_ISO_8601, $end) . "\n"); $codes = array_filter(array_map('trim', explode(',', $this->getOption('lang')))); $supportedCodes = array_keys(TranslateUtils::getLanguageNames('en')); ksort($supportedCodes); if ($codes[0] === '*') { $codes = $supportedCodes; } /** @var FileBasedMessageGroup $group */ foreach ($groups as $groupId => &$group) { if ($group->isMeta()) { $this->output("Skipping meta message group {$groupId}.\n"); continue; } $this->output("{$group->getLabel()} ", $group); foreach ($codes as $code) { // No sync possible for unsupported language codes. if (!in_array($code, $supportedCodes)) { $this->output("Unsupported code " . $code . ": skipping.\n"); continue; } $file = $group->getSourceFilePath($code); if (!$file) { continue; } if (!file_exists($file)) { continue; } $cs = new ChangeSyncer($group, $this); $cs->setProgressCallback(array($this, 'myOutput')); $cs->interactive = !$this->hasOption('noask'); $cs->nocolor = $this->hasOption('nocolor'); $cs->norc = $this->hasOption('norc'); # @todo FIXME: Make this auto detect. # Guess last modified date of the file from either git, svn or filesystem if ($this->hasOption('git')) { $ts = $cs->getTimestampsFromGit($file); } else { $ts = $cs->getTimestampsFromSvn($file); } if (!$ts) { $ts = $cs->getTimestampsFromFs($file); } $this->output("Modify time for {$code}: " . wfTimestamp(TS_ISO_8601, $ts) . "\n"); $cs->checkConflicts($code, $start, $end, $ts); } unset($group); } // Print timestamp if the user wants to store it $this->output(wfTimestamp(TS_RFC2822) . "\n"); }
public function getGroups() { if (!isset($this->groups)) { $groups = array(); $ids = (array) $this->conf['GROUPS']; $ids = MessageGroups::expandWildcards($ids); foreach ($ids as $id) { // Do not try to include self and go to infinite loop. if ($id === $this->getId()) { continue; } $group = MessageGroups::getGroup($id); if ($group === null) { error_log("Invalid group id in {$this->getId()}: {$id}"); continue; } if (MessageGroups::getPriority($group) === 'discouraged') { continue; } $groups[$id] = $group; } $this->groups = $groups; } return $this->groups; }
/** * Gets list of message groups filtered by user input. * @return MessageGroup[] */ protected function getGroups() { $groups = MessageGroups::getGroupsByType('FileBasedMessageGroup'); // Include all if option not given $include = $this->getOption('group', '*'); $include = explode(',', $include); $include = array_map('trim', $include); $include = MessageGroups::expandWildcards($include); // Exclude nothing if option not given $exclude = $this->getOption('skipgroup', ''); $exclude = explode(',', $exclude); $exclude = array_map('trim', $exclude); $exclude = MessageGroups::expandWildcards($exclude); // Flip to allow isset $include = array_flip($include); $exclude = array_flip($exclude); $groups = array_filter($groups, function (MessageGroup $group) use($include, $exclude) { $id = $group->getId(); return isset($include[$id]) && !isset($exclude[$id]); }); return $groups; }
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() { $codes = Language::fetchLanguageNames(false); // Exclude the documentation language code global $wgTranslateDocumentationLanguageCode; if ($wgTranslateDocumentationLanguageCode) { unset($codes[$wgTranslateDocumentationLanguageCode]); } $reqGroups = $this->getOption('group'); if ($reqGroups) { $reqGroups = explode(',', $reqGroups); $reqGroups = array_map('trim', $reqGroups); $reqGroups = MessageGroups::expandWildcards($reqGroups); } $verbose = isset($options['verbose']); $groups = MessageGroups::singleton()->getGroups(); /** @var $g MessageGroup */ foreach ($groups as $g) { $id = $g->getId(); $sourceLanguage = $g->getSourceLanguage(); // Skip groups that are not requested if ($reqGroups && !in_array($id, $reqGroups)) { unset($g); continue; } $checker = $g->getChecker(); if (!$checker) { unset($g); continue; } // Initialise messages, using unique definitions if appropriate $collection = $g->initCollection($sourceLanguage, true); if (!count($collection)) { continue; } $this->output("Working with {$id}: ", $id); // Skip source language code $langCodes = $codes; unset($langCodes[$sourceLanguage]); $langCodes = array_keys($langCodes); sort($langCodes); foreach ($langCodes as $code) { $this->output("{$code} ", $id); $problematic = array(); $collection->resetForNewLanguage($code); $collection->loadTranslations(); global $wgContLang; foreach ($collection as $key => $message) { $prob = $checker->checkMessageFast($message, $code); if ($prob) { if ($verbose) { // Print it $nsText = $wgContLang->getNsText($g->namespaces[0]); $this->output("# [[{$nsText}:{$key}/{$code}]]\n"); } // Add it to the array $problematic[] = array($g->namespaces[0], "{$key}/{$code}"); } } self::tagFuzzy($problematic); } } }