00001 <?php
00002
00018 class LanguageConverter {
00019 var $mPreferredVariant='';
00020 var $mMainLanguageCode;
00021 var $mVariants, $mVariantFallbacks, $mVariantNames;
00022 var $mTablesLoaded = false;
00023 var $mTables;
00024 var $mManualAddTables;
00025 var $mManualRemoveTables;
00026 var $mNamespaceTables;
00027 var $mTitleDisplay='';
00028 var $mDoTitleConvert=true, $mDoContentConvert=true;
00029 var $mManualLevel;
00030 var $mTitleFromFlag = false;
00031 var $mCacheKey;
00032 var $mLangObj;
00033 var $mMarkup;
00034 var $mFlags;
00035 var $mDescCodeSep = ':',$mDescVarSep = ';';
00036 var $mUcfirst = false;
00037
00038 const CACHE_VERSION_KEY = 'VERSION 6';
00039
00051 function __construct($langobj, $maincode,
00052 $variants=array(),
00053 $variantfallbacks=array(),
00054 $markup=array(),
00055 $flags = array(),
00056 $manualLevel = array() ) {
00057 $this->mLangObj = $langobj;
00058 $this->mMainLanguageCode = $maincode;
00059 $this->mVariants = $variants;
00060 $this->mVariantFallbacks = $variantfallbacks;
00061 global $wgLanguageNames;
00062 $this->mVariantNames = $wgLanguageNames;
00063 $this->mCacheKey = wfMemcKey( 'conversiontables', $maincode );
00064 $m = array(
00065 'begin'=>'-{',
00066 'flagsep'=>'|',
00067 'unidsep'=>'=>',
00068 'codesep'=>':',
00069 'varsep'=>';',
00070 'end'=>'}-'
00071 );
00072 $this->mMarkup = array_merge($m, $markup);
00073 $f = array(
00074
00075
00076
00077
00078 'A'=>'A',
00079 'T'=>'T',
00080 'R'=>'R',
00081 'D'=>'D',
00082 '-'=>'-',
00083 'H'=>'H',
00084 'N'=>'N'
00085 );
00086 $this->mFlags = array_merge($f, $flags);
00087 foreach( $this->mVariants as $v) {
00088 $this->mManualLevel[$v]=array_key_exists($v,$manualLevel)
00089 ?$manualLevel[$v]
00090 :'bidirectional';
00091 $this->mManualAddTables[$v] = array();
00092 $this->mManualRemoveTables[$v] = array();
00093 $this->mNamespaceTables[$v] = array();
00094 $this->mFlags[$v] = $v;
00095 }
00096 }
00097
00101 function getVariants() {
00102 return $this->mVariants;
00103 }
00104
00116 function getVariantFallbacks($v) {
00117 if( isset( $this->mVariantFallbacks[$v] ) ) {
00118 return $this->mVariantFallbacks[$v];
00119 }
00120 return $this->mMainLanguageCode;
00121 }
00122
00129 function getPreferredVariant( $fromUser = true ) {
00130 global $wgUser, $wgRequest, $wgVariantArticlePath, $wgDefaultLanguageVariant;
00131
00132 if($this->mPreferredVariant)
00133 return $this->mPreferredVariant;
00134
00135
00136 if( $fromUser )
00137 $defaultUserLang = $wgUser->getOption( 'language' );
00138 else
00139 $defaultUserLang = $this->mMainLanguageCode;
00140 $userLang = $wgRequest->getVal( 'uselang', $defaultUserLang );
00141
00142 if( ! in_array( $userLang, $this->mVariants ) ){
00143 $this->mPreferredVariant = $this->mMainLanguageCode;
00144 return $this->mPreferredVariant;
00145 }
00146
00147
00148 $req = $wgRequest->getText( 'variant' );
00149 if( in_array( $req, $this->mVariants ) ) {
00150 $this->mPreferredVariant = $req;
00151 return $req;
00152 }
00153
00154
00155 if($wgVariantArticlePath!=false && isset($_SERVER['SCRIPT_NAME'])){
00156
00157
00158 $scriptBase = basename( $_SERVER['SCRIPT_NAME'] );
00159 if(in_array($scriptBase,$this->mVariants)){
00160 $this->mPreferredVariant = $scriptBase;
00161 return $this->mPreferredVariant;
00162 }
00163 }
00164
00165
00166
00167
00168 if( $fromUser && $wgUser->isLoggedIn() ) {
00169 $this->mPreferredVariant = $wgUser->getOption('variant');
00170 return $this->mPreferredVariant;
00171 }
00172
00173
00174 if($wgDefaultLanguageVariant != false && in_array( $wgDefaultLanguageVariant, $this->mVariants )){
00175 $this->mPreferredVariant = $wgDefaultLanguageVariant;
00176 return $this->mPreferredVariant;
00177 }
00178
00179 # FIXME rewrite code for parsing http header. The current code
00180 # is written specific for detecting zh- variants
00181 if( !$this->mPreferredVariant ) {
00182
00183
00184
00185
00186 $pv=$this->mMainLanguageCode;
00187 if(array_key_exists('HTTP_ACCEPT_LANGUAGE', $_SERVER)) {
00188 $header = str_replace( '_', '-', strtolower($_SERVER["HTTP_ACCEPT_LANGUAGE"]));
00189 $zh = strstr($header, $pv.'-');
00190 if($zh) {
00191 $ary = split("[,;]",$zh);
00192 $pv = $ary[0];
00193 }
00194 }
00195
00196 if(in_array( $pv, $this->mVariants ))
00197 return $pv;
00198 }
00199
00200 return $this->mMainLanguageCode;
00201
00202 }
00203
00213 function captionConvert( $matches ) {
00214 $toVariant = $this->getPreferredVariant();
00215 $title = $matches[1];
00216 $text = $matches[2];
00217
00218 if( !strpos( $text, '://' ) )
00219 $text = $this->translate($text, $toVariant);
00220 return " $title=\"$text\"";
00221 }
00222
00231 function autoConvert($text, $toVariant=false) {
00232 $fname="LanguageConverter::autoConvert";
00233
00234 wfProfileIn( $fname );
00235
00236 if(!$this->mTablesLoaded)
00237 $this->loadTables();
00238
00239 if(!$toVariant)
00240 $toVariant = $this->getPreferredVariant();
00241 if(!in_array($toVariant, $this->mVariants))
00242 return $text;
00243
00244
00245
00246
00247
00248
00249 global $wgParser;
00250 if (isset($wgParser) && $wgParser->UniqPrefix()!=''){
00251 $marker = '|' . $wgParser->UniqPrefix() . '[\-a-zA-Z0-9]+';
00252 } else
00253 $marker = "";
00254
00255
00256 $htmlfix = '|<[^>]+$|^[^<>]*>';
00257
00258
00259 $codefix = '<code>.+?<\/code>|';
00260
00261 $scriptfix = '<script.*?>.*?<\/script>|';
00262
00263 $prefix = '<pre.*?>.*?<\/pre>|';
00264
00265 $reg = '/'.$codefix . $scriptfix . $prefix . '<[^>]+>|&[a-zA-Z#][a-z0-9]+;' . $marker . $htmlfix . '/s';
00266
00267 $matches = preg_split($reg, $text, -1, PREG_SPLIT_OFFSET_CAPTURE);
00268
00269 $m = array_shift($matches);
00270
00271 $ret = $this->translate($m[0], $toVariant);
00272 $mstart = $m[1]+strlen($m[0]);
00273
00274
00275 $captionpattern = '/\s(title|alt)\s*=\s*"([\s\S]*?)"/';
00276 foreach($matches as $m) {
00277 $mark = substr($text, $mstart, $m[1]-$mstart);
00278 $mark = preg_replace_callback($captionpattern, array(&$this, 'captionConvert'), $mark);
00279 $ret .= $mark;
00280 $ret .= $this->translate($m[0], $toVariant);
00281 $mstart = $m[1] + strlen($m[0]);
00282 }
00283 wfProfileOut( $fname );
00284 return $ret;
00285 }
00286
00296 function translate( $text, $variant ) {
00297 wfProfileIn( __METHOD__ );
00298 if( !$this->mTablesLoaded )
00299 $this->loadTables();
00300 $text = $this->mTables[$variant]->replace( $text );
00301 wfProfileOut( __METHOD__ );
00302 return $text;
00303 }
00304
00312 function autoConvertToAllVariants($text) {
00313 $fname="LanguageConverter::autoConvertToAllVariants";
00314 wfProfileIn( $fname );
00315 if( !$this->mTablesLoaded )
00316 $this->loadTables();
00317
00318 $ret = array();
00319 foreach($this->mVariants as $variant) {
00320 $ret[$variant] = $this->translate($text, $variant);
00321 }
00322
00323 wfProfileOut( $fname );
00324 return $ret;
00325 }
00326
00334 function convertLinkToAllVariants($text) {
00335 if( !$this->mTablesLoaded )
00336 $this->loadTables();
00337
00338 $ret = array();
00339 $tarray = explode($this->mMarkup['begin'], $text);
00340 $tfirst = array_shift($tarray);
00341
00342 foreach($this->mVariants as $variant)
00343 $ret[$variant] = $this->translate($tfirst,$variant);
00344
00345 foreach($tarray as $txt) {
00346 $marked = explode($this->mMarkup['end'], $txt, 2);
00347
00348 foreach($this->mVariants as $variant){
00349 $ret[$variant] .= $this->mMarkup['begin'].$marked[0].$this->mMarkup['end'];
00350 if(array_key_exists(1, $marked))
00351 $ret[$variant] .= $this->translate($marked[1],$variant);
00352 }
00353
00354 }
00355
00356 return $ret;
00357 }
00358
00363 function prepareManualConv( $convRule ){
00364
00365 $title = $convRule->getTitle();
00366 if( $title ){
00367 $this->mTitleFromFlag = true;
00368 $this->mTitleDisplay = $title;
00369 }
00370
00371
00372 $convTable = $convRule->getConvTable();
00373 $action = $convRule->getRulesAction();
00374 foreach( $convTable as $v => $t ) {
00375 if( !in_array( $v, $this->mVariants ) )continue;
00376 if( $action=="add" ) {
00377 foreach( $t as $from => $to ) {
00378
00379
00380 if ( $from || $to )
00381
00382 $this->mManualAddTables[$v][$from] = $to;
00383 }
00384 }
00385 elseif ( $action == "remove" ) {
00386 foreach ( $t as $from=>$to ) {
00387 if ( $from || $to )
00388 $this->mManualRemoveTables[$v][$from] = $to;
00389 }
00390 }
00391 }
00392 }
00393
00398 function applyManualConv(){
00399
00400 foreach($this->mVariants as $v) {
00401 if (count($this->mManualAddTables[$v]) > 0) {
00402 $this->mTables[$v]->mergeArray($this->mManualAddTables[$v]);
00403 }
00404 if (count($this->mManualRemoveTables[$v]) > 0)
00405 $this->mTables[$v]->removeArray($this->mManualRemoveTables[$v]);
00406 }
00407 }
00408
00413 function parserConvert( $text, &$parser ) {
00414 global $wgDisableLangConversion;
00415
00416 if ( $parser->getTitle()->getNamespace() == NS_MEDIAWIKI &&
00417 strpos($parser->mTitle->getText(), "Conversiontable") !== false )
00418 {
00419 return $text;
00420 }
00421
00422 if ( $wgDisableLangConversion )
00423 return $text;
00424
00425 $text = $this->convert( $text );
00426
00427 if ( $this->mTitleFromFlag )
00428 $parser->mOutput->setTitleText( $this->mTitleDisplay );
00429 return $text;
00430 }
00431
00438 function convertNamespace( $title, $variant ) {
00439 $splittitle = explode( ':', $title );
00440 if (count($splittitle) < 2)
00441 return $title;
00442 if ( isset( $this->mNamespaceTables[$variant][$splittitle[0]] ) )
00443 $splittitle[0] = $this->mNamespaceTables[$variant][$splittitle[0]];
00444 $ret = implode(':', $splittitle );
00445 return $ret;
00446 }
00447
00452 function convertTitle( $text, $variant ){
00453 global $wgDisableTitleConversion, $wgUser;
00454
00455
00456 if( $wgDisableTitleConversion || !$this->mDoTitleConvert || $wgUser->getOption('noconvertlink') == 1 ) {
00457 $this->mTitleDisplay = $text;
00458 return $text;
00459 }
00460
00461
00462 if( $this->mTitleFromFlag ){
00463 $this->mTitleFromFlag = false;
00464 return $this->mTitleDisplay;
00465 }
00466
00467 global $wgRequest;
00468 $isredir = $wgRequest->getText( 'redirect', 'yes' );
00469 $action = $wgRequest->getText( 'action' );
00470 $linkconvert = $wgRequest->getText( 'linkconvert', 'yes' );
00471 if ( $isredir == 'no' || $action == 'edit' || $action == 'submit' || $linkconvert == 'no' ) {
00472 return $text;
00473 } else {
00474 $text = $this->convertNamespace( $text, $variant );
00475 $this->mTitleDisplay = $this->convert( $text );
00476 return $this->mTitleDisplay;
00477 }
00478 }
00479
00496 function convert( $text, $isTitle = false ) {
00497
00498 $mw =& MagicWord::get( 'notitleconvert' );
00499 if( $mw->matchAndRemove( $text ) )
00500 $this->mDoTitleConvert = false;
00501 $mw =& MagicWord::get( 'nocontentconvert' );
00502 if( $mw->matchAndRemove( $text ) ) {
00503 $this->mDoContentConvert = false;
00504 }
00505
00506
00507 $mw =& MagicWord::get( 'redirect' );
00508 if( $mw->matchStart( $text ) )
00509 return $text;
00510
00511 $plang = $this->getPreferredVariant();
00512
00513
00514 if ( $isTitle ) return $this->convertTitle( $text, $plang );
00515
00516 $tarray = StringUtils::explode( $this->mMarkup['end'], $text );
00517 $text = '';
00518
00519 $marks = array();
00520 foreach ( $tarray as $txt ) {
00521 $marked = explode( $this->mMarkup['begin'], $txt, 2 );
00522 if ( array_key_exists( 1, $marked ) ) {
00523 $crule = new ConverterRule($marked[1], $this);
00524 $crule->parse( $plang );
00525 $marked[1] = $crule->getDisplay();
00526 $this->prepareManualConv( $crule );
00527 }
00528 else
00529 $marked[0] .= $this->mMarkup['end'];
00530 array_push( $marks, $marked );
00531 }
00532 $this->applyManualConv();
00533 foreach ( $marks as $marked ) {
00534 if( $this->mDoContentConvert )
00535 $text .= $this->autoConvert( $marked[0], $plang );
00536 else
00537 $text .= $marked[0];
00538 if( array_key_exists( 1, $marked ) )
00539 $text .= $marked[1];
00540 }
00541
00542 $text = substr( $text, 0, -strlen( $this->mMarkup['end'] ) );
00543
00544 return $text;
00545 }
00546
00560 function findVariantLink( &$link, &$nt, $ignoreOtherCond = false ) {
00561 global $wgDisableLangConversion, $wgDisableTitleConversion, $wgRequest, $wgUser;
00562 $isredir = $wgRequest->getText( 'redirect', 'yes' );
00563 $action = $wgRequest->getText( 'action' );
00564 $linkconvert = $wgRequest->getText( 'linkconvert', 'yes' );
00565 $disableLinkConversion = $wgDisableLangConversion || $wgDisableTitleConversion;
00566 $linkBatch = new LinkBatch();
00567
00568 $ns=NS_MAIN;
00569
00570 if ( $disableLinkConversion || ( !$ignoreOtherCond && ( $isredir == 'no' || $action == 'edit'
00571 || $action == 'submit' || $linkconvert == 'no' || $wgUser->getOption('noconvertlink') == 1 ) ) )
00572 return;
00573
00574 if(is_object($nt))
00575 $ns = $nt->getNamespace();
00576
00577 $variants = $this->autoConvertToAllVariants($link);
00578 if($variants == false)
00579 return;
00580
00581 $titles = array();
00582
00583 foreach( $variants as $v ) {
00584 if($v != $link){
00585 $varnt = Title::newFromText( $v, $ns );
00586 if(!is_null($varnt)){
00587 $linkBatch->addObj($varnt);
00588 $titles[]=$varnt;
00589 }
00590 }
00591 }
00592
00593
00594 $linkBatch->execute();
00595
00596 foreach( $titles as $varnt ) {
00597 if( $varnt->getArticleID() > 0 ) {
00598 $nt = $varnt;
00599 $link = $varnt->getText();
00600 break;
00601 }
00602 }
00603 }
00604
00610 function getExtraHashOptions() {
00611 $variant = $this->getPreferredVariant();
00612 return '!' . $variant ;
00613 }
00614
00620 function getParsedTitle() {
00621 return $this->mTitleDisplay;
00622 }
00623
00629 function lockCache() {
00630 global $wgMemc;
00631 $success = false;
00632 for($i=0; $i<30; $i++) {
00633 if($success = $wgMemc->add($this->mCacheKey . "lock", 1, 10))
00634 break;
00635 sleep(1);
00636 }
00637 return $success;
00638 }
00639
00645 function unlockCache() {
00646 global $wgMemc;
00647 $wgMemc->delete($this->mCacheKey . "lock");
00648 }
00649
00650
00657 function loadDefaultTables() {
00658 $name = get_class($this);
00659 wfDie("Must implement loadDefaultTables() method in class $name");
00660 }
00661
00666 function loadTables($fromcache=true) {
00667 global $wgMemc;
00668 if( $this->mTablesLoaded )
00669 return;
00670 wfProfileIn( __METHOD__ );
00671 $this->mTablesLoaded = true;
00672 $this->mTables = false;
00673 if($fromcache) {
00674 wfProfileIn( __METHOD__.'-cache' );
00675 $this->mTables = $wgMemc->get( $this->mCacheKey );
00676 wfProfileOut( __METHOD__.'-cache' );
00677 }
00678 if ( !$this->mTables || !isset( $this->mTables[self::CACHE_VERSION_KEY] ) ) {
00679 wfProfileIn( __METHOD__.'-recache' );
00680
00681
00682
00683 $this->loadDefaultTables();
00684 foreach($this->mVariants as $var) {
00685 $cached = $this->parseCachedTable($var);
00686 $this->mTables[$var]->mergeArray($cached);
00687 }
00688
00689 $this->postLoadTables();
00690 $this->mTables[self::CACHE_VERSION_KEY] = true;
00691
00692 if($this->lockCache()) {
00693 $wgMemc->set($this->mCacheKey, $this->mTables, 43200);
00694 $this->unlockCache();
00695 }
00696 wfProfileOut( __METHOD__.'-recache' );
00697 }
00698 wfProfileOut( __METHOD__ );
00699 }
00700
00705 function postLoadTables() {}
00706
00712 function reloadTables() {
00713 if($this->mTables)
00714 unset($this->mTables);
00715 $this->mTablesLoaded = false;
00716 $this->loadTables(false);
00717 }
00718
00719
00734 function parseCachedTable($code, $subpage='', $recursive=true) {
00735 global $wgMessageCache;
00736 static $parsed = array();
00737
00738 if(!is_object($wgMessageCache))
00739 return array();
00740
00741 $key = 'Conversiontable/'.$code;
00742 if($subpage)
00743 $key .= '/' . $subpage;
00744
00745 if(array_key_exists($key, $parsed))
00746 return array();
00747
00748 if ( strpos( $code, '/' ) === false ) {
00749 $txt = $wgMessageCache->get( 'Conversiontable', true, $code );
00750 } else {
00751 $title = Title::makeTitleSafe( NS_MEDIAWIKI, "Conversiontable/$code" );
00752 if ( $title && $title->exists() ) {
00753 $article = new Article( $title );
00754 $txt = $article->getContents();
00755 } else {
00756 $txt = '';
00757 }
00758 }
00759
00760
00761
00762 $linkhead = $this->mLangObj->getNsText(NS_MEDIAWIKI) . ':Conversiontable';
00763 $subs = explode('[[', $txt);
00764 $sublinks = array();
00765 foreach( $subs as $sub ) {
00766 $link = explode(']]', $sub, 2);
00767 if(count($link) != 2)
00768 continue;
00769 $b = explode('|', $link[0]);
00770 $b = explode('/', trim($b[0]), 3);
00771 if(count($b)==3)
00772 $sublink = $b[2];
00773 else
00774 $sublink = '';
00775
00776 if($b[0] == $linkhead && $b[1] == $code) {
00777 $sublinks[] = $sublink;
00778 }
00779 }
00780
00781
00782
00783 $blocks = explode($this->mMarkup['begin'], $txt);
00784 array_shift($blocks);
00785 $ret = array();
00786 foreach($blocks as $block) {
00787 $mappings = explode($this->mMarkup['end'], $block, 2);
00788 $stripped = str_replace(array("'", '"', '*','#'), '', $mappings[0]);
00789 $table = explode( ';', $stripped );
00790 foreach( $table as $t ) {
00791 $m = explode( '=>', $t );
00792 if( count( $m ) != 2)
00793 continue;
00794
00795 $tt = explode('//', $m[1], 2);
00796 $ret[trim($m[0])] = trim($tt[0]);
00797 }
00798 }
00799 $parsed[$key] = true;
00800
00801
00802
00803 if($recursive) {
00804 foreach($sublinks as $link) {
00805 $s = $this->parseCachedTable($code, $link, $recursive);
00806 $ret = array_merge($ret, $s);
00807 }
00808 }
00809
00810 if ($this->mUcfirst) {
00811 foreach ($ret as $k => $v) {
00812 $ret[Language::ucfirst($k)] = Language::ucfirst($v);
00813 }
00814 }
00815 return $ret;
00816 }
00817
00826 function markNoConversion($text, $noParse=false) {
00827 # don't mark if already marked
00828 if(strpos($text, $this->mMarkup['begin']) ||
00829 strpos($text, $this->mMarkup['end']))
00830 return $text;
00831
00832 $ret = $this->mMarkup['begin'] .'R|'. $text . $this->mMarkup['end'];
00833 return $ret;
00834 }
00835
00840 function convertCategoryKey( $key ) {
00841 return $key;
00842 }
00848 function OnArticleSaveComplete($article, $user, $text, $summary, $isminor, $iswatch, $section, $flags, $revision) {
00849 $titleobj = $article->getTitle();
00850 if($titleobj->getNamespace() == NS_MEDIAWIKI) {
00851 $title = $titleobj->getDBkey();
00852 $t = explode('/', $title, 3);
00853 $c = count($t);
00854 if( $c > 1 && $t[0] == 'Conversiontable' ) {
00855 if(in_array($t[1], $this->mVariants)) {
00856 $this->reloadTables();
00857 }
00858 }
00859 }
00860 return true;
00861 }
00862
00868 function armourMath($text){
00869 $ret = $this->mMarkup['begin'] . 'R|' . $text . $this->mMarkup['end'];
00870 return $ret;
00871 }
00872 }
00873
00879 class ConverterRule {
00880 var $mText;
00881 var $mConverter;
00882 var $mManualCodeError='<strong class="error">code error!</strong>';
00883 var $mRuleDisplay = '',$mRuleTitle=false;
00884 var $mRules = '';
00885 var $mRulesAction = 'none';
00886 var $mFlags = array();
00887 var $mConvTable = array();
00888 var $mBidtable = array();
00889 var $mUnidtable = array();
00890
00898 function __construct($text,$converter){
00899 $this->mText = $text;
00900 $this->mConverter=$converter;
00901 foreach($converter->mVariants as $v){
00902 $this->mConvTable[$v]=array();
00903 }
00904 }
00905
00913 function getTextInBidtable($variants){
00914 if(is_string($variants)){ $variants=array($variants); }
00915 if(!is_array($variants)) return false;
00916 foreach ($variants as $variant){
00917 if(array_key_exists($variant, $this->mBidtable)){
00918 return $this->mBidtable[$variant];
00919 }
00920 }
00921 return false;
00922 }
00923
00928 function parseFlags(){
00929 $text = $this->mText;
00930 if(strlen($text) < 2 ) {
00931 $this->mFlags = array( 'R' );
00932 $this->mRules = $text;
00933 return;
00934 }
00935
00936 $flags = array();
00937 $markup = $this->mConverter->mMarkup;
00938 $validFlags = $this->mConverter->mFlags;
00939 $variants = $this->mConverter->mVariants;
00940
00941 $tt = explode($markup['flagsep'], $text, 2);
00942 if(count($tt) == 2) {
00943 $f = explode($markup['varsep'], $tt[0]);
00944 foreach($f as $ff) {
00945 $ff = trim($ff);
00946 if(array_key_exists($ff, $validFlags) &&
00947 !in_array($validFlags[$ff], $flags))
00948 $flags[] = $validFlags[$ff];
00949 }
00950 $rules = $tt[1];
00951 } else {
00952 $rules = $text;
00953 }
00954
00955
00956 if( in_array('R',$flags) ){
00957 $flags = array('R');
00958 } elseif ( in_array('N',$flags) ){
00959 $flags = array('N');
00960 } elseif ( in_array('-',$flags) ){
00961 $flags = array('-');
00962 } elseif (count($flags)==1 && $flags[0]=='T'){
00963 $flags[]='H';
00964 } elseif ( in_array('H',$flags) ){
00965
00966 $temp=array('+','H');
00967 if(in_array('T',$flags)) $temp[] = 'T';
00968 if(in_array('D',$flags)) $temp[] = 'D';
00969 $flags = $temp;
00970 } else {
00971 if ( in_array('A',$flags) ) {
00972 $flags[]='+';
00973 $flags[]='S';
00974 }
00975 if ( in_array('D',$flags) )
00976 $flags=array_diff($flags,array('S'));
00977 $flags_temp = array();
00978 foreach ($variants as $variant) {
00979
00980
00981 if ( in_array($variant, $flags) )
00982 $flags_temp[] = $variant;
00983 }
00984 if ( count($flags_temp) !== 0 )
00985 $flags = $flags_temp;
00986 }
00987 if ( count($flags) == 0 )
00988 $flags = array('S');
00989 $this->mRules=$rules;
00990 $this->mFlags=$flags;
00991 }
00992
00997 function parseRules() {
00998 $rules = $this->mRules;
00999 $flags = $this->mFlags;
01000 $bidtable = array();
01001 $unidtable = array();
01002 $markup = $this->mConverter->mMarkup;
01003 $variants = $this->mConverter->mVariants;
01004
01005
01006
01007
01008
01009
01010
01011
01012
01013
01014
01015 $varsep_pattern = '/' . $markup['varsep'] . '\s*' . '(?=';
01016 foreach( $variants as $variant ) {
01017 $varsep_pattern .= $variant . '\s*' . $markup['codesep'] . '|';
01018 $varsep_pattern .= '[^;]*?' . $markup['unidsep'] . '\s*' . $variant
01019 . '\s*' . $markup['codesep'] . '|';
01020 }
01021 $varsep_pattern .= '\s*$)/';
01022
01023 $choice = preg_split($varsep_pattern, $rules);
01024
01025 foreach( $choice as $c ) {
01026 $v = explode($markup['codesep'], $c, 2);
01027 if( count($v) != 2 )
01028 continue;
01029 $to = trim($v[1]);
01030 $v = trim($v[0]);
01031 $u = explode($markup['unidsep'], $v);
01032
01033 if( count($u) == 1 && $to && in_array( $v, $variants ) ) {
01034 $bidtable[$v] = $to;
01035 } else if(count($u) == 2){
01036 $from = trim($u[0]);
01037 $v = trim($u[1]);
01038 if( array_key_exists( $v, $unidtable ) && !is_array( $unidtable[$v] )
01039 && $to && in_array( $v, $variants ) )
01040 $unidtable[$v] = array( $from=>$to );
01041 elseif ( $to && in_array( $v, $variants ) )
01042 $unidtable[$v][$from] = $to;
01043 }
01044
01045 if ( !array_key_exists( $v, $this->mConverter->mVariantNames ) ){
01046 $bidtable = array();
01047 $unidtable = array();
01048 break;
01049 }
01050 }
01051 $this->mBidtable = $bidtable;
01052 $this->mUnidtable = $unidtable;
01053 }
01054
01058 function getRulesDesc(){
01059 $codesep = $this->mConverter->mDescCodeSep;
01060 $varsep = $this->mConverter->mDescVarSep;
01061 $text='';
01062 foreach($this->mBidtable as $k => $v)
01063 $text .= $this->mConverter->mVariantNames[$k]."$codesep$v$varsep";
01064 foreach($this->mUnidtable as $k => $a)
01065 foreach($a as $from=>$to)
01066 $text.=$from.'⇒'.$this->mConverter->mVariantNames[$k]."$codesep$to$varsep";
01067 return $text;
01068 }
01069
01074 function getRuleConvertedStr($variant,$doConvert){
01075 $bidtable = $this->mBidtable;
01076 $unidtable = $this->mUnidtable;
01077
01078 if( count($bidtable) + count($unidtable) == 0 ){
01079 return $this->mRules;
01080 } elseif ($doConvert){
01081
01082 $disp = $this->getTextInBidtable($variant);
01083
01084 if(!$disp)
01085 $disp = $this->getTextInBidtable(
01086 $this->mConverter->getVariantFallbacks($variant));
01087
01088 if(!$disp && array_key_exists($variant,$unidtable)){
01089 $disp = array_values($unidtable[$variant]);
01090 $disp = $disp[0];
01091 }
01092
01093 if(!$disp && $this->mConverter->mManualLevel[$variant]=='disable') {
01094 if(count($bidtable)>0){
01095 $disp = array_values($bidtable);
01096 $disp = $disp[0];
01097 } else {
01098 $disp = array_values($unidtable);
01099 $disp = array_values($disp[0]);
01100 $disp = $disp[0];
01101 }
01102 }
01103 return $disp;
01104 } else {
01105 return $this->mRules;
01106 }
01107 }
01108
01113 function generateConvTable(){
01114 $flags = $this->mFlags;
01115 $bidtable = $this->mBidtable;
01116 $unidtable = $this->mUnidtable;
01117 $manLevel = $this->mConverter->mManualLevel;
01118
01119 $vmarked=array();
01120 foreach($this->mConverter->mVariants as $v) {
01121
01122
01123
01124 if(!array_key_exists($v, $bidtable)) {
01125 $variantFallbacks = $this->mConverter->getVariantFallbacks($v);
01126 $vf = $this->getTextInBidtable($variantFallbacks);
01127 if($vf) $bidtable[$v] = $vf;
01128 }
01129
01130 if(array_key_exists($v,$bidtable)){
01131 foreach($vmarked as $vo){
01132
01133
01134
01135
01136 if($manLevel[$v]=='bidirectional'){
01137 $this->mConvTable[$v][$bidtable[$vo]]=$bidtable[$v];
01138 }
01139 if($manLevel[$vo]=='bidirectional'){
01140 $this->mConvTable[$vo][$bidtable[$v]]=$bidtable[$vo];
01141 }
01142 }
01143 $vmarked[]=$v;
01144 }
01145
01146
01147 $allow_unid = $manLevel[$v]=='bidirectional'
01148 || $manLevel[$v]=='unidirectional';
01149 if($allow_unid && array_key_exists($v,$unidtable)){
01150 $ct=$this->mConvTable[$v];
01151 $this->mConvTable[$v] = array_merge($ct,$unidtable[$v]);
01152 }
01153 }
01154 }
01155
01160 function parse($variant){
01161 if(!$variant)
01162 $variant = $this->mConverter->getPreferredVariant();
01163
01164 $variants = $this->mConverter->mVariants;
01165 $this->parseFlags();
01166 $flags = $this->mFlags;
01167
01168
01169
01170 if( count( array_diff( $flags, $variants ) ) == 0 and count( $flags ) != 0 ) {
01171 if ( in_array( $variant, $flags ) )
01172
01173 $this->mRules = $this->mConverter->autoConvert( $this->mRules, $variant );
01174 else {
01175
01176 $variantFallbacks = $this->mConverter->getVariantFallbacks($variant);
01177 foreach ( $variantFallbacks as $variantFallback ) {
01178
01179 if ( in_array( $variantFallback, $flags ) ) {
01180
01181 $this->mRules = $this->mConverter->autoConvert( $this->mRules, $variantFallback );
01182 break;
01183 }
01184 }
01185 }
01186 $this->mFlags = $flags = array('R');
01187 }
01188
01189 if( !in_array( 'R', $flags ) || !in_array( 'N', $flags ) ) {
01190
01191 $this->mRules = str_replace('=>','=>',$this->mRules);
01192
01193 $this->parseRules();
01194 }
01195 $rules = $this->mRules;
01196
01197 if( count( $this->mBidtable ) == 0 && count( $this->mUnidtable ) == 0 ){
01198 if(in_array('+',$flags) || in_array('-',$flags))
01199
01200 foreach($this->mConverter->mVariants as $v)
01201 $this->mBidtable[$v] = $rules;
01202 elseif (!in_array('N',$flags) && !in_array('T',$flags) )
01203 $this->mFlags = $flags = array('R');
01204 }
01205
01206 if( in_array('R',$flags) ) {
01207
01208 $this->mRuleDisplay = $rules;
01209 } elseif ( in_array('N',$flags) ){
01210
01211 $this->mRuleDisplay = $this->mConverter->mVariantNames[trim($rules)];
01212 } elseif ( in_array('D',$flags) ){
01213
01214 $this->mRuleDisplay = $this->getRulesDesc();
01215 } elseif ( in_array('H',$flags) || in_array('-',$flags) ) {
01216
01217 $this->mRuleDisplay = '';
01218 } elseif ( in_array('S',$flags) ){
01219 $this->mRuleDisplay = $this->getRuleConvertedStr($variant,
01220 $this->mConverter->mDoContentConvert);
01221 } else {
01222 $this->mRuleDisplay= $this->mManualCodeError;
01223 }
01224
01225 if ( in_array('T',$flags) ) {
01226 $this->mRuleTitle = $this->getRuleConvertedStr($variant,
01227 $this->mConverter->mDoTitleConvert);
01228 }
01229
01230 if (in_array('-', $flags))
01231 $this->mRulesAction='remove';
01232 if (in_array('+', $flags))
01233 $this->mRulesAction='add';
01234
01235 $this->generateConvTable();
01236 }
01237
01241 function hasRules(){
01242
01243 }
01244
01249 function getDisplay(){
01250 return $this->mRuleDisplay;
01251 }
01256 function getTitle(){
01257 return $this->mRuleTitle;
01258 }
01259
01264 function getRulesAction(){
01265 return $this->mRulesAction;
01266 }
01267
01272 function getConvTable(){
01273 return $this->mConvTable;
01274 }
01275
01280 function getRules(){
01281 return $this->mRules;
01282 }
01283
01288 function getFlags(){
01289 return $this->mFlags;
01290 }
01291 }