Index: trunk/extensions/Translate/MessageCollection.php |
— | — | @@ -42,6 +42,9 @@ |
43 | 43 | /// \type{Database Result Resource} Stored translations in database. |
44 | 44 | protected $dbData = null; |
45 | 45 | |
| 46 | + /// \type{Database Result Resource} Stored reviews in database. |
| 47 | + protected $dbReviewData = null; |
| 48 | + |
46 | 49 | /** |
47 | 50 | * Tags, copied to thin messages |
48 | 51 | * tagtype => keys |
— | — | @@ -51,6 +54,9 @@ |
52 | 55 | /// \list{String} Authors. |
53 | 56 | protected $authors = array(); |
54 | 57 | |
| 58 | + /// bool Whether review info is loaded |
| 59 | + protected $reviewMode = false; |
| 60 | + |
55 | 61 | /** |
56 | 62 | * Constructors. Use newFromDefinitions() instead. |
57 | 63 | * @param $code \string Language code. |
— | — | @@ -184,6 +190,14 @@ |
185 | 191 | $this->authors = array_unique( $authors ); |
186 | 192 | } |
187 | 193 | |
| 194 | + /** |
| 195 | + * Call this to load list of reviewers for each message. |
| 196 | + * Can be accessed from TMessage::getReviewers(). |
| 197 | + */ |
| 198 | + public function setReviewMode( $value = true ) { |
| 199 | + $this->reviewMode = $value; |
| 200 | + } |
| 201 | + |
188 | 202 | // Data modifiers |
189 | 203 | |
190 | 204 | /** |
— | — | @@ -195,6 +209,9 @@ |
196 | 210 | public function loadTranslations( $dbtype = DB_SLAVE ) { |
197 | 211 | $this->loadData( $this->keys, $dbtype ); |
198 | 212 | $this->loadInfo( $this->keys, $dbtype ); |
| 213 | + if ( $this->reviewMode ) { |
| 214 | + $this->loadReviewInfo( $this->keys, $dbtype ); |
| 215 | + } |
199 | 216 | $this->initMessages(); |
200 | 217 | } |
201 | 218 | |
— | — | @@ -510,6 +527,40 @@ |
511 | 528 | } |
512 | 529 | |
513 | 530 | /** |
| 531 | + * Loads reviewers for given messages. |
| 532 | + * @param $keys \list{String} List of keys in database format. |
| 533 | + * @param $dbtype One of DB_* constants. |
| 534 | + */ |
| 535 | + protected function loadReviewInfo( array $keys, $dbtype = DB_SLAVE ) { |
| 536 | + if ( $this->dbReviewData !== null ) { |
| 537 | + return; |
| 538 | + } |
| 539 | + |
| 540 | + $this->dbReviewData = array(); |
| 541 | + |
| 542 | + if ( !count( $keys ) ) { |
| 543 | + return; |
| 544 | + } |
| 545 | + |
| 546 | + $dbr = wfGetDB( $dbtype ); |
| 547 | + |
| 548 | + $tables = array( 'page', 'translate_reviews' ); |
| 549 | + $fields = array( 'page_title', 'trr_user' ); |
| 550 | + $conds = array( |
| 551 | + 'page_namespace' => $this->definitions->namespace, |
| 552 | + 'page_title' => array_values( $keys ), |
| 553 | + ); |
| 554 | + $joins = array( 'translate_reviews' => |
| 555 | + array( |
| 556 | + 'JOIN', |
| 557 | + array( 'page_id=trr_page', 'page_latest=trr_revision' ) |
| 558 | + ) |
| 559 | + ); |
| 560 | + |
| 561 | + $this->dbReviewData = $dbr->select( $tables, $fields, $conds, __METHOD__, array(), $joins ); |
| 562 | + } |
| 563 | + |
| 564 | + /** |
514 | 565 | * Loads translation for given list of keys. |
515 | 566 | * @param $keys \list{String} List of keys in database format. |
516 | 567 | * @param $dbtype One of DB_* constants. |
— | — | @@ -528,7 +579,7 @@ |
529 | 580 | $dbr = wfGetDB( $dbtype ); |
530 | 581 | |
531 | 582 | $tables = array( 'page', 'revision', 'text' ); |
532 | | - $fields = array( 'page_title', 'rev_user_text', 'old_flags', 'old_text' ); |
| 583 | + $fields = array( 'page_title', 'page_latest', 'rev_user_text', 'old_flags', 'old_text' ); |
533 | 584 | $conds = array( |
534 | 585 | 'page_namespace' => $this->definitions->namespace, |
535 | 586 | 'page_title' => array_values( $keys ), |
— | — | @@ -567,6 +618,7 @@ |
568 | 619 | |
569 | 620 | $key = $flipKeys[$row->page_title]; |
570 | 621 | $messages[$key]->setRow( $row ); |
| 622 | + $messages[$key]->setProperty( 'revision', $row->page_latest ); |
571 | 623 | } |
572 | 624 | } |
573 | 625 | |
— | — | @@ -601,6 +653,16 @@ |
602 | 654 | } |
603 | 655 | } |
604 | 656 | |
| 657 | + if ( $this->dbReviewData !== null ) { |
| 658 | + foreach ( $this->dbReviewData as $row ) { |
| 659 | + if ( !isset( $flipKeys[$row->page_title] ) ) { |
| 660 | + continue; |
| 661 | + } |
| 662 | + $key = $flipKeys[$row->page_title]; |
| 663 | + $messages[$key]->addReviewer( $row->trr_user ); |
| 664 | + } |
| 665 | + } |
| 666 | + |
605 | 667 | $this->messages = $messages; |
606 | 668 | } |
607 | 669 | |
Index: trunk/extensions/Translate/Message.php |
— | — | @@ -20,6 +20,10 @@ |
21 | 21 | protected $infile; |
22 | 22 | /// \list{String} Message tags. |
23 | 23 | protected $tags = array(); |
| 24 | + /// \array Message properties. |
| 25 | + protected $props = array(); |
| 26 | + /// \list{String} Message reviewers. |
| 27 | + protected $reviewers = array(); |
24 | 28 | |
25 | 29 | /** |
26 | 30 | * Creates new message object. |
— | — | @@ -97,6 +101,22 @@ |
98 | 102 | public function getTags() { |
99 | 103 | return $this->tags; |
100 | 104 | } |
| 105 | + |
| 106 | + public function setProperty( $key, $value ) { |
| 107 | + $this->props[$key] = $value; |
| 108 | + } |
| 109 | + |
| 110 | + public function getProperty( $key ) { |
| 111 | + return isset( $this->props[$key] ) ? $this->props[$key] : null; |
| 112 | + } |
| 113 | + |
| 114 | + public function addReviewer( $userid ) { |
| 115 | + $this->reviewers[] = $userid; |
| 116 | + } |
| 117 | + |
| 118 | + public function getReviewers() { |
| 119 | + return $this->reviewers; |
| 120 | + } |
101 | 121 | } |
102 | 122 | |
103 | 123 | /** |
Index: trunk/extensions/Translate/Translate.php |
— | — | @@ -165,8 +165,17 @@ |
166 | 166 | ) + $resourcePaths; |
167 | 167 | |
168 | 168 | $wgResourceModules['ext.translate.messagetable'] = array( |
| 169 | + 'scripts' => 'resources/ext.translate.messagetable.js', |
169 | 170 | 'styles' => 'resources/ext.translate.messagetable.css', |
170 | 171 | 'position' => 'top', |
| 172 | + 'messages' => array( |
| 173 | + 'translate-messagereview-submit', |
| 174 | + 'translate-messagereview-progress', |
| 175 | + 'translate-messagereview-failure', |
| 176 | + 'translate-messagereview-done', |
| 177 | + 'translate-messagereview-apierror-invalidrevision', |
| 178 | + 'translate-messagereview-apierror-unknownmessage', |
| 179 | + ), |
171 | 180 | ) + $resourcePaths; |
172 | 181 | |
173 | 182 | $wgResourceModules['ext.translate.special.translate'] = array( |
Index: trunk/extensions/Translate/TranslateTasks.php |
— | — | @@ -204,6 +204,7 @@ |
205 | 205 | protected function preinit() { |
206 | 206 | $code = $this->options->getLanguage(); |
207 | 207 | $this->collection = $this->group->initCollection( $code ); |
| 208 | + $this->collection->setReviewMode( true ); |
208 | 209 | $this->collection->setInfile( $this->group->load( $code ) ); |
209 | 210 | $this->collection->filter( 'ignored' ); |
210 | 211 | $this->collection->filter( 'hastranslation', false ); |
— | — | @@ -328,6 +329,7 @@ |
329 | 330 | protected function preinit() { |
330 | 331 | $code = $this->options->getLanguage(); |
331 | 332 | $this->collection = $this->group->initCollection( $code ); |
| 333 | + $this->collection->setReviewMode( true ); |
332 | 334 | $this->collection->setInfile( $this->group->load( $code ) ); |
333 | 335 | $this->collection->filter( 'ignored' ); |
334 | 336 | $this->collection->filter( 'hastranslation', false ); |
Index: trunk/extensions/Translate/utils/MessageTable.php |
— | — | @@ -95,28 +95,17 @@ |
96 | 96 | |
97 | 97 | public function contents() { |
98 | 98 | global $wgUser; |
99 | | - |
100 | 99 | $sk = $wgUser->getSkin(); |
101 | 100 | |
102 | 101 | $optional = wfMsgHtml( 'translate-optional' ); |
103 | 102 | |
104 | | - $batch = new LinkBatch(); |
105 | | - if ( method_exists( $batch, 'setCaller' ) ) { |
106 | | - $batch->setCaller( __METHOD__ ); |
107 | | - } |
| 103 | + $this->doLinkBatch(); |
108 | 104 | |
109 | | - $ns = $this->group->getNamespace(); |
110 | | - |
111 | | - foreach ( $this->collection->keys() as $key ) { |
112 | | - $batch->add( $ns, $key ); |
113 | | - } |
114 | | - |
115 | | - $batch->execute(); |
116 | | - |
117 | 105 | $sourceLang = Language::factory( $this->group->getSourceLanguage() ); |
118 | 106 | $targetLang = Language::factory( $this->collection->getLanguage() ); |
119 | 107 | |
120 | 108 | $output = ''; |
| 109 | + |
121 | 110 | $this->collection->initMessages(); // Just to be sure |
122 | 111 | foreach ( $this->collection as $key => $m ) { |
123 | 112 | $tools = array(); |
— | — | @@ -135,7 +124,6 @@ |
136 | 125 | } |
137 | 126 | |
138 | 127 | global $wgLang; |
139 | | - |
140 | 128 | $niceTitle = htmlspecialchars( $wgLang->truncate( $key, - 30 ) ); |
141 | 129 | |
142 | 130 | $tools['edit'] = $sk->link( |
— | — | @@ -153,9 +141,9 @@ |
154 | 142 | if ( $m->hasTag( 'optional' ) ) { |
155 | 143 | $extra = '<br />' . $optional; |
156 | 144 | } |
| 145 | + |
| 146 | + $leftColumn = $anchor . $tools['edit'] . $this->getReviewButton( $m ) . $extra . $this->getReviewStatus( $m ); |
157 | 147 | |
158 | | - $leftColumn = $anchor . $tools['edit'] . $extra; |
159 | | - |
160 | 148 | if ( $this->reviewMode && $original !== $message ) { |
161 | 149 | $output .= Xml::tags( 'tr', array( 'class' => 'orig' ), |
162 | 150 | Xml::tags( 'td', array( 'rowspan' => '2' ), $leftColumn ) . |
— | — | @@ -217,4 +205,68 @@ |
218 | 206 | |
219 | 207 | return array( 'lang' => $code, 'dir' => $dir ); |
220 | 208 | } |
| 209 | + |
| 210 | + protected function getReviewButton( TMessage $message ) { |
| 211 | + global $wgUser; |
| 212 | + $revision = $message->getProperty( 'revision' ); |
| 213 | + if ( !$this->reviewMode || !$wgUser->isAllowed( 'translate-messagereview' ) || !$revision || $message->hasTag( 'fuzzy' ) ) { |
| 214 | + return ''; |
| 215 | + } |
| 216 | + |
| 217 | + $attribs = array( |
| 218 | + 'type' => 'button', |
| 219 | + 'class' => 'mw-translate-messagereviewbutton', |
| 220 | + 'data-token' => ApiTranslationReview::getToken( 0, '' ), |
| 221 | + 'data-revision' => $revision, |
| 222 | + ); |
| 223 | + |
| 224 | + $reviewers = $message->getReviewers(); |
| 225 | + if ( in_array( $wgUser->getId(), $reviewers ) ) { |
| 226 | + $attribs['value'] = wfMessage( 'translate-messagereview-done' )->text(); |
| 227 | + $attribs['disabled'] = 'disabled'; |
| 228 | + } else { |
| 229 | + $attribs['value'] = wfMessage( 'translate-messagereview-submit' )->text(); |
| 230 | + } |
| 231 | + |
| 232 | + |
| 233 | + $review = Html::element( 'input', $attribs ); |
| 234 | + return $review; |
| 235 | + } |
| 236 | + |
| 237 | + protected function getReviewStatus( TMessage $message ) { |
| 238 | + global $wgUser; |
| 239 | + if ( !$this->reviewMode ) { |
| 240 | + return ''; |
| 241 | + } |
| 242 | + |
| 243 | + $reviewers = $message->getReviewers(); |
| 244 | + if ( count( $reviewers ) === 0 ) { |
| 245 | + return ''; |
| 246 | + } |
| 247 | + |
| 248 | + $you = $wgUser->getId(); |
| 249 | + if ( in_array( $you, $reviewers ) ) { |
| 250 | + if ( count( $reviewers ) === 1 ) { |
| 251 | + $msg = wfMessage( 'translate-messagereview-reviewsyou' )->parse(); |
| 252 | + } else { |
| 253 | + $msg = wfMessage( 'translate-messagereview-reviewswithyou' )->numParams( count( $reviewers ) )->parse(); |
| 254 | + } |
| 255 | + } else { |
| 256 | + $msg = wfMessage( 'translate-messagereview-reviews' )->numParams( count( $reviewers ) )->parse(); |
| 257 | + } |
| 258 | + return Html::rawElement( 'div', array( 'class' => 'mw-translate-messagereviewstatus' ), $msg ); |
| 259 | + } |
| 260 | + |
| 261 | + protected function doLinkBatch() { |
| 262 | + $batch = new LinkBatch(); |
| 263 | + if ( method_exists( $batch, 'setCaller' ) ) { |
| 264 | + $batch->setCaller( __METHOD__ ); |
| 265 | + } |
| 266 | + $ns = $this->group->getNamespace(); |
| 267 | + foreach ( $this->collection->keys() as $key ) { |
| 268 | + $batch->add( $ns, $key ); |
| 269 | + } |
| 270 | + $batch->execute(); |
| 271 | + } |
| 272 | + |
221 | 273 | } |
Index: trunk/extensions/Translate/Translate.i18n.php |
— | — | @@ -366,6 +366,16 @@ |
367 | 367 | 'translate-searchprofile-tooltip' => 'Search from all translations', |
368 | 368 | 'translate-search-languagefilter' => 'Filter by language:', |
369 | 369 | 'translate-search-nofilter' => 'No filtering', |
| 370 | + |
| 371 | + 'translate-messagereview-submit' => 'Review', |
| 372 | + 'translate-messagereview-progress' => 'Reviewing...', |
| 373 | + 'translate-messagereview-failure' => 'Reviewing... failed: $1', |
| 374 | + 'translate-messagereview-done' => 'Reviewed', |
| 375 | + 'translate-messagereview-apierror-invalidrevision' => 'Translation was not found', |
| 376 | + 'translate-messagereview-apierror-unknownmessage' => 'Message was not found', |
| 377 | + 'translate-messagereview-reviews' => 'Reviewed by {{PLURAL:$1|one user|$1 users}}', |
| 378 | + 'translate-messagereview-reviewswithyou' => 'Reviewed by {{PLURAL:$1|one user|$1 users}} including you', |
| 379 | + 'translate-messagereview-reviewsyou' => 'Reviewed by you', |
370 | 380 | ); |
371 | 381 | |
372 | 382 | /** Message documentation (Message documentation) |
— | — | @@ -575,6 +585,16 @@ |
576 | 586 | 'translate-searchprofile' => 'Tab in [[Special:Search]] |
577 | 587 | {{Identical|Translation}}', |
578 | 588 | 'translate-searchprofile-tooltip' => 'Tooltip for a tab in [[Special:Search]]', |
| 589 | + |
| 590 | + 'translate-messagereview-submit' => 'Button label in Special:Translate review mode', |
| 591 | + 'translate-messagereview-progress' => 'Button label in Special:Translate review mode. Button is disabled.', |
| 592 | + 'translate-messagereview-failure' => 'Button label in Special:Translate review mode. Button is disabled. $1 can be {{msg-mw|translate-messagereview-apierror-invalidrevision}} or {{msg-mw|translate-messagereview-apierror-unknownmessage}}.', |
| 593 | + 'translate-messagereview-done' => 'Button label in Special:Translate review mode. Button is disabled.', |
| 594 | + 'translate-messagereview-apierror-invalidrevision' => 'Error message for {{msg-mw|translate-messagereview-failure}}', |
| 595 | + 'translate-messagereview-apierror-unknownmessage' => 'Error message for {{msg-mw|translate-messagereview-failure}}', |
| 596 | + 'translate-messagereview-reviews' => 'Status message in Special:Translate in review mode', |
| 597 | + 'translate-messagereview-reviewswithyou' => 'Status message in Special:Translate in review mode', |
| 598 | + 'translate-messagereview-reviewsyou' => 'Status message in Special:Translate in review mode', |
579 | 599 | ); |
580 | 600 | |
581 | 601 | /** Faeag Rotuma (Faeag Rotuma) |
Index: trunk/extensions/Translate/resources/ext.translate.messagetable.css |
— | — | @@ -39,4 +39,13 @@ |
40 | 40 | vertical-align: top; |
41 | 41 | border-style: solid; |
42 | 42 | border-width: 1px; |
43 | | -} |
\ No newline at end of file |
| 43 | +} |
| 44 | + |
| 45 | +.mw-translate-messagereviewbutton { |
| 46 | + float: right; |
| 47 | +} |
| 48 | + |
| 49 | +.mw-translate-messagereviewstatus { |
| 50 | + clear: right; |
| 51 | + text-align: right; |
| 52 | +} |