[ Index ] |
PHP Cross Reference of MediaWiki-1.24.0 |
[Summary view] [Print] [Text view]
1 <?php 2 /** 3 * This program is free software; you can redistribute it and/or modify 4 * it under the terms of the GNU General Public License as published by 5 * the Free Software Foundation; either version 2 of the License, or 6 * (at your option) any later version. 7 * 8 * This program is distributed in the hope that it will be useful, 9 * but WITHOUT ANY WARRANTY; without even the implied warranty of 10 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 11 * GNU General Public License for more details. 12 * 13 * You should have received a copy of the GNU General Public License along 14 * with this program; if not, write to the Free Software Foundation, Inc., 15 * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. 16 * http://www.gnu.org/copyleft/gpl.html 17 * 18 * @file 19 * @ingroup Language 20 */ 21 22 /** 23 * Parser for rules of language conversion , parse rules in -{ }- tag. 24 * @ingroup Language 25 * @author fdcn <[email protected]>, PhiLiP <[email protected]> 26 */ 27 class ConverterRule { 28 public $mText; // original text in -{text}- 29 public $mConverter; // LanguageConverter object 30 public $mRuleDisplay = ''; 31 public $mRuleTitle = false; 32 public $mRules = '';// string : the text of the rules 33 public $mRulesAction = 'none'; 34 public $mFlags = array(); 35 public $mVariantFlags = array(); 36 public $mConvTable = array(); 37 public $mBidtable = array();// array of the translation in each variant 38 public $mUnidtable = array();// array of the translation in each variant 39 40 /** 41 * Constructor 42 * 43 * @param string $text The text between -{ and }- 44 * @param LanguageConverter $converter 45 */ 46 public function __construct( $text, $converter ) { 47 $this->mText = $text; 48 $this->mConverter = $converter; 49 } 50 51 /** 52 * Check if variants array in convert array. 53 * 54 * @param array|string $variants Variant language code 55 * @return string Translated text 56 */ 57 public function getTextInBidtable( $variants ) { 58 $variants = (array)$variants; 59 if ( !$variants ) { 60 return false; 61 } 62 foreach ( $variants as $variant ) { 63 if ( isset( $this->mBidtable[$variant] ) ) { 64 return $this->mBidtable[$variant]; 65 } 66 } 67 return false; 68 } 69 70 /** 71 * Parse flags with syntax -{FLAG| ... }- 72 * @private 73 */ 74 function parseFlags() { 75 $text = $this->mText; 76 $flags = array(); 77 $variantFlags = array(); 78 79 $sepPos = strpos( $text, '|' ); 80 if ( $sepPos !== false ) { 81 $validFlags = $this->mConverter->mFlags; 82 $f = StringUtils::explode( ';', substr( $text, 0, $sepPos ) ); 83 foreach ( $f as $ff ) { 84 $ff = trim( $ff ); 85 if ( isset( $validFlags[$ff] ) ) { 86 $flags[$validFlags[$ff]] = true; 87 } 88 } 89 $text = strval( substr( $text, $sepPos + 1 ) ); 90 } 91 92 if ( !$flags ) { 93 $flags['S'] = true; 94 } elseif ( isset( $flags['R'] ) ) { 95 $flags = array( 'R' => true );// remove other flags 96 } elseif ( isset( $flags['N'] ) ) { 97 $flags = array( 'N' => true );// remove other flags 98 } elseif ( isset( $flags['-'] ) ) { 99 $flags = array( '-' => true );// remove other flags 100 } elseif ( count( $flags ) == 1 && isset( $flags['T'] ) ) { 101 $flags['H'] = true; 102 } elseif ( isset( $flags['H'] ) ) { 103 // replace A flag, and remove other flags except T 104 $temp = array( '+' => true, 'H' => true ); 105 if ( isset( $flags['T'] ) ) { 106 $temp['T'] = true; 107 } 108 if ( isset( $flags['D'] ) ) { 109 $temp['D'] = true; 110 } 111 $flags = $temp; 112 } else { 113 if ( isset( $flags['A'] ) ) { 114 $flags['+'] = true; 115 $flags['S'] = true; 116 } 117 if ( isset( $flags['D'] ) ) { 118 unset( $flags['S'] ); 119 } 120 // try to find flags like "zh-hans", "zh-hant" 121 // allow syntaxes like "-{zh-hans;zh-hant|XXXX}-" 122 $variantFlags = array_intersect( array_keys( $flags ), $this->mConverter->mVariants ); 123 if ( $variantFlags ) { 124 $variantFlags = array_flip( $variantFlags ); 125 $flags = array(); 126 } 127 } 128 $this->mVariantFlags = $variantFlags; 129 $this->mRules = $text; 130 $this->mFlags = $flags; 131 } 132 133 /** 134 * Generate conversion table. 135 * @private 136 */ 137 function parseRules() { 138 $rules = $this->mRules; 139 $bidtable = array(); 140 $unidtable = array(); 141 $variants = $this->mConverter->mVariants; 142 $varsep_pattern = $this->mConverter->getVarSeparatorPattern(); 143 144 // Split according to $varsep_pattern, but ignore semicolons from HTML entities 145 $rules = preg_replace( '/(&[#a-zA-Z0-9]+);/', "$1\x01", $rules ); 146 $choice = preg_split( $varsep_pattern, $rules ); 147 $choice = str_replace( "\x01", ';', $choice ); 148 149 foreach ( $choice as $c ) { 150 $v = explode( ':', $c, 2 ); 151 if ( count( $v ) != 2 ) { 152 // syntax error, skip 153 continue; 154 } 155 $to = trim( $v[1] ); 156 $v = trim( $v[0] ); 157 $u = explode( '=>', $v, 2 ); 158 // if $to is empty, strtr() could return a wrong result 159 if ( count( $u ) == 1 && $to && in_array( $v, $variants ) ) { 160 $bidtable[$v] = $to; 161 } elseif ( count( $u ) == 2 ) { 162 $from = trim( $u[0] ); 163 $v = trim( $u[1] ); 164 if ( array_key_exists( $v, $unidtable ) 165 && !is_array( $unidtable[$v] ) 166 && $to 167 && in_array( $v, $variants ) ) { 168 $unidtable[$v] = array( $from => $to ); 169 } elseif ( $to && in_array( $v, $variants ) ) { 170 $unidtable[$v][$from] = $to; 171 } 172 } 173 // syntax error, pass 174 if ( !isset( $this->mConverter->mVariantNames[$v] ) ) { 175 $bidtable = array(); 176 $unidtable = array(); 177 break; 178 } 179 } 180 $this->mBidtable = $bidtable; 181 $this->mUnidtable = $unidtable; 182 } 183 184 /** 185 * @private 186 * 187 * @return string 188 */ 189 function getRulesDesc() { 190 $codesep = $this->mConverter->mDescCodeSep; 191 $varsep = $this->mConverter->mDescVarSep; 192 $text = ''; 193 foreach ( $this->mBidtable as $k => $v ) { 194 $text .= $this->mConverter->mVariantNames[$k] . "$codesep$v$varsep"; 195 } 196 foreach ( $this->mUnidtable as $k => $a ) { 197 foreach ( $a as $from => $to ) { 198 $text .= $from . '⇒' . $this->mConverter->mVariantNames[$k] . 199 "$codesep$to$varsep"; 200 } 201 } 202 return $text; 203 } 204 205 /** 206 * Parse rules conversion. 207 * @private 208 * 209 * @param string $variant 210 * 211 * @return string 212 */ 213 function getRuleConvertedStr( $variant ) { 214 $bidtable = $this->mBidtable; 215 $unidtable = $this->mUnidtable; 216 217 if ( count( $bidtable ) + count( $unidtable ) == 0 ) { 218 return $this->mRules; 219 } else { 220 // display current variant in bidirectional array 221 $disp = $this->getTextInBidtable( $variant ); 222 // or display current variant in fallbacks 223 if ( !$disp ) { 224 $disp = $this->getTextInBidtable( 225 $this->mConverter->getVariantFallbacks( $variant ) ); 226 } 227 // or display current variant in unidirectional array 228 if ( !$disp && array_key_exists( $variant, $unidtable ) ) { 229 $disp = array_values( $unidtable[$variant] ); 230 $disp = $disp[0]; 231 } 232 // or display frist text under disable manual convert 233 if ( !$disp && $this->mConverter->mManualLevel[$variant] == 'disable' ) { 234 if ( count( $bidtable ) > 0 ) { 235 $disp = array_values( $bidtable ); 236 $disp = $disp[0]; 237 } else { 238 $disp = array_values( $unidtable ); 239 $disp = array_values( $disp[0] ); 240 $disp = $disp[0]; 241 } 242 } 243 return $disp; 244 } 245 } 246 247 /** 248 * Similar to getRuleConvertedStr(), but this prefers to use original 249 * page title if $variant === $this->mConverter->mMainLanguageCode 250 * and may return false in this case (so this title conversion rule 251 * will be ignored and the original title is shown). 252 * 253 * @since 1.22 254 * @param string $variant The variant code to display page title in 255 * @return string|bool The converted title or false if just page name 256 */ 257 function getRuleConvertedTitle( $variant ) { 258 if ( $variant === $this->mConverter->mMainLanguageCode ) { 259 // If a string targeting exactly this variant is set, 260 // use it. Otherwise, just return false, so the real 261 // page name can be shown (and because variant === main, 262 // there'll be no further automatic conversion). 263 $disp = $this->getTextInBidtable( $variant ); 264 if ( $disp ) { 265 return $disp; 266 } 267 if ( array_key_exists( $variant, $this->mUnidtable ) ) { 268 $disp = array_values( $this->mUnidtable[$variant] ); 269 $disp = $disp[0]; 270 } 271 // Assigned above or still false. 272 return $disp; 273 } else { 274 return $this->getRuleConvertedStr( $variant ); 275 } 276 } 277 278 /** 279 * Generate conversion table for all text. 280 * @private 281 */ 282 function generateConvTable() { 283 // Special case optimisation 284 if ( !$this->mBidtable && !$this->mUnidtable ) { 285 $this->mConvTable = array(); 286 return; 287 } 288 289 $bidtable = $this->mBidtable; 290 $unidtable = $this->mUnidtable; 291 $manLevel = $this->mConverter->mManualLevel; 292 293 $vmarked = array(); 294 foreach ( $this->mConverter->mVariants as $v ) { 295 /* for bidirectional array 296 fill in the missing variants, if any, 297 with fallbacks */ 298 if ( !isset( $bidtable[$v] ) ) { 299 $variantFallbacks = 300 $this->mConverter->getVariantFallbacks( $v ); 301 $vf = $this->getTextInBidtable( $variantFallbacks ); 302 if ( $vf ) { 303 $bidtable[$v] = $vf; 304 } 305 } 306 307 if ( isset( $bidtable[$v] ) ) { 308 foreach ( $vmarked as $vo ) { 309 // use syntax: -{A|zh:WordZh;zh-tw:WordTw}- 310 // or -{H|zh:WordZh;zh-tw:WordTw}- 311 // or -{-|zh:WordZh;zh-tw:WordTw}- 312 // to introduce a custom mapping between 313 // words WordZh and WordTw in the whole text 314 if ( $manLevel[$v] == 'bidirectional' ) { 315 $this->mConvTable[$v][$bidtable[$vo]] = $bidtable[$v]; 316 } 317 if ( $manLevel[$vo] == 'bidirectional' ) { 318 $this->mConvTable[$vo][$bidtable[$v]] = $bidtable[$vo]; 319 } 320 } 321 $vmarked[] = $v; 322 } 323 /* for unidirectional array fill to convert tables */ 324 if ( ( $manLevel[$v] == 'bidirectional' || $manLevel[$v] == 'unidirectional' ) 325 && isset( $unidtable[$v] ) 326 ) { 327 if ( isset( $this->mConvTable[$v] ) ) { 328 $this->mConvTable[$v] = array_merge( $this->mConvTable[$v], $unidtable[$v] ); 329 } else { 330 $this->mConvTable[$v] = $unidtable[$v]; 331 } 332 } 333 } 334 } 335 336 /** 337 * Parse rules and flags. 338 * @param string $variant Variant language code 339 */ 340 public function parse( $variant = null ) { 341 if ( !$variant ) { 342 $variant = $this->mConverter->getPreferredVariant(); 343 } 344 345 $this->parseFlags(); 346 $flags = $this->mFlags; 347 348 // convert to specified variant 349 // syntax: -{zh-hans;zh-hant[;...]|<text to convert>}- 350 if ( $this->mVariantFlags ) { 351 // check if current variant in flags 352 if ( isset( $this->mVariantFlags[$variant] ) ) { 353 // then convert <text to convert> to current language 354 $this->mRules = $this->mConverter->autoConvert( $this->mRules, 355 $variant ); 356 } else { 357 // if current variant no in flags, 358 // then we check its fallback variants. 359 $variantFallbacks = 360 $this->mConverter->getVariantFallbacks( $variant ); 361 if ( is_array( $variantFallbacks ) ) { 362 foreach ( $variantFallbacks as $variantFallback ) { 363 // if current variant's fallback exist in flags 364 if ( isset( $this->mVariantFlags[$variantFallback] ) ) { 365 // then convert <text to convert> to fallback language 366 $this->mRules = 367 $this->mConverter->autoConvert( $this->mRules, 368 $variantFallback ); 369 break; 370 } 371 } 372 } 373 } 374 $this->mFlags = $flags = array( 'R' => true ); 375 } 376 377 if ( !isset( $flags['R'] ) && !isset( $flags['N'] ) ) { 378 // decode => HTML entities modified by Sanitizer::removeHTMLtags 379 $this->mRules = str_replace( '=>', '=>', $this->mRules ); 380 $this->parseRules(); 381 } 382 $rules = $this->mRules; 383 384 if ( !$this->mBidtable && !$this->mUnidtable ) { 385 if ( isset( $flags['+'] ) || isset( $flags['-'] ) ) { 386 // fill all variants if text in -{A/H/-|text} without rules 387 foreach ( $this->mConverter->mVariants as $v ) { 388 $this->mBidtable[$v] = $rules; 389 } 390 } elseif ( !isset( $flags['N'] ) && !isset( $flags['T'] ) ) { 391 $this->mFlags = $flags = array( 'R' => true ); 392 } 393 } 394 395 $this->mRuleDisplay = false; 396 foreach ( $flags as $flag => $unused ) { 397 switch ( $flag ) { 398 case 'R': 399 // if we don't do content convert, still strip the -{}- tags 400 $this->mRuleDisplay = $rules; 401 break; 402 case 'N': 403 // process N flag: output current variant name 404 $ruleVar = trim( $rules ); 405 if ( isset( $this->mConverter->mVariantNames[$ruleVar] ) ) { 406 $this->mRuleDisplay = $this->mConverter->mVariantNames[$ruleVar]; 407 } else { 408 $this->mRuleDisplay = ''; 409 } 410 break; 411 case 'D': 412 // process D flag: output rules description 413 $this->mRuleDisplay = $this->getRulesDesc(); 414 break; 415 case 'H': 416 // process H,- flag or T only: output nothing 417 $this->mRuleDisplay = ''; 418 break; 419 case '-': 420 $this->mRulesAction = 'remove'; 421 $this->mRuleDisplay = ''; 422 break; 423 case '+': 424 $this->mRulesAction = 'add'; 425 $this->mRuleDisplay = ''; 426 break; 427 case 'S': 428 $this->mRuleDisplay = $this->getRuleConvertedStr( $variant ); 429 break; 430 case 'T': 431 $this->mRuleTitle = $this->getRuleConvertedTitle( $variant ); 432 $this->mRuleDisplay = ''; 433 break; 434 default: 435 // ignore unknown flags (but see error case below) 436 } 437 } 438 if ( $this->mRuleDisplay === false ) { 439 $this->mRuleDisplay = '<span class="error">' 440 . wfMessage( 'converter-manual-rule-error' )->inContentLanguage()->escaped() 441 . '</span>'; 442 } 443 444 $this->generateConvTable(); 445 } 446 447 /** 448 * @todo FIXME: code this function :) 449 */ 450 public function hasRules() { 451 // TODO: 452 } 453 454 /** 455 * Get display text on markup -{...}- 456 * @return string 457 */ 458 public function getDisplay() { 459 return $this->mRuleDisplay; 460 } 461 462 /** 463 * Get converted title. 464 * @return string 465 */ 466 public function getTitle() { 467 return $this->mRuleTitle; 468 } 469 470 /** 471 * Return how deal with conversion rules. 472 * @return string 473 */ 474 public function getRulesAction() { 475 return $this->mRulesAction; 476 } 477 478 /** 479 * Get conversion table. (bidirectional and unidirectional 480 * conversion table) 481 * @return array 482 */ 483 public function getConvTable() { 484 return $this->mConvTable; 485 } 486 487 /** 488 * Get conversion rules string. 489 * @return string 490 */ 491 public function getRules() { 492 return $this->mRules; 493 } 494 495 /** 496 * Get conversion flags. 497 * @return array 498 */ 499 public function getFlags() { 500 return $this->mFlags; 501 } 502 }
title
Description
Body
title
Description
Body
title
Description
Body
title
Body
Generated: Fri Nov 28 14:03:12 2014 | Cross-referenced by PHPXref 0.7.1 |