r51180 MediaWiki - Code Review archive

Repository:MediaWiki
Revision:r51179‎ | r51180 | r51181 >
Date:08:06, 30 May 2009
Author:nikerabbit
Status:ok
Tags:
Comment:
Committing my changes for the new fuzzy system... this version still contains some bugs
Modified paths:
  • /trunk/extensions/Translate/Message.php (modified) (history)
  • /trunk/extensions/Translate/MessageChecks.php (modified) (history)
  • /trunk/extensions/Translate/MessageCollection.php (added) (history)
  • /trunk/extensions/Translate/MessageGroups.php (modified) (history)
  • /trunk/extensions/Translate/SpecialLanguageStats.php (modified) (history)
  • /trunk/extensions/Translate/Translate.php (modified) (history)
  • /trunk/extensions/Translate/TranslateEditAddons.php (modified) (history)
  • /trunk/extensions/Translate/TranslateTasks.php (modified) (history)
  • /trunk/extensions/Translate/TranslateUtils.php (modified) (history)
  • /trunk/extensions/Translate/_autoload.php (modified) (history)
  • /trunk/extensions/Translate/ffs/Gettext.php (modified) (history)
  • /trunk/extensions/Translate/ffs/Java.php (modified) (history)
  • /trunk/extensions/Translate/ffs/OpenLayers.php (modified) (history)
  • /trunk/extensions/Translate/ffs/PhpVariables.php (modified) (history)
  • /trunk/extensions/Translate/ffs/Simple.php (modified) (history)
  • /trunk/extensions/Translate/ffs/Wiki.php (modified) (history)
  • /trunk/extensions/Translate/ffs/Xliff.php (modified) (history)
  • /trunk/extensions/Translate/scripts/autoexport.php (modified) (history)
  • /trunk/extensions/Translate/scripts/createCheckIndex.php (modified) (history)
  • /trunk/extensions/Translate/scripts/groupStatistics.php (modified) (history)
  • /trunk/extensions/Translate/scripts/sync-group.php (modified) (history)
  • /trunk/extensions/Translate/tag/RenderJob.php (modified) (history)
  • /trunk/extensions/Translate/tag/SpecialPageTranslation.php (modified) (history)
  • /trunk/extensions/Translate/tag/TPParse.php (modified) (history)
  • /trunk/extensions/Translate/tag/TranslatablePage.php (modified) (history)
  • /trunk/extensions/Translate/utils/MemoryCache.php (added) (history)
  • /trunk/extensions/Translate/utils/MessageTable.php (modified) (history)

Diff [purge]

Index: trunk/extensions/Translate/Message.php
@@ -1,256 +1,13 @@
22 <?php
3 -if ( !defined( 'MEDIAWIKI' ) ) die();
4 -/**
5 - * An extension to ease the translation of Mediawiki
6 - *
7 - * @addtogroup Extensions
8 - *
9 - * @author Niklas Laxström
10 - * @copyright Copyright © 2007-2008, Niklas Laxström
11 - * @license http://www.gnu.org/copyleft/gpl.html GNU General Public License 2.0 or later
12 - */
133
 4+abstract class TMessage {
 5+ protected $key;
 6+ protected $definition;
147
15 -/**
16 - * MessageCollection is a collection of TMessages. It supports array accces of
17 - * TMessage object by message key. One collection can only have items for one
18 - * translation target language.
19 - */
20 -class MessageCollection implements Iterator, ArrayAccess, Countable {
218 /**
22 - * Information of what type of MessageCollection this is.
23 - */
24 - public $code = null;
25 -
26 - /**
27 - * Messages are stored in an array.
28 - */
29 - private $messages = array();
30 -
31 - /**
32 - * Creates new empty messages collection.
33 - *
34 - * @param $code Language code
35 - */
36 - public function __construct( $code ) {
37 - $this->code = $code;
38 - }
39 -
40 - public function __clone() {
41 - foreach ( $this->messages as $key => $obj ) {
42 - $this->messages[$key] = clone $obj;
43 - }
44 - }
45 -
46 - /* Iterator methods */
47 - public function rewind() {
48 - reset( $this->messages );
49 - }
50 -
51 - public function current() {
52 - $messages = current( $this->messages );
53 - return $messages;
54 - }
55 -
56 - public function key() {
57 - $messages = key( $this->messages );
58 - return $messages;
59 - }
60 -
61 - public function next() {
62 - $messages = next( $this->messages );
63 - return $messages;
64 - }
65 -
66 - public function valid() {
67 - $messages = $this->current() !== false;
68 - return $messages;
69 - }
70 -
71 - /* ArrayAccess methods */
72 - public function offsetExists( $offset ) {
73 - return isset( $this->messages[$offset] );
74 - }
75 -
76 - public function offsetGet( $offset ) {
77 - return $this->messages[$offset];
78 - }
79 -
80 - public function offsetSet( $offset, $value ) {
81 - if ( !$value instanceof TMessage ) {
82 - throw new MWException( __METHOD__ . ": Trying to set member to invalid type" );
83 - }
84 - $this->messages[$offset] = $value;
85 - }
86 -
87 - public function offsetUnset( $offset ) {
88 - unset( $this->messages[$offset] );
89 - }
90 -
91 - /* Countable methods */
92 - /**
93 - * Counts the number of items in this collection.
94 - *
95 - * @return Integer count of items.
96 - */
97 - public function count() {
98 - return count( $this->messages );
99 - }
100 -
101 -
102 - /**
103 - * Adds new TMessage object to collection.
104 - */
105 - public function add( TMessage $message ) {
106 - $this->messages[$message->key] = $message;
107 - }
108 -
109 - /**
110 - * Adds array of TMessages to this collection.
111 - *
112 - * @param $messages Array of TMessage objects.
113 - * @throws MWException
114 - */
115 - public function addMany( array $messages ) {
116 - foreach ( $messages as $message ) {
117 - if ( !$message instanceof TMessage ) {
118 - throw new MWException( __METHOD__ . ": Array contains something else than TMessage" );
119 - }
120 - $this->messages[$message->key] = $message;
121 - }
122 - }
123 -
124 - /**
125 - * Provides an array of keys for safe iteration.
126 - *
127 - * @return Array of string keys.
128 - */
129 - public function keys() {
130 - return array_keys( $this->messages );
131 - }
132 -
133 - /**
134 - * Does array_slice to the messages.
135 - *
136 - * @param $offset Starting offset.
137 - * @param $count Numer of items to slice.
138 - */
139 - public function slice( $offset, $count ) {
140 - $this->messages = array_slice( $this->messages, $offset, $count );
141 - }
142 -
143 - /**
144 - * PHP function array_intersect_key doesn't seem to like object-as-arrays, so
145 - * have to do provide some way to do it. Does not change object state.
146 - *
147 - * @param $array List of keys for messages that should be returned.
148 - * @return New MessageCollection.
149 - */
150 - public function intersect_key( Array $array ) {
151 - $collection = new MessageCollection( $this->code );
152 - $collection->addMany( array_intersect_key( $this->messages, $array ) );
153 - return $collection;
154 - }
155 -
156 - /* Fail fast */
157 - public function __get( $name ) {
158 - throw new MWException( __METHOD__ . ": Trying to access unknown property $name" );
159 - }
160 -
161 - /* Fail fast */
162 - public function __set( $name, $value ) {
163 - throw new MWException( __METHOD__ . ": Trying to modify unknown property $name" );
164 - }
165 -
166 - public function getAuthors() {
167 - global $wgTranslateFuzzyBotName;
168 -
169 - $authors = array();
170 - foreach ( $this->keys() as $key ) {
171 - // Check if there is authors
172 - $_authors = $this->messages[$key]->authors;
173 - if ( !count( $_authors ) ) continue;
174 -
175 - foreach ( $_authors as $author ) {
176 - if ( !isset( $authors[$author] ) ) {
177 - $authors[$author] = 1;
178 - } else {
179 - $authors[$author]++;
180 - }
181 - }
182 - }
183 -
184 - arsort( $authors, SORT_NUMERIC );
185 - foreach ( $authors as $author => $edits ) {
186 - if ( $author !== $wgTranslateFuzzyBotName ) {
187 - $filteredAuthors[] = $author;
188 - }
189 - }
190 - return isset( $filteredAuthors ) ? $filteredAuthors : array();
191 - }
192 -
193 - /**
194 - * Filters messages based on some condition.
195 - *
196 - * @param $type Any accessible value of TMessage.
197 - * @param $condition What the value is compared to.
198 - */
199 - public function filter( $type, $condition = true ) {
200 - foreach ( $this->keys() as $key ) {
201 - if ( $this->messages[$key]->$type == $condition ) {
202 - unset( $this->messages[$key] );
203 - }
204 - }
205 - }
206 -
207 -}
208 -
209 -class TMessage {
210 - /**
211 - * String that uniquely identifies this message.
212 - */
213 - public $key = null;
214 -
215 - /**
216 - * The definition of this message - usually in English.
217 - */
218 - public $definition = null;
219 -
220 - // Following properties are lazy declared to save memory
221 -
222 - /**
223 - * Authors who have taken part in translating this message.
224 - */
225 - // protected $authors;
226 -
227 - /**
228 - * External translation.
229 - */
230 - // protected $infile = null;
231 -
232 - /**
233 - * Translation in local database, may differ from above.
234 - */
235 - // private $database = null;
236 -
237 - // Values that can be accessed with $message->value syntax
238 - protected static $callable = array(
239 - // Basic values
240 - 'infile', 'database', 'optional',
241 - // Derived values
242 - 'authors', 'changed', 'translated', 'translation', 'fuzzy',
243 - );
244 -
245 - protected static $writable = array(
246 - 'infile', 'database', 'optional',
247 - // Ugly.. maybe I'm trying to be to clever here
248 - 'authors',
249 - );
250 -
251 - /**
2529 * Creates new message object.
25310 *
254 - * @param $key Uniquer key identifying this message.
 11+ * @param $key Unique key identifying this message.
25512 * @param $definition The authoritave definition of this message.
25613 */
25714 public function __construct( $key, $definition ) {
@@ -258,89 +15,61 @@
25916 $this->definition = $definition;
26017 }
26118
262 - // Getters for basic values
26319 public function key() { return $this->key; }
26420 public function definition() { return $this->definition; }
 21+ abstract public function translation();
 22+}
26523
266 - public function infile() { return @$this->infile; }
267 - public function database() { return @$this->database; }
 24+class ThinMessage extends TMessage {
 25+ private $infile;
 26+ private $row;
 27+ private $tags = array();
26828
269 - public function optional() { return !!@$this->optional; }
270 -
271 - // Getters for derived values
272 - /** Returns authors added for this message. */
273 - public function authors() {
274 - return @$this->authors ? $this->authors : array();
 29+ public function setInfile( $text ) {
 30+ $this->infile = $text;
27531 }
27632
277 - /** Determines if this message has uncommitted changes. */
278 - public function changed() {
279 - return @$this->database !== null && ( @$this->infile !== @$this->database );
 33+ public function setRow( $row ) {
 34+ $this->row = $row;
28035 }
28136
282 - /**
283 - * Determies if this message has a proper translation.
284 - * To check if message has translation at all, use translation !== null
285 - */
286 - public function translated() {
287 - if ( @$this->translation === null || $this->fuzzy() ) return false;
288 - return true;
 37+ public function setTag( $tag ) {
 38+ $this->tags[] = $tag;
28939 }
29040
291 - /**
292 - * Returns the current translation of message. Translation in database are
293 - * preferred over those in source files.
294 - *
295 - * @return Translated string or null if there isn't translation.
296 - */
 41+
 42+ public function key() {
 43+ return $this->key;
 44+ }
 45+ public function definition() {
 46+ return $this->definition;
 47+ }
29748 public function translation() {
298 - return ( @$this->database !== null ) ? @$this->database : @$this->infile;
 49+ if ( !isset($this->row) ) return null;
 50+ return Revision::getRevisionText( $this->row );
29951 }
300 -
301 - /**
302 - * Determines if the current translation in database (if any) is marked as
303 - * fuzzy.
304 - *
305 - * @return true or false
306 - */
307 - public function fuzzy() {
308 - if ( @$this->translation !== null ) {
309 - return strpos( $this->translation, TRANSLATE_FUZZY ) !== false;
310 - } else {
311 - return false;
312 - }
 52+ public function author() {
 53+ if ( !isset($this->row) ) return null;
 54+ return $this->row->rev_user_text;
31355 }
31456
315 - // Complex setters
316 - public function addAuthor( $author ) {
317 - $authors = $this->authors();
318 - $authors[] = $author;
319 - $this->authors = $authors;
 57+ public function infile() {
 58+ if ( !isset($this->infile) ) return null;
 59+ return $this->infile;
32060 }
32161
322 - // Code for PHP syntax magic to hide the difference between functions and values
323 - public function __get( $name ) {
324 - if ( in_array( $name, self::$callable ) ) {
325 - return $this->$name();
326 - }
327 - throw new MWException( __METHOD__ . ": Trying to access unknown property $name" );
 62+ public function hasTag( $tag ) {
 63+ return in_array( $tag, $this->tags, true );
32864 }
 65+}
32966
330 - public function __set( $name, $value ) {
331 - if ( in_array( $name, self::$writable ) ) {
332 - if ( gettype( $this->$name ) === gettype( $value ) || $this->$name === null && is_string( $value ) ) {
333 - $this->$name = $value;
334 - } else {
335 - $type = gettype( $value );
336 - throw new MWException( __METHOD__ . ": Trying to set the value of property $name to illegal data type $type" );
337 - }
338 - } else {
339 - throw new MWException( __METHOD__ . ": Trying to set unknown property $name with value $value" );
340 - }
 67+class FatMessage extends TMessage {
 68+ protected $translation = null;
 69+ public function setTranslation( $text ) {
 70+ $this->translation = $text;
34171 }
34272
343 - public function __isset( $name ) {
344 - return @$this->$name !== null;
 73+ public function translation() {
 74+ return $this->translation;
34575 }
346 -
347 -}
 76+}
\ No newline at end of file
Index: trunk/extensions/Translate/MessageGroups.php
@@ -157,21 +157,6 @@
158158 private $messages = array();
159159
160160 /**
161 - * In this function message group should add translations from the stored file
162 - * for language code $code and it's fallback language, if used.
163 - *
164 - * @param $messages MessageCollection
165 - */
166 - function fill( MessageCollection $messages ) {
167 - $cache = $this->load( $messages->code );
168 - foreach ( $messages->keys() as $key ) {
169 - if ( isset( $cache[$key] ) ) {
170 - $messages[$key]->infile = $cache[$key];
171 - }
172 - }
173 - }
174 -
175 - /**
176161 * Returns path to the file where translation of language code $code are.
177162 *
178163 * @return Path to the file or false if not applicable.
@@ -193,7 +178,6 @@
194179 * group only.
195180 */
196181 public function initCollection( $code, $unique = false ) {
197 - $collection = new MessageCollection( $code );
198182
199183 if ( !$unique ) {
200184 $definitions = $this->getDefinitions();
@@ -201,31 +185,16 @@
202186 $definitions = $this->getUniqueDefinitions();
203187 }
204188
205 - foreach ( $definitions as $key => $definition ) {
206 - $collection->add( new TMessage( $key, $definition ) );
207 - }
 189+ $defs = new MessageDefinitions( $this->namespaces[0], $definitions );
 190+ $collection = MessageCollection::newFromDefinitions( $defs, $code );
208191
209192 $bools = $this->getBools();
210 - foreach ( $bools['optional'] as $key ) {
211 - if ( isset( $collection[$key] ) ) {
212 - $collection[$key]->optional = true;
213 - }
214 - }
 193+ $collection->setTags( 'ignored', $bools['ignored'] );
 194+ $collection->setTags( 'optional', $bools['optional'] );
215195
216 - foreach ( $bools['ignored'] as $key ) {
217 - if ( isset( $collection[$key] ) ) {
218 - unset( $collection[$key] );
219 - }
220 - }
221 -
222196 return $collection;
223197 }
224198
225 - public function fillCollection( MessageCollection $collection ) {
226 - TranslateUtils::fillContents( $collection, $this->namespaces );
227 - $this->fill( $collection );
228 - }
229 -
230199 public function __construct() {
231200 $this->mangler = StringMatcher::emptyMatcher();
232201 }
@@ -554,10 +523,6 @@
555524 $this->source = $source;
556525 }
557526
558 - public function fill( MessageCollection $messages ) {
559 - return; // no-op
560 - }
561 -
562527 /* Fetch definitions from database */
563528 public function getDefinitions() {
564529 $definitions = array();
@@ -593,6 +558,8 @@
594559 }
595560
596561 class WikiPageMessageGroup extends WikiMessageGroup {
 562+ protected $type = 'mediawiki';
 563+
597564 public $title;
598565
599566 public function __construct( $id, $source ) {
@@ -631,6 +598,7 @@
632599
633600 public function load( $code ) {
634601 if ( $code === 'en' ) return $this->getDefinitions();
 602+ else return array();
635603 }
636604
637605 /**
@@ -651,37 +619,6 @@
652620 if ( !$rev ) return null;
653621 return $rev->getText();
654622 }
655 -
656 - public function fillCollection( MessageCollection $messages ) {
657 - parent::fillCollection( $messages );
658 - $page = TranslatablePage::newFromTitle( $this->title );
659 - $markedRevs = $page->getMarkedRevs( 'tp:mark' );
660 -
661 - foreach ( $messages as $key => $m ) {
662 - $rev = $page->getTransrev( $key .'/' . $messages->code );
663 - if ( $rev === false ) {
664 - if ( !$m->database === null ) {
665 - //TODO: fixme, ugly ugly ugly
666 - $m->database = TRANSLATE_FUZZY . $m->database;
667 - }
668 - continue;
669 - }
670 - foreach ( $markedRevs as $r ) {
671 - if ( $rev === $r->rt_revision ) break;
672 - $changed = explode( '|', unserialize($r->rt_value) );
673 -
674 - // Get a suitable section key
675 - $parts = explode( '/', $key );
676 - $ikey = $parts[count($parts)-1];
677 -
678 - // If the section was changed, reduce the score
679 - if ( in_array($ikey, $changed, true) ) {
680 - $m->database = TRANSLATE_FUZZY . $m->database;
681 - continue 2;
682 - }
683 - }
684 - }
685 - }
686623 }
687624
688625 class MessageGroups {
Index: trunk/extensions/Translate/tag/RenderJob.php
@@ -35,9 +35,13 @@
3636
3737 // Return the actual translation page...
3838 $page = TranslatablePage::isTranslationPage( $title );
 39+ if ( $page ) {
 40+ var_dump( $params );
 41+ throw new MWException( "Oops, this should not happen!");
 42+ }
 43+
3944 $group = MessageGroups::getGroup( "page|$key" );
4045 $collection = $group->initCollection( $code );
41 - $group->fillCollection( $collection );
4246
4347 // Muck up the text
4448 $text = $page->getParse()->getTranslationPageText( $collection );
Index: trunk/extensions/Translate/tag/SpecialPageTranslation.php
@@ -393,6 +393,7 @@
394394 // Store changed sections in the database for easy access.
395395 // Used when determinen the up-to-datedness for section translations.
396396 $page->addMarkedTag( $newrevision, $changed );
 397+ $this->addFuzzyTags( $page, $changed );
397398
398399 $this->setupRenderJobs( $page );
399400
@@ -403,6 +404,37 @@
404405 return false;
405406 }
406407
 408+ public function addFuzzyTags( $page, $changed ) {
 409+ $titles = array();
 410+ $prefix = $page->getTitle->getPrefixedText();
 411+ $db = wfGetDB( DB_MASTER );
 412+ foreach ( $changed as $c ) {
 413+ $title = Title::makeTitleSafe( NS_TRANSLATIONS, "$prefix/$c" );
 414+ if ( $title ) {
 415+ $titles[] = 'page_title like \'' . $db->escapeLike( $title->getPrefixedDBkey() ) . '/%\'';
 416+ }
 417+ }
 418+
 419+ $titleCond = $db->makeList( $titles, LIST_OR );
 420+
 421+ $id = $db->selectField( 'revtag_type', 'rtt_id', array( 'rtt_name' => 'fuzzy' ), __METHOD__ );
 422+
 423+ $fields = array( 'page_id', 'page_latest' );
 424+ $conds = array( 'page_namespace' => NS_TRANSLATIONS, $titleCond );
 425+ $res = $db->select( 'page', $fields, $conds, __METHOD__ );
 426+
 427+ $inserts = array();
 428+
 429+ foreach( $res as $r ) {
 430+ $inserts[] = array(
 431+ 'rt_page' => $r->page_id,
 432+ 'rt_type' => $id,
 433+ 'rt_revision' => $r->page_latest,
 434+ );
 435+ }
 436+ $db->replace( 'revtag', array( 'rt_type_page_revision' ), $inserts, __METHOD__ );
 437+ }
 438+
407439 public function setupRenderJobs( TranslatablePage $page ) {
408440 $titles = $page->getTranslationPages();
409441 $jobs = array();
Index: trunk/extensions/Translate/tag/TPParse.php
@@ -111,6 +111,8 @@
112112 // For finding the messages
113113 $prefix = $this->title->getPrefixedDBKey() . '/';
114114
 115+ $collection->loadTranslations();
 116+
115117 foreach ( $this->sections as $ph => $s ) {
116118 if ( isset($collection[$prefix.$s->id]) ) {
117119 $msg = $collection[$prefix.$s->id];
Index: trunk/extensions/Translate/tag/TranslatablePage.php
@@ -301,7 +301,6 @@
302302 foreach ( $titles as $t ) {
303303 list( , $code ) = TranslateUtils::figureMessage( $t->getText() );
304304 $collection = $group->initCollection( $code );
305 - $group->fillCollection( $collection );
306305
307306 $percent = $this->getPercentageInternal( $collection, $markedRevs );
308307 // To avoid storing 40 decimals of inaccuracy, truncate to two decimals
@@ -320,16 +319,17 @@
321320 $count = count($collection);
322321 if ( $count === 0 ) return 0;
323322
 323+ // We want to get fuzzy though
 324+ $collection->filter( 'hastranslation', false );
 325+ $collection->initMessages();
 326+
324327 $total = 0;
325328
326329 foreach ( $collection as $key => $message ) {
327 -
328 - if ( $message->translation() === null ) continue; // No score
329 -
330330 $score = 1;
331331
332332 // Fuzzy halves score
333 - if ( $message->fuzzy() ) $score *= 0.5;
 333+ if ( $message->hasTag('fuzzy') ) $score *= 0.5;
334334
335335 // Reduce 20% for every newer revision than what is translated against
336336 $rev = $this->getTransrev( $key .'/' . $collection->code );
Index: trunk/extensions/Translate/TranslateEditAddons.php
@@ -18,9 +18,8 @@
1919
2020 if ( !in_array( $ns, $wgTranslateMessageNamespaces) ) return true;
2121
22 - list( $key, $code ) = self::figureMessage( $wgTitle );
2322
24 - $group = self::getMessageGroup( $ns, $key );
 23+ list( $key, $code, $group) = self::getKeyCodeGroup( $wgTitle );
2524 if ( $group === null ) return true;
2625
2726 $defs = $group->getDefinitions();
@@ -213,7 +212,7 @@
214213 /**
215214 * @return Array of the message and the language
216215 */
217 - private static function figureMessage( $title ) {
 216+ private static function figureMessage( Title $title ) {
218217 $text = $title->getDBkey();
219218 $pos = strrpos( $text, '/' );
220219 $code = substr( $text, $pos + 1 );
@@ -221,6 +220,12 @@
222221 return array( $key, $code );
223222 }
224223
 224+ public static function getKeyCodeGroup( Title $title ) {
 225+ list( $key, $code ) = self::figureMessage( $title );
 226+ $group = self::getMessageGroup( $title->getNamespace(), $key );
 227+ return array( $key, $code, $group );
 228+ }
 229+
225230 /**
226231 * Tries to determine from which group this message belongs. It tries to get
227232 * group id from loadgroup GET-paramater, but fallbacks to messageIndex file
@@ -249,9 +254,7 @@
250255 wfLoadExtensionMessages( 'Translate' );
251256 global $wgTranslateDocumentationLanguageCode, $wgOut, $wgTranslateMessageNamespaces;
252257
253 - list( $key, $code ) = self::figureMessage( $object->mTitle );
254 -
255 - $group = self::getMessageGroup( $object->mTitle->getNamespace(), $key );
 258+ list( $key, $code, $group ) = self::getKeyCodeGroup( $object->mTitle );
256259 if ( $group === null ) return;
257260
258261 list( $nsMain, /* $nsTalk */ ) = $group->namespaces;
@@ -264,11 +267,7 @@
265268 $inOtherLanguages = array();
266269 $namespace = $object->mTitle->getNsText();
267270 foreach ( self::getFallbacks( $code ) as $fbcode ) {
268 - $fb = $group->getMessage( $key, $fbcode );
269 - /* For fallback, even uncommitted translation may be useful */
270 - if ( $fb === null ) {
271 - $fb = TranslateUtils::getMessageContent( $key, $fbcode );
272 - }
 271+ $fb = TranslateUtils::getMessageContent( $key, $fbcode, $nsMain );
273272 if ( $fb !== null ) {
274273 /* add a link for editing the fallback messages */
275274 $inOtherLanguages[] = self::dobox( $fb, $fbcode, false, $namespace . ':' . $key . '/' . $fbcode );
@@ -376,9 +375,9 @@
377376 // Some syntactic checks
378377 $translation = ( $editField !== null ) ? $editField : $xx;
379378 if ( $translation !== null && $code !== $wgTranslateDocumentationLanguageCode) {
380 - $message = new TMessage( $key, $en );
 379+ $message = new FatMessage( $key, $en );
381380 // Take the contents from edit field as a translation
382 - $message->database = $translation;
 381+ $message->setTranslation( $translation );
383382 $checker = MessageChecks::getInstance();
384383 if ( $checker->hasChecks( $group->getType() ) ) {
385384 $checks = $checker->doChecks( $message, $group->getType(), $code );
@@ -420,4 +419,63 @@
421420 );
422421 return true;
423422 }
 423+
 424+ public static function onSave( $article, $user, $text, $summary,
 425+ $minor, $_, $_, $flags, $revision ) {
 426+
 427+ global $wgTranslateMessageNamespaces;
 428+
 429+ $title = $article->getTitle();
 430+
 431+ $ns = $title->getNamespace();
 432+ if ( !in_array( $ns, $wgTranslateMessageNamespaces) ) return true;
 433+
 434+ list( $key, $code, $group ) = self::getKeyCodeGroup( $title );
 435+ $cache = new ArrayMemoryCache( 'groupstats' );
 436+ $cache->clear( $group->getId(), $code );
 437+
 438+ $fuzzy = false;
 439+
 440+ // Check for explicit tag
 441+ if ( strpos( $text, TRANSLATE_FUZZY ) !== false ) $fuzzy = true;
 442+
 443+ // Check for problems
 444+ global $wgTranslateDocumentationLanguageCode;
 445+ if ( !$fuzzy && $code !== $wgTranslateDocumentationLanguageCode ) {
 446+ $message = new FatMessage( $key, $en );
 447+ // Take the contents from edit field as a translation
 448+ $message->setTranslation( $translation );
 449+ $checker = MessageChecks::getInstance();
 450+ if ( $checker->hasChecks( $group->getType() ) ) {
 451+ $checks = $checker->doChecks( $message, $group->getType(), $code );
 452+ if ( count( $checks ) ) $fuzzy = true;
 453+ }
 454+ }
 455+
 456+ if ( $fuzzy === false ) return true;
 457+
 458+ // Update it
 459+ if ( $revision === null ) {
 460+ $rev = $article->getTitle()->getLatestRevId();
 461+ } else {
 462+ $rev = $revision->getID();
 463+ }
 464+
 465+ // Add the ready tag
 466+ $dbw = wfGetDB( DB_MASTER );
 467+
 468+ $id = $dbw->selectField( 'revtag_type', 'rtt_id', array( 'rtt_name' => 'fuzzy' ), __METHOD__ );
 469+
 470+ $conds = array(
 471+ 'rt_page' => $article->getTitle()->getArticleId(),
 472+ 'rt_type' => $id,
 473+ 'rt_revision' => $rev
 474+ );
 475+ $dbw->delete( 'revtag', $conds, __METHOD__ );
 476+ $dbw->insert( 'revtag', $conds, __METHOD__ );
 477+
 478+ return true;
 479+ }
 480+
424481 }
 482+
Index: trunk/extensions/Translate/Translate.php
@@ -11,7 +11,7 @@
1212 * @license http://www.gnu.org/copyleft/gpl.html GNU General Public License 2.0 or later
1313 */
1414
15 -define( 'TRANSLATE_VERSION', '11:2009-05-09' );
 15+define( 'TRANSLATE_VERSION', '12bb:2009-05-28' );
1616
1717 $wgExtensionCredits['specialpage'][] = array(
1818 'path' => __FILE__,
@@ -164,12 +164,10 @@
165165 'view' => 'ViewMessagesTask',
166166 'untranslated' => 'ViewUntranslatedTask',
167167 'optional' => 'ViewOptionalTask',
168 - 'untranslatedoptional' => 'ViewUntranslatedOptionalTask',
169 - 'problematic' => 'ViewProblematicTask',
 168+// 'untranslatedoptional' => 'ViewUntranslatedOptionalTask',
170169 'review' => 'ReviewMessagesTask',
171170 'reviewall' => 'ReviewAllMessagesTask',
172171 'export-as-po' => 'ExportasPoMessagesTask',
173 -// 'export' => 'ExportMessagesTask',
174172 'export-to-file' => 'ExportToFileMessagesTask',
175173 // 'export-to-xliff' => 'ExportToXliffMessagesTask',
176174 );
@@ -198,9 +196,8 @@
199197 }
200198
201199 // Fuzzy tags for speed
202 - $wgHooks['ArticleSaveComplete'][] = 'efTranslateAddFuzzy';
 200+ $wgHooks['ArticleSaveComplete'][] = 'TranslateEditAddons::onSave';
203201
204 -
205202 global $wgEnablePageTranslation;
206203 if ( $wgEnablePageTranslation ) {
207204
@@ -265,7 +262,6 @@
266263 $memcKey = wfMemcKey( 'pt' );
267264 $ok = $wgMemc->get( $memcKey );
268265
269 - wfLoadExtensionMessages( 'PageTranslation' );
270266 if ( $ok === $version ) {
271267 return true;
272268 }
@@ -277,7 +273,7 @@
278274
279275 $dbw = wfGetDB( DB_MASTER );
280276 if ( !$dbw->tableExists('revtag_type') ) {
281 - $wgHooks['SiteNoticeAfter'][] = array('efTranslateCheckWarn', wfMsg( 'tpt-install' ) );
 277+ $wgHooks['SiteNoticeAfter'][] = array('efTranslateCheckWarn', 'tpt-install' );
282278 return false;
283279 }
284280
@@ -295,7 +291,8 @@
296292
297293 function efTranslateCheckWarn( $msg, &$sitenotice ) {
298294 global $wgOut;
299 - $sitenotice = $msg;
 295+ wfLoadExtensionMessages( 'PageTranslation' );
 296+ $sitenotice = wfMsg($msg);
300297 $wgOut->enableClientCache( false );
301298 return true;
302299 }
@@ -305,42 +302,3 @@
306303 $parser->setHook( 'languages', array( 'PageTranslationHooks', 'languages' ) );
307304 return true;
308305 }
309 -
310 -
311 -if ( !defined('TRANSLATE_CLI') ) {
312 - function STDOUT() {}
313 - function STDERR() {}
314 -}
315 -
316 -function efTranslateAddFuzzy( $article, $user, $text, $summary,
317 - $minor, $_, $_, $flags, $revision ) {
318 -
319 - global $wgTranslateMessageNamespaces;
320 -
321 - $ns = $article->getTitle()->getNamespace();
322 - if ( !in_array( $ns, $wgTranslateMessageNamespaces) ) return true;
323 -
324 - // No fuzzy - no tag
325 - if ( strpos( $text, TRANSLATE_FUZZY ) === false ) return true;
326 -
327 - if ( $revision === null ) {
328 - $rev = $article->getTitle()->getLatestRevId();
329 - } else {
330 - $rev = $revision->getID();
331 - }
332 -
333 - // Add the ready tag
334 - $dbw = wfGetDB( DB_MASTER );
335 -
336 - $id = $dbw->selectField( 'revtag_type', 'rtt_id', array( 'rtt_name' => 'fuzzy' ), __METHOD__ );
337 -
338 - $conds = array(
339 - 'rt_page' => $article->getTitle()->getArticleId(),
340 - 'rt_type' => $id,
341 - 'rt_revision' => $rev
342 - );
343 - $dbw->delete( 'revtag', $conds, __METHOD__ );
344 - $dbw->insert( 'revtag', $conds, __METHOD__ );
345 -
346 - return true;
347 -}
\ No newline at end of file
Index: trunk/extensions/Translate/SpecialLanguageStats.php
@@ -192,29 +192,38 @@
193193
194194 $out = '';
195195
 196+ $cache = new ArrayMemoryCache( 'groupstats' );
 197+
196198 # Fetch groups stats have to be displayed for
197199 $groups = $this->getGroups();
198200
199201 # Get statistics for the message groups
200 - foreach ( $groups as $g ) {
 202+ foreach ( $groups as $groupName => $g ) {
201203
202 - // Initialise messages
203 - $collection = $g->initCollection( $code );
204 - $collection->filter( 'optional' );
205 - // Store the count of real messages for later calculation.
206 - $total = count( $collection );
 204+ $incache = $cache->get( $groupName, $code );
 205+ if ( $incache !== false ) {
 206+ list( $fuzzy, $translated, $total ) = $incache;
 207+ } else {
207208
208 - // Fill translations in for counting
209 - $g->fillCollection( $collection );
 209+ // Initialise messages
 210+ $collection = $g->initCollection( $code );
 211+ $collection->filter( 'ignored' );
 212+ $collection->filter( 'optional' );
 213+ // Store the count of real messages for later calculation.
 214+ $total = count( $collection );
210215
211 - // Count fuzzy first
212 - $collection->filter( 'fuzzy' );
213 - $fuzzy = $total - count( $collection );
 216+ // Count fuzzy first
 217+ $collection->filter( 'fuzzy' );
 218+ $fuzzy = $total - count( $collection );
214219
215 - // Count the completion percent
216 - $collection->filter( 'translated', false );
217 - $translated = count( $collection );
 220+ // Count the completion percent
 221+ $collection->filter( 'hastranslation', false );
 222+ $translated = count( $collection );
218223
 224+ $cache->set( $groupName, $code, array( $fuzzy, $translated, $total ) );
 225+
 226+ }
 227+
219228 // FIXME: avoid division by 0. Should not happen, but core-mostused has this on Windows at the moment
220229 if( !$total ) {
221230 continue;
Index: trunk/extensions/Translate/_autoload.php
@@ -22,8 +22,11 @@
2323 $wgAutoloadClasses['WikiPageMessageGroup'] = $dir . 'MessageGroups.php';
2424 $wgAutoloadClasses['AliasMessageGroup'] = $dir . 'MessageGroups.php';
2525
26 -$wgAutoloadClasses['MessageCollection'] = $dir . 'Message.php';
 26+$wgAutoloadClasses['MessageCollection'] = $dir . 'MessageCollection.php';
 27+$wgAutoloadClasses['MessageDefinitions'] = $dir . 'MessageCollection.php';
2728 $wgAutoloadClasses['TMessage'] = $dir . 'Message.php';
 29+$wgAutoloadClasses['ThinMessage'] = $dir . 'Message.php';
 30+$wgAutoloadClasses['FatMessage'] = $dir . 'Message.php';
2831
2932 $wgAutoloadClasses['TranslateEditAddons'] = $dir . 'TranslateEditAddons.php';
3033 $wgAutoloadClasses['languages'] = $IP . '/maintenance/language/languages.inc';
@@ -60,6 +63,8 @@
6164 $wgAutoloadClasses['StringMatcher'] = $dir . 'utils/StringMatcher.php';
6265 $wgAutoloadClasses['FCFontFinder'] = $dir . 'utils/Font.php';
6366
 67+$wgAutoloadClasses['ArrayMemoryCache'] = $dir . 'utils/MemoryCache.php';
 68+
6469 $wgAutoloadClasses['StringMangler'] = $dir . 'utils/StringMangler.php';
6570 $wgAutoloadClasses['SmItem'] = $dir . 'utils/StringMangler.php';
6671 $wgAutoloadClasses['SmRewriter'] = $dir . 'utils/StringMangler.php';
Index: trunk/extensions/Translate/utils/MemoryCache.php
@@ -0,0 +1,54 @@
 2+<?php
 3+
 4+class ArrayMemoryCache {
 5+ protected $table;
 6+ protected $key;
 7+ protected $memc;
 8+ protected $cache;
 9+
 10+ public function __construct( $table ) {
 11+ $this->table = $table;
 12+ $this->key = wfMemcKey( $this->table );
 13+ global $wgMemc;
 14+ $this->memc = $wgMemc;
 15+ }
 16+
 17+ public function __destruct() {
 18+ $this->save();
 19+ }
 20+
 21+ public function get( $group, $code ) {
 22+ $this->load();
 23+ if ( !isset($this->cache[$group][$code]) ) return false;
 24+ return explode( ',', $this->cache[$group][$code] );
 25+ }
 26+
 27+ public function set( $group, $code, $value ) {
 28+ $this->load();
 29+ if ( !isset($this->cache[$group]) ) $this->cache[$group] = array();
 30+ $this->cache[$group][$code] = implode(',', $value);
 31+ }
 32+
 33+ public function clear( $group, $code ) {
 34+ $this->load();
 35+ unset($this->cache[$group][$code]);
 36+ if ( !count($this->cache[$group]) ) unset($this->cache[$group]);
 37+ }
 38+
 39+ public function commit() {
 40+ $this->load();
 41+ $this->save();
 42+ }
 43+
 44+
 45+ protected function load() {
 46+ if ( $this->cache === null ) {
 47+ $this->cache = $this->memc->get( $this->key );
 48+ if ( !is_array($this->cache) ) $this->cache = array();
 49+ }
 50+ }
 51+
 52+ protected function save() {
 53+ $this->memc->set( $this->key, $this->cache );
 54+ }
 55+}
\ No newline at end of file
Property changes on: trunk/extensions/Translate/utils/MemoryCache.php
___________________________________________________________________
Added: svn:eol-style
156 + native
Index: trunk/extensions/Translate/utils/MessageTable.php
@@ -83,21 +83,23 @@
8484 global $wgUser;
8585 $sk = $wgUser->getSkin();
8686 wfLoadExtensionMessages( 'Translate' );
 87+ $optional = wfMsgHtml( 'translate-optional' );
8788
88 - $uimsg = array();
89 - foreach ( array( 'optional' ) as $msg ) {
90 - $uimsg[$msg] = wfMsgHtml( 'translate-'.$msg );
 89+ $batch = new LinkBatch();
 90+ $ns = $this->group->namespaces[0];
 91+ foreach ( $this->collection->keys() as $key ) {
 92+ $batch->add( $ns, $key );
9193 }
 94+ $batch->execute();
9295
9396 $output = '';
94 -
 97+ $this->collection->initMessages(); // Just to be sure
9598 foreach ( $this->collection as $key => $m ) {
96 -
9799 $tools = array();
98100 $title = $this->keyToTitle( $key );
99101
100 - $original = $m->definition;
101 - $message = $m->translation ? $m->translation : $original;
 102+ $original = $m->definition();
 103+ $message = $m->translation() ? $m->translation() : $original;
102104
103105 global $wgLang;
104106 $niceTitle = htmlspecialchars( $wgLang->truncate( $key, - 30 ) );
@@ -114,11 +116,11 @@
115117 $anchor = Xml::element( 'a', array( 'name' => $anchor, 'href' => "#$anchor" ), "↓" );
116118
117119 $extra = '';
118 - if ( $m->optional ) $extra = '<br />' . $uimsg['optional'];
 120+ if ( $m->hasTag( 'optional' ) ) $extra = '<br />' . $optional;
119121
120122 $leftColumn = $anchor . $tools['edit'] . $extra;
121123
122 - if ( $this->reviewMode ) {
 124+ if ( $this->reviewMode && $original !== $message ) {
123125 $output .= Xml::tags( 'tr', array( 'class' => 'orig' ),
124126 Xml::tags( 'td', array( 'rowspan' => '2' ), $leftColumn ) .
125127 Xml::tags( 'td', null, TranslateUtils::convertWhiteSpaceToHTML( $original ) )
Index: trunk/extensions/Translate/ffs/Java.php
@@ -119,9 +119,9 @@
120120 */
121121 protected function exportMessages( $handle, MessageCollection $collection ) {
122122 $mangler = $this->group->getMangler();
123 - foreach ( $collection->keys() as $item ) {
124 - $key = $mangler->unmangle( $item );
125 - $value = str_replace( TRANSLATE_FUZZY, '', $collection[$item]->translation );
 123+ foreach ( $collection as $key => $item ) {
 124+ $key = $mangler->unmangle( $key );
 125+ $value = str_replace( TRANSLATE_FUZZY, '', $item->translation() );
126126
127127 # Make sure we don't slip newlines trough... it would be fatal
128128 $value = str_replace( "\n", '\\n', $value );
Index: trunk/extensions/Translate/ffs/OpenLayers.php
@@ -118,7 +118,9 @@
119119
120120 // Get and write messages.
121121 foreach( $collection as $message ) {
122 - $value = str_replace( '"', '\"', $message->database() );
 122+ $key = Xml::escapeJsString( $message->key() );
 123+ $value = Xml::escapeJsString( $message->translation() );
 124+
123125 $line = " '{$message->key()}': \"{$value}\",\n\n";
124126 fwrite( $target, $line );
125127 }
Index: trunk/extensions/Translate/ffs/Wiki.php
@@ -142,7 +142,7 @@
143143 foreach ( $messages as $key => $m ) {
144144 $key = $mangler->unMangle( $key );
145145 # Remove fuzzy markings before export
146 - $translation = str_replace( TRANSLATE_FUZZY, '', $m->translation );
 146+ $translation = str_replace( TRANSLATE_FUZZY, '', $m->translation() );
147147 $new[$key] = $translation;
148148 }
149149
Index: trunk/extensions/Translate/ffs/Gettext.php
@@ -248,12 +248,12 @@
249249 foreach ( $messages as $key => $m ) {
250250 $flags = array();
251251
252 - $translation = $m->translation;
 252+ $translation = $m->translation();
253253 # CASE2: no translation
254254 if ( $translation === null ) $translation = '';
255255
256256 # CASE3: optional messages; accept only if different
257 - if ( $m->optional ) $flags[] = 'x-optional';
 257+ if ( $m->hasTag( 'optional') ) $flags[] = 'x-optional';
258258
259259 # Remove fuzzy markings before export
260260 $flags = array();
@@ -282,7 +282,7 @@
283283 if ( isset( $this->data[$key]['ctxt'] ) ) {
284284 $ckey = $this->data[$key]['ctxt'];
285285 }
286 - fwrite( $handle, $this->formatmsg( $m->definition, $translation, $ckey ) );
 286+ fwrite( $handle, $this->formatmsg( $m->definition(), $translation, $ckey ) );
287287
288288 }
289289
Index: trunk/extensions/Translate/ffs/Xliff.php
@@ -59,11 +59,11 @@
6060 protected function messages( XMLWriter $w, $handle, MessageCollection $collection ) {
6161 $w->startElement( 'body' );
6262
63 - foreach ( $collection->keys() as $key ) {
 63+ foreach ( $collection as $key => $m) {
6464 $w->startElement( 'trans-unit' );
6565 $w->writeAttribute( 'id', $key );
66 - $w->writeElement( 'source', $collection[$key]->definition );
67 - $translation = $collection[$key]->translation;
 66+ $w->writeElement( 'source', $m->definition() );
 67+ $translation = $m->translatiom();
6868 if ( $translation !== null ) {
6969 $w->writeElement( 'target', $translation );
7070 }
Index: trunk/extensions/Translate/ffs/Simple.php
@@ -171,8 +171,8 @@
172172
173173 protected function getMessagesForExport( MessageGroup $group, $code ) {
174174 $collection = $this->group->initCollection( $code );
175 - $this->group->fillCollection( $collection );
176 - $collection->filter( 'translation', null );
 175+ $collection->filter( 'hastranslation', false );
 176+ $collection->loadTranslations();
177177 $this->addAuthors( $collection->getAuthors(), $code );
178178 return $collection;
179179 }
@@ -245,9 +245,9 @@
246246
247247 protected function exportMessages( $handle, MessageCollection $collection ) {
248248 $mangler = $this->group->getMangler();
249 - foreach ( $collection->keys() as $item ) {
250 - $key = $mangler->unMangle( $item );
251 - $value = str_replace( TRANSLATE_FUZZY, '', $collection[$item]->translation );
 249+ foreach ( $collection as $item ) {
 250+ $key = $mangler->unMangle( $item->key() );
 251+ $value = str_replace( TRANSLATE_FUZZY, '', $item->translation() );
252252 fwrite( $handle, "$key\000$value\000\n" );
253253 }
254254 }
Index: trunk/extensions/Translate/ffs/PhpVariables.php
@@ -143,12 +143,12 @@
144144 */
145145 protected function exportMessages( $handle, MessageCollection $collection ) {
146146 $mangler = $this->group->getMangler();
147 - foreach ( $collection->keys() as $item ) {
 147+ foreach ( $collection as $item ) {
148148
149 - $key = $mangler->unmangle( $item );
 149+ $key = $mangler->unmangle( $item->key() );
150150 $key = stripcslashes( $key );
151151
152 - $value = $collection[$item]->translation;
 152+ $value = $item->translation();
153153 $value = str_replace( TRANSLATE_FUZZY, '', $value );
154154 $value = addcslashes( $value, "'" );
155155
Index: trunk/extensions/Translate/MessageCollection.php
@@ -0,0 +1,423 @@
 2+<?php
 3+if ( !defined( 'MEDIAWIKI' ) ) die();
 4+/**
 5+ * An extension to ease the translation of Mediawiki
 6+ *
 7+ * @addtogroup Extensions
 8+ *
 9+ * @author Niklas Laxström
 10+ * @copyright Copyright © 2007-2009, Niklas Laxström
 11+ * @license http://www.gnu.org/copyleft/gpl.html GNU General Public License 2.0 or later
 12+ */
 13+
 14+class MessageCollection implements ArrayAccess, Iterator, Countable {
 15+ /**
 16+ * It is handy to store the language code here.
 17+ */
 18+ public $code = null;
 19+
 20+ // External stuff
 21+ private $definitions = null; // MessageDefinitions
 22+ private $infile = array(); // message key => translation
 23+
 24+ // Keys and messages
 25+ private $keys = null; // message key => database key
 26+ private $messages = null; // message key => ThinMessage
 27+
 28+ // Database resources
 29+ private $dbInfo = null; // existence, fuzzy
 30+ private $dbData = null; // all translations
 31+
 32+ // Tags, copied to thin messages
 33+ private $tags = array(); // tagtype => keys
 34+
 35+ // Constructors etc.
 36+ //
 37+ public function __construct( $code ) {
 38+ $this->code = $code;
 39+ }
 40+
 41+ public static function newFromDefinitions( MessageDefinitions $definitions, $code ) {
 42+ $collection = new self( $code );
 43+ $collection->definitions = $definitions;
 44+ $collection->resetForNewLanguage( $code );
 45+ return $collection;
 46+ }
 47+
 48+ // Data setters
 49+ //
 50+ public function setInfile( array $messages ) {
 51+ $this->infile = $messages;
 52+ }
 53+
 54+ public function setTags( $type, array $keys ) {
 55+ $this->tags[$type] = $keys;
 56+ }
 57+
 58+ // Getters
 59+ public function keys() {
 60+ return $this->keys;
 61+ }
 62+
 63+ public function getTags( $type ) {
 64+ return isset($this->tags[$type]) ? $this->tags[$type] : null;
 65+ }
 66+
 67+ public function getAuthors() {
 68+ global $wgTranslateFuzzyBotName;
 69+
 70+ $this->loadTranslations();
 71+
 72+ $authors = array();
 73+ foreach ( $this->messages as $m ) {
 74+ // Check if there is authors
 75+ $author = $m->author();
 76+ if ( $author === null ) continue;
 77+ if ( !isset( $authors[$author] ) ) {
 78+ $authors[$author] = 1;
 79+ } else {
 80+ $authors[$author]++;
 81+ }
 82+ }
 83+
 84+ arsort( $authors, SORT_NUMERIC );
 85+ foreach ( $authors as $author => $edits ) {
 86+ if ( $author !== $wgTranslateFuzzyBotName ) {
 87+ $filteredAuthors[] = $author;
 88+ }
 89+ }
 90+ return isset( $filteredAuthors ) ? $filteredAuthors : array();
 91+ }
 92+
 93+ // Data modifiers
 94+
 95+ public function loadTranslations() {
 96+ $this->loadData( $this->keys );
 97+ $this->initMessages();
 98+ }
 99+
 100+ /**
 101+ * Filters messages based on some condition. Some filters cause data to be
 102+ * loaded from the database. PAGEINFO: existence and fuzzy tags.
 103+ * TRANSLATIONS: translations for every message. It is recommended to first
 104+ * filter with messages that do not need those. It is recommended to add
 105+ * translations from file with addInfile, and it is needed for chagned
 106+ * filter to work.
 107+ *
 108+ * @param $type
 109+ * fuzzy: messages with fuzzy tag (PAGEINFO)
 110+ * optional: messages marked for optional.
 111+ * ignored: messages which are not for translation.
 112+ * hastranslation: messages which have translation (be if fuzzy or not) (PAGEINFO, *INFILE).
 113+ * translated: messages which have translation which is not fuzzy (PAGEINFO, *INFILE).
 114+ * changed: translation in database differs from infile. (INFILE, TRANSLATIONS)
 115+ * @param $condition True or false.
 116+ */
 117+ public function filter( $type, $condition = true ) {
 118+ switch( $type ) {
 119+ case 'fuzzy':
 120+ case 'optional':
 121+ case 'ignored':
 122+ case 'hastranslation':
 123+ case 'changed':
 124+ case 'translated':
 125+ $this->applyFilter( $type, $condition );
 126+ break;
 127+ default:
 128+ throw new MWException( "Unknown filter $type" );
 129+ }
 130+ }
 131+
 132+ /**
 133+ * Some statistics scripts for example loop the same collection over every
 134+ * language. This is a shortcut which keeps tags and definitions.
 135+ */
 136+ public function resetForNewLanguage( $code ) {
 137+ $this->code = $code;
 138+
 139+ $this->keys = $this->fixKeys( array_keys($this->definitions->messages) );
 140+ $this->dbInfo = null;
 141+ $this->dbData = null;
 142+ $this->messages = null;
 143+ $this->infile = array();
 144+ unset($this->tags['fuzzy']);
 145+ }
 146+
 147+ /**
 148+ * For paging messages. One can count messages before and after slice.
 149+ */
 150+ public function slice( $offset, $limit ) {
 151+ $this->keys = array_slice( $this->keys, $offset, $limit, true );
 152+ }
 153+
 154+ // Protected functions
 155+ //
 156+ protected function applyFilter( $filter, $condition ) {
 157+ $keys = $this->keys;
 158+ if ( $filter === 'fuzzy' ) {
 159+ $keys = $this->filterFuzzy( $keys, $condition );
 160+ } elseif ( $filter === 'hastranslation' ) {
 161+ $keys = $this->filterHastranslation( $keys, $condition );
 162+ } elseif ( $filter === 'translated' ) {
 163+ $fuzzy = $this->filterFuzzy( $keys, false );
 164+ $hastranslation = $this->filterHastranslation( $keys, false );
 165+ // Fuzzy messages are not translated messages
 166+ $translated = $this->filterOnCondition( $hastranslation, $fuzzy );
 167+ $keys = $this->filterOnCondition( $keys, $translated, $condition );
 168+ } elseif( $filter === 'changed' ) {
 169+ $keys = $this->filterChanged( $keys, $condition );
 170+ } else { // Filter based on tags
 171+ if ( !isset($this->tags[$filter]) ) throw new MWException( "No tagged messages for filter $filter" );
 172+ $taggedKeys = array_flip( $this->tags[$filter] );
 173+ $keys = $this->filterOnCondition( $keys, $taggedKeys, $condition );
 174+ }
 175+ $this->keys = $keys;
 176+ }
 177+
 178+ protected function filterOnCondition( array $keys, array $condKeys, $condition = true ) {
 179+ if ( $condition === true ) {
 180+ // Delete $condKeys from $keys
 181+ foreach( array_keys($condKeys) as $key ) {
 182+ unset($keys[$key]);
 183+ }
 184+ } else {
 185+ // Keep the keys which are in $condKeys
 186+ foreach( array_keys($keys) as $key ) {
 187+ if ( !isset($condKeys[$key]) ) {
 188+ unset($keys[$key]);
 189+ }
 190+ }
 191+ }
 192+ return $keys;
 193+ }
 194+
 195+ protected function filterFuzzy( array $keys, $condition ) {
 196+ $this->loadInfo( $keys );
 197+
 198+ if ( $condition === false ) $origKeys = $keys;
 199+
 200+ $fuzzy = array();
 201+ $flipKeys = array_flip( $keys );
 202+ foreach ( $this->dbInfo as $row ) {
 203+ if ( $row->rt_type !== null ) {
 204+ if ( !isset($flipKeys[$row->page_title]) ) continue;
 205+ unset($keys[$flipKeys[$row->page_title]]);
 206+ $fuzzy[] = $flipKeys[$row->page_title];
 207+ }
 208+ }
 209+
 210+ if ( !isset($this->tags['fuzzy']) )
 211+ $this->setTags( 'fuzzy', $fuzzy );
 212+
 213+ if ( $condition === false ) $keys = array_diff( $origKeys, $keys );
 214+
 215+ return $keys;
 216+ }
 217+
 218+ protected function filterHastranslation( array $keys, $condition ) {
 219+ $this->loadInfo( $keys );
 220+
 221+ if ( $condition === false ) $origKeys = $keys;
 222+
 223+ $flipKeys = array_flip( $keys );
 224+ foreach ( $this->dbInfo as $row ) {
 225+ // Remove messages which have a translation from keys
 226+ if ( !isset($flipKeys[$row->page_title]) ) continue;
 227+ unset($keys[$flipKeys[$row->page_title]]);
 228+ }
 229+
 230+ // Check also if there is something in the file that is not yet in the db
 231+ foreach ( array_keys($this->infile) as $inf ) {
 232+ unset($keys[$inf]);
 233+ }
 234+
 235+ // Remove the messages which do not have a translation from the list
 236+ if ( $condition === false ) $keys = array_diff( $origKeys, $keys );
 237+
 238+ return $keys;
 239+ }
 240+
 241+ protected function filterChanged( array $keys, $condition ) {
 242+ $this->loadData( $keys );
 243+
 244+ if ( $condition === false ) $origKeys = $keys;
 245+ $flipKeys = array_flip( $keys );
 246+ foreach ( $this->dbData as $row ) {
 247+ $realKey = $flipKeys[$row->page_title];
 248+ if ( !isset($this->infile[$realKey]) ) continue;
 249+
 250+ $text = Revision::getRevisionText( $row );
 251+ if ( $this->infile[$realKey] === $text ) {
 252+ // Remove changed messages from the list
 253+ unset($keys[$realKey]);
 254+ }
 255+ }
 256+
 257+ // Remove the messages which have not changed from the list
 258+ if ( $condition === false ) {
 259+ $keys = $this->filterOnCondition( $keys, $origKeys, false );
 260+ }
 261+
 262+ return $keys;
 263+ }
 264+
 265+ protected function fixKeys( array $keys ) {
 266+ $newkeys = array();
 267+ $namespace = $this->definitions->namespace;
 268+ $code = $this->code;
 269+ foreach( $keys as $key ) {
 270+ $title = Title::makeTitleSafe( $namespace, $key. '/' . $code );
 271+ $newkeys[$key] = $title->getDBKey();
 272+ }
 273+ return $newkeys;
 274+ }
 275+
 276+ protected function loadInfo( array $keys ) {
 277+ if ( $this->dbInfo !== null ) return;
 278+ if ( !count($keys) ) return;
 279+
 280+ $dbr = wfGetDB( DB_SLAVE );
 281+
 282+ static $id = null;
 283+ if ( $id === null )
 284+ $id = $dbr->selectField( 'revtag_type', 'rtt_id', array( 'rtt_name' => 'fuzzy' ), __METHOD__ );
 285+
 286+ $tables = array( 'page', 'revtag' );
 287+ $fields = array( 'page_title', 'rt_type' );
 288+ $conds = array(
 289+ 'page_namespace' => $this->definitions->namespace,
 290+ 'page_title' => array_values( $keys ),
 291+ );
 292+ $joins = array( 'revtag' =>
 293+ array(
 294+ 'LEFT JOIN',
 295+ array( 'page_id=rt_page', 'page_latest=rt_revision', 'rt_type' => $id )
 296+ )
 297+ );
 298+
 299+ $this->dbInfo = $dbr->select( $tables, $fields, $conds, __METHOD__, array(), $joins );
 300+ }
 301+
 302+ protected function loadData( $keys ) {
 303+ if ( $this->dbData !== null ) return;
 304+ if ( !count($keys) ) return;
 305+
 306+ $dbr = wfGetDB( DB_SLAVE );
 307+
 308+ $tables = array( 'page', 'revision', 'text' );
 309+ $fields = array( 'page_title', 'rev_user_text', 'old_flags', 'old_text' );
 310+ $conds = array(
 311+ 'page_namespace' => $this->definitions->namespace,
 312+ 'page_title' => array_values( $keys ),
 313+ 'page_latest = rev_id',
 314+ 'old_id = rev_text_id',
 315+ );
 316+
 317+ $res = $dbr->select( $tables, $fields, $conds, __METHOD__ );
 318+
 319+ $this->dbData = $res;
 320+ }
 321+
 322+ public function initMessages() {
 323+ if ( $this->messages !== null ) return;
 324+
 325+ $messages = array();
 326+
 327+ foreach ( array_keys($this->keys) as $key ) {
 328+ $messages[$key] = new ThinMessage( $key, $this->definitions->messages[$key] );
 329+ }
 330+
 331+ // Copy rows if any
 332+ if ( $this->dbData !== null ) {
 333+ $flipKeys = array_flip( $this->keys );
 334+ foreach ( $this->dbData as $row ) {
 335+ if ( !isset($flipKeys[$row->page_title]) ) continue;
 336+ $key = $flipKeys[$row->page_title];
 337+ $messages[$key]->setRow( $row );
 338+ }
 339+ }
 340+
 341+ // Copy tags if any
 342+ foreach ( $this->tags as $type => $keys ) {
 343+ foreach( $keys as $key ) {
 344+ if ( isset($messages[$key]) ) {
 345+ $messages[$key]->setTag( $type );
 346+ }
 347+ }
 348+ }
 349+
 350+ // Copy infile if any
 351+ foreach ( $this->infile as $key => $value ) {
 352+ if ( isset($messages[$key]) ) {
 353+ $messages[$key]->setInfile( $value );
 354+ }
 355+ }
 356+
 357+ $this->messages = $messages;
 358+ }
 359+
 360+ // Interfaces etc.
 361+ //
 362+ /* ArrayAccess methods */
 363+ public function offsetExists( $offset ) {
 364+ return isset( $this->messages[$offset] );
 365+ }
 366+
 367+ public function offsetGet( $offset ) {
 368+ return $this->messages[$offset];
 369+ }
 370+
 371+ public function offsetSet( $offset, $value ) {
 372+ throw new MWException( "Cannot add or modify elements" );
 373+ }
 374+
 375+ public function offsetUnset( $offset ) {
 376+ unset( $this->messages[$offset] );
 377+ }
 378+
 379+ /* Fail fast */
 380+ public function __get( $name ) {
 381+ throw new MWException( __METHOD__ . ": Trying to access unknown property $name" );
 382+ }
 383+
 384+ /* Fail fast */
 385+ public function __set( $name, $value ) {
 386+ throw new MWException( __METHOD__ . ": Trying to modify unknown property $name" );
 387+ }
 388+
 389+ /* Iterator methods */
 390+ public function rewind() {
 391+ reset( $this->messages );
 392+ }
 393+
 394+ public function current() {
 395+ if ( !count($this->messages) ) return false;
 396+ return current($this->messages);
 397+ }
 398+
 399+ public function key() {
 400+ return key( $this->messages );
 401+ }
 402+
 403+ public function next() {
 404+ return next( $this->messages );
 405+ }
 406+
 407+ public function valid() {
 408+ return $this->current() !== false;
 409+ }
 410+
 411+ public function count() {
 412+ return count($this->keys());
 413+ }
 414+
 415+}
 416+
 417+class MessageDefinitions {
 418+ public $namespace;
 419+ public $messages;
 420+ public function __construct( $namespace, array $messages ) {
 421+ $this->namespace = $namespace;
 422+ $this->messages = $messages;
 423+ }
 424+}
\ No newline at end of file
Property changes on: trunk/extensions/Translate/MessageCollection.php
___________________________________________________________________
Added: svn:eol-style
1425 + native
Index: trunk/extensions/Translate/scripts/sync-group.php
@@ -130,7 +130,7 @@
131131 if ( !count( $messages ) ) return;
132132
133133 $collection = $this->group->initCollection( $code );
134 - $this->group->fillCollection( $collection );
 134+ $collection->loadTranslations();
135135
136136 foreach ( $messages as $key => $translation ) {
137137
@@ -145,13 +145,13 @@
146146
147147 $page = $title->getPrefixedText();
148148
149 - if ( $collection[$key]->database === null ) {
 149+ if ( $collection[$key]->translation() === null ) {
150150 STDOUT( "Importing $page as a new translation" );
151151 $this->import( $title, $translation, 'Importing a new translation' );
152152 continue;
153153 }
154154
155 - $current = str_replace( TRANSLATE_FUZZY, '', $collection[$key]->translation );
 155+ $current = str_replace( TRANSLATE_FUZZY, '', $collection[$key]->translation() );
156156 $translation = str_replace( TRANSLATE_FUZZY, '', $translation );
157157 if ( $translation === $current ) continue;
158158
Index: trunk/extensions/Translate/scripts/groupStatistics.php
@@ -105,43 +105,70 @@
106106 }
107107 $out->blockend();
108108
109 -// Perform the statistic calculations on every language
 109+$rows = array();
110110 foreach ( $languages as $code => $name ) {
111111 // Skip list
112112 if ( in_array( $code, $skipLanguages ) ) continue;
 113+ $rows[$code] = array();
 114+}
113115
114 - // Tracker for skipping languages with no localisation
115 - $allZero = true;
116 - $columns = array();
 116+$cache = new ArrayMemoryCache( 'groupstats' );
117117
118 - foreach ( $groups as $g ) {
119 - // Initialise messages
120 - $collection = $g->initCollection( $code );
121 - $collection->filter( 'optional' );
122 - // Store the count of real messages for later calculation.
123 - $total = count( $collection );
 118+foreach ( $groups as $groupName => $g ) {
 119+ // Initialise messages
 120+ $collection = $g->initCollection( 'en' );
124121
125 - // Fill translations in for counting
126 - $g->fillCollection( $collection );
 122+ // Perform the statistic calculations on every language
 123+ foreach ( $languages as $code => $name ) {
 124+ // Skip list
 125+ if ( in_array( $code, $skipLanguages ) ) continue;
127126
128 - // Count fuzzy first
129 - $collection->filter( 'fuzzy' );
130 - $fuzzy = $total - count( $collection );
 127+ $incache = $cache->get( $groupName, $code );
 128+ if ( $incache !== false ) {
 129+ list( $fuzzy, $translated, $total ) = $incache;
 130+ } else {
131131
132 - // Count the completion percent
133 - $collection->filter( 'translated', false );
134 - $translated = count( $collection );
135 - if ( $translated ) $allZero = false;
 132+ $collection->resetForNewLanguage( $code );
 133+ $collection->filter( 'ignored' );
 134+ $collection->filter( 'optional' );
 135+ // Store the count of real messages for later calculation.
 136+ $total = count( $collection );
136137
137 - $columns[] = $out->formatPercent( $translated, $total,
138 - /* Inverted color */ false, /* Decimals */ 2 );
 138+ // Count fuzzy first
 139+ $collection->filter( 'fuzzy' );
 140+ $fuzzy = $total - count( $collection );
139141
 142+ // Count the completion percent
 143+ $collection->filter( 'hastranslation', false );
 144+ $translated = count( $collection );
 145+
 146+ $cache->set( $groupName, $code, array( $fuzzy, $translated, $total ) );
 147+ }
 148+
 149+ $rows[$code][] = array( $translated, $total );
 150+
140151 if ( isset( $options['fuzzy'] ) ) {
141 - $columns[] = $out->formatPercent( $fuzzy, $total,
142 - /* Inverted color */ true, /* Decimals */ 2 );
 152+ $rows[$code][] = array( $fuzzy, $total );
143153 }
 154+
144155 }
145156
 157+ $cache->commit(); // Don't keep open too long... to avoid concurrent access
 158+
 159+ unset($collection);
 160+}
 161+
 162+foreach ( $languages as $code => $name ) {
 163+ // Skip list
 164+ if ( in_array( $code, $skipLanguages ) ) continue;
 165+
 166+ $columns = $rows[$code];
 167+
 168+ $allZero = true;
 169+ foreach ( $columns as $fields ) {
 170+ if ( $fields[0] !== 0 ) $allZero = false;
 171+ }
 172+
146173 // Skip dummy languages if requested
147174 if ( $allZero && isset( $options['skipzero'] ) ) continue;
148175
@@ -149,7 +176,11 @@
150177 $out->blockstart();
151178 $out->element( $code );
152179 $out->element( $name );
153 - foreach ( $columns as $c ) $out->element( $c );
 180+ foreach ( $columns as $fields ) {
 181+ list( $upper, $total ) = $fields;
 182+ $c = $out->formatPercent( $upper, $total, /* Inverted color */ false, /* Decimals */ 2 );
 183+ $out->element( $c );
 184+ }
154185 $out->blockend();
155186 }
156187
Index: trunk/extensions/Translate/scripts/createCheckIndex.php
@@ -60,13 +60,11 @@
6161 foreach ( $codes as $code ) {
6262 STDOUT( "$code ", $id );
6363
64 - $collection = clone $collection_skel;
65 - $collection->code = $code;
 64+ $collection->reset( $code );
 65+ $collection->loadTranslations();
6666
67 - $g->fillCollection( $collection );
68 -
69 - foreach ( $collection->keys() as $key ) {
70 - $prob = $checker->doFastChecks( $collection[$key], $type, $code );
 67+ foreach ( $collection as $key => $message ) {
 68+ $prob = $checker->doFastChecks( $message, $type, $code );
7169 if ( $prob ) {
7270
7371 if ( $verbose ) {
Index: trunk/extensions/Translate/scripts/autoexport.php
@@ -111,6 +111,8 @@
112112 sort( $languages );
113113 $languages = checkThreshold( $group, $languages, $threshold );
114114
 115+ if ( !count($languages) ) continue;
 116+
115117 $languagelist = implode( ', ', $languages );
116118 STDOUT( str_replace(
117119 array( '$GROUP', '$LANG', '$TARGET' ),
@@ -135,17 +137,10 @@
136138 foreach ( $languages as $code ) {
137139 // Initialise messages
138140 $collection = $g->initCollection( $code );
 141+ $collection->filter( 'ignored' );
139142 $collection->filter( 'optional' );
140143 // Store the count of real messages for later calculation.
141144 $total = count( $collection );
142 -
143 - // Fill translations in for counting
144 - $g->fillCollection( $collection );
145 -
146 - // Count fuzzy first
147 - $collection->filter( 'fuzzy' );
148 -
149 - // Count the completion percent
150145 $collection->filter( 'translated', false );
151146 $translated = count( $collection );
152147
Index: trunk/extensions/Translate/TranslateTasks.php
@@ -72,7 +72,15 @@
7373 }
7474
7575 protected $process = array();
76 - abstract protected function setProcess();
 76+
 77+ protected function setProcess() {
 78+ $this->process = array(
 79+ array( $this, 'preinit' ),
 80+ array( $this, 'doPaging' ),
 81+ array( $this, 'postinit' ),
 82+ );
 83+ }
 84+
7785 abstract protected function output();
7886
7987 public final function execute() {
@@ -85,14 +93,12 @@
8694
8795 protected function doPaging() {
8896 $total = count( $this->collection );
89 -
9097 $this->collection->slice(
9198 $this->options->getOffset(),
9299 $this->options->getLimit()
93100 );
 101+ $left = count( $this->collection );
94102
95 - $left = count( $this->collection );
96 -
97103 $callback = $this->options->getPagingCB();
98104 call_user_func( $callback, $this->options->getOffset(), $left, $total );
99105 }
@@ -101,26 +107,15 @@
102108 class ViewMessagesTask extends TranslateTask {
103109 protected $id = 'view';
104110
105 - protected function setProcess() {
106 - $this->process = array(
107 - array( $this, 'preinit' ),
108 - array( $this, 'filterOptional' ),
109 - array( $this, 'doPaging' ),
110 - array( $this, 'postinit' ),
111 - );
112 - }
113 -
114111 protected function preinit() {
115112 $code = $this->options->getLanguage();
116113 $this->collection = $this->group->initCollection( $code );
117 - }
118 -
119 - protected function filterOptional() {
 114+ $this->collection->filter( 'ignored' );
120115 $this->collection->filter( 'optional' );
121116 }
122117
123118 protected function postinit() {
124 - $this->group->fillCollection( $this->collection );
 119+ $this->collection->loadTranslations();
125120 }
126121
127122 protected function output() {
@@ -131,26 +126,45 @@
132127
133128 }
134129
135 -class ViewUntranslatedTask extends ViewMessagesTask {
136 - protected $id = 'untranslated';
 130+class ReviewMessagesTask extends ViewMessagesTask {
 131+ protected $id = 'review';
137132
138 - protected function setProcess() {
139 - $this->process = array(
140 - array( $this, 'preinit' ),
141 - array( $this, 'filterOptional' ),
142 - array( $this, 'postinit' ),
143 - array( $this, 'filterTranslated' ),
144 - array( $this, 'doPaging' ),
145 - );
 133+ protected function preinit() {
 134+ $code = $this->options->getLanguage();
 135+ $this->collection = $this->group->initCollection( $code );
 136+ $this->collection->setInfile( $this->group->load( $code ) );
 137+ $this->collection->filter( 'ignored' );
 138+ $this->collection->filter( 'changed', false );
146139 }
147140
148 - /**
149 - * Filters all translated messages. Fuzzy messages are not considered to be
150 - * translated, because they need attention from translators. Also optional
151 - * messages can not have identical translations.
152 - */
153 - protected function filterTranslated() {
 141+ protected function output() {
 142+ $table = new MessageTable( $this->collection, $this->group );
 143+ $table->appendEditLinkParams( 'loadtask', $this->getId() );
 144+ $table->setReviewMode();
 145+
 146+ return $table->fullTable();
 147+ }
 148+
 149+}
 150+
 151+class ViewUntranslatedTask extends ReviewMessagesTask {
 152+ protected $id = 'untranslated';
 153+
 154+ protected function preinit() {
 155+ $code = $this->options->getLanguage();
 156+ $this->collection = $this->group->initCollection( $code );
 157+ $this->collection->setInfile( $this->group->load( $code ) );
 158+ $this->collection->filter( 'ignored' );
 159+ $this->collection->filter( 'optional' );
 160+
 161+ // Update the cache while we are at it
 162+ $total = count($this->collection);
154163 $this->collection->filter( 'translated' );
 164+ $translated = $total - count($this->collection);
 165+ $fuzzy = count($this->collection->getTags('fuzzy'));
 166+
 167+ $cache = new ArrayMemoryCache( 'groupstats' );
 168+ $cache->set( $this->group->getID(), $code, array( $fuzzy, $translated, $total ) );
155169 }
156170
157171 }
@@ -161,13 +175,16 @@
162176 protected function setProcess() {
163177 $this->process = array(
164178 array( $this, 'preinit' ),
165 - array( $this, 'filterNonOptional' ),
166179 array( $this, 'doPaging' ),
167180 array( $this, 'postinit' ),
168181 );
169182 }
170183
171 - protected function filterNonOptional() {
 184+ protected function preinit() {
 185+ $code = $this->options->getLanguage();
 186+ $this->collection = $this->group->initCollection( $code );
 187+ $this->collection->setInfile( $this->group->load( $code ) );
 188+ $this->collection->filter( 'ignored' );
172189 $this->collection->filter( 'optional', false );
173190 }
174191
@@ -179,90 +196,38 @@
180197 protected function setProcess() {
181198 $this->process = array(
182199 array( $this, 'preinit' ),
183 - array( $this, 'filterNonOptional' ),
184 - array( $this, 'postinit' ),
185 - array( $this, 'filterTranslated' ),
186200 array( $this, 'doPaging' ),
187 - );
188 - }
189 -
190 - protected function filterTranslated() {
191 - $this->collection->filter( 'translated' );
192 - }
193 -
194 -}
195 -
196 -class ViewProblematicTask extends ReviewMessagesTask {
197 - protected $id = 'problematic';
198 -
199 - protected function setProcess() {
200 - $this->process = array(
201 - array( $this, 'preinit' ),
202201 array( $this, 'postinit' ),
203 - array( $this, 'filterNonProblematic' ),
204 - array( $this, 'doPaging' ),
205202 );
206203 }
207204
208 - protected function filterNonProblematic() {
 205+ protected function preinit() {
209206 $code = $this->options->getLanguage();
210 - $problematic = $this->group->getProblematic( $code );
211 - $checker = MessageChecks::getInstance();
212 - $type = $this->group->getType();
213 -
214 - foreach ( $this->collection->keys() as $key ) {
215 - $item = $this->collection[$key];
216 - if ( in_array( $key, $problematic ) ) {
217 - if ( $checker->doFastChecks( $item, $type, $code ) ) continue;
218 - }
219 -
220 - unset( $this->collection[$key] );
221 - }
 207+ $this->collection = $this->group->initCollection( $code );
 208+ $this->collection->setInfile( $this->group->load( $code ) );
 209+ $this->collection->filter( 'ignored' );
 210+ $this->collection->filter( 'optional', false );
 211+ $this->collection->filter( 'translated' );
222212 }
223 -
224213 }
225214
226 -
227 -class ReviewMessagesTask extends ViewMessagesTask {
228 - protected $id = 'review';
229 -
230 - protected function setProcess() {
231 - $this->process = array(
232 - array( $this, 'preinit' ),
233 - array( $this, 'postinit' ),
234 - array( $this, 'filterUnchanged' ),
235 - array( $this, 'doPaging' ),
236 - );
237 - }
238 -
239 - protected function filterUnchanged() {
240 - $this->collection->filter( 'changed', false );
241 - }
242 -
243 - protected function output() {
244 - $table = new MessageTable( $this->collection, $this->group );
245 - $table->appendEditLinkParams( 'loadtask', $this->getId() );
246 - $table->setReviewMode();
247 -
248 - return $table->fullTable();
249 - }
250 -
251 -}
252 -
253215 class ReviewAllMessagesTask extends ReviewMessagesTask {
254216 protected $id = 'reviewall';
255217
256218 protected function setProcess() {
257219 $this->process = array(
258220 array( $this, 'preinit' ),
259 - array( $this, 'postinit' ),
260 - array( $this, 'filterUntranslated' ),
261221 array( $this, 'doPaging' ),
 222+ array( $this, 'postinit' ),
262223 );
263224 }
264225
265 - protected function filterUntranslated() {
266 - $this->collection->filter( 'translated', false );
 226+ protected function preinit() {
 227+ $code = $this->options->getLanguage();
 228+ $this->collection = $this->group->initCollection( $code );
 229+ $this->collection->setInfile( $this->group->load( $code ) );
 230+ $this->collection->filter( 'ignored' );
 231+ $this->collection->filter( 'hastranslation', false );
267232 }
268233
269234 }
@@ -297,7 +262,7 @@
298263
299264 public function output() {
300265 $writer = $this->group->getWriter();
301 - $this->collection->filter( 'translation', null );
 266+ $this->collection->filter( 'translated', false );
302267 return $writer->webExport( $this->collection );
303268 }
304269 }
@@ -356,12 +321,12 @@
357322 foreach ( $this->collection as $key => $m ) {
358323 $flags = array();
359324
360 - $translation = $m->translation;
 325+ $translation = $m->translation();
361326 # CASE2: no translation
362327 if ( $translation === null ) $translation = '';
363328
364329 # CASE3: optional messages; accept only if different
365 - if ( $m->optional ) $flags[] = 'optional';
 330+ if ( $m->hasTag( 'optional') ) $flags[] = 'optional';
366331
367332 # Remove fuzzy markings before export
368333 if ( strpos( $translation, TRANSLATE_FUZZY ) !== false ) {
@@ -376,7 +341,7 @@
377342 }
378343
379344 $out .= self::formatcomments( $comments, $flags );
380 - $out .= self::formatmsg( $m->definition, $translation, $key, $flags );
 345+ $out .= self::formatmsg( $m->definition(), $translation, $key, $flags );
381346
382347 }
383348
Index: trunk/extensions/Translate/MessageChecks.php
@@ -69,7 +69,7 @@
7070 * @return Array of warning messages, html-format.
7171 */
7272 public function doChecks( TMessage $message, $type, $code ) {
73 - if ( $message->translation === null ) return array();
 73+ if ( $message->translation() === null ) return array();
7474 $warnings = array();
7575
7676 foreach ( $this->checksForType[$type] as $check ) {
@@ -83,7 +83,7 @@
8484 }
8585
8686 public function doFastChecks( TMessage $message, $type, $code ) {
87 - if ( $message->translation === null ) return false;
 87+ if ( $message->translation() === null ) return false;
8888
8989 foreach ( $this->checksForType[$type] as $check ) {
9090 if ( $this->$check( $message, $code ) ) return true;
@@ -103,8 +103,8 @@
104104 $variables = array( '\$1', '\$2', '\$3', '\$4', '\$5', '\$6', '\$7', '\$8', '\$9' );
105105
106106 $missing = array();
107 - $definition = $message->definition;
108 - $translation = $message->translation;
 107+ $definition = $message->definition();
 108+ $translation = $message->translation();
109109 if ( strpos( $definition, '$' ) === false ) return false;
110110
111111 for ( $i = 1; $i < 10; $i++ ) {
@@ -129,8 +129,8 @@
130130 $variables = array( '\$1', '\$2', '\$3', '\$4', '\$5', '\$6', '\$7', '\$8', '\$9' );
131131
132132 $missing = array();
133 - $definition = $message->definition;
134 - $translation = $message->translation;
 133+ $definition = $message->definition();
 134+ $translation = $message->translation();
135135 if ( strpos( $translation, '$' ) === false ) return false;
136136
137137 for ( $i = 1; $i < 10; $i++ ) {
@@ -160,7 +160,7 @@
161161 * and closing count as value.
162162 */
163163 protected function checkBalance( TMessage $message, $code, &$desc = null ) {
164 - $translation = preg_replace( '/[^{}[\]()]/u', '', $message->translation );
 164+ $translation = preg_replace( '/[^{}[\]()]/u', '', $message->translation() );
165165 $counts = array( '{' => 0, '}' => 0, '[' => 0, ']' => 0, '(' => 0, ')' => 0 );
166166
167167 $i = 0;
@@ -197,12 +197,12 @@
198198 * @return Array of problematic links.
199199 */
200200 protected function checkLinks( TMessage $message, $code, &$desc = null ) {
201 - if ( strpos( $message->translation, '[[' ) === false ) return false;
 201+ if ( strpos( $message->translation(), '[[' ) === false ) return false;
202202
203203 $matches = array();
204204 $links = array();
205205 $tc = Title::legalChars() . '#%{}';
206 - preg_match_all( "/\[\[([{$tc}]+)(?:\\|(.+?))?]]/sDu", $message->translation, $matches );
 206+ preg_match_all( "/\[\[([{$tc}]+)(?:\\|(.+?))?]]/sDu", $message->translation(), $matches );
207207 for ( $i = 0; $i < count( $matches[0] ); $i++ ) {
208208 // if ( preg_match( '/({{ns:)?special(}})?:.*/sDui', $matches[1][$i] ) ) continue;
209209 // if ( preg_match( '/{{mediawiki:.*}}/sDui', $matches[1][$i] ) ) continue;
@@ -210,7 +210,7 @@
211211 // if ( preg_match( '/:?\$[1-9]/sDu', $matches[1][$i] ) ) continue;
212212
213213 $backMatch = preg_quote( $matches[1][$i], '/' );
214 - if ( preg_match( "/$backMatch/", $message->definition ) ) continue;
 214+ if ( preg_match( "/$backMatch/", $message->definition() ) ) continue;
215215
216216 $links[] = "[[{$matches[1][$i]}|{$matches[2][$i]}]]";
217217 }
@@ -234,7 +234,7 @@
235235 * value.
236236 */
237237 protected function checkXHTML( TMessage $message, $code, &$desc = null ) {
238 - $translation = $message->translation;
 238+ $translation = $message->translation();
239239 if ( strpos( $translation, '<' ) === false ) return false;
240240
241241 $tags = array(
@@ -277,8 +277,8 @@
278278 && in_array( 'plural', $this->blacklist[$code] ) )
279279 return false;
280280
281 - $definition = $message->definition;
282 - $translation = $message->translation;
 281+ $definition = $message->definition();
 282+ $translation = $message->translation();
283283 if ( stripos( $definition, '{{plural:' ) !== false &&
284284 stripos( $translation, '{{plural:' ) === false ) {
285285 $desc = array( 'translate-checks-plural' );
@@ -295,8 +295,8 @@
296296 * @return True if namespace has been tampered with.
297297 */
298298 protected function checkPagename( TMessage $message, $code, &$desc = null ) {
299 - $definition = $message->definition;
300 - $translation = $message->translation;
 299+ $definition = $message->definition();
 300+ $translation = $message->translation();
301301
302302 $namespaces = 'help|project|\{\{ns:project}}|mediawiki';
303303 $matches = array();
@@ -317,9 +317,9 @@
318318 */
319319 protected function miscMWChecks( TMessage $message, $code, &$desc = null ) {
320320 $timeList = array( 'protect-expiry-options', 'ipboptions' );
321 - if ( in_array( strtolower($message->key), $timeList, true ) ) {
322 - $defArray = explode( ',', $message->definition );
323 - $traArray = explode( ',', $message->translation );
 321+ if ( in_array( strtolower($message->key()), $timeList, true ) ) {
 322+ $defArray = explode( ',', $message->definition() );
 323+ $traArray = explode( ',', $message->translation() );
324324
325325 $defCount = count($defArray);
326326 $traCount = count($traArray);
@@ -353,10 +353,10 @@
354354 protected function checkFreeColMissingVars( TMessage $message, $code, &$desc = null ) {
355355 $varPattern = '%[a-zA-Z_]+%';
356356
357 - if ( !preg_match_all( "/$varPattern/U", $message->definition, $defVars ) ) {
 357+ if ( !preg_match_all( "/$varPattern/U", $message->definition(), $defVars ) ) {
358358 return false;
359359 }
360 - preg_match_all( "/$varPattern/U", $message->translation, $transVars );
 360+ preg_match_all( "/$varPattern/U", $message->translation(), $transVars );
361361
362362 $missing = self::compareArrays( $defVars[0], $transVars[0] );
363363
@@ -381,8 +381,8 @@
382382 protected function checkFreeColExtraVars( TMessage $message, $code, &$desc = null ) {
383383 $varPattern = '%[a-zA-Z_]+%';
384384
385 - preg_match_all( "/$varPattern/U", $message->definition, $defVars );
386 - preg_match_all( "/$varPattern/U", $message->translation, $transVars );
 385+ preg_match_all( "/$varPattern/U", $message->definition(), $defVars );
 386+ preg_match_all( "/$varPattern/U", $message->translation(), $transVars );
387387
388388 $missing = self::compareArrays( $transVars[0], $defVars[0] );
389389
@@ -399,7 +399,7 @@
400400
401401 protected function checkFreeColEscapes( TMessage $message, $code, &$desc = null ) {
402402 $varPattern = '\\\\[^nt\'"]';
403 - preg_match_all( "/$varPattern/U", $message->translation, $transVars );
 403+ preg_match_all( "/$varPattern/U", $message->translation(), $transVars );
404404
405405 if ( $count = count( $transVars[0] ) ) {
406406 global $wgLang;
@@ -419,10 +419,10 @@
420420 * @return True if namespace has been tampered with.
421421 */
422422 protected function checkPrintfMissingVars( TMessage $message, $code, &$desc = null ) {
423 - if ( !preg_match_all( '/%[sd]/U', $message->definition, $defVars ) ) {
 423+ if ( !preg_match_all( '/%[sd]/U', $message->definition(), $defVars ) ) {
424424 return false;
425425 }
426 - preg_match_all( '/%[sd]/U', $message->translation, $transVars );
 426+ preg_match_all( '/%[sd]/U', $message->translation(), $transVars );
427427
428428 $missing = self::compareArrays( $defVars[0], $transVars[0] );
429429
@@ -445,8 +445,8 @@
446446 * @return True if namespace has been tampered with.
447447 */
448448 protected function checkPrintfExtraVars( TMessage $message, $code, &$desc = null ) {
449 - preg_match_all( '/%[sd]/U', $message->definition, $defVars );
450 - preg_match_all( '/%[sd]/U', $message->translation, $transVars );
 449+ preg_match_all( '/%[sd]/U', $message->definition(), $defVars );
 450+ preg_match_all( '/%[sd]/U', $message->translation(), $transVars );
451451
452452 $missing = self::compareArrays( $transVars[0], $defVars[0] );
453453
@@ -469,10 +469,10 @@
470470 * @return True if namespace has been tampered with.
471471 */
472472 protected function checkI18nSprintMissingVars( TMessage $message, $code, &$desc = null ) {
473 - if ( !preg_match_all( '/%[^% ]+/U', $message->definition, $defVars ) ) {
 473+ if ( !preg_match_all( '/%[^% ]+/U', $message->definition(), $defVars ) ) {
474474 return false;
475475 }
476 - preg_match_all( '/%[^% ]+/U', $message->translation, $transVars );
 476+ preg_match_all( '/%[^% ]+/U', $message->translation(), $transVars );
477477
478478 $missing = self::compareArrays( $defVars[0], $transVars[0] );
479479
@@ -495,8 +495,8 @@
496496 * @return True if namespace has been tampered with.
497497 */
498498 protected function checkI18nSprintExtraVars( TMessage $message, $code, &$desc = null ) {
499 - preg_match_all( '/%[^% ]+/U', $message->definition, $defVars );
500 - preg_match_all( '/%[^% ]+/U', $message->translation, $transVars );
 499+ preg_match_all( '/%[^% ]+/U', $message->definition(), $defVars );
 500+ preg_match_all( '/%[^% ]+/U', $message->translation(), $transVars );
501501
502502 $missing = self::compareArrays( $transVars[0], $defVars[0] );
503503
Index: trunk/extensions/Translate/TranslateUtils.php
@@ -36,35 +36,6 @@
3737 return array( $key, $code );
3838 }
3939
40 - /**
41 - * Fills the actual translation from database, if any.
42 - *
43 - * @param $messages MessageCollection
44 - * @param $namespaces Array: two-item 1-d array with namespace numbers
45 - */
46 - public static function fillContents( MessageCollection $messages,
47 - array $namespaces ) {
48 -
49 - $titles = array();
50 - foreach ( $messages->keys() as $key ) {
51 - $titles[] = self::title( $key, $messages->code );
52 - }
53 -
54 - if ( !count( $titles ) ) return;
55 -
56 - // Fetch contents
57 - $titles = self::getContents( $titles, $namespaces[0] );
58 -
59 - foreach ( $messages->keys() as $key ) {
60 - $title = self::title( $key, $messages->code );
61 - if ( isset( $titles[$title] ) ) {
62 - $messages[$key]->database = $titles[$title][0];
63 - $messages[$key]->addAuthor( $titles[$title][1] );
64 - }
65 - }
66 -
67 - }
68 -
6940 public static function getMessageContent( $key, $language,
7041 $namespace = NS_MEDIAWIKI ) {
7142

Status & tagging log