Index: trunk/extensions/Translate/js/ext.translate.special.supportedlanguages.css |
— | — | @@ -0,0 +1,8 @@ |
| 2 | +.mw-translate-spsl-translators { |
| 3 | + line-height: 200%; |
| 4 | +} |
| 5 | + |
| 6 | +.mw-special-SupportedLanguages h2 { |
| 7 | + font-weight: bold; |
| 8 | + margin-top: 2em; |
| 9 | +} |
\ No newline at end of file |
Property changes on: trunk/extensions/Translate/js/ext.translate.special.supportedlanguages.css |
___________________________________________________________________ |
Added: svn:eol-style |
1 | 10 | + native |
Index: trunk/extensions/Translate/Translate.php |
— | — | @@ -153,6 +153,10 @@ |
154 | 154 | 'styles' => 'js/ext.translate.special.translate.css', |
155 | 155 | ) + $resourcePaths; |
156 | 156 | |
| 157 | +$wgResourceModules['ext.translate.special.supportedlanguages'] = array( |
| 158 | + 'styles' => 'js/ext.translate.special.supportedlanguages.css', |
| 159 | +) + $resourcePaths; |
| 160 | + |
157 | 161 | $wgResourceModules['jquery.autoresize'] = array( |
158 | 162 | 'scripts' => 'js/jquery.autoresize.js', |
159 | 163 | ) + $resourcePaths; |
Index: trunk/extensions/Translate/specials/SpecialSupportedLanguages.php |
— | — | @@ -20,27 +20,38 @@ |
21 | 21 | * @ingroup SpecialPage TranslateSpecialPage |
22 | 22 | */ |
23 | 23 | class SpecialSupportedLanguages extends UnlistedSpecialPage { |
| 24 | + // Whether to skip and regenerate caches |
| 25 | + protected $purge = false; |
| 26 | + |
24 | 27 | public function __construct() { |
25 | 28 | parent::__construct( 'SupportedLanguages' ); |
26 | 29 | } |
27 | 30 | |
28 | 31 | public function execute( $par ) { |
29 | | - global $wgLang, $wgOut; |
| 32 | + global $wgLang, $wgOut, $wgRequest; |
30 | 33 | |
31 | | - /** |
32 | | - * Requires NS_PORTAL. If not present, display error text. |
33 | | - */ |
| 34 | + // Requires NS_PORTAL. If not present, display error text. |
34 | 35 | if ( !defined( 'NS_PORTAL' ) ) { |
35 | 36 | $wgOut->showErrorPage( 'supportedlanguages-noportal-title', 'supportedlanguages-noportal' ); |
36 | 37 | return; |
37 | 38 | } |
38 | 39 | |
39 | | - $this->outputHeader(); |
| 40 | + $this->purge = $wgRequest->getVal( 'action' ) === 'purge'; |
| 41 | + |
40 | 42 | $this->setHeaders(); |
| 43 | + $wgOut->addModuleStyles( 'ext.translate.special.supportedlanguages' ); |
41 | 44 | |
42 | | - /** |
43 | | - * Check if CLDR extension has been installed. |
44 | | - */ |
| 45 | + $cache = wfGetCache( CACHE_ANYTHING ); |
| 46 | + $cachekey = wfMemcKey( 'translate-supportedlanguages', $wgLang->getCode() ); |
| 47 | + $data = $cache->get( $cachekey ); |
| 48 | + if ( !$this->purge && is_string( $data ) ) { |
| 49 | + $wgOut->addHtml( $data ); |
| 50 | + return; |
| 51 | + } |
| 52 | + |
| 53 | + $this->outputHeader(); |
| 54 | + |
| 55 | + // Check if CLDR extension has been installed. |
45 | 56 | $cldrInstalled = class_exists( 'LanguageNames' ); |
46 | 57 | |
47 | 58 | if ( $cldrInstalled ) { |
— | — | @@ -83,14 +94,14 @@ |
84 | 95 | $user = Title::capitalize( $match[1], NS_USER ); |
85 | 96 | $lb->add( NS_USER, $user ); |
86 | 97 | $lb->add( NS_USER_TALK, $user ); |
87 | | - |
88 | 98 | if ( !isset( $users[$code] ) ) $users[$code] = array(); |
89 | | - $users[$code][] = $user; |
| 99 | + $users[$code][] = strtr( $user, '_', ' ' ); |
90 | 100 | } |
91 | 101 | } |
92 | 102 | |
93 | 103 | $lb->execute(); |
94 | 104 | |
| 105 | + list( $editcounts, $lastedits ) = $this->getUserStats(); |
95 | 106 | global $wgUser; |
96 | 107 | |
97 | 108 | $skin = $wgUser->getSkin(); |
— | — | @@ -106,16 +117,12 @@ |
107 | 118 | $portalTitle = Title::makeTitleSafe( NS_PORTAL, $code ); |
108 | 119 | $portalText = $portalBaseText; |
109 | 120 | |
110 | | - /** |
111 | | - * If CLDR is installed, add localised header and link title. |
112 | | - */ |
| 121 | + // If CLDR is installed, add localised header and link title. |
113 | 122 | if ( $cldrInstalled ) { |
114 | 123 | $headerText = wfMsg( 'supportedlanguages-portallink', $code, $locals[$code], $natives[$code] ); |
115 | 124 | $portalText .= ' ' . $locals[$code]; |
116 | 125 | } else { |
117 | | - /** |
118 | | - * No CLDR, so a less localised header and link title. |
119 | | - */ |
| 126 | + // No CLDR, so a less localised header and link title. |
120 | 127 | $headerText = wfMsg( 'supportedlanguages-portallink-nocldr', $code, $natives[$code] ); |
121 | 128 | $portalText .= ' ' . $natives[$code]; |
122 | 129 | } |
— | — | @@ -133,9 +140,7 @@ |
134 | 141 | |
135 | 142 | $wgOut->addHTML( "<h2>" . $portalLink . "</h2>" ); |
136 | 143 | |
137 | | - /** |
138 | | - * Add useful links for language stats and recent changes for the language. |
139 | | - */ |
| 144 | + // Add useful links for language stats and recent changes for the language. |
140 | 145 | $links = array(); |
141 | 146 | $links[] = $skin->link( |
142 | 147 | $linkInfo['stats']['title'], |
— | — | @@ -160,20 +165,109 @@ |
161 | 166 | $linkList = $wgLang->listToText( $links ); |
162 | 167 | |
163 | 168 | $wgOut->addHTML( "<p>" . $linkList . "</p>\n" ); |
| 169 | + $this->makeUserList( $users[$code], $editcounts, $lastedits ); |
164 | 170 | |
165 | | - foreach ( $users[$code] as $index => $username ) { |
166 | | - $title = Title::makeTitleSafe( NS_USER, $username ); |
167 | | - $users[$code][$index] = $skin->link( $title, $username ); |
168 | | - } |
169 | | - |
170 | | - $wgOut->addHTML( "<p>" . wfMsgExt( |
171 | | - 'supportedlanguages-translators', |
172 | | - 'parsemag', |
173 | | - $wgLang->listToText( $users[$code] ), |
174 | | - count( $users[$code] ) |
175 | | - ) . "</p>\n" ); |
176 | 171 | } |
177 | 172 | $wgOut->addHtml( Html::element( 'hr' ) ); |
178 | 173 | $wgOut->addWikiMsg( 'supportedlanguages-count', $wgLang->formatNum( count( $users ) ) ); |
| 174 | + |
| 175 | + $cache->set( $cachekey, $wgOut->getHTML(), 3600 ); |
179 | 176 | } |
| 177 | + |
| 178 | + protected function makeUserList( $users, $editcounts, $lastedits ) { |
| 179 | + global $wgOut, $wgLang, $wgUser; |
| 180 | + $skin = $wgUser->getSkin(); |
| 181 | + |
| 182 | + $day = 60*60*24; |
| 183 | + |
| 184 | + // Scale of the activity colors, anything |
| 185 | + // longer than this is just inactive |
| 186 | + $period = 180; |
| 187 | + |
| 188 | + foreach ( $users as $index => $username ) { |
| 189 | + $title = Title::makeTitleSafe( NS_USER, $username ); |
| 190 | + $enc = htmlspecialchars( $username ); |
| 191 | + |
| 192 | + $attribs = array(); |
| 193 | + $styles = array(); |
| 194 | + if ( isset( $editcounts[$username] ) ) { |
| 195 | + $count = $editcounts[$username]; |
| 196 | + $styles['font-size'] = round( log( $count, 10 ) * 30 ) + 70 . '%'; |
| 197 | + |
| 198 | + $last = wfTimestamp( TS_UNIX ) - $lastedits[$username]; |
| 199 | + $last = round( $last / $day ); |
| 200 | + $attribs['title'] = wfMsgExt( 'supportedlanguages-activity', 'parsemag', |
| 201 | + $username, $wgLang->formatNum( $count ), $wgLang->formatNum( $last ) ); |
| 202 | + $last = max( 1, min( $period, $last ) ); |
| 203 | + $styles['border-bottom'] = '3px solid #' . $this->getActivityColour( $period - $last, $period ); |
| 204 | + #$styles['color'] = '#' . $this->getBackgroundColour( $period - $last, $period ); |
| 205 | + } else { |
| 206 | + $enc = "<s>$enc</s>"; |
| 207 | + } |
| 208 | + |
| 209 | + $stylestr = $this->formatStyle( $styles ); |
| 210 | + if ( $stylestr ) $attribs['style'] = $stylestr; |
| 211 | + |
| 212 | + $users[$index] = $skin->link( $title, $enc, $attribs ); |
| 213 | + } |
| 214 | + |
| 215 | + $wgOut->addHTML( "<p class='mw-translate-spsl-translators'>" . wfMsgExt( |
| 216 | + 'supportedlanguages-translators', |
| 217 | + 'parsemag', |
| 218 | + $wgLang->listToText( $users ), |
| 219 | + count( $users ) |
| 220 | + ) . "</p>\n" ); |
| 221 | + } |
| 222 | + |
| 223 | + protected function getUserStats() { |
| 224 | + $cache = wfGetCache( CACHE_ANYTHING ); |
| 225 | + $cachekey = wfMemcKey( 'translate-supportedlanguages-userstats' ); |
| 226 | + $data = $cache->get( $cachekey ); |
| 227 | + if ( !$this->purge && is_array( $data ) ) { |
| 228 | + return $data; |
| 229 | + } |
| 230 | + |
| 231 | + $dbr = wfGetDB( DB_SLAVE ); |
| 232 | + $editcounts = $lastedits = array(); |
| 233 | + $tables = array( 'user', 'revision' ); |
| 234 | + $fields = array( 'user_name', 'user_editcount', 'MAX(rev_timestamp) as lastedit' ); |
| 235 | + $conds = array( 'user_id = rev_user' ); |
| 236 | + $options = array( 'GROUP BY' => 'user_name' ); |
| 237 | + |
| 238 | + $res = $dbr->select( $tables, $fields, $conds, __METHOD__, $options ); |
| 239 | + foreach ( $res as $row ) { |
| 240 | + $editcounts[$row->user_name] = $row->user_editcount; |
| 241 | + $lastedits[$row->user_name] = wfTimestamp( TS_UNIX, $row->lastedit ); |
| 242 | + } |
| 243 | + |
| 244 | + $data = array( $editcounts, $lastedits ); |
| 245 | + $cache->set( $cachekey, $data, 3600 ); |
| 246 | + return $data; |
| 247 | + } |
| 248 | + |
| 249 | + protected function formatStyle( $styles ) { |
| 250 | + $stylestr = ''; |
| 251 | + foreach ( $styles as $key => $value ) { |
| 252 | + $stylestr .= "$key:$value;"; |
| 253 | + } |
| 254 | + return $stylestr; |
| 255 | + } |
| 256 | + |
| 257 | + /// FIXME: copied from Special:LanguageStats |
| 258 | + protected function getActivityColour( $subset, $total ) { |
| 259 | + $v = @round( 255 * $subset / $total ); |
| 260 | + |
| 261 | + if ( $v < 128 ) { |
| 262 | + // Red to Yellow |
| 263 | + $red = 'FF'; |
| 264 | + $green = sprintf( '%02X', 2 * $v ); |
| 265 | + } else { |
| 266 | + // Yellow to Green |
| 267 | + $red = sprintf( '%02X', 2 * ( 255 - $v ) ); |
| 268 | + $green = 'FF'; |
| 269 | + } |
| 270 | + $blue = '00'; |
| 271 | + |
| 272 | + return $red . $green . $blue; |
| 273 | + } |
180 | 274 | } |