Index: trunk/extensions/Translate/tag/TranslatablePage.php |
— | — | @@ -263,13 +263,7 @@ |
264 | 264 | return $db->select( 'revtag', $fields, $conds, __METHOD__, $options ); |
265 | 265 | } |
266 | 266 | |
267 | | - public function getTranslationPercentages( $force = false ) { |
268 | | - // Check the memory cache, as this is very slow to calculate |
269 | | - global $wgMemc; |
270 | | - $memcKey = wfMemcKey( 'pt', 'status', $this->getTitle()->getPrefixedText() ); |
271 | | - $cache = $wgMemc->get( $memcKey ); |
272 | | - if ( !$force && is_array( $cache ) ) return $cache; |
273 | | - |
| 267 | + public function getTranslationPages() { |
274 | 268 | // Fetch the available translation pages from database |
275 | 269 | $dbr = wfGetDB( DB_SLAVE ); |
276 | 270 | $likePattern = $dbr->escapeLike( $this->getTitle()->getDBkey() ) . '/%%'; |
— | — | @@ -282,7 +276,20 @@ |
283 | 277 | ), __METHOD__ ); |
284 | 278 | |
285 | 279 | $titles = TitleArray::newFromResult( $res ); |
| 280 | + return $titles; |
| 281 | + } |
286 | 282 | |
| 283 | + public function getTranslationPercentages( $force = false ) { |
| 284 | + // Check the memory cache, as this is very slow to calculate |
| 285 | + global $wgMemc, $wgRequest; |
| 286 | + $memcKey = wfMemcKey( 'pt', 'status', $this->getTitle()->getPrefixedText() ); |
| 287 | + $cache = $wgMemc->get( $memcKey ); |
| 288 | + if ( !$force && $wgRequest->getText( 'action' ) !== 'purge' ) { |
| 289 | + if ( is_array($cache) ) return $cache; |
| 290 | + } |
| 291 | + |
| 292 | + $titles = $this->getTranslationPages(); |
| 293 | + |
287 | 294 | // Calculate percentages for the available translations |
288 | 295 | $group = MessageGroups::getGroup( 'page|' . $this->getTitle()->getPrefixedText() ); |
289 | 296 | if ( !$group instanceof WikiPageMessageGroup ) return null; |
— | — | @@ -292,8 +299,8 @@ |
293 | 300 | |
294 | 301 | $temp = array(); |
295 | 302 | foreach ( $titles as $t ) { |
296 | | - if ( $t->getSubpageText() === $t->getText() ) continue; |
297 | | - $collection = $group->initCollection( $t->getSubpageText() ); |
| 303 | + list( , $code ) = TranslateUtils::figureMessage( $t->getText() ); |
| 304 | + $collection = $group->initCollection( $code ); |
298 | 305 | $group->fillCollection( $collection ); |
299 | 306 | |
300 | 307 | $percent = $this->getPercentageInternal( $collection, $markedRevs ); |
Index: trunk/extensions/Translate/tag/RenderJob.php |
— | — | @@ -1,69 +1,112 @@ |
2 | 2 | <?php |
3 | 3 | |
4 | 4 | /** |
5 | | - * Job for updating tag translation pages when changes happen. |
| 5 | + * Job for updating translation pages. |
6 | 6 | * |
7 | 7 | * @addtogroup Extensions |
8 | 8 | * |
9 | 9 | * @author Niklas Laxström |
10 | | - * @copyright Copyright © 2008, Niklas Laxström |
| 10 | + * @copyright Copyright © 2008-2009, Niklas Laxström |
11 | 11 | * @license http://www.gnu.org/copyleft/gpl.html GNU General Public License 2.0 or later |
12 | 12 | */ |
13 | 13 | |
14 | 14 | class RenderJob extends Job { |
15 | | - public static function renderPage( Title $source, Title $target, $user, $summary, $flags, $now = false ) { |
16 | | - $job = new self( $source, array( |
17 | | - 'source' => $source, |
18 | | - 'target' => $target, |
19 | | - 'user' => $user, |
20 | | - 'summary' => $summary, |
21 | | - 'flags' => $flags, |
22 | | - ) ); |
| 15 | + public static function newJob( Title $target ) { |
| 16 | + global $wgTranslateFuzzyBotName; |
| 17 | + wfLoadExtensionMessages( 'PageTranslation' ); |
23 | 18 | |
24 | | - if ( $now ) $job->run(); |
25 | | - else Job::batchInsert( array( $job ) ); |
| 19 | + $job = new self( $target ); |
| 20 | + $job->setUser( $wgTranslateFuzzyBotName ); |
| 21 | + $job->setFlags( EDIT_FORCE_BOT ); |
| 22 | + $job->setSummary( wfMsg( 'tpt-render-summary' ) ); |
| 23 | + return $job; |
26 | 24 | } |
27 | 25 | |
28 | | - function __construct( $title, $params = false, $id = 0 ) { |
| 26 | + function __construct( $title, $params = array(), $id = 0 ) { |
29 | 27 | parent::__construct( __CLASS__, $title, $params, $id ); |
30 | 28 | $this->params = $params; |
31 | 29 | $this->removeDuplicates = true; |
32 | 30 | } |
33 | 31 | |
34 | 32 | function run() { |
35 | | - global $wgUser; |
| 33 | + // Initialization |
| 34 | + $title = $this->title; |
| 35 | + list( $key, $code ) = TranslateUtils::figureMessage( $title->getPrefixedText() ); |
36 | 36 | |
37 | | - $source = $this->params['source']; |
38 | | - $target = $this->params['target']; |
39 | | - $user = User::newFromName( $this->params['user'] ); |
40 | | - $summary = $this->params['summary']; |
41 | | - $flags = $this->params['flags']; |
| 37 | + // Return the actual translation page... |
| 38 | + $page = TranslatablePage::isTranslationPage( $title ); |
| 39 | + $group = MessageGroups::getGroup( "page|$key" ); |
| 40 | + $collection = $group->initCollection( $code ); |
| 41 | + $group->fillCollection( $collection ); |
42 | 42 | |
43 | | - list( , $code ) = TranslateTagUtils::keyAndCode( $target ); |
| 43 | + // Muck up the text |
| 44 | + $text = $page->getParse()->getTranslationPageText( $collection ); |
| 45 | + // Same as in renderSourcePage |
| 46 | + $cb = array( __CLASS__, 'replaceTagCb' ); |
| 47 | + $text = preg_replace_callback( '~(\n?<translate>\s*?)(.*?)(\s*?</translate>)~s', $cb, $text ); |
44 | 48 | |
45 | | - // Try to get the text of the page |
46 | | - $text = TranslateTagUtils::getTagPageSource( $source ); |
47 | | - if ( $text === null ) return; |
| 49 | + // Other stuff |
| 50 | + $user = $this->getUser(); |
| 51 | + $summary = $this->getSummary(); |
| 52 | + $flags = $this->getFlags(); |
48 | 53 | |
49 | | - // Construct a translated page |
50 | | - $tag = TranslateTag::getInstance(); |
51 | | - $text = $tag->renderPage( $text, $source, $code ); |
52 | | - $text .= '<translate />'; // hint that we know to set the parser language |
| 54 | + $article = new Article( $title ); |
53 | 55 | |
54 | | - # Save it |
| 56 | + // TODO: fuzzybot hack |
| 57 | + PageTranslationHooks::$allowTargetEdit = true; |
| 58 | + |
| 59 | + // User hack |
| 60 | + global $wgUser; |
55 | 61 | $oldUser = $wgUser; |
56 | 62 | $wgUser = $user; |
57 | | - $article = new Article( $target ); |
| 63 | + |
| 64 | + // Do the edit |
58 | 65 | $article->doEdit( $text, $summary, $flags ); |
| 66 | + |
| 67 | + // User hack |
59 | 68 | $wgUser = $oldUser; |
60 | 69 | |
| 70 | + PageTranslationHooks::$allowTargetEdit = false; |
| 71 | + |
| 72 | + // purge cache |
| 73 | + $page->getTranslationPercentages( true ); |
| 74 | + |
61 | 75 | return true; |
62 | 76 | } |
63 | 77 | |
| 78 | + public static function replaceTagCb( $matches ) { |
| 79 | + return $matches[2]; |
| 80 | + } |
| 81 | + |
| 82 | + public function setFlags( $flags ) { |
| 83 | + $this->params['flags'] = $flags; |
| 84 | + } |
| 85 | + |
| 86 | + public function getFlags() { |
| 87 | + return $this->params['flags']; |
| 88 | + } |
| 89 | + |
| 90 | + |
| 91 | + public function setSummary( $summary ) { |
| 92 | + $this->params['summary'] = $summary; |
| 93 | + } |
| 94 | + |
| 95 | + public function getSummary() { |
| 96 | + return $this->params['summary']; |
| 97 | + } |
| 98 | + |
| 99 | + |
| 100 | + public function setUser( $user ) { |
| 101 | + if ( $user instanceof User ) { |
| 102 | + $this->params['user'] = $user->getName(); |
| 103 | + } else { |
| 104 | + $this->params['user'] = $user; |
| 105 | + } |
| 106 | + } |
64 | 107 | /** |
65 | | - * Get a user object for doing edits, from a request-lifetime cache |
| 108 | + * Get a user object for doing edits. |
66 | 109 | */ |
67 | | - function getUser() { |
| 110 | + public function getUser() { |
68 | 111 | return User::newFromName( $this->params['user'], false ); |
69 | 112 | } |
70 | 113 | } |
Index: trunk/extensions/Translate/tag/SpecialPageTranslation.php |
— | — | @@ -1,6 +1,7 @@ |
2 | 2 | <?php |
3 | 3 | /** |
4 | 4 | * A special page for marking revisions of pages for translation. |
| 5 | + * There are two modes 1) list of all pages 2) review mode for one page. |
5 | 6 | * |
6 | 7 | * @author Niklas Laxström |
7 | 8 | * @copyright Copyright © 2009 Niklas Laxström |
— | — | @@ -40,9 +41,12 @@ |
41 | 42 | |
42 | 43 | // We are processing some specific page |
43 | 44 | if ( $revision === '0' ) { |
| 45 | + // Get the latest revision |
44 | 46 | $revision = $title->getLatestRevID(); |
45 | 47 | } elseif ( $revision !== $title->getLatestRevID() ) { |
| 48 | + // We do want to notify the reviewer if the underlying page changes during review |
46 | 49 | $wgOut->addWikiMsg( 'tpt-oldrevision', $title->getPrefixedText(), $revision ); |
| 50 | + $this->listPages(); |
47 | 51 | return; |
48 | 52 | } |
49 | 53 | |
— | — | @@ -238,7 +242,8 @@ |
239 | 243 | return $sections; |
240 | 244 | } |
241 | 245 | |
242 | | - public function showPage( TranslatablePage $page, $sections ) { |
| 246 | + /** Displays the sections and changes for the user to review */ |
| 247 | + public function showPage( TranslatablePage $page, Array $sections ) { |
243 | 248 | global $wgOut, $wgScript, $wgLang; |
244 | 249 | |
245 | 250 | $wgOut->setSubtitle( $this->user->getSkin()->link( $page->getTitle() ) ); |
— | — | @@ -317,31 +322,38 @@ |
318 | 323 | ); |
319 | 324 | } |
320 | 325 | |
321 | | - protected function makeSectionElement( $legend, $type, $content ) { |
322 | | - global $wgOut; |
| 326 | + protected function makeSectionElement( $legend, $type, $content ) { |
| 327 | + global $wgOut; |
323 | 328 | |
324 | | - $containerParams = array( 'class' => "mw-tpt-sp-section mw-tpt-sp-section-type-{$type}" ); |
325 | | - $legendParams = array( 'class' => 'mw-tpt-sp-legend' ); |
326 | | - $contentParams = array( 'class' => 'mw-tpt-sp-content' ); |
| 329 | + $containerParams = array( 'class' => "mw-tpt-sp-section mw-tpt-sp-section-type-{$type}" ); |
| 330 | + $legendParams = array( 'class' => 'mw-tpt-sp-legend' ); |
| 331 | + $contentParams = array( 'class' => 'mw-tpt-sp-content' ); |
327 | 332 | |
328 | | - $wgOut->addHTML( |
329 | | - Xml::tags( 'div', $containerParams, |
330 | | - Xml::tags( 'div', $legendParams, $legend ) . |
331 | | - Xml::tags( 'div', $contentParams, $content ) |
332 | | - ) |
333 | | - ); |
334 | | - } |
| 333 | + $wgOut->addHTML( |
| 334 | + Xml::tags( 'div', $containerParams, |
| 335 | + Xml::tags( 'div', $legendParams, $legend ) . |
| 336 | + Xml::tags( 'div', $contentParams, $content ) |
| 337 | + ) |
| 338 | + ); |
| 339 | + } |
335 | 340 | |
| 341 | + /** |
| 342 | + * This function does the heavy duty of marking a page. |
| 343 | + * - Updates the source page with section markers. |
| 344 | + * - Updates translate_sections table |
| 345 | + * - Updates revtags table |
| 346 | + * - Setups renderjobs to update the translation pages |
| 347 | + * - Invalidates caches |
| 348 | + */ |
| 349 | + public function markForTranslation( TranslatablePage $page, Array $sections ) { |
336 | 350 | |
337 | | - public function markForTranslation( TranslatablePage $page, $sections ) { |
338 | | - $text = $page->getParse()->getSourcePageText(); |
339 | | - |
| 351 | + // Add the section markers to the source page |
340 | 352 | $article = new Article( $page->getTitle() ); |
341 | 353 | $status = $article->doEdit( |
342 | | - $text, |
343 | | - wfMsgForContent( 'tpt-mark-summary' ), |
344 | | - EDIT_FORCE_BOT | EDIT_UPDATE, |
345 | | - $page->getRevision() |
| 354 | + $page->getParse()->getSourcePageText(), // Content |
| 355 | + wfMsgForContent( 'tpt-mark-summary' ), // Summary |
| 356 | + EDIT_FORCE_BOT | EDIT_UPDATE, // Flags |
| 357 | + $page->getRevision() // Based-on revision |
346 | 358 | ); |
347 | 359 | |
348 | 360 | if ( !$status->isOK() ) return array( 'tpt-edit-failed', $status->getWikiText() ); |
— | — | @@ -355,10 +367,11 @@ |
356 | 368 | } |
357 | 369 | |
358 | 370 | if ( $newrevision === null ) { |
359 | | - // Probably a no-change edit, so no new revision was assigned |
| 371 | + // Probably a no-change edit, so no new revision was assigned. |
| 372 | + // Get the latest revision manually |
360 | 373 | $newrevision = $page->getTitle()->getLatestRevId(); |
361 | 374 | } |
362 | | - |
| 375 | + |
363 | 376 | $inserts = array(); |
364 | 377 | $changed = array(); |
365 | 378 | foreach ( $sections as $s ) { |
— | — | @@ -369,19 +382,40 @@ |
370 | 383 | 'trs_text' => $s->getText(), |
371 | 384 | ); |
372 | 385 | } |
373 | | - // Don't add empty rows |
| 386 | + |
| 387 | + // Don't add stuff is no changes, use the plain null instead for prettiness |
374 | 388 | if ( !count($changed) ) $changed = null; |
375 | 389 | |
376 | 390 | $dbw = wfGetDB( DB_MASTER ); |
377 | 391 | $dbw->delete( 'translate_sections', array( 'trs_page' => $page->getTitle()->getArticleId() ), __METHOD__ ); |
378 | 392 | $ok = $dbw->insert( 'translate_sections', $inserts, __METHOD__ ); |
379 | 393 | |
| 394 | + // Store changed sections in the database for easy access. |
| 395 | + // Used when determinen the up-to-datedness for section translations. |
380 | 396 | $page->addMarkedTag( $newrevision, $changed ); |
| 397 | + |
| 398 | + $this->setupRenderJobs( $page ); |
| 399 | + |
381 | 400 | // Re-generate caches |
382 | 401 | MessageIndex::cache( NS_TRANSLATIONS ); |
383 | | - $page->getTranslationPercentages( true ); |
| 402 | + $page->getTranslationPercentages( /*re-generate*/ true ); |
384 | 403 | |
385 | 404 | return false; |
386 | 405 | } |
387 | 406 | |
| 407 | + public function setupRenderJobs( TranslatablePage $page ) { |
| 408 | + $titles = $page->getTranslationPages(); |
| 409 | + $jobs = array(); |
| 410 | + foreach ( $titles as $t ) { |
| 411 | + $jobs[] = RenderJob::newJob( $t ); |
| 412 | + } |
| 413 | + |
| 414 | + if ( count($jobs) < 10 ) { |
| 415 | + foreach ( $jobs as $j ) $j->run(); |
| 416 | + } else { |
| 417 | + // Use the job queue |
| 418 | + Job::batchInsert( $jobs ); |
| 419 | + } |
| 420 | + } |
| 421 | + |
388 | 422 | } |
Index: trunk/extensions/Translate/tag/PageTranslationHooks.php |
— | — | @@ -52,7 +52,7 @@ |
53 | 53 | |
54 | 54 | // Update the target translation page |
55 | 55 | list(, $code ) = TranslateUtils::figureMessage( $title->getDBkey() ); |
56 | | - self::updateTranslationPage( $page, $group, $code, $user, $flags, $summary ); |
| 56 | + self::updateTranslationPage( $page, $code, $user, $flags, $summary ); |
57 | 57 | |
58 | 58 | return true; |
59 | 59 | } |
— | — | @@ -79,31 +79,17 @@ |
80 | 80 | } |
81 | 81 | |
82 | 82 | public static function updateTranslationPage( TranslatablePage $page, |
83 | | - MessageGroup $group, $code, $user, $flags, $summary ) { |
| 83 | + $code, $user, $flags, $summary ) { |
84 | 84 | |
85 | 85 | $source = $page->getTitle(); |
86 | 86 | $target = Title::makeTitle( $source->getNamespace(), $source->getDBkey() . "/$code" ); |
87 | | - |
88 | | - $collection = $group->initCollection( $code ); |
89 | | - $group->fillCollection( $collection ); |
90 | | - |
91 | | - $text = $page->getParse()->getTranslationPageText( $collection ); |
92 | | - |
93 | | - // Same as in renderSourcePage |
94 | | - $cb = array( __CLASS__, 'replaceTagCb' ); |
95 | | - $text = preg_replace_callback( '~(\n?<translate>\s*?)(.*?)(\s*?</translate>)~s', $cb, $text ); |
96 | | - |
97 | | - #$flags |= EDIT_SUPPRESS_RC; // We can filter using CleanChanges |
98 | 87 | $flags &= ~EDIT_NEW & ~EDIT_UPDATE; // We don't know |
99 | 88 | |
100 | | - $article = new Article( $target ); |
101 | | - |
102 | | - self::$allowTargetEdit = true; |
103 | | - $article->doEdit( $text, $summary, $flags ); |
104 | | - self::$allowTargetEdit = false; |
105 | | - |
106 | | - // purge cache |
107 | | - $page->getTranslationPercentages( true ); |
| 89 | + $job = RenderJob::newJob( $target ); |
| 90 | + $job->setUser( $user ); |
| 91 | + $job->setSummary( $summary ); |
| 92 | + $job->setFlags( $flags ); |
| 93 | + $job->run(); |
108 | 94 | } |
109 | 95 | |
110 | 96 | public static function addSidebar( $out, $tpl ) { |
— | — | @@ -268,10 +254,7 @@ |
269 | 255 | // Case 2: Target pages |
270 | 256 | $page = TranslatablePage::isTranslationPage( $title ); |
271 | 257 | if ( $page !== false ) { |
272 | | - // Local override of fuzzybot is allowed |
273 | | - global $wgTranslateFuzzyBotName; |
274 | | - if ( self::$allowTargetEdit || |
275 | | - $user->getName() === $wgTranslateFuzzyBotName ) return true; |
| 258 | + if ( self::$allowTargetEdit ) return true; |
276 | 259 | |
277 | 260 | if ( $page->getMarkedTag() ) { |
278 | 261 | list( , $code ) = TranslateUtils::figureMessage( $title->getText() ); |
Index: trunk/extensions/Translate/Translate.php |
— | — | @@ -64,7 +64,7 @@ |
65 | 65 | $wgEnablePageTranslation = false; |
66 | 66 | $wgPageTranslationNamespace = 1198; |
67 | 67 | |
68 | | -//$wgJobClasses['RenderJob'] = 'RenderJob'; |
| 68 | +$wgJobClasses['RenderJob'] = 'RenderJob'; |
69 | 69 | $wgAvailableRights[] = 'translate'; |
70 | 70 | |
71 | 71 | define( 'TRANSLATE_FUZZY', '!!FUZZY!!' ); |
Index: trunk/extensions/Translate/_autoload.php |
— | — | @@ -80,8 +80,6 @@ |
81 | 81 | $wgAutoloadClasses['NoccMessageGroup'] = $dir . 'groups/Nocc.php'; |
82 | 82 | $wgAutoloadClasses['OpenLayersMessageGroup'] = $dir . 'groups/OpenLayers.php'; |
83 | 83 | |
84 | | -# tag |
85 | | -#$wgAutoloadClasses['RenderJob'] = $dir . 'tag/RenderJob.php'; |
86 | 84 | # page translation |
87 | 85 | $wgAutoloadClasses['PageTranslationHooks'] = $dir . 'tag/PageTranslationHooks.php'; |
88 | 86 | $wgAutoloadClasses['TranslatablePage'] = $dir . 'tag/TranslatablePage.php'; |
— | — | @@ -89,3 +87,4 @@ |
90 | 88 | $wgAutoloadClasses['TPParse'] = $dir . 'tag/TPParse.php'; |
91 | 89 | $wgAutoloadClasses['TPSection'] = $dir . 'tag/TPSection.php'; |
92 | 90 | $wgAutoloadClasses['SpecialPageTranslation'] = $dir . 'tag/SpecialPageTranslation.php'; |
| 91 | +$wgAutoloadClasses['RenderJob'] = $dir . 'tag/RenderJob.php'; |
Index: trunk/extensions/Translate/PageTranslation.i18n.php |
— | — | @@ -68,6 +68,8 @@ |
69 | 69 | The page you are trying to edit does not seem to correspond any page marked for translation.', |
70 | 70 | |
71 | 71 | 'tpt-install' => 'Run php maintenance/update.php or web install to enable page translation feature.', |
| 72 | + |
| 73 | + 'tpt-render-summary' => 'Updating to match new version of source page', |
72 | 74 | ); |
73 | 75 | |
74 | 76 | /** Message documentation (Message documentation) |