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; }
/** * @dataProvider provideTestFiles */ public function testParsing($file) { $filename = basename($file); list($pagename, ) = explode('.', $filename, 2); $title = Title::newFromText($pagename); $translatablePage = TranslatablePage::newFromText($title, file_get_contents($file)); $pattern = $file; if ($filename === 'FailNotAtomic.ptfile') { $this->markTestSkipped('Extended validation not yet implemented'); } $failureExpected = strpos($pagename, 'Fail') === 0; if ($failureExpected) { $this->setExpectedException('TPException'); } $parse = $translatablePage->getParse(); $this->assertInstanceOf('TPParse', $parse); if (file_exists("{$pattern}.ptsource")) { $source = $parse->getSourcePageText(); $this->assertEquals($source, file_get_contents("{$pattern}.ptsource")); } if (file_exists("{$pattern}.pttarget")) { $target = $parse->getTranslationPageText(MessageCollection::newEmpty('foo')); $this->assertEquals($target, file_get_contents("{$pattern}.pttarget")); } // Custom tests written in php if (file_exists("{$pattern}.pttest")) { require "{$pattern}.pttest"; } }
public function testGetTranslationPageText() { $title = Title::newFromText(__CLASS__); $page = TranslatablePage::newFromText($title, '<translate>Hello <tvar|abc>peter!</></translate>'); $prefix = $title->getPrefixedDBKey() . '/'; $parse = $page->getParse(); $collection = array(); $expected = 'Hello peter!'; $actual = $parse->getTranslationPageText($collection); $this->assertEquals($expected, $actual, 'Variable declarations are substituted when no translation'); foreach ($parse->sections as $section) { $key = $prefix . $section->id; $message = new FatMessage($key, $section->getText()); $message->setTranslation($section->getText()); $collection[$key] = $message; } $actual = $parse->getTranslationPageText($collection); $this->assertEquals($expected, $actual, 'Variable declarations are substituted in source language'); foreach ($parse->sections as $section) { $key = $prefix . $section->id; $message = new FatMessage($key, $section->getText()); $message->setTranslation($section->getTextForTrans()); $collection[$key] = $message; } $actual = $parse->getTranslationPageText($collection); $this->assertEquals($expected, $actual, 'Variable declarations are substituted in translation'); }
/** * Returns only translation subpages. * @return Array of titles. */ protected function getTranslationPages() { if ( $this->singleLanguage() ) { return array( $this->title ); } if ( !isset( $this->translationPages ) ) { $this->translationPages = $this->page->getTranslationPages(); } return $this->translationPages; }
function run() { global $wgUser; // Initialization $title = $this->title; // Other stuff $user = $this->getUser(); $summary = $this->getSummary(); $base = $this->getBase(); PageTranslationHooks::$allowTargetEdit = true; $oldUser = $wgUser; $wgUser = $user; $error = ''; $article = new Article( $title, 0 ); $ok = $article->doDeleteArticle( $summary, false, 0, true, $error ); if ( !$ok ) { $logger = new LogPage( 'pagetranslation' ); $params = array( 'user' => $this->getPerformer(), 'target' => $base, 'error' => base64_encode( serialize( $ok ) ), // This is getting ridiculous ); $doer = User::newFromName( $this->getPerformer() ); $msg = $this->getFull() ? 'deletefnok' : 'deletelnok'; $logger->addEntry( $msg, $title, null, array( serialize( $params ) ), $doer ); } PageTranslationHooks::$allowTargetEdit = false; $cache = wfGetCache( CACHE_DB ); $pages = (array) $cache->get( wfMemcKey( 'pt-base', $base ) ); $lastitem = array_pop( $pages ); if ( $title->getPrefixedText() === $lastitem ) { $cache->delete( wfMemcKey( 'pt-base', $base ) ); $logger = new LogPage( 'pagetranslation' ); $params = array( 'user' => $this->getPerformer() ); $doer = User::newFromName( $this->getPerformer() ); $msg = $this->getFull() ? 'deletefok' : 'deletelok'; $logger->addEntry( $msg, Title::newFromText( $base ), null, array( serialize( $params ) ), $doer ); $tpage = TranslatablePage::newFromTitle( $title ); $tpage->getTranslationPercentages( true ); foreach ( $tpage->getTranslationPages() as $page ) { $page->invalidateCache(); } $title->invalidateCache(); } $wgUser = $oldUser; return true; }
public function execute() { $dir = dirname( __FILE__ ); $testDirectory = "$dir/../tests/pagetranslation"; $testFiles = glob( "$testDirectory/*.ptfile" ); foreach ( $testFiles as $file ) { $filename = basename( $file ); list( $pagename, ) = explode( '.', $filename, 2 ); $title = Title::newFromText( $pagename ); $translatablePage = TranslatablePage::newFromText( $title, file_get_contents( $file ) ); $pattern = realpath( "$testDirectory" ) . "/$pagename"; $failureExpected = strpos( $pagename, 'Fail' ) === 0; try { $parse = $translatablePage->getParse(); if ( $failureExpected ) { $target = $parse->getTranslationPageText( MessageCollection::newEmpty( "foo" ) ); $this->output( "Testfile $filename should have failed... see $pattern.pttarget.fail\n" ); file_put_contents( "$pattern.pttarget.fail", $target ); } } catch ( TPException $e ) { if ( !$failureExpected ) { $this->output( "Testfile $filename failed to parse... see $pattern.ptfile.fail\n" ); file_put_contents( "$pattern.ptfile.fail", $e->getMessage() ); } continue; } if ( file_exists( "$pattern.ptsource" ) ) { $source = $parse->getSourcePageText(); if ( $source !== file_get_contents( "$pattern.ptsource" ) ) { $this->output( "Testfile $filename failed with source page output... writing $pattern.ptsource.fail\n" ); file_put_contents( "$pattern.ptsource.fail", $source ); } } if ( file_exists( "$pattern.pttarget" ) ) { $target = $parse->getTranslationPageText( MessageCollection::newEmpty( "foo" ) ); if ( $target !== file_get_contents( "$pattern.pttarget" ) ) { $this->output( "Testfile $filename failed with target page output... writing $pattern.pttarget.fail\n" ); file_put_contents( "$pattern.pttarget.fail", $target ); } } // Custom tests written in php if ( file_exists( "$pattern.pttest" ) ) { require( "$pattern.pttest" ); } } }
public function execute() { $groups = MessageGroups::singleton()->getGroups(); /** @var MessageGroup $group */ foreach ($groups as $group) { if (!$group instanceof WikiPageMessageGroup) { continue; } // Get all translation subpages and refresh each one of them $page = TranslatablePage::newFromTitle($group->getTitle()); $translationPages = $page->getTranslationPages(); foreach ($translationPages as $subpage) { $job = TranslateRenderJob::newJob($subpage); $job->run(); } } }
function run() { // Initialization $title = $this->title; // Other stuff $user = $this->getUser(); $summary = $this->getSummary(); $base = $this->getBase(); $doer = User::newFromName($this->getPerformer()); PageTranslationHooks::$allowTargetEdit = true; $error = ''; $wikipage = new WikiPage($title); $ok = $wikipage->doDeleteArticle($summary, false, 0, true, $error, $user); if (!$ok) { $params = array('target' => $base, 'error' => $ok); $type = $this->getFull() ? 'deletefnok' : 'deletelnok'; $entry = new ManualLogEntry('pagetranslation', $type); $entry->setPerformer($doer); $entry->setTarget($title); $entry->setParameters($params); $logid = $entry->insert(); $entry->publish($logid); } PageTranslationHooks::$allowTargetEdit = false; $cache = wfGetCache(CACHE_DB); $pages = (array) $cache->get(wfMemcKey('pt-base', $base)); $lastitem = array_pop($pages); if ($title->getPrefixedText() === $lastitem) { $cache->delete(wfMemcKey('pt-base', $base)); $type = $this->getFull() ? 'deletefok' : 'deletelok'; $entry = new ManualLogEntry('pagetranslation', $type); $entry->setPerformer($doer); $entry->setTarget(Title::newFromText($base)); $logid = $entry->insert(); $entry->publish($logid); $tpage = TranslatablePage::newFromTitle($title); $tpage->getTranslationPercentages(true); foreach ($tpage->getTranslationPages() as $page) { $page->invalidateCache(); } $title->invalidateCache(); } return true; }
/** * Keep the usual diiba daaba hidden from translators. * Hook: AlternateEdit */ public static function intro(EditPage $editpage) { $handle = new MessageHandle($editpage->getTitle()); if ($handle->isValid()) { $editpage->suppressIntro = true; $group = $handle->getGroup(); $languages = $group->getTranslatableLanguages(); if ($handle->getCode() && $languages !== null && !isset($languages[$handle->getCode()])) { $editpage->getArticle()->getContext()->getOutput()->wrapWikiMsg("<div class='error'>\$1</div>", 'translate-language-disabled'); return false; } return true; } $msg = wfMessage('translate-edit-tag-warning')->inContentLanguage(); if (!$msg->isDisabled() && TranslatablePage::isSourcePage($editpage->getTitle())) { $editpage->editFormTextTop .= $editpage->getArticle()->getContext()->getOutput()->parse($msg->plain()); } return true; }
public function testTranslationPageRestrictions() { $superUser = new MockSuperUser(); $title = Title::newFromText('Translatable page'); $page = WikiPage::factory($title); $content = ContentHandler::makeContent('<translate>Hello</translate>', $title); $status = $page->doEditContent($content, 'New page', 0, false, $superUser); $revision = $status->value['revision']->getId(); $translatablePage = TranslatablePage::newFromRevision($title, $revision); $translatablePage->addMarkedTag($revision); MessageGroups::singleton()->recache(); $translationPage = Title::newFromText('Translatable page/fi'); TranslateRenderJob::newJob($translationPage)->run(); $this->assertTrue($translationPage->userCan('read', $superUser), 'Users can read existing translation pages'); $this->assertFalse($translationPage->userCan('edit', $superUser), 'Users can not edit existing translation pages'); $translationPage = Title::newFromText('Translatable page/ab'); $this->assertTrue($translationPage->userCan('read', $superUser), 'Users can read non-existing translation pages'); $this->assertFalse($translationPage->userCan('edit', $superUser), 'Users can not edit non-existing translation pages'); }
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; }
protected function checkMoveBlockers() { $blockers = array(); $target = $this->newTitle; if ( !$target ) { $blockers[] = array( 'pt-movepage-block-base-invalid' ); return $blockers; } if ( $target->getNamespace() == NS_MEDIAWIKI || $target->getNamespace() == NS_TRANSLATIONS ) { $blockers[] = array( 'immobile-target-namespace', $target->getNsText() ); return $blockers; } $base = $this->oldTitle->getPrefixedText(); if ( $target->exists() ) { $blockers[] = array( 'pt-movepage-block-base-exists', $target->getPrefixedText() ); } else { $errors = $this->oldTitle->isValidMoveOperation( $target, true, $this->reason ); if ( is_array( $errors ) ) $blockers = array_merge( $blockers, $errors ); } // Don't spam the same errors for all pages if base page fails if ( $blockers ) return $blockers; $translationPages = $this->getTranslationPages(); foreach ( $translationPages as $old ) { $new = $this->newPageTitle( $base, $old, $target ); if ( !$new ) { $blockers[] = array( 'pt-movepage-block-tp-invalid', $old->getPrefixedText() ); } elseif ( $new->exists() ) { $blockers[] = array( 'pt-movepage-block-tp-exists', $old->getPrefixedText(), $new->getPrefixedText() ); } else { $errors = $old->isValidMoveOperation( $target, false ); if ( is_array( $errors ) ) $blockers = array_merge( $blockers, $errors ); } } $sections = $this->getSectionPages(); foreach ( $sections as $old ) { $new = $this->newPageTitle( $base, $old, $target ); if ( !$new ) { $blockers[] = array( 'pt-movepage-block-section-invalid', $old->getPrefixedText() ); } elseif ( $new->exists() ) { $blockers[] = array( 'pt-movepage-block-section-exists', $old->getPrefixedText(), $new->getPrefixedText() ); } else { $errors = $old->isValidMoveOperation( $target, false ); if ( is_array( $errors ) ) $blockers = array_merge( $blockers, $errors ); } } if ( $this->moveSubpages ) { $subpages = $this->getSubpages(); foreach ( $subpages as $old ) { if ( TranslatablePage::isTranslationPage( $old ) ) { continue; } $new = $this->newPageTitle( $base, $old, $target ); if ( !$new ) { $blockers[] = array( 'pt-movepage-block-subpage-invalid', $old->getPrefixedText() ); } elseif ( $new->exists() ) { $blockers[] = array( 'pt-movepage-block-subpage-exists', $old->getPrefixedText(), $new->getPrefixedText() ); } else { $errors = $old->isValidMoveOperation( $target, false ); if ( is_array( $errors ) ) $blockers = array_merge( $blockers, $errors ); } } } return $blockers; }
/** * Hook to update source and destination translation pages on moving translation units * Hook: TitleMoveComplete * @since 2014.08 */ public static function onMoveTranslationUnits(Title &$ot, Title &$nt, User &$user, $oldid, $newid, $reason) { // Do the update only once. In case running by job queue, the update is not done here if (self::$jobQueueRunning) { return; } $groupLast = null; foreach (array($ot, $nt) as $title) { $handle = new MessageHandle($title); if (!$handle->isValid()) { continue; } // Documentation pages are never translation pages if ($handle->isDoc()) { continue; } $group = $handle->getGroup(); if (!$group instanceof WikiPageMessageGroup) { continue; } $language = $handle->getCode(); // Ignore pages such as Translations:Page/unit without language code if (strval($code) === '') { continue; } // Update the page only once if source and destination units // belong to the same page if ($group !== $groupLast) { $groupLast = $group; $page = TranslatablePage::newFromTitle($group->getTitle()); self::updateTranslationPage($page, $language, $user, 0, $reason); } } }
/** * @param Title $title * @return bool|TranslatablePage */ public static function isTranslationPage(Title $title) { $handle = new MessageHandle($title); $key = $handle->getKey(); $code = $handle->getCode(); if ($key === '' || $code === '') { return false; } $codes = Language::fetchLanguageNames(); global $wgTranslateDocumentationLanguageCode; unset($codes[$wgTranslateDocumentationLanguageCode]); if (!isset($codes[$code])) { return false; } $newtitle = self::changeTitleText($title, $key); if (!$newtitle) { return false; } $page = TranslatablePage::newFromTitle($newtitle); if ($page->getMarkedTag() === false) { return false; } return $page; }
public static function replaceSubtitle(&$subpages, $skin = null, $out = null) { global $wgOut; // $out was only added in some MW version if ($out === null) { $out = $wgOut; } $linker = class_exists('DummyLinker') ? new DummyLinker() : new Linker(); if (!TranslatablePage::isTranslationPage($out->getTitle()) && !TranslatablePage::isSourcePage($out->getTitle())) { return true; } // Copied from Skin::subPageSubtitle() if ($out->isArticle() && MWNamespace::hasSubpages($out->getTitle()->getNamespace())) { $ptext = $out->getTitle()->getPrefixedText(); if (preg_match('/\\//', $ptext)) { $links = explode('/', $ptext); array_pop($links); // Also pop of one extra for language code is needed if (TranslatablePage::isTranslationPage($out->getTitle())) { array_pop($links); } $c = 0; $growinglink = ''; $display = ''; foreach ($links as $link) { $growinglink .= $link; $display .= $link; $linkObj = Title::newFromText($growinglink); if (is_object($linkObj) && $linkObj->exists()) { $getlink = $linker->linkKnown(SpecialPage::getTitleFor('MyLanguage', $growinglink), htmlspecialchars($display)); $c++; if ($c > 1) { $subpages .= wfMsgExt('pipe-separator', 'escapenoentities'); } else { // This one is stupid imho, doesn't work with chihuahua // $subpages .= '< '; } $subpages .= $getlink; $display = ''; } else { $display .= '/'; } $growinglink .= '/'; } } return false; } return true; }
protected function checkTransrevRevision( $revId ) { static $cache = array(); if ( isset( $cache[$revId] ) ) { return $cache[$revId]; } $revision = Revision::newFromId( $revId ); if ( !$revision ) { $cache[$revId] = 'no such revision'; } else { $title = $revision->getTitle(); if ( !$title ) { $cache[$revId] = 'no title for the revision'; } else { $page = TranslatablePage::newFromTitle( $title ); if ( $page->getMarkedTag() === false ) { $cache[$revId] = 'revision belongs to a page that is not marked for translation'; } else { $cache[$revId] = true; } } } return $cache[$revId]; }
/** * This constructs the list of all groups from multiple different * sources. When possible, a cache dependency is created to automatically * recreate the cache when configuration changes. * @todo Reduce the ways of which messages can be added. Target is just * to have three ways: Yaml files, translatable pages and with the hook. * @todo In conjuction with the above, reduce the number of global * variables like wgTranslate#C and have the message groups specify * their own cache dependencies. */ protected static function loadGroupDefinitions() { global $wgTranslateAddMWExtensionGroups; global $wgEnablePageTranslation, $wgTranslateGroupFiles; global $wgTranslateAC, $wgTranslateEC, $wgTranslateCC; global $wgAutoloadClasses; global $wgTranslateWorkflowStates; $deps = array(); $deps[] = new GlobalDependency('wgTranslateAddMWExtensionGroups'); $deps[] = new GlobalDependency('wgEnablePageTranslation'); $deps[] = new GlobalDependency('wgTranslateGroupFiles'); $deps[] = new GlobalDependency('wgTranslateAC'); $deps[] = new GlobalDependency('wgTranslateEC'); $deps[] = new GlobalDependency('wgTranslateCC'); $deps[] = new GlobalDependency('wgTranslateExtensionDirectory'); $deps[] = new GlobalDependency('wgTranslateWorkflowStates'); $deps[] = new FileDependency(dirname(__FILE__) . '/groups/mediawiki-defines.txt'); $deps[] = new FileDependency(dirname(__FILE__) . '/groups/Wikia/extensions.txt'); $deps[] = new FileDependency(dirname(__FILE__) . '/groups/Toolserver/toolserver-textdomains.txt'); if ($wgTranslateAddMWExtensionGroups) { $a = new PremadeMediawikiExtensionGroups(); $a->addAll(); } if ($wgEnablePageTranslation) { $dbr = wfGetDB(DB_MASTER); $tables = array('page', 'revtag'); $vars = array('page_id', 'page_namespace', 'page_title'); $conds = array('page_id=rt_page', 'rt_type' => RevTag::getType('tp:mark')); $options = array('GROUP BY' => 'rt_page'); $res = $dbr->select($tables, $vars, $conds, __METHOD__, $options); foreach ($res as $r) { $title = Title::makeTitle($r->page_namespace, $r->page_title); $id = TranslatablePage::getMessageGroupIdFromTitle($title); $wgTranslateCC[$id] = new WikiPageMessageGroup($id, $title); $wgTranslateCC[$id]->setLabel($title->getPrefixedText()); } } if ($wgTranslateWorkflowStates) { $wgTranslateCC['translate-workflow-states'] = new WorkflowStatesMessageGroup(); } $autoload = array(); wfRunHooks('TranslatePostInitGroups', array(&$wgTranslateCC, &$deps, &$autoload)); foreach ($wgTranslateGroupFiles as $configFile) { wfDebug($configFile . "\n"); $deps[] = new FileDependency(realpath($configFile)); $fgroups = TranslateYaml::parseGroupFile($configFile); foreach ($fgroups as $id => $conf) { if (!empty($conf['AUTOLOAD']) && is_array($conf['AUTOLOAD'])) { $dir = dirname($configFile); foreach ($conf['AUTOLOAD'] as $class => $file) { // For this request and for caching. $wgAutoloadClasses[$class] = "{$dir}/{$file}"; $autoload[$class] = "{$dir}/{$file}"; } } $group = MessageGroupBase::factory($conf); $wgTranslateCC[$id] = $group; } } $key = wfMemckey('translate-groups'); $value = array('ac' => $wgTranslateAC, 'ec' => $wgTranslateEC, 'cc' => $wgTranslateCC, 'autoload' => $autoload); $wrapper = new DependencyWrapper($value, $deps); $wrapper->storeToCache(self::getCache(), $key, 60 * 60 * 2); wfDebug(__METHOD__ . "-end\n"); }
/** * @param $title Title * @return bool|TranslatablePage */ public static function isTranslationPage(Title $title) { list($key, $code) = TranslateUtils::figureMessage($title->getText()); if ($key === '' || $code === '') { return false; } $codes = Language::getLanguageNames(false); global $wgTranslateDocumentationLanguageCode; unset($codes[$wgTranslateDocumentationLanguageCode]); if (!isset($codes[$code])) { return false; } $newtitle = self::changeTitleText($title, $key); if (!$newtitle) { return false; } $page = TranslatablePage::newFromTitle($newtitle); if ($page->getMarkedTag() === false) { return false; } return $page; }
/** * Keep the usual diiba daaba hidden from translators. * Hook: AlternateEdit */ public static function intro( EditPage $editpage ) { $handle = new MessageHandle( $editpage->mTitle ); if ( $handle->isValid() ) { $editpage->suppressIntro = true; return true; } $msg = wfMsgForContent( 'translate-edit-tag-warning' ); if ( $msg !== '' && $msg !== '-' && TranslatablePage::isSourcePage( $editpage->mTitle ) ) { global $wgOut; $editpage->editFormTextTop .= $wgOut->parse( $msg ); } return true; }
protected function checkMoveBlockers() { $blockers = array(); $target = $this->newTitle; if (!$target) { $blockers[] = array('pt-movepage-block-base-invalid'); return $blockers; } if ($target->getNamespace() == NS_MEDIAWIKI || $target->getNamespace() == NS_TRANSLATIONS) { $blockers[] = array('immobile-target-namespace', $target->getNsText()); return $blockers; } $base = $this->oldTitle->getPrefixedText(); if ($target->exists()) { $blockers[] = array('pt-movepage-block-base-exists', $target->getPrefixedText()); } else { $errors = $this->oldTitle->isValidMoveOperation($target, true, $this->reason); if (is_array($errors)) { $blockers = array_merge($blockers, $errors); } } // Don't spam the same errors for all pages if base page fails if ($blockers) { return $blockers; } // Collect all the old and new titles for checcks $titles = array(); $pages = $this->getTranslationPages(); foreach ($pages as $old) { $titles['tp'][] = array($old, $this->newPageTitle($base, $old, $target)); } $pages = $this->getSectionPages(); foreach ($pages as $old) { $titles['section'][] = array($old, $this->newPageTitle($base, $old, $target)); } $subpages = array(); if ($this->moveSubpages) { $subpages = $this->getSubpages(); } foreach ($subpages as $old) { if (!TranslatablePage::isTranslationPage($old)) { $titles['subpage'][] = array($old, $this->newPageTitle($base, $old, $target)); } } // Check that all new titles are valid $lb = new LinkBatch(); foreach ($titles as $type => $list) { // Give grep a chance to find the usages: // pt-movepage-block-tp-invalid, pt-movepage-block-section-invalid, // pt-movepage-block-subpage-invalid foreach ($list as $pair) { list($old, $new) = $pair; if ($new === null) { $blockers[] = array("pt-movepage-block-{$type}-invalid", $old->getPrefixedText()); continue; } $lb->addObj($old); $lb->addObj($new); } } if ($blockers) { return $blockers; } // Check that there are no move blockers $lb->execute(); foreach ($titles as $type => $list) { // Give grep a chance to find the usages: // pt-movepage-block-tp-exists, pt-movepage-block-section-exists, // pt-movepage-block-subpage-exists foreach ($list as $pair) { list($old, $new) = $pair; if ($new->exists()) { $blockers[] = array("pt-movepage-block-{$type}-exists", $old->getPrefixedText(), $new->getPrefixedText()); } else { /* This method has terrible performance: * - 2 queries by core * - 3 queries by lqt * - and no obvious way to preload the data! */ $errors = $old->isValidMoveOperation($target, false); if (is_array($errors)) { $blockers = array_merge($blockers, $errors); } /* Because of the above, check only one of the possibly thousands * of section pages and assume rest are fine. */ if ($type === 'section') { break; } } } } return $blockers; }
public static function getTranslatablePages(array &$groups, array &$deps, array &$autoload) { global $wgEnablePageTranslation; $deps[] = new GlobalDependency('wgEnablePageTranslation'); if (!$wgEnablePageTranslation) { return; } $db = wfGetDB(DB_MASTER); $tables = array('page', 'revtag'); $vars = array('page_id', 'page_namespace', 'page_title'); $conds = array('page_id=rt_page', 'rt_type' => RevTag::getType('tp:mark')); $options = array('GROUP BY' => 'rt_page'); $res = $db->select($tables, $vars, $conds, __METHOD__, $options); foreach ($res as $r) { $title = Title::newFromRow($r); $id = TranslatablePage::getMessageGroupIdFromTitle($title); $groups[$id] = new WikiPageMessageGroup($id, $title); $groups[$id]->setLabel($title->getPrefixedText()); } }
/** * Returns translation page with all possible translations replaced in * and ugly translation tags removed. * * @param MessageCollection $collection Collection that holds translated messages. * @return string Whole page as wikitext. */ public function getTranslationPageText($collection) { $text = $this->template; // The source // For finding the messages $prefix = $this->title->getPrefixedDBKey() . '/'; if ($collection instanceof MessageCollection) { $collection->loadTranslations(DB_MASTER); $collection->filter('translated', false); } foreach ($this->sections as $ph => $s) { $sectiontext = null; if (isset($collection[$prefix . $s->id])) { /** * @var TMessage $msg */ $msg = $collection[$prefix . $s->id]; $sectiontext = $msg->translation(); } // Use the original text if no translation is available. // For the source language, this will actually be the source, which // contains variable declarations (tvar) instead of variables ($1). // The getTextWithVariables will convert declarations to normal variables // for us so that the variable substitutions below will also work // for the source language. if ($sectiontext === null || $sectiontext === $s->getText()) { $sectiontext = $s->getTextWithVariables(); } // Substitute variables into section text and substitute text into document $sectiontext = strtr($sectiontext, $s->getVariables()); $text = str_replace($ph, $sectiontext, $text); } $nph = array(); $text = TranslatablePage::armourNowiki($nph, $text); // Remove translation markup from the template to produce final text $cb = array(__CLASS__, 'replaceTagCb'); $text = preg_replace_callback('~(<translate>)(.*)(</translate>)~sU', $cb, $text); $text = TranslatablePage::unArmourNowiki($nph, $text); return $text; }
protected function getTranslationPageDiff() { global $wgEnablePageTranslation; if (!$wgEnablePageTranslation) { return null; } $this->mustBeKnownMessage(); if (!$this->group instanceof WikiPageMessageGroup) { return null; } // Shortcuts $code = $this->handle->getCode(); $key = $this->handle->getKey(); // TODO: encapsulate somewhere $page = TranslatablePage::newFromTitle($this->group->getTitle()); $rev = $page->getTransRev("{$key}/{$code}"); $latest = $page->getMarkedTag(); if ($rev === $latest) { return null; } $oldpage = TranslatablePage::newFromRevision($this->group->getTitle(), $rev); $oldtext = $newtext = null; foreach ($oldpage->getParse()->getSectionsForSave() as $section) { if ($this->group->getTitle()->getPrefixedDBKey() . '/' . $section->id === $key) { $oldtext = $section->getTextForTrans(); } } foreach ($page->getParse()->getSectionsForSave() as $section) { if ($this->group->getTitle()->getPrefixedDBKey() . '/' . $section->id === $key) { $newtext = $section->getTextForTrans(); } } if ($oldtext === $newtext) { return null; } $diff = new DifferenceEngine(); if (method_exists('DifferenceEngine', 'setTextLanguage')) { $diff->setTextLanguage($this->group->getSourceLanguage()); } $diff->setText($oldtext, $newtext); $diff->setReducedLineNumbers(); $diff->showDiffStyle(); return $diff->getDiff(wfMsgHtml('tpt-diff-old'), wfMsgHtml('tpt-diff-new')); }
/** * Returns translation page with all possible translations replaced in, ugly * translation tags removed and outdated translation marked with a class * mw-translate-fuzzy. * @todo The class marking has to be more intelligent with span&div use. * @param $collection \type{MessageCollection} Collection that holds translated messages. * @return \string Whole page as wikitext. */ public function getTranslationPageText( /*MessageCollection*/ $collection ) { $text = $this->template; // The source // For finding the messages $prefix = $this->title->getPrefixedDBKey() . '/'; if ( $collection instanceof MessageCollection ) { $collection->filter( 'hastranslation', false ); $collection->loadTranslations(); } foreach ( $this->sections as $ph => $s ) { $sectiontext = null; if ( isset( $collection[$prefix . $s->id] ) ) { $msg = $collection[$prefix . $s->id]; $translation = $msg->translation(); if ( $translation !== null ) { // Ideally we should not have fuzzy here, but old texts do $sectiontext = str_replace( TRANSLATE_FUZZY, '', $translation ); if ( $msg->hasTag( 'fuzzy' ) ) { $sectiontext = "<span class=\"mw-translate-fuzzy\">\n$sectiontext\n</span>"; } } } // Use the original text if no translation is available if ( $sectiontext === null ) { $sectiontext = $s->getTextForTrans(); } // Substitute variables into section text and substitute text into document $sectiontext = self::replaceVariables( $s->getVariables(), $sectiontext ); $text = str_replace( $ph, $sectiontext, $text ); } $nph = array(); $text = TranslatablePage::armourNowiki( $nph, $text ); // Remove translation markup $cb = array( __CLASS__, 'replaceTagCb' ); $text = preg_replace_callback( '~(<translate>)(.*)(</translate>)~sU', $cb, $text ); $text = TranslatablePage::unArmourNowiki( $nph, $text ); return $text; }
public function setupRenderJobs( TranslatablePage $page ) { $titles = $page->getTranslationPages(); $this->addInitialRenderJob( $page, $titles ); $jobs = array(); foreach ( $titles as $t ) { self::superDebug( __METHOD__, 'renderjob', $t ); $jobs[] = RenderJob::newJob( $t ); } if ( count( $jobs ) < 10 ) { self::superDebug( __METHOD__, 'renderjob-immediate' ); foreach ( $jobs as $j ) { $j->run(); } } else { // Use the job queue self::superDebug( __METHOD__, 'renderjob-delayed' ); Job::batchInsert( $jobs ); } }
/** * Creates jobs needed to create or update all translation page definitions. * @param TranslatablePage $page * @param array $sections * @return Job[] * @since 2013-01-28 */ public static function getTranslationUnitJobs(TranslatablePage $page, array $sections) { $jobs = array(); $code = $page->getSourceLanguageCode(); $prefix = $page->getTitle()->getPrefixedText(); foreach ($sections as $s) { $unit = $s->name; $title = Title::makeTitle(NS_TRANSLATIONS, "{$prefix}/{$unit}/{$code}"); $fuzzy = $s->type === 'changed'; $jobs[] = MessageUpdateJob::newJob($title, $s->getTextWithVariables(), $fuzzy); } return $jobs; }