00001 <?php
00016 class MediaWikiMessageChecker extends MessageChecker {
00025 protected function wikiParameterCheck( $messages, $code, &$warnings ) {
00026 parent::parameterCheck( $messages, $code, $warnings, '/\$[1-9]/' );
00027 }
00028
00039 protected function wikiLinksCheck( $messages, $code, &$warnings ) {
00040 $tc = Title::legalChars() . '#%{}';
00041
00042 foreach ( $messages as $message ) {
00043 $key = $message->key();
00044 $definition = $message->definition();
00045 $translation = $message->translation();
00046
00047 $subcheck = 'extra';
00048 $matches = $links = array();
00049 preg_match_all( "/\[\[([{$tc}]+)(\\|(.+?))?]]/sDu", $translation, $matches );
00050 $count = count( $matches[0] );
00051 for ( $i = 0; $i < $count; $i++ ) {
00052 $backMatch = preg_quote( $matches[1][$i], '/' );
00053
00054 if ( preg_match( "/\[\[$backMatch/", $definition ) ) {
00055 continue;
00056 }
00057
00058 $links[] = "[[{$matches[1][$i]}{$matches[2][$i]}]]";
00059 }
00060
00061 if ( count( $links ) ) {
00062 $warnings[$key][] = array(
00063 array( 'links', $subcheck, $key, $code ),
00064 'translate-checks-links',
00065 array( 'PARAMS', $links ),
00066 array( 'COUNT', count( $links ) ),
00067 );
00068 }
00069
00070 $subcheck = 'missing';
00071 $matches = $links = array();
00072 preg_match_all( "/\[\[([{$tc}]+)(\\|(.+?))?]]/sDu", $definition, $matches );
00073 $count = count( $matches[0] );
00074 for ( $i = 0; $i < $count; $i++ ) {
00075 $backMatch = preg_quote( $matches[1][$i], '/' );
00076
00077 if ( preg_match( "/\[\[$backMatch/", $translation ) ) {
00078 continue;
00079 }
00080
00081 $links[] = "[[{$matches[1][$i]}{$matches[2][$i]}]]";
00082 }
00083
00084 if ( count( $links ) ) {
00085 $warnings[$key][] = array(
00086 array( 'links', $subcheck, $key, $code ),
00087 'translate-checks-links-missing',
00088 array( 'PARAMS', $links ),
00089 array( 'COUNT', count( $links ) ),
00090 );
00091 }
00092 }
00093 }
00094
00102 protected function XhtmlCheck( $messages, $code, &$warnings ) {
00103 foreach ( $messages as $message ) {
00104 $key = $message->key();
00105 $translation = $message->translation();
00106 if ( strpos( $translation, '<' ) === false ) {
00107 continue;
00108 }
00109
00110 $subcheck = 'invalid';
00111 $tags = array(
00112 '~<hr *(\\\\)?>~suDi' => '<hr />',
00113 '~<br *(\\\\)?>~suDi' => '<br />',
00114 '~<hr/>~suDi' => '<hr />',
00115 '~<br/>~suDi' => '<br />',
00116 '~<(HR|Hr|hR) />~su' => '<hr />',
00117 '~<(BR|Br|bR) />~su' => '<br />',
00118 );
00119
00120 $wrongTags = array();
00121 foreach ( $tags as $wrong => $correct ) {
00122 $matches = array();
00123 preg_match_all( $wrong, $translation, $matches, PREG_PATTERN_ORDER );
00124 foreach ( $matches[0] as $wrongMatch ) {
00125 $wrongTags[$wrongMatch] = "$wrongMatch → $correct";
00126 }
00127 }
00128
00129 if ( count( $wrongTags ) ) {
00130 $warnings[$key][] = array(
00131 array( 'xhtml', $subcheck, $key, $code ),
00132 'translate-checks-xhtml',
00133 array( 'PARAMS', $wrongTags ),
00134 array( 'COUNT', count( $wrongTags ) ),
00135 );
00136 }
00137 }
00138 }
00139
00147 protected function pluralCheck( $messages, $code, &$warnings ) {
00148 foreach ( $messages as $message ) {
00149 $key = $message->key();
00150 $definition = $message->definition();
00151 $translation = $message->translation();
00152
00153 $subcheck = 'missing';
00154 if (
00155 stripos( $definition, '{{plural:' ) !== false &&
00156 stripos( $translation, '{{plural:' ) === false
00157 ) {
00158 $warnings[$key][] = array(
00159 array( 'plural', $subcheck, $key, $code ),
00160 'translate-checks-plural',
00161 );
00162 }
00163 }
00164 }
00165
00173 protected function pluralFormsCheck( $messages, $code, &$warnings ) {
00174 foreach ( $messages as $message ) {
00175 $key = $message->key();
00176 $translation = $message->translation();
00177
00178
00179 if ( !method_exists( 'Language', 'getPluralRules' ) ) {
00180 return;
00181 }
00182
00183
00184 if ( stripos( $translation, '{{plural:' ) === false ) {
00185 return;
00186 }
00187
00188 $plurals = self::getPluralForms( $translation );
00189 $allowed = self::getPluralFormCount( $code );
00190
00191 foreach ( $plurals as $forms ) {
00192 $forms = self::removeExplicitPluralForms( $forms );
00193 $provided = count( $forms );
00194
00195 if ( $provided > $allowed ) {
00196 $warnings[$key][] = array(
00197 array( 'plural', 'forms', $key, $code ),
00198 'translate-checks-plural-forms', $provided, $allowed
00199 );
00200 }
00201
00202
00203 if ( $provided > 1 && $forms[$provided - 1] === $forms[$provided - 2] ) {
00204 $warnings[$key][] = array(
00205 array( 'plural', 'dupe', $key, $code ),
00206 'translate-checks-plural-dupe'
00207 );
00208 }
00209 }
00210 }
00211 }
00212
00220 public static function getPluralFormCount( $code ) {
00221 $forms = Language::factory( $code )->getPluralRules();
00222
00223
00224 return count( $forms ) + 1;
00225 }
00226
00235 public static function getPluralForms( $translation ) {
00236 $plurals = array();
00237 while ( true ) {
00238 $pos = stripos( $translation, '{{plural:' );
00239 if ( $pos === false ) {
00240 break;
00241 }
00242
00243 $len = strlen( $translation );
00244 $stack = 0;
00245 for ( $i = $pos; $i < $len; $i++ ) {
00246 if ( $translation[$i] === '{' ) {
00247 $stack++;
00248 } elseif ( $translation[$i] === '}' ) {
00249 $stack--;
00250 } elseif ( $stack > 2 && $translation[$i] === '|' ) {
00251 # These pipes belong to another thing, ignore them
00252 $translation[$i] = '_';
00253 }
00254
00255 if ( $stack === 0 ) {
00256
00257 $pluralString = substr( $translation, $pos, $i - $pos - 1 );
00258 $forms = explode( '|', $pluralString );
00259 array_shift( $forms );
00260
00261
00262 $translation = substr( $translation, $i );
00263
00264 $plurals[] = $forms;
00265 break;
00266 }
00267 }
00268
00269
00270 if ( $i === $len ) {
00271 break;
00272 }
00273 }
00274
00275 return $plurals;
00276 }
00277
00285 public static function removeExplicitPluralForms( array $forms ) {
00286
00287 foreach ( $forms as $index => $form ) {
00288 if ( isset( $form[1] ) && $form[1] === '=' ) {
00289 unset( $forms[$index] );
00290 }
00291 }
00292
00293 return array_values( $forms );
00294 }
00295
00303 protected function pagenameMessagesCheck( $messages, $code, &$warnings ) {
00304 foreach ( $messages as $message ) {
00305 $key = $message->key();
00306 $definition = $message->definition();
00307 $translation = $message->translation();
00308
00309 $subcheck = 'namespace';
00310 $namespaces = 'help|project|\{\{ns:project}}|mediawiki';
00311 $matches = array();
00312 if ( preg_match( "/^($namespaces):[\w\s]+$/ui", $definition, $matches ) ) {
00313 if ( !preg_match( "/^{$matches[1]}:.+$/u", $translation ) ) {
00314 $warnings[$key][] = array(
00315 array( 'pagename', $subcheck, $key, $code ),
00316 'translate-checks-pagename',
00317 );
00318 }
00319 }
00320 }
00321 }
00322
00330 protected function miscMWChecks( $messages, $code, &$warnings ) {
00331 $timeList = array( 'protect-expiry-options', 'ipboptions' );
00332
00333 foreach ( $messages as $message ) {
00334 $key = $message->key();
00335 $definition = $message->definition();
00336 $translation = $message->translation();
00337
00338 if ( in_array( strtolower( $key ), $timeList, true ) ) {
00339 $defArray = explode( ',', $definition );
00340 $traArray = explode( ',', $translation );
00341
00342 $subcheck = 'timelist-count';
00343 $defCount = count( $defArray );
00344 $traCount = count( $traArray );
00345 if ( $defCount !== $traCount ) {
00346 $warnings[$key][] = array(
00347 array( 'miscmw', $subcheck, $key, $code ),
00348 'translate-checks-format',
00349 wfMessage( 'translate-checks-parametersnotequal' )
00350 ->numParams( $traCount, $defCount )->text()
00351 );
00352
00353 continue;
00354 }
00355
00356 for ( $i = 0; $i < $defCount; $i++ ) {
00357 $defItems = array_map( 'trim', explode( ':', $defArray[$i] ) );
00358 $traItems = array_map( 'trim', explode( ':', $traArray[$i] ) );
00359
00360 $subcheck = 'timelist-format';
00361 if ( count( $traItems ) !== 2 ) {
00362 $warnings[$key][] = array(
00363 array( 'miscmw', $subcheck, $key, $code ),
00364 'translate-checks-format',
00365 wfMessage(
00366 'translate-checks-malformed',
00367 $traArray[$i]
00368 )->text()
00369 );
00370 continue;
00371 }
00372
00373 $subcheck = 'timelist-format-value';
00374 if ( $traItems[1] !== $defItems[1] ) {
00375 $warnings[$key][] = array(
00376 array( 'miscmw', $subcheck, $key, $code ),
00377 'translate-checks-format',
00378 "<samp><nowiki>$traItems[1] !== $defItems[1]</nowiki></samp>",
00379 );
00380 continue;
00381 }
00382 }
00383 }
00384 }
00385 }
00386 }