r97158 MediaWiki - Code Review archive

Repository:MediaWiki
Revision:r97157‎ | r97158 | r97159 >
Date:15:19, 15 September 2011
Author:nikerabbit
Status:deferred
Tags:
Comment:
Use the new MessageGroupStats instead of ArrayMemoryCache
* Moved few hooks to global level
* Cached transformed message group descriptions per language
* Removed lots of duplicated code for calculating the numbers, some cases the code even differed slightly
* Special:LanguageStats now uses a timeout and notifies the user if not all numbers were calculated
Modified paths:
  • /trunk/extensions/Translate/Translate.i18n.php (modified) (history)
  • /trunk/extensions/Translate/Translate.php (modified) (history)
  • /trunk/extensions/Translate/TranslateEditAddons.php (modified) (history)
  • /trunk/extensions/Translate/TranslateHooks.php (modified) (history)
  • /trunk/extensions/Translate/TranslateTasks.php (modified) (history)
  • /trunk/extensions/Translate/_autoload.php (modified) (history)
  • /trunk/extensions/Translate/scripts/groupStatistics.php (modified) (history)
  • /trunk/extensions/Translate/specials/SpecialLanguageStats.php (modified) (history)
  • /trunk/extensions/Translate/tag/SpecialPageTranslation.php (modified) (history)
  • /trunk/extensions/Translate/utils/MemoryCache.php (deleted) (history)
  • /trunk/extensions/Translate/utils/MessageGroupStats.php (modified) (history)
  • /trunk/extensions/Translate/utils/MessageHandle.php (modified) (history)
  • /trunk/extensions/Translate/utils/MessageIndexRebuilder.php (modified) (history)

Diff [purge]

Index: trunk/extensions/Translate/scripts/groupStatistics.php
@@ -372,12 +372,7 @@
373373 $rows[$code] = array();
374374 }
375375
376 -$cache = new ArrayMemoryCache( 'groupstats' );
377 -
378376 foreach ( $groups as $groupName => $g ) {
379 - // Initialise messages
380 - $collection = $g->initCollection( 'en' );
381 -
382377 // Perform the statistic calculations on every language
383378 foreach ( $languages as $code => $name ) {
384379 // Skip list
@@ -395,27 +390,8 @@
396391 continue;
397392 }
398393
399 - $incache = $cache->get( $groupName, $code );
400 - if ( $incache !== false ) {
401 - list( $fuzzy, $translated, $total ) = $incache;
402 - } else {
403 - $collection->resetForNewLanguage( $code );
404 - $collection->filter( 'ignored' );
405 - $collection->filter( 'optional' );
406 - // Store the count of real messages for later calculation.
407 - $total = count( $collection );
 394+ list( $total, $translated, $fuzzy ) = MessageGroupStats::forItem( $groupName, $code );
408395
409 - // Count fuzzy first
410 - $collection->filter( 'fuzzy' );
411 - $fuzzy = $total - count( $collection );
412 -
413 - // Count the completion percent
414 - $collection->filter( 'hastranslation', false );
415 - $translated = count( $collection );
416 -
417 - $cache->set( $groupName, $code, array( $fuzzy, $translated, $total ) );
418 - }
419 -
420396 $rows[$code][] = array( false, $translated, $total );
421397
422398 if ( isset( $options['fuzzy'] ) ) {
@@ -423,8 +399,6 @@
424400 }
425401 }
426402
427 - $cache->commit(); // Do not keep open too long to avoid concurrent access
428 -
429403 unset( $collection );
430404 }
431405
Index: trunk/extensions/Translate/tag/SpecialPageTranslation.php
@@ -535,7 +535,7 @@
536536
537537 // Re-generate caches
538538 $page->getTranslationPercentages( /*re-generate*/ true );
539 - ArrayMemoryCache::factory( 'groupstats' )->clearGroup( $page->getMessageGroupId() );
 539+ MessageGroupStats::clearGroup( $page->getMessageGroupId() );
540540 MessageIndexRebuilder::execute();
541541 MessageGroups::clearCache();
542542 return false;
Index: trunk/extensions/Translate/TranslateEditAddons.php
@@ -274,7 +274,8 @@
275275 * @return \bool If string contains fuzzy string.
276276 */
277277 public static function hasFuzzyString( $text ) {
278 - return strpos( $text, TRANSLATE_FUZZY ) !== false;
 278+ #wfDeprecated( __METHOD__, '1.19' );
 279+ return MessageHandle::hasFuzzyString( $text );
279280 }
280281
281282 /**
@@ -283,24 +284,11 @@
284285 * @return \bool If title is marked fuzzy.
285286 */
286287 public static function isFuzzy( Title $title ) {
287 - $dbr = wfGetDB( DB_SLAVE );
288 -
289 - $tables = array( 'page', 'revtag' );
290 - $field = 'rt_type';
291 - $conds = array(
292 - 'page_namespace' => $title->getNamespace(),
293 - 'page_title' => $title->getDBkey(),
294 - 'rt_type' => RevTag::getType( 'fuzzy' ),
295 - 'page_id=rt_page',
296 - 'page_latest=rt_revision'
297 - );
298 -
299 - $res = $dbr->selectField( $tables, $field, $conds, __METHOD__ );
300 -
301 - return $res !== false;
 288+ #wfDeprecated( __METHOD__, '1.19' );
 289+ $handle = new MessageHandle( $title );
 290+ return $handle->isFuzzy();
302291 }
303292
304 -
305293 /**
306294 * Check if a title is in a message namespace.
307295 * @param $title Title
@@ -346,97 +334,110 @@
347335 $minor, $_, $_, $flags, $revision
348336 ) {
349337 $title = $article->getTitle();
 338+ $handle = new MessageHandle( $title );
350339
351 - if ( !self::isMessageNamespace( $title ) ) {
 340+ if ( !$handle->isValid() ) {
352341 return true;
353342 }
354343
355 - list( $key, $code, $group ) = self::getKeyCodeGroup( $title );
356 -
357 - // Unknown message, do not handle.
358 - if ( !$group || !$code ) {
359 - return true;
 344+ // Update it.
 345+ if ( $revision === null ) {
 346+ $rev = $article->getTitle()->getLatestRevId();
 347+ } else {
 348+ $rev = $revision->getID();
360349 }
361350
362 - $groups = TranslateUtils::messageKeyToGroups( $title->getNamespace(), $key );
363 - $cache = new ArrayMemoryCache( 'groupstats' );
 351+ $fuzzy = self::checkNeedsFuzzy( $handle, $text );
 352+ self::updateFuzzyTag( $title, $rev, $fuzzy );
 353+ MessageGroupStats::clear( $handle );
364354
365 - foreach ( $groups as $g ) {
366 - $cache->clear( $g, $code );
 355+ if ( $fuzzy === false ) {
 356+ // Fuzzy versions are not real translations
 357+ self::updateTransverTag( $handle, $rev );
367358 }
368359
 360+ return true;
 361+ }
 362+
 363+ protected static function checkNeedsFuzzy( MessageHandle $handle, $text ) {
369364 // Check for explicit tag.
370365 $fuzzy = self::hasFuzzyString( $text );
371366
372 - // Check for problems, but only if not fuzzy already.
 367+ // Docs are exempt for checks
373368 global $wgTranslateDocumentationLanguageCode;
374 - if ( $code !== $wgTranslateDocumentationLanguageCode ) {
375 - $checker = $group->getChecker();
 369+ if ( $code === $wgTranslateDocumentationLanguageCode ) {
 370+ return $fuzzy;
 371+ }
 372+
 373+ // Not all groups have checkers
 374+ $group = $handle->getGroup();
 375+ $checker = $group->getChecker();
 376+ if ( !$checker ) {
 377+ return $fuzzy;
 378+ }
376379
377 - if ( $checker ) {
378 - $en = $group->getMessage( $key, $group->getSourceLanguage() );
379 - $message = new FatMessage( $key, $en );
380 - /**
381 - * Take the contents from edit field as a translation.
382 - */
383 - $message->setTranslation( $text );
 380+ $en = $group->getMessage( $key, $group->getSourceLanguage() );
 381+ $message = new FatMessage( $key, $en );
 382+ // Take the contents from edit field as a translation.
 383+ $message->setTranslation( $text );
384384
385 - $checks = $checker->checkMessage( $message, $code );
386 - if ( count( $checks ) ) {
387 - $fuzzy = true;
388 - }
389 - }
 385+ $checks = $checker->checkMessage( $message, $code );
 386+ if ( count( $checks ) ) {
 387+ $fuzzy = true;
390388 }
 389+ return $fuzzy;
 390+ }
391391
392 - // Update it.
393 - if ( $revision === null ) {
394 - $rev = $article->getTitle()->getLatestRevId();
395 - } else {
396 - $rev = $revision->getID();
397 - }
398 -
399 - // begin fuzzy tag.
 392+ protected static function updateFuzzyTag( Title $title, $revision, $fuzzy ) {
400393 $dbw = wfGetDB( DB_MASTER );
401394
402395 $conds = array(
403 - 'rt_page' => $article->getTitle()->getArticleId(),
 396+ 'rt_page' => $title->getArticleId(),
404397 'rt_type' => RevTag::getType( 'fuzzy' ),
405 - 'rt_revision' => $rev
 398+ 'rt_revision' => $revision
406399 );
407 - // Remove any existing fuzzy tags for this revision
408 - $dbw->delete( 'revtag', $conds, __METHOD__ );
409 -
410 - // Add the fuzzy tag if needed.
 400+
 401+ // Replace the existing fuzzy tag, if any
411402 if ( $fuzzy !== false ) {
412 - $dbw->insert( 'revtag', $conds, __METHOD__ );
 403+ $index = array_keys( $conds );
 404+ $dbw->replace( 'revtag', array( $index ), $conds, __METHOD__ );
 405+ } else {
 406+ $dbw->delete( 'revtag', $conds, __METHOD__ );
413407 }
 408+ }
414409
415 - // Diffs for changed messages.
416 - if ( $fuzzy !== false ) {
417 - return true;
418 - }
419410
 411+ /**
 412+ * Adds tag which identifies the revision of source message at that time.
 413+ * This is used to show diff against current version of source message
 414+ * when updating a translation.
 415+ */
 416+ protected static function updateTransverTag( MessageHandle $handle, $revision ) {
 417+ $group = $handle->getGroup();
420418 if ( $group instanceof WikiPageMessageGroup ) {
421 - return true;
 419+ // WikiPageMessageGroup has different method
 420+ return;
422421 }
423422
 423+ $title = $handle->getTitle();
 424+ $fullKey = $handle->getKey() . '/' . $group->getSourceLanguage();
 425+ $definitionTitle = Title::makeTitleSafe( $title->getNamespace(), $fullkey );
 426+ if ( !$definitionTitle || !$definitionTitle->exists() ) {
 427+ return;
 428+ }
424429
 430+ $definitionRevision = $definitionTitle->getLatestRevID();
425431
426 - $definitionTitle = Title::makeTitleSafe( $title->getNamespace(), "$key/" . $group->getSourceLanguage() );
427 - if ( $definitionTitle && $definitionTitle->exists() ) {
428 - $definitionRevision = $definitionTitle->getLatestRevID();
 432+ $dbw = wfGetDB( DB_MASTER );
429433
430 - $conds = array(
431 - 'rt_page' => $title->getArticleId(),
432 - 'rt_type' => RevTag::getType( 'tp:transver' ),
433 - 'rt_revision' => $rev,
434 - 'rt_value' => $definitionRevision,
435 - );
436 - $index = array( 'rt_type', 'rt_page', 'rt_revision' );
437 - $dbw->replace( 'revtag', array( $index ), $conds, __METHOD__ );
438 - }
439 -
440 - return true;
 434+ $conds = array(
 435+ 'rt_page' => $title->getArticleId(),
 436+ 'rt_type' => RevTag::getType( 'tp:transver' ),
 437+ 'rt_revision' => $revision,
 438+ 'rt_value' => $definitionRevision,
 439+ );
 440+ $index = array( 'rt_type', 'rt_page', 'rt_revision' );
 441+ $dbw->replace( 'revtag', array( $index ), $conds, __METHOD__ );
441442 }
442443
443444 public static function preserveWhitespaces( $text ) {
Index: trunk/extensions/Translate/Translate.php
@@ -92,6 +92,10 @@
9393 $wgHooks['SkinTemplateTabs'][] = 'TranslateEditAddons::tabs';
9494 $wgHooks['LanguageGetTranslatedLanguageNames'][] = 'TranslateEditAddons::translateMessageDocumentationLanguage';
9595 $wgHooks['ArticlePrepareTextForEdit'][] = 'TranslateEditAddons::disablePreSaveTransform';
 96+// Hook for database schema.
 97+$wgHooks['LoadExtensionSchemaUpdates'][] = 'PageTranslationHooks::schemaUpdates';
 98+// Fuzzy tags for speed.
 99+$wgHooks['ArticleSaveComplete'][] = 'TranslateEditAddons::onSave';
96100
97101 // Custom preferences
98102 $wgDefaultUserOptions['translate'] = 0;
Index: trunk/extensions/Translate/TranslateHooks.php
@@ -39,12 +39,6 @@
4040 global $wgReservedUsernames, $wgTranslateFuzzyBotName;
4141 $wgReservedUsernames[] = $wgTranslateFuzzyBotName;
4242
43 - // Hook for database schema.
44 - $wgHooks['LoadExtensionSchemaUpdates'][] = 'PageTranslationHooks::schemaUpdates';
45 -
46 - // Fuzzy tags for speed.
47 - $wgHooks['ArticleSaveComplete'][] = 'TranslateEditAddons::onSave';
48 -
4943 // Page translation setup check and init if enabled.
5044 global $wgEnablePageTranslation;
5145 if ( $wgEnablePageTranslation ) {
Index: trunk/extensions/Translate/TranslateTasks.php
@@ -222,15 +222,7 @@
223223 $this->collection->setInfile( $this->group->load( $code ) );
224224 $this->collection->filter( 'ignored' );
225225 $this->collection->filter( 'optional' );
226 -
227 - // Update the cache while we are at it.
228 - $total = count( $this->collection );
229226 $this->collection->filter( 'translated' );
230 - $translated = $total - count( $this->collection );
231 - $fuzzy = count( $this->collection->getTags( 'fuzzy' ) );
232 -
233 - $cache = new ArrayMemoryCache( 'groupstats' );
234 - $cache->set( $this->group->getID(), $code, array( $fuzzy, $translated, $total ) );
235227 }
236228 }
237229
Index: trunk/extensions/Translate/_autoload.php
@@ -94,8 +94,6 @@
9595 $wgAutoloadClasses['StringMatcher'] = $dir . 'utils/StringMatcher.php';
9696 $wgAutoloadClasses['FCFontFinder'] = $dir . 'utils/Font.php';
9797
98 -$wgAutoloadClasses['ArrayMemoryCache'] = $dir . 'utils/MemoryCache.php';
99 -
10098 $wgAutoloadClasses['TranslatePreferences'] = $dir . 'utils/UserToggles.php';
10199 $wgAutoloadClasses['TranslateToolbox'] = $dir . 'utils/ToolBox.php';
102100
Index: trunk/extensions/Translate/utils/MemoryCache.php
@@ -1,116 +0,0 @@
2 -<?php
3 -/**
4 - * Code for caching translation completion percentages.
5 - *
6 - * @file
7 - * @author Niklas Laxström
8 - * @copyright Copyright © 2009-2010, Niklas Laxström
9 - * @license http://www.gnu.org/copyleft/gpl.html GNU General Public License 2.0 or later
10 - */
11 -
12 -/**
13 - * Class for caching translation completion percentages.
14 - * @todo Figure out a better name.
15 - * @todo Tries to be generic, but is not.
16 - * @ingroup Stats
17 - */
18 -class ArrayMemoryCache {
19 - /// Key for the data stored
20 - protected $key;
21 - /// Memory cache wrapper
22 - protected $memc;
23 - /// Object cache of the data
24 - protected $cache;
25 -
26 - /**
27 - * Constructor
28 - * @param $table \string Name of the cache.
29 - */
30 - public function __construct( $table ) {
31 - $this->key = wfMemcKey( $table );
32 -
33 - $cacher = wfGetCache( CACHE_MEMCACHED );
34 - if ( $cacher instanceof FakeMemCachedClient ) {
35 - $cacher = wfGetCache( CACHE_DB );
36 - }
37 -
38 - $this->memc = $cacher;
39 - }
40 -
41 - /// Destructor
42 - public function __destruct() {
43 - $this->save();
44 - }
45 -
46 - /**
47 - * @copydoc ArrayMemoryCache::__construct()
48 - * Static factory function for the constructor.
49 - */
50 - public static function factory( $table ) {
51 - // __CLASS__ doesn't work, but this is PHP
52 - return new ArrayMemoryCache( $table );
53 - }
54 -
55 - public function get( $group, $code ) {
56 - $this->load();
57 -
58 - if ( !isset( $this->cache[$group][$code] ) ) {
59 - return false;
60 - }
61 -
62 - return explode( ',', $this->cache[$group][$code] );
63 - }
64 -
65 - public function set( $group, $code, $value ) {
66 - $this->load();
67 -
68 - if ( !isset( $this->cache[$group] ) ) {
69 - $this->cache[$group] = array();
70 - }
71 -
72 - $this->cache[$group][$code] = implode( ',', $value );
73 - }
74 -
75 - public function clear( $group, $code ) {
76 - $this->load();
77 -
78 - if ( isset( $this->cache[$group][$code] ) ) {
79 - unset( $this->cache[$group][$code] );
80 - }
81 -
82 - if ( isset( $this->cache[$group] ) && !count( $this->cache[$group] ) ) {
83 - unset( $this->cache[$group] );
84 - }
85 - }
86 -
87 - public function clearGroup( $group ) {
88 - $this->load();
89 - unset( $this->cache[$group] );
90 - }
91 -
92 - public function clearAll() {
93 - $this->load();
94 - $this->cache = array();
95 - }
96 -
97 - public function commit() {
98 - $this->save();
99 - }
100 -
101 -
102 - protected function load() {
103 - if ( $this->cache === null ) {
104 - $this->cache = $this->memc->get( $this->key );
105 -
106 - if ( !is_array( $this->cache ) ) {
107 - $this->cache = array();
108 - }
109 - }
110 - }
111 -
112 - protected function save() {
113 - if ( $this->cache !== null ) {
114 - $this->memc->set( $this->key, $this->cache );
115 - }
116 - }
117 -}
Index: trunk/extensions/Translate/utils/MessageHandle.php
@@ -99,4 +99,37 @@
100100 return $this->title;
101101 }
102102
 103+ /**
 104+ * Check if a string contains the fuzzy string.
 105+ *
 106+ * @param $text \string Arbitrary text
 107+ * @return \bool If string contains fuzzy string.
 108+ */
 109+ public static function hasFuzzyString( $text ) {
 110+ return strpos( $text, TRANSLATE_FUZZY ) !== false;
 111+ }
 112+
 113+ /**
 114+ * Check if a title is marked as fuzzy.
 115+ * @param $title Title
 116+ * @return \bool If title is marked fuzzy.
 117+ */
 118+ public function isFuzzy() {
 119+ $dbr = wfGetDB( DB_SLAVE );
 120+
 121+ $tables = array( 'page', 'revtag' );
 122+ $field = 'rt_type';
 123+ $conds = array(
 124+ 'page_namespace' => $this->title->getNamespace(),
 125+ 'page_title' => $this->title->getDBkey(),
 126+ 'rt_type' => RevTag::getType( 'fuzzy' ),
 127+ 'page_id=rt_page',
 128+ 'page_latest=rt_revision'
 129+ );
 130+
 131+ $res = $dbr->selectField( $tables, $field, $conds, __METHOD__ );
 132+
 133+ return $res !== false;
 134+ }
 135+
103136 }
Index: trunk/extensions/Translate/utils/MessageIndexRebuilder.php
@@ -59,10 +59,7 @@
6060 foreach ( (array) $groups as $group ) $changes[$group] = true;
6161 }
6262
63 - $cache = new ArrayMemoryCache( 'groupstats' );
64 - foreach ( $changes as $key => $_ ) {
65 - $cache->clearGroup( $key );
66 - }
 63+ MessageGroupStats::clearGroup( array_keys( $changes ) );
6764 }
6865
6966 protected static function checkAndAdd( &$hugearray, $g, $ignore = false ) {
Index: trunk/extensions/Translate/utils/MessageGroupStats.php
@@ -34,6 +34,26 @@
3535 }
3636
3737 /**
 38+ * Returns stats for given group in given language.
 39+ * @param $id string Group id
 40+ * @param $code string Language code
 41+ * @return Array
 42+ */
 43+ public static function forItem( $id, $code ) {
 44+ $stats = array();
 45+ $res = self::selectRowsIdLang( $id, $code );
 46+ $stats = self::extractResults( $res, $stats );
 47+
 48+ $group = MessageGroups::getGroup( $id );
 49+
 50+ if ( !isset( $stats[$id][$code] ) ) {
 51+ $stats[$id][$code] = self::forItemInternal( $stats, $group, $code );
 52+ }
 53+
 54+ return $stats[$id][$code];
 55+ }
 56+
 57+ /**
3858 * Returns stats for all groups in given language.
3959 * @param $code string Language code
4060 * @return Array
@@ -76,6 +96,28 @@
7797 return $stats;
7898 }
7999
 100+ public static function clear( MessageHandle $handle ) {
 101+ $dbw = wfGetDB( DB_MASTER );
 102+ $conds = array(
 103+ 'tgs_group' => $handle->getGroupIds(),
 104+ 'tgs_lang' => $handle->getCode(),
 105+ );
 106+
 107+ $dbw->delete( self::TABLE, $conds, __METHOD__ );
 108+ }
 109+
 110+ public static function clearGroup( $id ) {
 111+ $dbw = wfGetDB( DB_MASTER );
 112+ $conds = array( 'tgs_group' => $id );
 113+ $dbw->delete( self::TABLE, $conds, __METHOD__ );
 114+ }
 115+
 116+ public static function clearLanguage( $code ) {
 117+ $dbw = wfGetDB( DB_MASTER );
 118+ $conds = array( 'tgs_lang' => $code );
 119+ $dbw->delete( self::TABLE, $conds, __METHOD__ );
 120+ }
 121+
80122 /**
81123 * Purges all cached stats.
82124 */
@@ -91,6 +133,24 @@
92134 return $stats;
93135 }
94136
 137+ public static function update( MessageHandle $handle, $changes = array() ) {
 138+ $dbw = wfGetDB( DB_MASTER );
 139+ $conds = array(
 140+ 'tgs_group' => $handle->getGroupIds(),
 141+ 'tgs_lang' => $handle->getCode(),
 142+ );
 143+
 144+ $values = array();
 145+ foreach ( array( 'total', 'translated', 'fuzzy' ) as $type ) {
 146+ if ( !isset( $changes[$type] ) ) {
 147+ $values[] = "tgs_$type=tgs_$type" .
 148+ self::stringifyNumber( $changes[$type] );
 149+ }
 150+ }
 151+
 152+ $dbw->update( self::TABLE, $values, $conds, __METHOD__ );
 153+ }
 154+
95155 /**
96156 * Returns an array of needed database fields.
97157 */
@@ -162,7 +222,7 @@
163223 if ( !isset( $stats[$sid][$code] ) ) {
164224 $stats[$sid][$code] = self::forItemInternal( $stats, $sgroup, $code );
165225 }
166 - self::multiAdd( $aggregates, $stats[$sid][$code] );
 226+ $aggregates = self::multiAdd( $aggregates, $stats[$sid][$code] );
167227 }
168228 $stats[$id] = $aggregates;
169229 } else {
@@ -235,34 +295,6 @@
236296 return array( $total, $translated, $fuzzy );
237297 }
238298
239 - public static function update( MessageHandle $handle, $changes = array() ) {
240 - $dbw = wfGetDB( DB_MASTER );
241 - $conds = array(
242 - 'tgs_group' => $handle->getGroupIds(),
243 - 'tgs_lang' => $handle->getCode(),
244 - );
245 -
246 - $values = array();
247 - foreach ( array( 'total', 'translated', 'fuzzy' ) as $type ) {
248 - if ( !isset( $changes[$type] ) ) {
249 - $values[] = "tgs_$type=tgs_$type" .
250 - self::stringifyNumber( $changes[$type] );
251 - }
252 - }
253 -
254 - $dbw->update( self::TABLE, $values, $conds, __METHOD__ );
255 - }
256 -
257 - public static function clear( MessageHandle $handle ) {
258 - $dbw = wfGetDB( DB_MASTER );
259 - $conds = array(
260 - 'tgs_group' => $handle->getGroupIds(),
261 - 'tgs_lang' => $handle->getCode(),
262 - );
263 -
264 - $dbw->delete( self::TABLE, $conds, __METHOD__ );
265 - }
266 -
267299 /**
268300 * Converts input to "+2" "-4" type of string.
269301 * @param $number int
Index: trunk/extensions/Translate/Translate.i18n.php
@@ -220,6 +220,7 @@
221221 'languagestats-summary' => 'This page shows translation statistics for all message groups for a language.',
222222 'languagestats-stats-for' => 'Translation statistics for $1 ($2).',
223223 'languagestats-recenttranslations' => 'recent translations',
 224+ 'translate-langstats-incomplete' => 'Some of the statistics on this page are incomplete. Please reload to get more statistics.',
224225 'translate-langstats-expand' => 'expand',
225226 'translate-langstats-collapse' => 'collapse',
226227 'translate-langstats-expandall' => 'expand all',
Index: trunk/extensions/Translate/specials/SpecialLanguageStats.php
@@ -23,6 +23,8 @@
2424 class SpecialLanguageStats extends IncludableSpecialPage {
2525 protected $purge = false;
2626
 27+ protected $incomplete = false;
 28+
2729 function __construct() {
2830 parent::__construct( 'LanguageStats' );
2931 }
@@ -52,10 +54,8 @@
5355 }
5456
5557 if ( !$code ) {
56 -
5758 if ( $wgUser->isLoggedIn() ) {
5859 global $wgLang;
59 -
6060 $code = $wgLang->getCode();
6161 }
6262 }
@@ -64,6 +64,9 @@
6565
6666 if ( array_key_exists( $code, Language::getLanguageNames() ) ) {
6767 $out .= $this->getGroupStats( $code, $suppressComplete );
 68+ if ( $this->incomplete ) {
 69+ $wgOut->wrapWikiMsg( "<div class='error'>$1</div>", 'translate-langstats-incomplete' );
 70+ }
6871 } elseif ( $code ) {
6972 $wgOut->wrapWikiMsg( "<div class='error'>$1</div>", 'translate-page-no-such-language' );
7073 }
@@ -213,15 +216,18 @@
214217
215218 $out = '';
216219
217 - $cache = new ArrayMemoryCache( 'groupstats' );
 220+ if ( $this->purge ) {
 221+ MessageGroupStats::clearLanguage( $code );
 222+ }
 223+
 224+ MessageGroupStats::setTimeLimit( 8 );
 225+ $cache = MessageGroupStats::forLanguage( $code );
218226 $structure = MessageGroups::getGroupStructure();
219227
220228 foreach ( $structure as $item ) {
221229 $out .= $this->makeGroupGroup( $item, $cache );
222230 }
223231
224 - $cache->commit();
225 -
226232 if ( $out ) {
227233 $out = $this->createHeader( $code ) . "\n" . $out;
228234 $out .= $this->makeTotalRow( $this->totals );
@@ -241,7 +247,7 @@
242248 }
243249
244250 protected function makeTotalRow( $numbers ) {
245 - list( $fuzzy, $translated, $total ) = $numbers;
 251+ list( $total, $translated, $fuzzy ) = $numbers;
246252 $out = "\t" . Html::openElement( 'tr' );
247253 $out .= "\n\t\t" . Html::rawElement( 'td', array(), wfMsg( 'translate-languagestats-overall' ) );
248254 $out .= $this->makeNumberColumns( $fuzzy, $translated, $total );
@@ -249,6 +255,14 @@
250256 }
251257
252258 protected function makeNumberColumns( $fuzzy, $translated, $total ) {
 259+ if ( $total === null ) {
 260+ $na = "\n\t\t" . Html::element( 'td', array( 'data-sort-value' => -1 ), '...' );
 261+ $nap = "\n\t\t" . $this->element( '...', 'AFAFAF', -1 );
 262+ $out = $na . $na . $nap . $nap;
 263+ $out .= "\n\t" . Xml::closeElement( 'tr' ) . "\n";
 264+ return $out;
 265+ }
 266+
253267 global $wgLang;
254268 $out = "\n\t\t" . Html::element( 'td',
255269 array( 'data-sort-value' => $total ),
@@ -299,39 +313,36 @@
300314 return '';
301315 }
302316
303 - $fuzzy = $translated = $total = 0;
304 -
305 - if ( $g instanceof AggregateMessageGroup ) {
306 - foreach ( $g->getGroups() as $subgroup ) {
307 - $result = $this->loadPercentages( $cache, $subgroup, $code );
308 - $fuzzy += $result[0];
309 - $translated += $result[1];
310 - $total += $result[2];
311 - }
312 - } else {
313 - list( $fuzzy, $translated, $total ) = $this->loadPercentages( $cache, $g, $code );
314 - $this->totals[2] += $total;
315 - $this->totals[1] += $translated;
316 - $this->totals[0] += $fuzzy;
 317+ $stats = $cache[$groupId];
 318+ list( $total, $translated, $fuzzy ) = $stats;
 319+ if ( !$group instanceof AggregateMessageGroup ) {
 320+ $this->totals = MessageGroupStats::multiAdd( $this->totals, $stats );
317321 }
 322+ if ( $total !== null ) {
318323
319 - if ( $total == 0 ) {
320 - $zero = serialize( $total );
321 - error_log( __METHOD__ . ": Group $groupName has zero message ($code): $zero" );
322 - return '';
323 - }
324324
325 - // Skip if $suppressComplete and complete
326 - if ( $suppressComplete && !$fuzzy && $translated === $total ) {
327 - return '';
328 - }
 325+ if ( $total == 0 ) {
 326+ $zero = serialize( $total );
 327+ error_log( __METHOD__ . ": Group $groupName has zero message ($code): $zero" );
 328+ return '';
 329+ }
329330
330 - if ( $translated === $total ) {
331 - $extra = array( 'task' => 'reviewall' );
 331+ // Skip if $suppressComplete and complete
 332+ if ( $suppressComplete && !$fuzzy && $translated === $total ) {
 333+ return '';
 334+ }
 335+
 336+ if ( $translated === $total ) {
 337+ $extra = array( 'task' => 'reviewall' );
 338+ } else {
 339+ $extra = array();
 340+ }
332341 } else {
333342 $extra = array();
 343+ $this->incomplete = true;
334344 }
335345
 346+
336347 $rowParams = array();
337348 $rowParams['data-groupid'] = $groupId;
338349 if ( is_string( $parent ) ) {
@@ -343,65 +354,10 @@
344355 $out .= "\t" . Html::openElement( 'tr', $rowParams );
345356 $out .= "\n\t\t" . Html::rawElement( 'td', array(), $this->makeGroupLink( $g, $code, $extra ) );
346357 $out .= $this->makeNumberColumns( $fuzzy, $translated, $total );
 358+
347359 return $out;
348360 }
349361
350 - protected function loadPercentages( $cache, $group, $code ) {
351 - wfProfileIn( __METHOD__ );
352 - $id = $group->getId();
353 -
354 -
355 - $result = $cache->get( $id, $code );
356 - if ( !$this->purge && is_array( $result ) ) {
357 - wfProfileOut( __METHOD__ );
358 - return $result;
359 - }
360 -
361 - // Initialise messages.
362 - $collection = $group->initCollection( $code );
363 -
364 - $ffs = $group->getFFS();
365 - if ( $ffs instanceof GettextFFS && $code === 'qqq' ) {
366 - $template = $ffs->read( 'en' );
367 - $infile = array();
368 - foreach ( $template['TEMPLATE'] as $key => $data ) {
369 - if ( isset( $data['comments']['.'] ) ) {
370 - $infile[$key] = '1';
371 - }
372 - }
373 - $collection->setInFile( $infile );
374 - }
375 -
376 -
377 - // Takes too much memory and only hides inconsistent import state
378 - # $collection->setInFile( $group->load( $code ) );
379 - $collection->filter( 'ignored' );
380 - $collection->filter( 'optional' );
381 - // Store the count of real messages for later calculation.
382 - $total = count( $collection );
383 -
384 - // Count fuzzy first.
385 - $collection->filter( 'fuzzy' );
386 - $fuzzy = $total - count( $collection );
387 -
388 - // Count the completed translations.
389 - $collection->filter( 'hastranslation', false );
390 - $translated = count( $collection );
391 -
392 - $result = array( $fuzzy, $translated, $total );
393 -
394 - $cache->set( $id, $code, $result );
395 -
396 - static $i = 0;
397 - if ( $i++ % 50 === 0 ) {
398 - $cache->commit();
399 - }
400 -
401 - wfProfileOut( __METHOD__ );
402 -
403 - return $result;
404 - }
405 -
406362 protected function formatPercentage( $num ) {
407363 global $wgLang;
408364 $fmt = $wgLang->formatNum( number_format( round( 100 * $num, 2 ), 2 ) );
@@ -439,15 +395,27 @@
440396
441397 protected function getGroupDescription( $group ) {
442398 global $wgLang;
 399+ $code = $wgLang->getCode();
 400+
 401+ $cache = wfGetCache( CACHE_ANYTHING );
 402+ $key = wfMemckey( "translate-groupdesc-$code-" . $group->getId() );
 403+ $desc = $cache->get( $key );
 404+ if ( is_string( $desc ) ) {
 405+ return $desc;
 406+ }
443407
 408+ global $wgLang;
 409+
444410 $realFunction = array( 'MessageCache', 'singleton' );
445411 if ( is_callable( $realFunction ) ) {
446 - $cache = MessageCache::singleton();
 412+ $mc = MessageCache::singleton();
447413 } else {
448414 global $wgMessageCache;
449 - $cache = $wgMessageCache;
 415+ $mc = $wgMessageCache;
450416 }
451 - return $cache->transform( $group->getDescription(), true, $wgLang, $this->getTitle() );
 417+ $desc = $mc->transform( $group->getDescription(), true, $wgLang, $this->getTitle() );
 418+ $cache->set( $key, $desc );
 419+ return $desc;
452420 }
453421
454422 protected function isBlacklisted( $groupId, $code ) {

Status & tagging log