Index: branches/wmf/1.18wmf1/extensions/LocalisationUpdate/tests/tokenTest.php |
— | — | @@ -32,7 +32,7 @@ |
33 | 33 | if( count( $args ) ) { |
34 | 34 | $sources = $args; |
35 | 35 | } else { |
36 | | - $sources = |
| 36 | + $sources = |
37 | 37 | array_merge( |
38 | 38 | glob("$IP/extensions/*/*.i18n.php"), |
39 | 39 | glob("$IP/languages/messages/Messages*.php") ); |
— | — | @@ -41,9 +41,9 @@ |
42 | 42 | foreach( $sources as $sourceFile ) { |
43 | 43 | $rel = basename( $sourceFile ); |
44 | 44 | $out = str_replace( '/', '-', $rel ); |
45 | | - |
| 45 | + |
46 | 46 | $sourceData = file_get_contents( $sourceFile ); |
47 | | - |
| 47 | + |
48 | 48 | if( preg_match( '!extensions/!', $sourceFile ) ) { |
49 | 49 | $sourceData = LocalisationUpdate::cleanupExtensionFile( $sourceData ); |
50 | 50 | $items = 'langs'; |
— | — | @@ -51,32 +51,32 @@ |
52 | 52 | $sourceData = LocalisationUpdate::cleanupFile( $sourceData ); |
53 | 53 | $items = 'messages'; |
54 | 54 | } |
55 | | - |
| 55 | + |
56 | 56 | file_put_contents( "$out.txt", $sourceData ); |
57 | 57 | |
58 | 58 | $start = microtime(true); |
59 | 59 | $eval = evalExtractArray( $sourceData, 'messages' ); |
60 | 60 | $deltaEval = microtime(true) - $start; |
61 | | - |
| 61 | + |
62 | 62 | $start = microtime(true); |
63 | 63 | $quick = quickTokenExtractArray( $sourceData, 'messages' ); |
64 | 64 | $deltaQuick = microtime(true) - $start; |
65 | | - |
| 65 | + |
66 | 66 | $start = microtime(true); |
67 | 67 | $token = confExtractArray( $sourceData, 'messages' ); |
68 | 68 | $deltaToken = microtime(true) - $start; |
69 | | - |
| 69 | + |
70 | 70 | $hashEval = md5(serialize($eval)); |
71 | 71 | $hashToken = md5(serialize($token)); |
72 | 72 | $hashQuick = md5(serialize($quick)); |
73 | 73 | $countEval = count( (array)$eval); |
74 | 74 | $countToken = count( (array)$token ); |
75 | 75 | $countQuick = count( (array)$quick ); |
76 | | - |
| 76 | + |
77 | 77 | printf( "%s %s %d $items - %0.1fms - eval\n", $rel, $hashEval, $countEval, $deltaEval * 1000 ); |
78 | 78 | printf( "%s %s %d $items - %0.1fms - QuickArrayReader\n", $rel, $hashQuick, $countQuick, $deltaQuick * 1000 ); |
79 | 79 | printf( "%s %s %d $items - %0.1fms - ConfEditor\n", $rel, $hashToken, $countToken, $deltaToken * 1000 ); |
80 | | - |
| 80 | + |
81 | 81 | if( $hashEval !== $hashToken || $hashEval !== $hashQuick ) { |
82 | 82 | echo "FAILED on $rel\n"; |
83 | 83 | file_put_contents( "$out-eval.txt", var_export( $eval, true ) ); |
Index: branches/wmf/1.18wmf1/extensions/LocalisationUpdate/QuickArrayReader.php |
— | — | @@ -9,7 +9,10 @@ |
10 | 10 | */ |
11 | 11 | class QuickArrayReader { |
12 | 12 | var $vars = array(); |
13 | | - |
| 13 | + |
| 14 | + /** |
| 15 | + * @param $string string |
| 16 | + */ |
14 | 17 | function __construct( $string ) { |
15 | 18 | $scalarTypes = array( |
16 | 19 | T_LNUMBER => true, |
— | — | @@ -36,30 +39,30 @@ |
37 | 40 | // '$messages' -> 'messages' |
38 | 41 | $varname = trim( substr( $tokens[$i][1], 1 ) ); |
39 | 42 | $varindex = null; |
40 | | - |
| 43 | + |
41 | 44 | while( isset($skipTypes[$tokens[++$i][0]] ) ); |
42 | | - |
| 45 | + |
43 | 46 | if( $tokens[$i] === '[' ) { |
44 | 47 | while( isset($skipTypes[$tokens[++$i][0]] ) ); |
45 | | - |
| 48 | + |
46 | 49 | if( isset($scalarTypes[$tokens[$i][0]] ) ) { |
47 | 50 | $varindex = $this->parseScalar( $tokens[$i] ); |
48 | 51 | } else { |
49 | 52 | throw $this->except( $tokens[$i], 'scalar index' ); |
50 | 53 | } |
51 | 54 | while( isset($skipTypes[$tokens[++$i][0]] ) ); |
52 | | - |
| 55 | + |
53 | 56 | if( $tokens[$i] !== ']' ) { |
54 | 57 | throw $this->except( $tokens[$i], ']' ); |
55 | 58 | } |
56 | 59 | while( isset($skipTypes[$tokens[++$i][0]] ) ); |
57 | 60 | } |
58 | | - |
| 61 | + |
59 | 62 | if( $tokens[$i] !== '=' ) { |
60 | 63 | throw $this->except( $tokens[$i], '=' ); |
61 | 64 | } |
62 | 65 | while( isset($skipTypes[$tokens[++$i][0]] ) ); |
63 | | - |
| 66 | + |
64 | 67 | if( isset($scalarTypes[$tokens[$i][0]] ) ) { |
65 | 68 | $buildval = $this->parseScalar( $tokens[$i] ); |
66 | 69 | } elseif( $tokens[$i][0] === T_ARRAY ) { |
— | — | @@ -70,7 +73,7 @@ |
71 | 74 | $buildval = array(); |
72 | 75 | do { |
73 | 76 | while( isset($skipTypes[$tokens[++$i][0]] ) ); |
74 | | - |
| 77 | + |
75 | 78 | if( $tokens[$i] === ')' ) { |
76 | 79 | break; |
77 | 80 | } |
— | — | @@ -78,18 +81,18 @@ |
79 | 82 | $key = $this->parseScalar( $tokens[$i] ); |
80 | 83 | } |
81 | 84 | while( isset($skipTypes[$tokens[++$i][0]] ) ); |
82 | | - |
| 85 | + |
83 | 86 | if( $tokens[$i][0] !== T_DOUBLE_ARROW ) { |
84 | 87 | throw $this->except( $tokens[$i], '=>' ); |
85 | 88 | } |
86 | 89 | while( isset($skipTypes[$tokens[++$i][0]] ) ); |
87 | | - |
| 90 | + |
88 | 91 | if( isset($scalarTypes[$tokens[$i][0]] ) ) { |
89 | 92 | $val = $this->parseScalar( $tokens[$i] ); |
90 | 93 | } |
91 | 94 | @$buildval[$key] = $val; |
92 | 95 | while( isset($skipTypes[$tokens[++$i][0]] ) ); |
93 | | - |
| 96 | + |
94 | 97 | if( $tokens[$i] === ',' ) { |
95 | 98 | continue; |
96 | 99 | } elseif( $tokens[$i] === ')' ) { |
— | — | @@ -117,7 +120,12 @@ |
118 | 121 | } |
119 | 122 | } |
120 | 123 | } |
121 | | - |
| 124 | + |
| 125 | + /** |
| 126 | + * @param $got string |
| 127 | + * @param $expected string |
| 128 | + * @return Exception |
| 129 | + */ |
122 | 130 | private function except( $got, $expected ) { |
123 | 131 | if( is_array( $got ) ) { |
124 | 132 | $got = token_name( $got[0] ) . " ('" . $got[1] . "')"; |
— | — | @@ -129,6 +137,9 @@ |
130 | 138 | |
131 | 139 | /** |
132 | 140 | * Parse a scalar value in PHP |
| 141 | + * |
| 142 | + * @param $token string |
| 143 | + * |
133 | 144 | * @return mixed Parsed value |
134 | 145 | */ |
135 | 146 | function parseScalar( $token ) { |
— | — | @@ -160,7 +171,11 @@ |
161 | 172 | // be useful for a change |
162 | 173 | return $str; |
163 | 174 | } |
164 | | - |
| 175 | + |
| 176 | + /** |
| 177 | + * @param $varname string |
| 178 | + * @return null|string |
| 179 | + */ |
165 | 180 | function getVar( $varname ) { |
166 | 181 | if( isset( $this->vars[$varname] ) ) { |
167 | 182 | return $this->vars[$varname]; |
Index: branches/wmf/1.18wmf1/extensions/LocalisationUpdate/LocalisationUpdate.i18n.php |
— | — | @@ -37,6 +37,13 @@ |
38 | 38 | 'localisationupdate-desc' => 'يبقي الرسائل المترجمة محدثة كأفضل ما يكون', |
39 | 39 | ); |
40 | 40 | |
| 41 | +/** Asturian (Asturianu) |
| 42 | + * @author Xuacu |
| 43 | + */ |
| 44 | +$messages['ast'] = array( |
| 45 | + 'localisationupdate-desc' => 'Caltién los mensaxes llocalizaos tan anovaos como se pueda', |
| 46 | +); |
| 47 | + |
41 | 48 | /** Bashkir (Башҡортса) |
42 | 49 | * @author Assele |
43 | 50 | */ |
— | — | @@ -107,11 +114,19 @@ |
108 | 115 | 'localisationupdate-desc' => "Yn diweddaru'r cyfieithiadau o negeseuon mor aml â phosib", |
109 | 116 | ); |
110 | 117 | |
| 118 | +/** Danish (Dansk) |
| 119 | + * @author Peter Alberti |
| 120 | + */ |
| 121 | +$messages['da'] = array( |
| 122 | + 'localisationupdate-desc' => 'Holder de lokaliserede meddelelser så opdaterede som muligt', |
| 123 | +); |
| 124 | + |
111 | 125 | /** German (Deutsch) |
| 126 | + * @author Kghbln |
112 | 127 | * @author Purodha |
113 | 128 | */ |
114 | 129 | $messages['de'] = array( |
115 | | - 'localisationupdate-desc' => 'Lokalisierte Texte und Nachrichten möglichst aktuell halten', |
| 130 | + 'localisationupdate-desc' => 'Ermöglicht es lokalisierte Texte und Nachrichten so aktuell wie möglich zu halten', |
116 | 131 | ); |
117 | 132 | |
118 | 133 | /** Lower Sorbian (Dolnoserbski) |
— | — | @@ -290,6 +305,13 @@ |
291 | 306 | 'localisationupdate-desc' => 'പ്രാദേശികഭാഷയിലാക്കിയ സന്ദേശങ്ങൾ കഴിയുന്നത്ര വേഗം ചേർക്കാൻ ഉപയോഗിക്കുന്നു', |
292 | 307 | ); |
293 | 308 | |
| 309 | +/** Malay (Bahasa Melayu) |
| 310 | + * @author Anakmalaysia |
| 311 | + */ |
| 312 | +$messages['ms'] = array( |
| 313 | + 'localisationupdate-desc' => 'Memastikan kekemaskinian mesej-mesej yang disetempatkan', |
| 314 | +); |
| 315 | + |
294 | 316 | /** Dutch (Nederlands) |
295 | 317 | * @author Siebrand |
296 | 318 | */ |
— | — | @@ -375,14 +397,14 @@ |
376 | 398 | 'localisationupdate-desc' => 'Udržiava lokalizované správy čo najaktuálnejšie', |
377 | 399 | ); |
378 | 400 | |
379 | | -/** Serbian Cyrillic ekavian (Српски (ћирилица)) |
| 401 | +/** Serbian (Cyrillic script) (Српски (ћирилица)) |
380 | 402 | * @author Михајло Анђелковић |
381 | 403 | */ |
382 | 404 | $messages['sr-ec'] = array( |
383 | 405 | 'localisationupdate-desc' => 'Ажурира локализоване поруке колико је то могуће', |
384 | 406 | ); |
385 | 407 | |
386 | | -/** Serbian Latin ekavian (Srpski (latinica)) |
| 408 | +/** Serbian (Latin script) (Srpski (latinica)) |
387 | 409 | * @author Liangent |
388 | 410 | */ |
389 | 411 | $messages['sr-el'] = array( |
Index: branches/wmf/1.18wmf1/extensions/LocalisationUpdate/update.php |
— | — | @@ -4,6 +4,7 @@ |
5 | 5 | ? getenv( 'MW_INSTALL_PATH' ) |
6 | 6 | : realpath( dirname( __FILE__ ) . "/../../" ); |
7 | 7 | |
| 8 | +// TODO: migrate to maintenance class |
8 | 9 | require_once( "$IP/maintenance/commandLine.inc" ); |
9 | 10 | |
10 | 11 | if( isset( $options['help'] ) ) { |
— | — | @@ -17,6 +18,7 @@ |
18 | 19 | print " --skip-extensions Don't fetch any extension files\n"; |
19 | 20 | print " --all Fetch all present extensions, not just those enabled\n"; |
20 | 21 | print " --outdir=<dir> Override output directory for serialized update files\n"; |
| 22 | + print " --svnurl=<url> URL to SVN repository, or path to local SVN checkout. Default: $wgLocalisationUpdateSVNURL\n"; |
21 | 23 | print "\n"; |
22 | 24 | exit( 0 ); |
23 | 25 | } |
Index: branches/wmf/1.18wmf1/extensions/LocalisationUpdate/LocalisationUpdate.php |
— | — | @@ -11,7 +11,7 @@ |
12 | 12 | /** |
13 | 13 | * Directory to store serialized cache files in. Defaults to $wgCacheDirectory. |
14 | 14 | * It's OK to share this directory among wikis as long as the wiki you run |
15 | | - * update.php on has all extensions the other wikis using the same directory |
| 15 | + * update.php on has all extensions the other wikis using the same directory |
16 | 16 | * have. |
17 | 17 | * NOTE: If this variable and $wgCacheDirectory are both false, this extension |
18 | 18 | * WILL NOT WORK. |
— | — | @@ -33,14 +33,13 @@ |
34 | 34 | |
35 | 35 | $wgLocalisationUpdateRetryAttempts = 5; |
36 | 36 | |
37 | | - |
38 | 37 | // Info about me! |
39 | 38 | $wgExtensionCredits['other'][] = array( |
40 | 39 | 'path' => __FILE__, |
41 | 40 | 'name' => 'LocalisationUpdate', |
42 | 41 | 'author' => array( 'Tom Maaswinkel', 'Niklas Laxström', 'Roan Kattouw' ), |
43 | 42 | 'version' => '0.3', |
44 | | - 'url' => 'http://www.mediawiki.org/wiki/Extension:LocalisationUpdate', |
| 43 | + 'url' => 'https://www.mediawiki.org/wiki/Extension:LocalisationUpdate', |
45 | 44 | 'descriptionmsg' => 'localisationupdate-desc', |
46 | 45 | ); |
47 | 46 | |
Index: branches/wmf/1.18wmf1/extensions/LocalisationUpdate/LocalisationUpdate.class.php |
— | — | @@ -2,72 +2,89 @@ |
3 | 3 | |
4 | 4 | /** |
5 | 5 | * Class for localization updates. |
6 | | - * |
| 6 | + * |
7 | 7 | * TODO: refactor code to remove duplication |
8 | 8 | */ |
9 | 9 | class LocalisationUpdate { |
10 | | - |
| 10 | + |
11 | 11 | private static $newHashes = null; |
12 | 12 | private static $filecache = array(); |
13 | | - |
| 13 | + |
14 | 14 | /** |
15 | 15 | * LocalisationCacheRecache hook handler. |
16 | | - * |
| 16 | + * |
17 | 17 | * @param $lc LocalisationCache |
18 | 18 | * @param $langcode String |
19 | 19 | * @param $cache Array |
20 | | - * |
| 20 | + * |
21 | 21 | * @return true |
22 | 22 | */ |
23 | 23 | public static function onRecache( LocalisationCache $lc, $langcode, array &$cache ) { |
24 | | - $cache['messages'] = array_merge( |
25 | | - $cache['messages'], |
26 | | - self::readFile( $langcode ) |
27 | | - ); |
28 | | - |
29 | | - $cache['deps'][] = new FileDependency( |
30 | | - self::filename( $langcode ) |
31 | | - ); |
32 | | - |
| 24 | + // Handle fallback sequence and load all fallback messages from the cache |
| 25 | + $codeSequence = array_merge( array( $langcode ), $cache['fallbackSequence'] ); |
| 26 | + // Iterate over the fallback sequence in reverse, otherwise the fallback |
| 27 | + // language will override the requested language |
| 28 | + foreach ( array_reverse( $codeSequence ) as $code ) { |
| 29 | + if ( $code == 'en' ) { |
| 30 | + // Skip English, otherwise we end up trying to read |
| 31 | + // the nonexistent cache file for en a couple hundred times |
| 32 | + continue; |
| 33 | + } |
| 34 | + |
| 35 | + $cache['messages'] = array_merge( |
| 36 | + $cache['messages'], |
| 37 | + self::readFile( $code ) |
| 38 | + ); |
| 39 | + |
| 40 | + $cache['deps'][] = new FileDependency( |
| 41 | + self::filename( $code ) |
| 42 | + ); |
| 43 | + } |
| 44 | + |
33 | 45 | return true; |
34 | 46 | } |
35 | 47 | |
36 | 48 | /** |
37 | 49 | * Called from the cronjob to fetch new messages from SVN. |
38 | | - * |
| 50 | + * |
39 | 51 | * @param $options Array |
40 | | - * |
| 52 | + * |
41 | 53 | * @return true |
42 | 54 | */ |
43 | 55 | public static function updateMessages( array $options ) { |
44 | | - global $wgLocalisationUpdateDirectory; |
45 | | - |
| 56 | + global $wgLocalisationUpdateDirectory, $wgLocalisationUpdateSVNURL; |
| 57 | + |
46 | 58 | $verbose = !isset( $options['quiet'] ); |
47 | 59 | $all = isset( $options['all'] ); |
48 | 60 | $skipCore = isset( $options['skip-core'] ); |
49 | 61 | $skipExtensions = isset( $options['skip-extensions'] ); |
50 | | - |
| 62 | + |
51 | 63 | if( isset( $options['outdir'] ) ) { |
52 | 64 | $wgLocalisationUpdateDirectory = $options['outdir']; |
53 | 65 | } |
54 | 66 | |
| 67 | + if ( isset( $options['svnurl['] ) ) { |
| 68 | + // FIXME: Ewwwww. Refactor so this can be done properly |
| 69 | + $wgLocalisationUpdateSVNURL = $options['svnurl']; |
| 70 | + } |
| 71 | + |
55 | 72 | $result = 0; |
56 | | - |
| 73 | + |
57 | 74 | // Update all MW core messages. |
58 | 75 | if( !$skipCore ) { |
59 | 76 | $result = self::updateMediawikiMessages( $verbose ); |
60 | 77 | } |
61 | | - |
| 78 | + |
62 | 79 | // Update all Extension messages. |
63 | 80 | if( !$skipExtensions ) { |
64 | 81 | if( $all ) { |
65 | 82 | global $IP; |
66 | 83 | $extFiles = array(); |
67 | | - |
| 84 | + |
68 | 85 | // Look in extensions/ for all available items... |
69 | 86 | // TODO: add support for $wgExtensionAssetsPath |
70 | 87 | $dirs = new RecursiveDirectoryIterator( "$IP/extensions/" ); |
71 | | - |
| 88 | + |
72 | 89 | // I ain't kidding... RecursiveIteratorIterator. |
73 | 90 | foreach( new RecursiveIteratorIterator( $dirs ) as $pathname => $item ) { |
74 | 91 | $filename = basename( $pathname ); |
— | — | @@ -85,33 +102,33 @@ |
86 | 103 | $result += self::updateExtensionMessages( $locFile, $extension, $verbose ); |
87 | 104 | } |
88 | 105 | } |
89 | | - |
| 106 | + |
90 | 107 | self::writeHashes(); |
91 | 108 | |
92 | 109 | // And output the result! |
93 | 110 | self::myLog( "Updated {$result} messages in total" ); |
94 | 111 | self::myLog( "Done" ); |
95 | | - |
| 112 | + |
96 | 113 | return true; |
97 | 114 | } |
98 | 115 | |
99 | 116 | /** |
100 | 117 | * Update Extension Messages. |
101 | | - * |
| 118 | + * |
102 | 119 | * @param $file String |
103 | 120 | * @param $extension String |
104 | 121 | * @param $verbose Boolean |
105 | | - * |
| 122 | + * |
106 | 123 | * @return Integer: the amount of updated messages |
107 | 124 | */ |
108 | 125 | public static function updateExtensionMessages( $file, $extension, $verbose ) { |
109 | 126 | global $IP, $wgLocalisationUpdateSVNURL; |
110 | | - |
| 127 | + |
111 | 128 | $relfile = wfRelativePath( $file, "$IP/extensions" ); |
112 | | - |
| 129 | + |
113 | 130 | // Create a full path. |
114 | 131 | // TODO: add support for $wgExtensionAssetsPath |
115 | | - $localfile = "$IP/extensions/$relfile"; |
| 132 | + // $localfile = "$IP/extensions/$relfile"; |
116 | 133 | |
117 | 134 | // Get the full SVN directory path. |
118 | 135 | // TODO: add support for $wgExtensionAssetsPath |
— | — | @@ -119,15 +136,15 @@ |
120 | 137 | |
121 | 138 | // Compare the 2 files. |
122 | 139 | $result = self::compareExtensionFiles( $extension, $svnfile, $file, $verbose, false, true ); |
123 | | - |
| 140 | + |
124 | 141 | return $result; |
125 | 142 | } |
126 | 143 | |
127 | 144 | /** |
128 | | - * Update the Mediawiki Core Messages. |
129 | | - * |
| 145 | + * Update the MediaWiki Core Messages. |
| 146 | + * |
130 | 147 | * @param $verbose Boolean |
131 | | - * |
| 148 | + * |
132 | 149 | * @return Integer: the amount of updated messages |
133 | 150 | */ |
134 | 151 | public static function updateMediawikiMessages( $verbose ) { |
— | — | @@ -173,22 +190,22 @@ |
174 | 191 | |
175 | 192 | // Compare the files. |
176 | 193 | $result = self::compareFiles( $svnfile, $localfile, $verbose, $changedEnglishStrings, false, true ); |
177 | | - |
| 194 | + |
178 | 195 | // And update the change counter. |
179 | 196 | $changedCount += count( $result ); |
180 | 197 | } |
181 | 198 | |
182 | 199 | // Log some nice info. |
183 | | - self::myLog( "{$changedCount} Mediawiki messages are updated" ); |
184 | | - |
| 200 | + self::myLog( "{$changedCount} MediaWiki messages are updated" ); |
| 201 | + |
185 | 202 | return $changedCount; |
186 | 203 | } |
187 | 204 | |
188 | 205 | /** |
189 | 206 | * Removes all unneeded content from a file and returns it. |
190 | | - * |
| 207 | + * |
191 | 208 | * @param $contents String |
192 | | - * |
| 209 | + * |
193 | 210 | * @return String |
194 | 211 | */ |
195 | 212 | public static function cleanupFile( $contents ) { |
— | — | @@ -199,9 +216,9 @@ |
200 | 217 | '?' . '>' => '' |
201 | 218 | ) |
202 | 219 | ); |
203 | | - |
| 220 | + |
204 | 221 | $results = array(); |
205 | | - |
| 222 | + |
206 | 223 | // And we only want the messages array. |
207 | 224 | preg_match( "/\\\$messages(.*\s)*?\);/", $contents, $results ); |
208 | 225 | |
— | — | @@ -218,26 +235,26 @@ |
219 | 236 | // Return the cleaned up file. |
220 | 237 | return $contents; |
221 | 238 | } |
222 | | - |
| 239 | + |
223 | 240 | /** |
224 | 241 | * Removes all unneeded content from a file and returns it. |
225 | | - * |
226 | | - * FIXME: duplicated cleanupFile code |
227 | | - * |
| 242 | + * |
| 243 | + * FIXME: duplicated cleanupFile code |
| 244 | + * |
228 | 245 | * @param $contents String |
229 | | - * |
| 246 | + * |
230 | 247 | * @return string |
231 | 248 | */ |
232 | 249 | public static function cleanupExtensionFile( $contents ) { |
233 | 250 | // We don't want PHP tags. |
234 | 251 | $contents = preg_replace( "/<\?php/", "", $contents ); |
235 | 252 | $contents = preg_replace( "/\?" . ">/", "", $contents ); |
236 | | - |
| 253 | + |
237 | 254 | $results = array(); |
238 | | - |
| 255 | + |
239 | 256 | // And we only want message arrays. |
240 | 257 | preg_match_all( "/\\\$messages(.*\s)*?\);/", $contents, $results ); |
241 | | - |
| 258 | + |
242 | 259 | // But we want them all in one string. |
243 | 260 | if( !empty( $results[0] ) && is_array( $results[0] ) ) { |
244 | 261 | $contents = implode( "\n\n", $results[0] ); |
— | — | @@ -247,23 +264,23 @@ |
248 | 265 | |
249 | 266 | // And we hate the windows vs linux linebreaks. |
250 | 267 | $contents = preg_replace( "/\\\r\\\n?/", "\n", $contents ); |
251 | | - |
| 268 | + |
252 | 269 | return $contents; |
253 | | - } |
| 270 | + } |
254 | 271 | |
255 | 272 | /** |
256 | 273 | * Returns the contents of a file or false on failiure. |
257 | | - * |
| 274 | + * |
258 | 275 | * @param $basefile String |
259 | | - * |
| 276 | + * |
260 | 277 | * @return string or false |
261 | 278 | */ |
262 | 279 | public static function getFileContents( $basefile ) { |
263 | 280 | global $wgLocalisationUpdateRetryAttempts; |
264 | | - |
| 281 | + |
265 | 282 | $attempts = 0; |
266 | 283 | $basefilecontents = ''; |
267 | | - |
| 284 | + |
268 | 285 | // Use cURL to get the SVN contents. |
269 | 286 | if ( preg_match( "/^http/", $basefile ) ) { |
270 | 287 | while( !$basefilecontents && $attempts <= $wgLocalisationUpdateRetryAttempts ) { |
— | — | @@ -272,7 +289,7 @@ |
273 | 290 | self::myLog( 'Failed to download ' . $basefile . "; retrying in ${delay}s..." ); |
274 | 291 | sleep( $delay ); |
275 | 292 | } |
276 | | - |
| 293 | + |
277 | 294 | $basefilecontents = Http::get( $basefile ); |
278 | 295 | $attempts++; |
279 | 296 | } |
— | — | @@ -286,20 +303,20 @@ |
287 | 304 | return false; |
288 | 305 | } |
289 | 306 | } |
290 | | - |
| 307 | + |
291 | 308 | return $basefilecontents; |
292 | 309 | } |
293 | 310 | |
294 | 311 | /** |
295 | 312 | * Returns an array containing the differences between the files. |
296 | | - * |
| 313 | + * |
297 | 314 | * @param $basefile String |
298 | 315 | * @param $comparefile String |
299 | 316 | * @param $verbose Boolean |
300 | 317 | * @param $forbiddenKeys Array |
301 | 318 | * @param $alwaysGetResult Boolean |
302 | 319 | * @param $saveResults Boolean |
303 | | - * |
| 320 | + * |
304 | 321 | * @return array |
305 | 322 | */ |
306 | 323 | public static function compareFiles( $basefile, $comparefile, $verbose, array $forbiddenKeys = array(), $alwaysGetResult = true, $saveResults = false ) { |
— | — | @@ -307,7 +324,7 @@ |
308 | 325 | $langcode = Language::getCodeFromFileName( $basefile, 'Messages' ); |
309 | 326 | |
310 | 327 | $basefilecontents = self::getFileContents( $basefile ); |
311 | | - |
| 328 | + |
312 | 329 | if ( $basefilecontents === false || $basefilecontents === '' ) { |
313 | 330 | return array(); // Failed |
314 | 331 | } |
— | — | @@ -318,7 +335,7 @@ |
319 | 336 | // Change the variable name. |
320 | 337 | $basefilecontents = preg_replace( "/\\\$messages/", "\$base_messages", $basefilecontents ); |
321 | 338 | $basehash = md5( $basefilecontents ); |
322 | | - |
| 339 | + |
323 | 340 | // Check if the file has changed since our last update. |
324 | 341 | if ( !$alwaysGetResult ) { |
325 | 342 | if ( !self::checkHash( $basefile, $basehash ) ) { |
— | — | @@ -331,7 +348,7 @@ |
332 | 349 | $base_messages = self::parsePHP( $basefilecontents, 'base_messages' ); |
333 | 350 | |
334 | 351 | $comparefilecontents = self::getFileContents( $comparefile ); |
335 | | - |
| 352 | + |
336 | 353 | if ( $comparefilecontents === false || $comparefilecontents === '' ) { |
337 | 354 | return array(); // Failed |
338 | 355 | } |
— | — | @@ -342,7 +359,7 @@ |
343 | 360 | // Rename the array. |
344 | 361 | $comparefilecontents = preg_replace( "/\\\$messages/", "\$compare_messages", $comparefilecontents ); |
345 | 362 | $comparehash = md5( $comparefilecontents ); |
346 | | - |
| 363 | + |
347 | 364 | // If this is the remote file check if the file has changed since our last update. |
348 | 365 | if ( preg_match( "/^http/", $comparefile ) && !$alwaysGetResult ) { |
349 | 366 | if ( !self::checkHash( $comparefile, $comparehash ) ) { |
— | — | @@ -350,7 +367,7 @@ |
351 | 368 | return array(); |
352 | 369 | } |
353 | 370 | } |
354 | | - |
| 371 | + |
355 | 372 | // Get the array. |
356 | 373 | $compare_messages = self::parsePHP( $comparefilecontents, 'compare_messages' ); |
357 | 374 | |
— | — | @@ -378,100 +395,113 @@ |
379 | 396 | } elseif ( $saveResults ) { |
380 | 397 | self::myLog( "--{$langcode} hasn't changed--", $verbose ); |
381 | 398 | } |
382 | | - |
| 399 | + |
383 | 400 | self::saveHash( $basefile, $basehash ); |
384 | | - |
| 401 | + |
385 | 402 | self::saveHash( $comparefile, $comparehash ); |
386 | | - |
| 403 | + |
387 | 404 | return $changedStrings; |
388 | 405 | } |
389 | 406 | |
390 | 407 | /** |
391 | 408 | * Checks whether a messages file has a certain hash. |
392 | | - * |
| 409 | + * |
393 | 410 | * TODO: Swap return values, this is insane |
394 | | - * |
| 411 | + * |
395 | 412 | * @param $file string Filename |
396 | 413 | * @param $hash string Hash |
397 | | - * |
| 414 | + * |
398 | 415 | * @return bool True if $file does NOT have hash $hash, false if it does |
399 | 416 | */ |
400 | 417 | public static function checkHash( $file, $hash ) { |
401 | 418 | $hashes = self::readFile( 'hashes' ); |
402 | 419 | return @$hashes[$file] !== $hash; |
403 | 420 | } |
404 | | - |
| 421 | + |
| 422 | + /** |
| 423 | + * @param $file |
| 424 | + * @param $hash |
| 425 | + */ |
405 | 426 | public static function saveHash( $file, $hash ) { |
406 | 427 | if ( is_null( self::$newHashes ) ) { |
407 | 428 | self::$newHashes = self::readFile( 'hashes' ); |
408 | 429 | } |
409 | | - |
| 430 | + |
410 | 431 | self::$newHashes[$file] = $hash; |
411 | 432 | } |
412 | | - |
| 433 | + |
413 | 434 | public static function writeHashes() { |
414 | 435 | self::writeFile( 'hashes', self::$newHashes ); |
415 | 436 | } |
416 | 437 | |
417 | 438 | /** |
418 | | - * |
419 | | - * |
| 439 | + * |
| 440 | + * |
420 | 441 | * @param $changedStrings Array |
421 | 442 | * @param $forbiddenKeys Array |
422 | 443 | * @param $compare_messages Array |
423 | 444 | * @param $base_messages Array |
424 | 445 | * @param $langcode String |
425 | 446 | * @param $verbose Boolean |
426 | | - * |
| 447 | + * |
427 | 448 | * @return Integer: the amount of updated messages |
428 | 449 | */ |
429 | 450 | public static function saveChanges( $changedStrings, array $forbiddenKeys, array $compare_messages, array $base_messages, $langcode, $verbose ) { |
430 | 451 | // Count the updates. |
431 | 452 | $updates = 0; |
432 | | - |
| 453 | + |
433 | 454 | if( !is_array( $changedStrings ) ) { |
434 | 455 | self::myLog("CRITICAL ERROR: \$changedStrings is not an array in file " . (__FILE__) . ' at line ' .( __LINE__ ) ); |
435 | 456 | return 0; |
436 | 457 | } |
437 | 458 | |
438 | | - $new_messages = self::readFile( $langcode ); |
439 | | - |
440 | | - foreach ( $changedStrings as $key => $value ) { |
441 | | - // If this message wasn't changed in English. |
442 | | - if ( !isset( $forbiddenKeys[$key] ) ) { |
| 459 | + $new_messages = array(); |
| 460 | + |
| 461 | + //foreach ( $changedStrings as $key => $value ) { |
| 462 | + // HACK for r103763 CR: store all messages, even unchanged ones |
| 463 | + // TODO this file is a mess and needs to be rewritten |
| 464 | + foreach ( array_merge( array_keys( $base_messages ), array_keys( $compare_messages ) ) as $key ) { |
| 465 | + // Only update the translation if this message wasn't changed in English |
| 466 | + if ( !isset( $forbiddenKeys[$key] ) && isset( $base_messages[$key] ) ) { |
443 | 467 | $new_messages[$key] = $base_messages[$key]; |
444 | | - |
445 | | - // Output extra logmessages when needed. |
446 | | - if ( $verbose ) { |
447 | | - $oldmsg = isset( $compare_messages[$key] ) ? "'{$compare_messages[$key]}'" : 'not set'; |
448 | | - self::myLog( "Updated message {$key} from $oldmsg to '{$base_messages[$key]}'", $verbose ); |
| 468 | + |
| 469 | + if ( !isset( $compare_messages[$key] ) || $compare_messages[$key] !== $base_messages[$key] ) { |
| 470 | + // Output extra logmessages when needed. |
| 471 | + if ( $verbose ) { |
| 472 | + $oldmsg = isset( $compare_messages[$key] ) ? "'{$compare_messages[$key]}'" : 'not set'; |
| 473 | + self::myLog( "Updated message {$key} from $oldmsg to '{$base_messages[$key]}'", $verbose ); |
| 474 | + } |
| 475 | + |
| 476 | + // Update the counter. |
| 477 | + $updates++; |
449 | 478 | } |
450 | | - |
451 | | - // Update the counter. |
452 | | - $updates++; |
| 479 | + } elseif ( isset( $forbiddenKeys[$key] ) && isset( $compare_messages[$key] ) ) { |
| 480 | + // The message was changed in English, but a previous translation still exists in the cache. |
| 481 | + // Use that previous translation rather than falling back to the .i18n.php file |
| 482 | + $new_messages[$key] = $compare_messages[$key]; |
453 | 483 | } |
454 | 484 | } |
455 | 485 | self::writeFile( $langcode, $new_messages ); |
456 | | - |
| 486 | + |
457 | 487 | return $updates; |
458 | 488 | } |
459 | 489 | |
460 | 490 | /** |
461 | | - * |
| 491 | + * |
462 | 492 | * @param $extension String |
463 | 493 | * @param $basefile String |
464 | 494 | * @param $comparefile String |
465 | 495 | * @param $verbose Boolean |
466 | 496 | * @param $alwaysGetResult Boolean |
467 | 497 | * @param $saveResults Boolean |
468 | | - * |
| 498 | + * |
469 | 499 | * @return Integer: the amount of updated messages |
470 | 500 | */ |
471 | 501 | public static function compareExtensionFiles( $extension, $basefile, $comparefile, $verbose, $alwaysGetResult = true, $saveResults = false ) { |
472 | 502 | // FIXME: Factor out duplicated code? |
473 | 503 | |
474 | 504 | $basefilecontents = self::getFileContents( $basefile ); |
475 | | - |
| 505 | + |
476 | 506 | if ( $basefilecontents === false || $basefilecontents === '' ) { |
477 | 507 | return 0; // Failed |
478 | 508 | } |
— | — | @@ -482,7 +512,7 @@ |
483 | 513 | // Rename the arrays. |
484 | 514 | $basefilecontents = preg_replace( "/\\\$messages/", "\$base_messages", $basefilecontents ); |
485 | 515 | $basehash = md5( $basefilecontents ); |
486 | | - |
| 516 | + |
487 | 517 | // If this is the remote file |
488 | 518 | if ( preg_match( "/^http/", $basefile ) && !$alwaysGetResult ) { |
489 | 519 | // Check if the hash has changed |
— | — | @@ -572,22 +602,23 @@ |
573 | 603 | } elseif($saveResults === true) { |
574 | 604 | self::myLog( "--{$language} hasn't changed--", $verbose ); |
575 | 605 | } |
576 | | - } |
| 606 | + } |
577 | 607 | |
578 | 608 | // And log some stuff. |
579 | 609 | self::myLog( "Updated " . $updates . " messages for the '{$extension}' extension", $verbose ); |
580 | 610 | |
581 | 611 | self::saveHash( $basefile, $basehash ); |
582 | | - |
| 612 | + |
583 | 613 | self::saveHash( $comparefile, $comparehash ); |
584 | | - |
| 614 | + |
585 | 615 | return $updates; |
586 | 616 | } |
587 | | - |
| 617 | + |
588 | 618 | /** |
589 | 619 | * Logs a message. |
590 | | - * |
| 620 | + * |
591 | 621 | * @param $log String |
| 622 | + * @param bool $verbose |
592 | 623 | */ |
593 | 624 | public static function myLog( $log, $verbose = true ) { |
594 | 625 | if ( !$verbose ) { |
— | — | @@ -599,7 +630,12 @@ |
600 | 631 | print( $log . "\n" ); |
601 | 632 | } |
602 | 633 | } |
603 | | - |
| 634 | + |
| 635 | + /** |
| 636 | + * @param $php |
| 637 | + * @param $varname |
| 638 | + * @return bool|array |
| 639 | + */ |
604 | 640 | public static function parsePHP( $php, $varname ) { |
605 | 641 | try { |
606 | 642 | $reader = new QuickArrayReader("<?php $php"); |
— | — | @@ -609,32 +645,41 @@ |
610 | 646 | return false; |
611 | 647 | } |
612 | 648 | } |
613 | | - |
| 649 | + |
| 650 | + /** |
| 651 | + * @param $lang |
| 652 | + * @return string |
| 653 | + * @throws MWException |
| 654 | + */ |
614 | 655 | public static function filename( $lang ) { |
615 | 656 | global $wgLocalisationUpdateDirectory, $wgCacheDirectory; |
616 | | - |
| 657 | + |
617 | 658 | $dir = $wgLocalisationUpdateDirectory ? |
618 | 659 | $wgLocalisationUpdateDirectory : |
619 | 660 | $wgCacheDirectory; |
620 | | - |
| 661 | + |
621 | 662 | if ( !$dir ) { |
622 | 663 | throw new MWException( 'No cache directory configured' ); |
623 | 664 | } |
624 | | - |
| 665 | + |
625 | 666 | return "$dir/l10nupdate-$lang.cache"; |
626 | 667 | } |
627 | | - |
| 668 | + |
| 669 | + /** |
| 670 | + * @param $lang |
| 671 | + * @return mixed |
| 672 | + */ |
628 | 673 | public static function readFile( $lang ) { |
629 | 674 | if ( !isset( self::$filecache[$lang] ) ) { |
630 | 675 | $file = self::filename( $lang ); |
631 | 676 | $contents = @file_get_contents( $file ); |
632 | | - |
| 677 | + |
633 | 678 | if ( $contents === false ) { |
634 | 679 | wfDebug( "Failed to read file '$file'\n" ); |
635 | 680 | $retval = array(); |
636 | 681 | } else { |
637 | 682 | $retval = unserialize( $contents ); |
638 | | - |
| 683 | + |
639 | 684 | if ( $retval === false ) { |
640 | 685 | wfDebug( "Corrupted data in file '$file'\n" ); |
641 | 686 | $retval = array(); |
— | — | @@ -642,18 +687,23 @@ |
643 | 688 | } |
644 | 689 | self::$filecache[$lang] = $retval; |
645 | 690 | } |
646 | | - |
| 691 | + |
647 | 692 | return self::$filecache[$lang]; |
648 | 693 | } |
649 | | - |
| 694 | + |
| 695 | + /** |
| 696 | + * @param $lang |
| 697 | + * @param $var |
| 698 | + * @throws MWException |
| 699 | + */ |
650 | 700 | public static function writeFile( $lang, $var ) { |
651 | 701 | $file = self::filename( $lang ); |
652 | | - |
| 702 | + |
653 | 703 | if ( !@file_put_contents( $file, serialize( $var ) ) ) { |
654 | 704 | throw new MWException( "Failed to write to file '$file'" ); |
655 | 705 | } |
656 | | - |
| 706 | + |
657 | 707 | self::$filecache[$lang] = $var; |
658 | 708 | } |
659 | | - |
660 | | -} |
\ No newline at end of file |
| 709 | + |
| 710 | +} |
Property changes on: branches/wmf/1.18wmf1/extensions/LocalisationUpdate |
___________________________________________________________________ |
Modified: svn:mergeinfo |
661 | 711 | Merged /trunk/extensions/LocalisationUpdate:r92477-106189 |