Index: trunk/extensions/Translate/SpecialTranslate.php |
— | — | @@ -386,65 +386,9 @@ |
387 | 387 | return $description; |
388 | 388 | } |
389 | 389 | |
390 | | - /** |
391 | | - * Returns group strucuted into sub groups. First group in each subgroup is |
392 | | - * considered as the main group. |
393 | | - */ |
394 | | - public function getGroupStructure() { |
395 | | - global $wgTranslateGroupStructure; |
396 | | - |
397 | | - $groups = MessageGroups::getAllGroups(); |
398 | | - |
399 | | - $structure = array(); |
400 | | - foreach ( $groups as $id => $o ) { |
401 | | - if ( !MessageGroups::getGroup( $id )->exists() ) { |
402 | | - continue; |
403 | | - } |
404 | | - |
405 | | - foreach ( $wgTranslateGroupStructure as $pattern => $hypergroup ) { |
406 | | - if ( preg_match( $pattern, $id ) ) { |
407 | | - // Emulate deepArraySet, because AFAIK php does not have one |
408 | | - self::deepArraySet( $structure, $hypergroup, $id, $o ); |
409 | | - // We need to continue the outer loop, because we have finished this item. |
410 | | - continue 2; |
411 | | - } |
412 | | - } |
413 | | - |
414 | | - // Does not belong to any subgroup, just shove it into main level. |
415 | | - $structure[$id] = $o; |
416 | | - } |
417 | | - |
418 | | - // Sort top-level groups according to labels, not ids |
419 | | - foreach ( $structure as $id => $data ) { |
420 | | - // Either it is a group itself, or the first group of the array |
421 | | - $nid = is_array( $data ) ? key( $data ) : $id; |
422 | | - $labels[$id] = $groups[$nid]->getLabel(); |
423 | | - } |
424 | | - natcasesort( $labels ); |
425 | | - |
426 | | - foreach ( array_keys( $labels ) as $id ) { |
427 | | - $sorted[$id] = $structure[$id]; |
428 | | - } |
429 | | - |
430 | | - return $sorted; |
431 | | - } |
432 | | - |
433 | | - /** |
434 | | - * Function do do $array[level1][level2]...[levelN][$key] = $value, if we have |
435 | | - * the indexes in an array. |
436 | | - */ |
437 | | - public static function deepArraySet( &$array, array $indexes, $key, $value ) { |
438 | | - foreach ( $indexes as $index ) { |
439 | | - if ( !isset( $array[$index] ) ) $array[$index] = array(); |
440 | | - $array = &$array[$index]; |
441 | | - } |
442 | | - |
443 | | - $array[$key] = $value; |
444 | | - } |
445 | | - |
446 | 390 | public function groupInformation() { |
447 | 391 | $out = ''; |
448 | | - $structure = $this->getGroupStructure(); |
| 392 | + $structure = MessageGroups::getGroupStructure(); |
449 | 393 | |
450 | 394 | foreach ( $structure as $blocks ) { |
451 | 395 | $out .= $this->formatGroupInformation( $blocks ); |
Index: trunk/extensions/Translate/SpecialLanguageStats.php |
— | — | @@ -58,7 +58,7 @@ |
59 | 59 | |
60 | 60 | if ( array_key_exists( $code, Language::getLanguageNames() ) ) { |
61 | 61 | $out .= $this->getGroupStats( $code, $suppressComplete ); |
62 | | - } else if ( $code ) { |
| 62 | + } elseif ( $code ) { |
63 | 63 | $wgOut->wrapWikiMsg( "<div class='error'>$1</div>", 'translate-page-no-such-language' ); |
64 | 64 | } |
65 | 65 | |
— | — | @@ -126,8 +126,8 @@ |
127 | 127 | if ( $sort ) $attributes['data-sort-value'] = $sort; |
128 | 128 | if ( $bgcolor ) $attributes['style'] = "background-color: #" . $bgcolor; |
129 | 129 | |
130 | | - $element = Xml::element( 'td', $attributes, $in ); |
131 | | - return "\t\t" . $element . "\n"; |
| 130 | + $element = Html::element( 'td', $attributes, $in ); |
| 131 | + return $element; |
132 | 132 | } |
133 | 133 | |
134 | 134 | function getBackgroundColour( $subset, $total, $fuzzy = false ) { |
— | — | @@ -171,20 +171,20 @@ |
172 | 172 | $out = wfMsgExt( 'languagestats-stats-for', array( 'parse', 'replaceafter' ), $languageName, $rcInLangLink ); |
173 | 173 | |
174 | 174 | // Create table header |
175 | | - $out .= Xml::openElement( |
| 175 | + $out .= Html::openElement( |
176 | 176 | 'table', |
177 | 177 | array( |
178 | 178 | 'class' => "sortable wikitable mw-sp-translate-table" |
179 | 179 | ) |
180 | 180 | ); |
181 | 181 | |
182 | | - $out .= Xml::openElement( 'tr' ); |
183 | | - $out .= Xml::element( 'th', array( 'title' => self::newlineToWordSeparator( wfMsg( 'translate-page-group-tooltip' ) ) ), wfMsg( 'translate-page-group' ) ); |
184 | | - $out .= Xml::element( 'th', array( 'title' => self::newlineToWordSeparator( wfMsg( 'translate-total-tooltip' ) ) ), wfMsg( 'translate-total' ) ); |
185 | | - $out .= Xml::element( 'th', array( 'title' => self::newlineToWordSeparator( wfMsg( 'translate-untranslated-tooltip' ) ) ), wfMsg( 'translate-untranslated' ) ); |
186 | | - $out .= Xml::element( 'th', array( 'title' => self::newlineToWordSeparator( wfMsg( 'translate-percentage-complete-tooltip' ) ) ), wfMsg( 'translate-percentage-complete' ) ); |
187 | | - $out .= Xml::element( 'th', array( 'title' => self::newlineToWordSeparator( wfMsg( 'translate-percentage-fuzzy-tooltip' ) ) ), wfMsg( 'translate-percentage-fuzzy' ) ); |
188 | | - $out .= Xml::closeElement( 'tr' ); |
| 182 | + $out .= "\n\t" . Html::openElement( 'tr' ); |
| 183 | + $out .= "\n\t\t" . Html::element( 'th', array( 'title' => self::newlineToWordSeparator( wfMsg( 'translate-page-group-tooltip' ) ) ), wfMsg( 'translate-page-group' ) ); |
| 184 | + $out .= "\n\t\t" . Html::element( 'th', array( 'title' => self::newlineToWordSeparator( wfMsg( 'translate-total-tooltip' ) ) ), wfMsg( 'translate-total' ) ); |
| 185 | + $out .= "\n\t\t" . Html::element( 'th', array( 'title' => self::newlineToWordSeparator( wfMsg( 'translate-untranslated-tooltip' ) ) ), wfMsg( 'translate-untranslated' ) ); |
| 186 | + $out .= "\n\t\t" . Html::element( 'th', array( 'title' => self::newlineToWordSeparator( wfMsg( 'translate-percentage-complete-tooltip' ) ) ), wfMsg( 'translate-percentage-complete' ) ); |
| 187 | + $out .= "\n\t\t" . Html::element( 'th', array( 'title' => self::newlineToWordSeparator( wfMsg( 'translate-percentage-fuzzy-tooltip' ) ) ), wfMsg( 'translate-percentage-fuzzy' ) ); |
| 188 | + $out .= "\n\t" . Xml::closeElement( 'tr' ); |
189 | 189 | |
190 | 190 | return $out; |
191 | 191 | } |
— | — | @@ -198,81 +198,118 @@ |
199 | 199 | * @return \string HTML |
200 | 200 | */ |
201 | 201 | function getGroupStats( $code, $suppressComplete = false ) { |
202 | | - global $wgLang; |
| 202 | + $this->code = $code; |
| 203 | + $this->suppressComplete = $suppressComplete; |
203 | 204 | |
204 | 205 | $out = ''; |
205 | 206 | |
206 | 207 | $cache = new ArrayMemoryCache( 'groupstats' ); |
207 | | - $groups = MessageGroups::singleton()->getGroups(); |
| 208 | + $structure = MessageGroups::getGroupStructure(); |
208 | 209 | |
209 | | - foreach ( $groups as $groupName => $g ) { |
210 | | - // Do not report if this group is blacklisted. |
211 | | - $groupId = $g->getId(); |
212 | | - $blacklisted = $this->isBlacklisted( $groupId, $code ); |
| 210 | + foreach ( $structure as $item ) { |
| 211 | + $out .= $this->makeGroupGroup( $item, $cache ); |
| 212 | + } |
213 | 213 | |
214 | | - if ( $blacklisted !== null ) { |
215 | | - continue; |
216 | | - } |
| 214 | + if ( $out ) { |
| 215 | + $out = $this->createHeader( $code ) ."\n" . $out; |
| 216 | + $out .= Xml::closeElement( 'table' ); |
| 217 | + } else { |
| 218 | + $out = wfMsgExt( 'translate-nothing-to-do', 'parse' ); |
| 219 | + } |
217 | 220 | |
218 | | - $fuzzy = $translated = $total = 0; |
| 221 | + return $out; |
| 222 | + } |
219 | 223 | |
220 | | - if ( $g instanceof AggregateMessageGroup ) { |
221 | | - foreach ( $g->getGroups() as $subgroup ) { |
222 | | - $result = $this->loadPercentages( $cache, $subgroup, $code ); |
223 | | - $fuzzy += $result[0]; |
224 | | - $translated += $result[1]; |
225 | | - $total += $result[2]; |
226 | | - } |
227 | | - } else { |
228 | | - list( $fuzzy, $translated, $total ) = $this->loadPercentages( $cache, $g, $code ); |
229 | | - } |
| 224 | + protected function makeGroupGroup( $item, $cache, $parent = '' ) { |
| 225 | + $out = ''; |
| 226 | + if ( !is_array( $item ) ) { |
| 227 | + return $this->makeGroupRow( $item, $cache, $parent === '' ? false : $parent ); |
| 228 | + } |
230 | 229 | |
231 | | - if ( $total == 0 ) { |
232 | | - $zero = serialize( $total ); |
233 | | - error_log( __METHOD__ . ": Group $groupName has zero message ($code): $zero" ); |
234 | | - continue; |
235 | | - } |
| 230 | + $out = ''; |
| 231 | + $top = array_shift( $item ); |
| 232 | + $out .= $this->makeGroupRow( $top, $cache, $parent === '' ? true : $parent ); |
| 233 | + foreach ( $item as $subgroup ) { |
| 234 | + $parents = trim( $parent . ' ' .$top->getId() ); |
| 235 | + $out .= $this->makeGroupGroup( $subgroup, $cache, $parents ); |
| 236 | + } |
| 237 | + return $out; |
| 238 | + } |
236 | 239 | |
237 | | - // Skip if $suppressComplete and complete |
238 | | - if ( $suppressComplete && !$fuzzy && $translated === $total ) { |
239 | | - continue; |
240 | | - } |
| 240 | + protected function makeGroupRow( $group, $cache, $parent = false ) { |
| 241 | + global $wgLang; |
241 | 242 | |
242 | | - if ( $translated === $total ) { |
243 | | - $extra = array( 'task' => 'reviewall' ); |
244 | | - } else { |
245 | | - $extra = array(); |
246 | | - } |
| 243 | + $out = ''; |
| 244 | + $code = $this->code; |
| 245 | + $suppressComplete = $this->suppressComplete; |
| 246 | + $g = $group; |
| 247 | + $groupName = $g->getId(); |
| 248 | + // Do not report if this group is blacklisted. |
| 249 | + $groupId = $g->getId(); |
| 250 | + $blacklisted = $this->isBlacklisted( $groupId, $code ); |
247 | 251 | |
248 | | - $out .= Xml::openElement( 'tr' ); |
249 | | - $out .= '<td>' . $this->makeGroupLink( $g, $code, $extra ) . '</td>'; |
| 252 | + if ( $blacklisted !== null ) { |
| 253 | + continue; |
| 254 | + } |
250 | 255 | |
251 | | - $out .= Xml::element( 'td', |
252 | | - array( 'data-sort-value' => $total ), |
253 | | - $wgLang->formatNum( $total ) ); |
| 256 | + $fuzzy = $translated = $total = 0; |
254 | 257 | |
255 | | - $out .= Xml::element( 'td', |
256 | | - array( 'data-sort-value' => $total - $translated ), |
257 | | - $wgLang->formatNum( $total - $translated ) ); |
| 258 | + if ( $g instanceof AggregateMessageGroup ) { |
| 259 | + foreach ( $g->getGroups() as $subgroup ) { |
| 260 | + $result = $this->loadPercentages( $cache, $subgroup, $code ); |
| 261 | + $fuzzy += $result[0]; |
| 262 | + $translated += $result[1]; |
| 263 | + $total += $result[2]; |
| 264 | + } |
| 265 | + } else { |
| 266 | + list( $fuzzy, $translated, $total ) = $this->loadPercentages( $cache, $g, $code ); |
| 267 | + } |
258 | 268 | |
259 | | - $out .= $this->element( $this->formatPercentage( $translated / $total ), |
260 | | - $this->getBackgroundColour( $translated, $total ), |
261 | | - sprintf( '%1.5f', $translated / $total ) ); |
| 269 | + if ( $total == 0 ) { |
| 270 | + $zero = serialize( $total ); |
| 271 | + error_log( __METHOD__ . ": Group $groupName has zero message ($code): $zero" ); |
| 272 | + continue; |
| 273 | + } |
262 | 274 | |
263 | | - $out .= $this->element( $this->formatPercentage( $fuzzy / $total ), |
264 | | - $this->getBackgroundColour( $fuzzy, $total, true ), |
265 | | - sprintf( '%1.5f', $fuzzy / $total ) ); |
266 | | - |
267 | | - $out .= Xml::closeElement( 'tr' ); |
| 275 | + // Skip if $suppressComplete and complete |
| 276 | + if ( $suppressComplete && !$fuzzy && $translated === $total ) { |
| 277 | + continue; |
268 | 278 | } |
269 | 279 | |
270 | | - if ( $out ) { |
271 | | - $out = $this->createHeader( $code ) . $out; |
272 | | - $out .= Xml::closeElement( 'table' ); |
| 280 | + if ( $translated === $total ) { |
| 281 | + $extra = array( 'task' => 'reviewall' ); |
273 | 282 | } else { |
274 | | - $out = wfMsgExt( 'translate-nothing-to-do', 'parse' ); |
| 283 | + $extra = array(); |
275 | 284 | } |
276 | 285 | |
| 286 | + $rowParams = array(); |
| 287 | + $rowParams['data-groupid'] = $groupId; |
| 288 | + if ( is_string( $parent ) ) { |
| 289 | + $rowParams['data-parentgroups'] = $parent; |
| 290 | + } elseif( $parent === true ) { |
| 291 | + $rowParams['data-ismeta'] = '1'; |
| 292 | + } |
| 293 | + |
| 294 | + $out .= "\t" . Html::openElement( 'tr', $rowParams ); |
| 295 | + $out .= "\n\t\t" . Html::rawElement( 'td', array(), $this->makeGroupLink( $g, $code, $extra ) ); |
| 296 | + |
| 297 | + $out .= "\n\t\t" . Html::element( 'td', |
| 298 | + array( 'data-sort-value' => $total ), |
| 299 | + $wgLang->formatNum( $total ) ); |
| 300 | + |
| 301 | + $out .= "\n\t\t" . Html::element( 'td', |
| 302 | + array( 'data-sort-value' => $total - $translated ), |
| 303 | + $wgLang->formatNum( $total - $translated ) ); |
| 304 | + |
| 305 | + $out .= "\n\t\t" .$this->element( $this->formatPercentage( $translated / $total ), |
| 306 | + $this->getBackgroundColour( $translated, $total ), |
| 307 | + sprintf( '%1.3f', $translated / $total ) ); |
| 308 | + |
| 309 | + $out .= "\n\t\t" .$this->element( $this->formatPercentage( $fuzzy / $total ), |
| 310 | + $this->getBackgroundColour( $fuzzy, $total, true ), |
| 311 | + sprintf( '%1.3f', $fuzzy / $total ) ); |
| 312 | + |
| 313 | + $out .= "\n\t" . Xml::closeElement( 'tr' ) ."\n"; |
277 | 314 | return $out; |
278 | 315 | } |
279 | 316 | |
Index: trunk/extensions/Translate/MessageGroups.php |
— | — | @@ -422,8 +422,12 @@ |
423 | 423 | |
424 | 424 | global $wgLang; |
425 | 425 | |
426 | | - $desc = $this->getMessage( $key, $wgLang->getCode() ); |
| 426 | + $desc = null; |
427 | 427 | |
| 428 | + if ( !wfEmptyMsg( $key ) ) { |
| 429 | + $desc = wfMsgNoTrans( $key ); |
| 430 | + } |
| 431 | + |
428 | 432 | if ( $desc === null ) { |
429 | 433 | $desc = $this->getMessage( $key, 'en' ); |
430 | 434 | } |
— | — | @@ -1013,4 +1017,61 @@ |
1014 | 1018 | } |
1015 | 1019 | return $this->classes; |
1016 | 1020 | } |
| 1021 | + |
| 1022 | + /** |
| 1023 | + * Returns group strucuted into sub groups. First group in each subgroup is |
| 1024 | + * considered as the main group. |
| 1025 | + */ |
| 1026 | + public static function getGroupStructure() { |
| 1027 | + global $wgTranslateGroupStructure; |
| 1028 | + |
| 1029 | + $groups = self::getAllGroups(); |
| 1030 | + |
| 1031 | + $structure = array(); |
| 1032 | + foreach ( $groups as $id => $o ) { |
| 1033 | + if ( !MessageGroups::getGroup( $id )->exists() ) { |
| 1034 | + continue; |
| 1035 | + } |
| 1036 | + |
| 1037 | + foreach ( $wgTranslateGroupStructure as $pattern => $hypergroup ) { |
| 1038 | + if ( preg_match( $pattern, $id ) ) { |
| 1039 | + // Emulate deepArraySet, because AFAIK php does not have one |
| 1040 | + self::deepArraySet( $structure, $hypergroup, $id, $o ); |
| 1041 | + // We need to continue the outer loop, because we have finished this item. |
| 1042 | + continue 2; |
| 1043 | + } |
| 1044 | + } |
| 1045 | + |
| 1046 | + // Does not belong to any subgroup, just shove it into main level. |
| 1047 | + $structure[$id] = $o; |
| 1048 | + } |
| 1049 | + |
| 1050 | + // Sort top-level groups according to labels, not ids |
| 1051 | + foreach ( $structure as $id => $data ) { |
| 1052 | + // Either it is a group itself, or the first group of the array |
| 1053 | + $nid = is_array( $data ) ? key( $data ) : $id; |
| 1054 | + $labels[$id] = $groups[$nid]->getLabel(); |
| 1055 | + } |
| 1056 | + natcasesort( $labels ); |
| 1057 | + |
| 1058 | + foreach ( array_keys( $labels ) as $id ) { |
| 1059 | + $sorted[$id] = $structure[$id]; |
| 1060 | + } |
| 1061 | + |
| 1062 | + return $sorted; |
| 1063 | + } |
| 1064 | + |
| 1065 | + /** |
| 1066 | + * Function do do $array[level1][level2]...[levelN][$key] = $value, if we have |
| 1067 | + * the indexes in an array. |
| 1068 | + */ |
| 1069 | + public static function deepArraySet( &$array, array $indexes, $key, $value ) { |
| 1070 | + foreach ( $indexes as $index ) { |
| 1071 | + if ( !isset( $array[$index] ) ) $array[$index] = array(); |
| 1072 | + $array = &$array[$index]; |
| 1073 | + } |
| 1074 | + |
| 1075 | + $array[$key] = $value; |
| 1076 | + } |
| 1077 | + |
1017 | 1078 | } |