public function getMessageParameters() { $params = parent::getMessageParameters(); $type = $this->entry->getFullType(); if ($type === 'translationreview/message') { $targetPage = $this->makePageLink($this->entry->getTarget(), array('oldid' => $params[3])); $params[2] = Message::rawParam($targetPage); } elseif ($type === 'translationreview/group') { /* * - 3: language code * - 4: label of the message group * - 5: old state * - 6: new state */ $uiLanguage = $this->context->getLanguage(); $language = $params[3]; $targetPage = $this->makePageLinkWithText($this->entry->getTarget(), $params[4], array('language' => $language)); $params[2] = Message::rawParam($targetPage); $params[3] = TranslateUtils::getLanguageName($language, $uiLanguage->getCode()); $params[5] = $this->formatStateMessage($params[5]); $params[6] = $this->formatStateMessage($params[6]); } elseif ($type === 'translatorsandbox/rejected') { // No point linking to the user page which cannot have existed $params[2] = $this->entry->getTarget()->getText(); } elseif ($type === 'translatorsandbox/promoted') { // Gender for the target $params[3] = User::newFromId($params[3])->getName(); } return $params; }
function run() { // Initialization $title = $this->title; list(, $code) = TranslateUtils::figureMessage($title->getPrefixedText()); // Return the actual translation page... $page = TranslatablePage::isTranslationPage($title); if (!$page) { var_dump($this->params); var_dump($title); throw new MWException("Oops, this should not happen!"); } $group = $page->getMessageGroup(); $collection = $group->initCollection($code); $text = $page->getParse()->getTranslationPageText($collection); // Other stuff $user = $this->getUser(); $summary = $this->getSummary(); $flags = $this->getFlags(); $page = WikiPage::factory($title); // @todo FuzzyBot hack PageTranslationHooks::$allowTargetEdit = true; $content = ContentHandler::makeContent($text, $page->getTitle()); $page->doEditContent($content, $summary, $flags, false, $user); PageTranslationHooks::$allowTargetEdit = false; return true; }
/** * 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 $skin Skin * * @return bool */ static function toolboxAllTranslations( &$skin ) { global $wgTranslateMessageNamespaces; if ( method_exists( $skin, 'getSkin' ) ) { $title = $skin->getSkin()->getTitle(); } else { global $wgTitle; $title = $wgTitle; } $ns = $title->getNamespace(); if ( !in_array( $ns, $wgTranslateMessageNamespaces ) ) { return true; } $inMessageGroup = TranslateUtils::messageKeyToGroup( $title->getNamespace(), $title->getBaseText() ); if ( $inMessageGroup ) { // Add a slash at the end, to not have basename in the result of Special:Prefixindex $message = $title->getNsText() . ":" . $title->getBaseText(); $desc = wfMsg( 'translate-sidebar-alltrans' ); $url = htmlspecialchars( SpecialPage::getTitleFor( 'Translations' )->getLocalURL( '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; }
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"); }
/** * Returns HTML5 output of the form * GLOBALS: $wgLang, $wgScript * @return string */ protected function getForm() { global $wgLang, $wgScript; $form = Xml::tags( 'form', array( 'action' => $wgScript, 'method' => 'get' ), '<table><tr><td>' . wfMsgHtml( 'translate-page-language' ) . '</td><td>' . TranslateUtils::languageSelector( $wgLang->getCode(), $this->options['language'] ) . '</td></tr><tr><td>' . wfMsgHtml( 'translate-magic-module' ) . '</td><td>' . $this->moduleSelector( $this->options['module'] ) . '</td></tr><tr><td colspan="2">' . Xml::submitButton( wfMsg( 'translate-magic-submit' ) ) . ' ' . Xml::submitButton( wfMsg( 'translate-magic-cm-export' ), array( 'name' => 'export' ) ) . '</td></tr></table>' . Html::hidden( 'title', $this->getTitle()->getPrefixedText() ) ); return $form; }
/** @dataProvider provideTokenClasses */ public function testTokenRetrieval($id, $class) { // Make sure we have the right to get the token global $wgGroupPermissions; $wgGroupPermissions['*'][$class::getRight()] = true; RequestContext::getMain()->getUser()->clearInstanceCache(); // Reread above global // We should be getting anonymous user token $expected = $class::getToken(); $this->assertNotSame(false, $expected, 'We did not get a valid token'); $actionString = TranslateUtils::getTokenAction($id); $params = wfCgiToArray($actionString); $req = new FauxRequest($params); $api = new ApiMain($req); $api->execute(); if (defined('ApiResult::META_CONTENT')) { $data = $api->getResult()->getResultData(null, array('Strip' => 'all')); } else { $data = $api->getResultData(); } if (isset($data['query'])) { foreach ($data['query']['pages'] as $page) { $this->assertSame($expected, $page[$id . 'token']); } } else { $this->assertArrayHasKey('tokens', $data, 'Result has tokens'); $this->assertSame($expected, $data['tokens'][$id . 'token']); } }
public function getDefinitions() { $groups = MessageGroups::getAllGroups(); $keys = array(); /** * @var $g MessageGroup */ foreach ($groups as $g) { $states = $g->getMessageGroupStates()->getStates(); foreach (array_keys($states) as $state) { $keys["Translate-workflow-state-{$state}"] = $state; } } $defs = TranslateUtils::getContents(array_keys($keys), $this->getNamespace()); foreach ($keys as $key => $state) { if (!isset($defs[$key])) { // @todo Use jobqueue $title = Title::makeTitleSafe($this->getNamespace(), $key); $page = new WikiPage($title); $content = ContentHandler::makeContent($state, $title); $page->doEditContent($content, wfMessage('translate-workflow-autocreated-summary', $state)->inContentLanguage()->text(), 0, false, FuzzyBot::getUser()); } else { // Use the wiki translation as definition if available. // getContents returns array( content, last author ) list($content, ) = $defs[$key]; $keys[$key] = $content; } } return $keys; }
protected function doHeader( MessageCollection $collection ) { global $wgSitename, $wgTranslateDocumentationLanguageCode; $code = $collection->code; $name = TranslateUtils::getLanguageName( $code ); $native = TranslateUtils::getLanguageName( $code, true ); if ( $wgTranslateDocumentationLanguageCode ) { $docu = "\n * See the $wgTranslateDocumentationLanguageCode 'language' for message documentation incl. usage of parameters"; } else { $docu = ''; } $authors = $this->doAuthors( $collection ); $output = <<<PHP /** $name ($native) * $docu * To improve a translation please visit http://$wgSitename * * @ingroup Language * @file * $authors */ PHP; return $output; }
/** * Returns of stored translation of message specified by the $key in language * code $code. * * @param string $key Key of the message. * @param string $code Language code. * @return string|null The translation or null if it doesn't exists. */ public function getMessage($key, $code) { if ($code && $this->getSourceLanguage() !== $code) { return TranslateUtils::getMessageContent($key, $code); } else { return TranslateUtils::getMessageContent($key, false); } }
public function execute($par) { $request = $this->getRequest(); $par = (string) $par; // Yes, the use of getVal() and getText() is wanted, see bug T22365 $this->text = $request->getVal('wpTitle', $par); $this->title = Title::newFromText($this->text); $this->reason = $request->getText('reason'); // Checkboxes that default being checked are tricky $this->doSubpages = $request->getBool('subpages', !$request->wasPosted()); $user = $this->getUser(); if ($this->doBasicChecks() !== true) { return; } $out = $this->getOutput(); // Real stuff starts here if (TranslatablePage::isSourcePage($this->title)) { $title = $this->msg('pt-deletepage-full-title', $this->title->getPrefixedText()); $out->setPagetitle($title); $this->code = ''; $this->page = TranslatablePage::newFromTitle($this->title); } else { $page = TranslatablePage::isTranslationPage($this->title); if ($page) { $title = $this->msg('pt-deletepage-lang-title', $this->title->getPrefixedText()); $out->setPagetitle($title); list(, $this->code) = TranslateUtils::figureMessage($this->title->getText()); $this->page = $page; } else { throw new ErrorPageError('pt-deletepage-invalid-title', 'pt-deletepage-invalid-text'); } } if (!$user->isAllowed('pagetranslation')) { throw new PermissionsError('pagetranslation'); } // Is there really no better way to do this? $subactionText = $request->getText('subaction'); switch ($subactionText) { case $this->msg('pt-deletepage-action-check')->text(): $subaction = 'check'; break; case $this->msg('pt-deletepage-action-perform')->text(): $subaction = 'perform'; break; case $this->msg('pt-deletepage-action-other')->text(): $subaction = ''; break; default: $subaction = ''; } if ($subaction === 'check' && $this->checkToken() && $request->wasPosted()) { $this->showConfirmation(); } elseif ($subaction === 'perform' && $this->checkToken() && $request->wasPosted()) { $this->performAction(); } else { $this->showForm(); } }
public function getData() { $translation = null; $title = $this->handle->getTitle(); $translation = TranslateUtils::getMessageContent($this->handle->getKey(), $this->handle->getCode(), $title->getNamespace()); Hooks::run('TranslatePrefillTranslation', array(&$translation, $this->handle)); $fuzzy = MessageHandle::hasFuzzyString($translation) || $this->handle->isFuzzy(); $translation = str_replace(TRANSLATE_FUZZY, '', $translation); return array('language' => $this->handle->getCode(), 'fuzzy' => $fuzzy, 'value' => $translation); }
protected function doHeader(MessageCollection $collection) { global $wgSitename; $code = $collection->code; $name = TranslateUtils::getLanguageName($code); $native = TranslateUtils::getLanguageName($code, $code); $output = "# Messages for {$name} ({$native})\n"; $output .= "# Exported from {$wgSitename}\n\n"; return $output; }
public function getData() { global $wgTranslateDocumentationLanguageCode, $wgContLang; if (!$wgTranslateDocumentationLanguageCode) { throw new TranslationHelperException('Message documentation is disabled'); } $page = $this->handle->getKey(); $ns = $this->handle->getTitle()->getNamespace(); $info = TranslateUtils::getMessageContent($page, $wgTranslateDocumentationLanguageCode, $ns); return array('language' => $wgContLang->getCode(), 'value' => $info, 'html' => $this->context->getOutput()->parse($info)); }
/** * @param $collection MessageCollection * @return string */ protected function doHeader(MessageCollection $collection) { global $wgSitename; global $wgTranslateYamlLibrary; $code = $collection->code; $name = TranslateUtils::getLanguageName($code); $native = TranslateUtils::getLanguageName($code, $code); $output = "# Messages for {$name} ({$native})\n"; $output .= "# Exported from {$wgSitename}\n"; if (isset($wgTranslateYamlLibrary)) { $output .= "# Export driver: {$wgTranslateYamlLibrary}\n"; } return $output; }
public function execute() { $hours = (int) $this->getOption('days'); $hours = $hours ? $hours * 7 : 7 * 24; $top = (int) $this->getOption('top'); $top = $top ? $top : 10; $bots = $this->hasOption('bots'); $namespaces = array(); if ($this->hasOption('ns')) { $input = explode(',', $this->getOption('ns')); foreach ($input as $namespace) { if (is_numeric($namespace)) { array_push($namespaces, $namespace); } } } /** * Select set of edits to report on */ $rows = TranslateUtils::translationChanges($hours, $bots, $namespaces); /** * Get counts for edits per language code after filtering out edits by FuzzyBot */ $codes = array(); global $wgTranslateFuzzyBotName; foreach ($rows as $_) { // Filter out edits by $wgTranslateFuzzyBotName if ($_->rc_user_text === $wgTranslateFuzzyBotName) { continue; } list(, $code) = TranslateUtils::figureMessage($_->rc_title); if (!isset($codes[$code])) { $codes[$code] = 0; } $codes[$code]++; } /** * Sort counts and report descending up to $top rows. */ arsort($codes); $i = 0; foreach ($codes as $code => $num) { if ($i++ === $top) { break; } $this->output("{$code}\t{$num}\n"); } }
/** * Returns all translations of a given message. * @param MessageHandle $handle Language code is ignored. * @return array[] * @since 2012-12-18 */ public static function getTranslations(MessageHandle $handle) { $namespace = $handle->getTitle()->getNamespace(); $base = $handle->getKey(); $dbr = wfGetDB(DB_SLAVE); $res = $dbr->select('page', array('page_namespace', 'page_title'), array('page_namespace' => $namespace, 'page_title ' . $dbr->buildLike("{$base}/", $dbr->anyString())), __METHOD__, array('ORDER BY' => 'page_title', 'USE INDEX' => 'name_title')); $titles = array(); foreach ($res as $row) { $titles[] = $row->page_title; } if ($titles === array()) { return array(); } $pageInfo = TranslateUtils::getContents($titles, $namespace); return $pageInfo; }
public function execute() { $params = $this->extractRequestParams(); $title = Title::newFromText($params['title']); if (!$title) { $this->dieUsage('Invalid title'); } $handle = new MessageHandle($title); if (!$handle->isValid()) { $this->dieUsage('Title does not correspond to a translatable message'); } $base = Title::makeTitle($title->getNamespace(), $handle->getKey()); $namespace = $base->getNamespace(); $message = $base->getDBKey(); $dbr = wfGetDB(DB_SLAVE); $res = $dbr->select('page', array('page_namespace', 'page_title'), array('page_namespace' => $namespace, 'page_title ' . $dbr->buildLike("{$message}/", $dbr->anyString())), __METHOD__, array('ORDER BY' => 'page_title', 'USE INDEX' => 'name_title')); $titles = array(); foreach ($res as $row) { $titles[] = $row->page_title; } $pageInfo = TranslateUtils::getContents($titles, $namespace); $result = $this->getResult(); $pages = array(); $count = 0; foreach ($pageInfo as $key => $info) { if (++$count <= $params['offset']) { continue; } $tTitle = Title::makeTitle($namespace, $key); $tHandle = new MessageHandle($tTitle); $data = array('title' => $tTitle->getPrefixedText(), 'language' => $tHandle->getCode(), 'lasttranslator' => $info[1]); $fuzzy = MessageHandle::hasFuzzyString($info[0]) || $tHandle->isFuzzy(); if ($fuzzy) { $data['fuzzy'] = 'fuzzy'; } $translation = str_replace(TRANSLATE_FUZZY, '', $info[0]); $result->setContent($data, $translation); $fit = $result->addValue(array('query', $this->getModuleName()), null, $data); if (!$fit) { $this->setContinueEnumParameter('offset', $count); break; } } $result->setIndexedTagName_internal(array('query', $this->getModuleName()), 'message'); }
function run() { // Initialization $title = $this->title; list( , $code ) = TranslateUtils::figureMessage( $title->getPrefixedText() ); // Return the actual translation page... $page = TranslatablePage::isTranslationPage( $title ); if ( !$page ) { var_dump( $this->params ); var_dump( $title ); throw new MWException( "Oops, this should not happen!" ); } $group = $page->getMessageGroup(); $collection = $group->initCollection( $code ); $collection->loadTranslations( DB_MASTER ); $text = $page->getParse()->getTranslationPageText( $collection ); // Other stuff $user = $this->getUser(); $summary = $this->getSummary(); $flags = $this->getFlags(); $article = new Article( $title, 0 ); // @todo FuzzyBot hack PageTranslationHooks::$allowTargetEdit = true; // Do the edit $status = $article->doEdit( $text, $summary, $flags, false, $user ); SpecialPageTranslation::superDebug( __METHOD__, 'edit', $user, $title, $flags, $status ); PageTranslationHooks::$allowTargetEdit = false; // purge cache $page->getTranslationPercentages( true ); return true; }
function run() { global $wgTranslateDocumentationLanguageCode; $title = $this->title; $params = $this->params; $user = FuzzyBot::getUser(); $flags = EDIT_DEFER_UPDATES | EDIT_FORCE_BOT; $wikiPage = WikiPage::factory($title); $summary = wfMessage('translate-manage-import-summary')->inContentLanguage()->plain(); $content = ContentHandler::makeContent($params['content'], $title); $wikiPage->doEditContent($content, $summary, $flags, false, $user); // NOTE: message documentation is excluded from fuzzying! if ($params['fuzzy']) { $handle = new MessageHandle($title); $key = $handle->getKey(); $languages = TranslateUtils::getLanguageNames('en'); unset($languages[$wgTranslateDocumentationLanguageCode]); $languages = array_keys($languages); $dbw = wfGetDB(DB_MASTER); $fields = array('page_id', 'page_latest'); $conds = array('page_namespace' => $title->getNamespace()); $pages = array(); foreach ($languages as $code) { $otherTitle = Title::makeTitleSafe($title->getNamespace(), "{$key}/{$code}"); $pages[$otherTitle->getDBKey()] = true; } unset($pages[$title->getDBKey()]); if (count($pages) === 0) { return true; } $conds['page_title'] = array_keys($pages); $res = $dbw->select('page', $fields, $conds, __METHOD__); $inserts = array(); foreach ($res as $row) { $inserts[] = array('rt_type' => RevTag::getType('fuzzy'), 'rt_page' => $row->page_id, 'rt_revision' => $row->page_latest); } $dbw->replace('revtag', array(array('rt_type', 'rt_page', 'rt_revision')), $inserts, __METHOD__); } return true; }
public function getMessageParameters() { $params = parent::getMessageParameters(); $legacy = $this->entry->getParameters(); $type = $this->entry->getFullType(); switch ($type) { case 'pagetranslation/mark': $revision = $legacy['revision']; $targetPage = $this->makePageLink($this->entry->getTarget(), array('oldid' => $revision)); $params[2] = Message::rawParam($targetPage); break; case 'pagetranslation/moveok': case 'pagetranslation/movenok': case 'pagetranslation/deletefnok': case 'pagetranslation/deletelnok': $target = $legacy['target']; $moveTarget = $this->makePageLink(Title::newFromText($target)); $params[3] = Message::rawParam($moveTarget); break; case 'pagetranslation/prioritylanguages': $params[3] = $legacy['force']; $languages = $legacy['languages']; if ($languages !== false) { $lang = $this->context->getLanguage(); $languages = array_map('trim', preg_split('/,/', $languages, -1, PREG_SPLIT_NO_EMPTY)); $languages = array_map(function ($code) use($lang) { return TranslateUtils::getLanguageName($code, $lang->getCode()); }, $languages); $params[4] = $lang->listToText($languages); } break; case 'pagetranslation/associate': case 'pagetranslation/dissociate': $params[3] = $legacy['aggregategroup']; break; } return $params; }
/** * Replace the normal save button with one that says if you are editing * message documentation to try to avoid accidents. * Hook: EditPageBeforeEditButtons */ static function buttonHack(EditPage $editpage, &$buttons, $tabindex) { $handle = new MessageHandle($editpage->getTitle()); if (!$handle->isValid()) { return true; } $context = $editpage->getArticle()->getContext(); if ($handle->isDoc()) { $langCode = $context->getLanguage()->getCode(); $name = TranslateUtils::getLanguageName($handle->getCode(), $langCode); $accessKey = $context->msg('accesskey-save')->plain(); $temp = array('id' => 'wpSave', 'name' => 'wpSave', 'type' => 'submit', 'tabindex' => ++$tabindex, 'value' => $context->msg('translate-save', $name)->text(), 'accesskey' => $accessKey, 'title' => $context->msg('tooltip-save')->text() . ' [' . $accessKey . ']'); $buttons['save'] = Xml::element('input', $temp, ''); } try { $supportUrl = SupportAid::getSupportUrl($handle->getTitle()); } catch (TranslationHelperException $e) { return true; } $temp = array('id' => 'wpSupport', 'name' => 'wpSupport', 'type' => 'button', 'tabindex' => ++$tabindex, 'value' => $context->msg('translate-js-support')->text(), 'title' => $context->msg('translate-js-support-title')->text(), 'data-load-url' => $supportUrl, 'onclick' => "window.open( jQuery(this).attr('data-load-url') );"); $buttons['ask'] = Html::element('input', $temp, ''); return true; }
public function execute($par) { $out = $this->getOutput(); $lang = $this->getLanguage(); // Only for manual debugging nowdays $this->purge = false; $this->setHeaders(); $out->addModules('ext.translate.special.supportedlanguages'); TranslateUtils::addSpecialHelpLink($out, 'Help:Extension:Translate/Statistics_and_reporting#List_of_languages_and_translators'); $this->outputHeader(); $dbr = wfGetDB(DB_SLAVE); if ($dbr->getType() === 'sqlite') { $out->addWikiText('<div class=errorbox>SQLite is not supported.</div>'); return; } $out->addWikiMsg('supportedlanguages-localsummary'); $names = Language::fetchLanguageNames(null, 'all'); $languages = $this->languageCloud(); // There might be all sorts of subpages which are not languages $languages = array_intersect_key($languages, $names); $this->outputLanguageCloud($languages, $names); $out->addWikiMsg('supportedlanguages-count', $lang->formatNum(count($languages))); if ($par && Language::isKnownLanguageTag($par)) { $code = $par; $out->addWikiMsg('supportedlanguages-colorlegend', $this->getColorLegend()); $users = $this->fetchTranslators($code); if ($users === false) { // generic-pool-error is from MW core $out->wrapWikiMsg('<div class="warningbox">$1</div>', 'generic-pool-error'); return; } global $wgTranslateAuthorBlacklist; $users = $this->filterUsers($users, $code, $wgTranslateAuthorBlacklist); $this->preQueryUsers($users); $this->showLanguage($code, $users); } }
public function execute() { global $wgTranslateFuzzyBotName, $wgSitename; $days = (int) $this->getOption('days', 30); $hours = $days * 24; $top = (int) $this->getOption('top', -1); $bots = $this->hasOption('bots'); $namespaces = array(); if ($this->hasOption('ns')) { $input = explode(',', $this->getOption('ns')); foreach ($input as $namespace) { if (is_numeric($namespace)) { $namespaces[] = $namespace; } } } // Select set of edits to report on // Fetch some extrac fields that normally TranslateUtils::translationChanges wont $extraFields = array('rc_old_len', 'rc_new_len'); $rows = TranslateUtils::translationChanges($hours, $bots, $namespaces, $extraFields); // Get counts for edits per language code after filtering out edits by FuzzyBot $codes = array(); foreach ($rows as $_) { // Filter out edits by $wgTranslateFuzzyBotName if ($_->rc_user_text === $wgTranslateFuzzyBotName) { continue; } $handle = new MessageHandle(Title::newFromText($_->rc_title)); $code = $handle->getCode(); if (!isset($codes[$code])) { $codes[$code] = 0; } if ($this->hasOption('diff')) { $diff = abs($_->rc_new_len - $_->rc_old_len); } else { $diff = $_->rc_new_len; } $codes[$code] += $diff; } // Sort counts and report descending up to $top rows. arsort($codes); $i = 0; $total = 0; $this->output("Character edit stats for last {$days} days in {$wgSitename}\n"); $this->output("code\tname\tedit\n"); $this->output("-----------------------\n"); foreach ($codes as $code => $num) { if ($i++ === $top) { break; } $language = Language::fetchLanguageName($code); if (!$language) { // this will be very rare, but avoid division by zero in next line continue; } $charRatio = mb_strlen($language, 'UTF-8') / strlen($language); $num = intval($num * $charRatio); $total += $num; $this->output("{$code}\t{$language}\t{$num}\n"); } $this->output("-----------------------\n"); $this->output("Total\t\t{$total}\n"); }
/** * Returns full path the the cache file. * @return string */ protected function getCacheFileName() { return TranslateUtils::cacheFile("translate_groupcache-{$this->group->getId()}-{$this->code}.cdb"); }
/** * Returns a localised language name. * @param string $code Language code. * @param string $language Language code of language the the name should be in. * @return string Best-effort localisation of wanted language name. */ public static function getLanguageName($code, $language = 'en') { $languages = TranslateUtils::getLanguageNames($language); if (isset($languages[$code])) { return $languages[$code]; } else { return $code; } }
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( $messages ) { global $wgOut, $wgLang; $this->out = $wgOut; // Set up diff engine $diff = new DifferenceEngine; $diff->showDiffStyle(); $diff->setReducedLineNumbers(); // Check whether we do processing $process = $this->allowProcess(); // Initialise collection $group = $this->getGroup(); $code = $this->getCode(); $collection = $group->initCollection( $code ); $collection->loadTranslations(); $this->out->addHTML( $this->doHeader() ); // Determine changes $alldone = $process; $changed = array(); foreach ( $messages as $key => $value ) { $fuzzy = $old = false; if ( isset( $collection[$key] ) ) { $old = $collection[$key]->translation(); } // No changes at all, ignore if ( strval( $old ) === strval( $value ) ) { continue; } if ( $old === false ) { $name = wfMsgHtml( 'translate-manage-import-new', '<code style="font-weight:normal;">' . htmlspecialchars( $key ) . '</code>' ); $text = TranslateUtils::convertWhiteSpaceToHTML( $value ); $changed[] = self::makeSectionElement( $name, 'new', $text ); } else { $diff->setText( $old, $value ); $text = $diff->getDiff( '', '' ); $type = 'changed'; global $wgRequest; $action = $wgRequest->getVal( self::escapeNameForPHP( "action-$type-$key" ) ); if ( $process ) { if ( !count( $changed ) ) { $changed[] = '<ul>'; } if ( $action === null ) { $message = wfMsgExt( 'translate-manage-inconsistent', 'parseinline', wfEscapeWikiText( "action-$type-$key" ) ); $changed[] = "<li>$message</li></ul>"; $process = false; } else { // Check processing time if ( !isset( $this->time ) ) { $this->time = wfTimestamp(); } $message = self::doAction( $action, $group, $key, $code, $value ); $key = array_shift( $message ); $params = $message; $message = wfMsgExt( $key, 'parseinline', $params ); $changed[] = "<li>$message</li>"; if ( $this->checkProcessTime() ) { $process = false; $duration = $wgLang->formatNum( $this->processingTime ); $message = wfMsgExt( 'translate-manage-toolong', 'parseinline', $duration ); $changed[] = "<li>$message</li></ul>"; } continue; } } $alldone = false; $actions = $this->getActions(); $defaction = $this->getDefaultAction( $fuzzy, $action ); $act = array(); foreach ( $actions as $action ) { $label = wfMsg( "translate-manage-action-$action" ); $name = self::escapeNameForPHP( "action-$type-$key" ); $id = Sanitizer::escapeId( "action-$key-$action" ); $act[] = Xml::radioLabel( $label, $name, $action, $id, $action === $defaction ); } $name = wfMsg( 'translate-manage-import-diff', '<code style="font-weight:normal;">' . htmlspecialchars( $key ) . '</code>', implode( ' ', $act ) ); $changed[] = self::makeSectionElement( $name, $type, $text ); } } if ( !$process ) { $collection->filter( 'hastranslation', false ); $keys = $collection->getMessageKeys(); $diff = array_diff( $keys, array_keys( $messages ) ); foreach ( $diff as $s ) { // @todo FIXME: Use CSS file. $name = wfMsgHtml( 'translate-manage-import-deleted', '<code style="font-weight:normal;">' . htmlspecialchars( $s ) . '</code>' ); $text = TranslateUtils::convertWhiteSpaceToHTML( $collection[$s]->translation() ); $changed[] = self::makeSectionElement( $name, 'deleted', $text ); } } if ( $process || ( !count( $changed ) && $code !== 'en' ) ) { if ( !count( $changed ) ) { $this->out->addWikiMsg( 'translate-manage-nochanges-other' ); } if ( !count( $changed ) || strpos( $changed[count( $changed ) - 1], '<li>' ) !== 0 ) { $changed[] = '<ul>'; } $message = wfMsgExt( 'translate-manage-import-done', 'parseinline' ); $changed[] = "<li>$message</li></ul>"; $this->out->addHTML( implode( "\n", $changed ) ); } else { // END if ( count( $changed ) ) { if ( $code === 'en' ) { $this->out->addWikiMsg( 'translate-manage-intro-en' ); } else { $lang = TranslateUtils::getLanguageName( $code, false, $wgLang->getCode() ); $this->out->addWikiMsg( 'translate-manage-intro-other', $lang ); } $this->out->addHTML( Html::hidden( 'language', $code ) ); $this->out->addHTML( implode( "\n", $changed ) ); $this->out->addHTML( Xml::submitButton( wfMsg( 'translate-manage-submit' ) ) ); } else { $this->out->addWikiMsg( 'translate-manage-nochanges' ); } } $this->out->addHTML( $this->doFooter() ); return $alldone; }
protected function store(array $array) { $file = TranslateUtils::cacheFile($this->filename); file_put_contents($file, serialize($array)); }
protected function formatDocumentation( $key ) { global $wgTranslateDocumentationLanguageCode; if ( !$this->offlineMode ) return ''; $code = $wgTranslateDocumentationLanguageCode; if ( !$code ) return ''; $documentation = TranslateUtils::getMessageContent( $key, $code, $this->group->getNamespace() ); if ( !is_string( $documentation ) ) return ''; $lines = explode( "\n", $documentation ); $out = ''; foreach ( $lines as $line ) { $out .= "#. [Wiki] $line\n"; } return $out; }
/** * Constructs and outputs file input form with supported methods. */ protected function outputForm() { global $wgOut; $wgOut->addModules('ext.translate.special.importtranslations'); TranslateUtils::addSpecialHelpLink($wgOut, 'Help:Extension:Translate/Off-line_translation'); /** * Ugly but necessary form building ahead, ohoy */ $this->out->addHTML(Xml::openElement('form', array('action' => $this->getTitle()->getLocalUrl(), 'method' => 'post', 'enctype' => 'multipart/form-data', 'id' => 'mw-translate-import')) . Html::hidden('token', $this->user->editToken()) . Html::hidden('title', $this->getTitle()->getPrefixedText()) . Xml::openElement('table') . Xml::openElement('tr') . Xml::openElement('td')); $class = array('class' => 'mw-translate-import-inputs'); $this->out->addHTML(Xml::radioLabel(wfMsg('translate-import-from-url'), 'upload-type', 'url', 'mw-translate-up-url', $this->request->getText('upload-type') === 'url') . "\n" . Xml::closeElement('td') . Xml::openElement('td') . "\n" . Xml::input('upload-url', 50, $this->request->getText('upload-url'), array('id' => 'mw-translate-up-url-input') + $class) . "\n" . Xml::closeElement('td') . Xml::closeElement('tr') . Xml::openElement('tr') . Xml::openElement('td') . "\n"); $this->out->addHTML(Xml::radioLabel(wfMsg('translate-import-from-wiki'), 'upload-type', 'wiki', 'mw-translate-up-wiki', $this->request->getText('upload-type') === 'wiki') . "\n" . Xml::closeElement('td') . Xml::openElement('td') . "\n" . Xml::input('upload-wiki', 50, $this->request->getText('upload-wiki', 'File:'), array('id' => 'mw-translate-up-wiki-input') + $class) . "\n" . Xml::closeElement('td') . Xml::closeElement('tr') . Xml::openElement('tr') . Xml::openElement('td') . "\n" . Xml::radioLabel(wfMsg('translate-import-from-local'), 'upload-type', 'local', 'mw-translate-up-local', $this->request->getText('upload-type') === 'local') . "\n" . Xml::closeElement('td') . Xml::openElement('td') . "\n" . Xml::input('upload-local', 50, $this->request->getText('upload-local'), array('type' => 'file', 'id' => 'mw-translate-up-local-input') + $class) . "\n" . Xml::closeElement('td') . Xml::closeElement('tr') . Xml::closeElement('table') . Xml::submitButton(wfMsg('translate-import-load')) . Xml::closeElement('form')); }