2005-04-15 14:12:39 +00:00
|
|
|
<?php
|
2008-06-26 03:00:34 +00:00
|
|
|
|
2005-04-15 14:12:39 +00:00
|
|
|
/**
|
WARNING: HUGE COMMIT
Doxygen documentation update:
* Changed alls @addtogroup to @ingroup. @addtogroup adds the comment to the group description, but doesn't add the file, class, function, ... to the group like @ingroup does. See for example http://svn.wikimedia.org/doc/group__SpecialPage.html where it's impossible to see related files, classes, ... that should belong to that group.
* Added @file to file description, it seems that it should be explicitely decalred for file descriptions, otherwise doxygen will think that the comment document the first class, variabled, function, ... that is in that file.
* Removed some empty comments
* Removed some ?>
Added following groups:
* ExternalStorage
* JobQueue
* MaintenanceLanguage
One more thing: there are still a lot of warnings when generating the doc.
2008-05-20 17:13:28 +00:00
|
|
|
* @ingroup Language
|
2005-04-15 14:21:56 +00:00
|
|
|
*
|
|
|
|
|
* @author Zhengzhu Feng <zhengzhu@gmail.com>
|
|
|
|
|
* @license http://www.gnu.org/copyleft/gpl.html GNU General Public License
|
2008-06-26 03:00:34 +00:00
|
|
|
* @maintainers fdcn <fdcn64@gmail.com>, shinjiman <shinjiman@gmail.com>
|
2005-04-15 14:12:39 +00:00
|
|
|
*/
|
|
|
|
|
|
|
|
|
|
class LanguageConverter {
|
|
|
|
|
var $mPreferredVariant='';
|
|
|
|
|
var $mMainLanguageCode;
|
2008-06-26 03:00:34 +00:00
|
|
|
var $mVariants, $mVariantFallbacks, $mVariantNames;
|
2005-04-15 14:12:39 +00:00
|
|
|
var $mTablesLoaded = false;
|
|
|
|
|
var $mTables;
|
|
|
|
|
var $mTitleDisplay='';
|
|
|
|
|
var $mDoTitleConvert=true, $mDoContentConvert=true;
|
2008-06-26 03:00:34 +00:00
|
|
|
var $mManualLevel; // 'bidirectional' 'unidirectional' 'disable' for each variants
|
2007-01-01 17:20:19 +00:00
|
|
|
var $mTitleFromFlag = false;
|
2005-04-15 14:12:39 +00:00
|
|
|
var $mCacheKey;
|
|
|
|
|
var $mLangObj;
|
|
|
|
|
var $mMarkup;
|
2005-04-20 02:33:04 +00:00
|
|
|
var $mFlags;
|
2005-05-19 17:34:09 +00:00
|
|
|
var $mUcfirst = false;
|
2007-12-03 04:54:28 +00:00
|
|
|
|
2008-06-26 03:00:34 +00:00
|
|
|
const CACHE_VERSION_KEY = 'VERSION 6';
|
2007-12-03 04:54:28 +00:00
|
|
|
|
2005-04-15 14:12:39 +00:00
|
|
|
/**
|
2008-06-26 03:00:34 +00:00
|
|
|
* Constructor
|
2005-04-15 14:12:39 +00:00
|
|
|
*
|
2008-06-26 03:00:34 +00:00
|
|
|
* @param string $maincode the main language code of this language
|
|
|
|
|
* @param array $variants the supported variants of this language
|
|
|
|
|
* @param array $variantfallback the fallback language of each variant
|
|
|
|
|
* @param array $markup array defining the markup used for manual conversion
|
2005-04-20 02:33:04 +00:00
|
|
|
* @param array $flags array defining the custom strings that maps to the flags
|
2008-06-26 03:00:34 +00:00
|
|
|
* @access public
|
|
|
|
|
*/
|
2006-06-24 18:48:58 +00:00
|
|
|
function __construct($langobj, $maincode,
|
2005-08-15 19:27:58 +00:00
|
|
|
$variants=array(),
|
|
|
|
|
$variantfallbacks=array(),
|
2005-04-20 02:33:04 +00:00
|
|
|
$markup=array(),
|
2008-06-26 03:00:34 +00:00
|
|
|
$flags = array(),
|
|
|
|
|
$manualLevel = array() ) {
|
2005-04-15 14:12:39 +00:00
|
|
|
$this->mLangObj = $langobj;
|
|
|
|
|
$this->mMainLanguageCode = $maincode;
|
2005-08-15 19:27:58 +00:00
|
|
|
$this->mVariants = $variants;
|
2005-04-15 14:12:39 +00:00
|
|
|
$this->mVariantFallbacks = $variantfallbacks;
|
2008-06-26 03:00:34 +00:00
|
|
|
global $wgLanguageNames;
|
|
|
|
|
$this->mVariantNames = $wgLanguageNames;
|
2006-12-27 01:49:09 +00:00
|
|
|
$this->mCacheKey = wfMemcKey( 'conversiontables', $maincode );
|
2008-06-26 03:00:34 +00:00
|
|
|
$m = array(
|
|
|
|
|
'begin'=>'-{',
|
|
|
|
|
'flagsep'=>'|',
|
|
|
|
|
'unidsep'=>'=>', //for unidirectional conversion
|
|
|
|
|
'codesep'=>':',
|
|
|
|
|
'varsep'=>';',
|
|
|
|
|
'end'=>'}-'
|
|
|
|
|
);
|
2005-04-20 02:33:04 +00:00
|
|
|
$this->mMarkup = array_merge($m, $markup);
|
2008-06-26 03:00:34 +00:00
|
|
|
$f = array(
|
|
|
|
|
// 'S' show converted text
|
|
|
|
|
// '+' add rules for alltext
|
|
|
|
|
// 'E' the gave flags is error
|
|
|
|
|
// these flags above are reserved for program
|
|
|
|
|
'A'=>'A', // add rule for convert code (all text convert)
|
|
|
|
|
'T'=>'T', // title convert
|
|
|
|
|
'R'=>'R', // raw content
|
|
|
|
|
'D'=>'D', // convert description (subclass implement)
|
|
|
|
|
'-'=>'-', // remove convert (not implement)
|
|
|
|
|
'H'=>'H', // add rule for convert code (but no display in placed code )
|
|
|
|
|
'N'=>'N' // current variant name
|
|
|
|
|
);
|
2005-04-20 02:33:04 +00:00
|
|
|
$this->mFlags = array_merge($f, $flags);
|
2008-06-26 03:00:34 +00:00
|
|
|
foreach( $this->mVariants as $v)
|
|
|
|
|
$this->mManualLevel[$v]=array_key_exists($v,$manualLevel)
|
|
|
|
|
?$manualLevel[$v]
|
|
|
|
|
:'bidirectional';
|
2005-04-15 14:12:39 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/**
|
2008-06-26 03:00:34 +00:00
|
|
|
* @access public
|
|
|
|
|
*/
|
2005-08-15 19:27:58 +00:00
|
|
|
function getVariants() {
|
2005-04-15 14:12:39 +00:00
|
|
|
return $this->mVariants;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/**
|
|
|
|
|
* in case some variant is not defined in the markup, we need
|
|
|
|
|
* to have some fallback. for example, in zh, normally people
|
2008-06-26 03:00:34 +00:00
|
|
|
* will define zh-hans and zh-hant, but less so for zh-sg or zh-hk.
|
|
|
|
|
* when zh-sg is preferred but not defined, we will pick zh-hans
|
2005-04-15 14:12:39 +00:00
|
|
|
* in this case. right now this is only used by zh.
|
2005-08-15 19:27:58 +00:00
|
|
|
*
|
2005-04-15 14:12:39 +00:00
|
|
|
* @param string $v the language code of the variant
|
2008-06-26 03:00:34 +00:00
|
|
|
* @return string array the code of the fallback language or false if there is no fallback
|
|
|
|
|
* @private
|
|
|
|
|
*/
|
|
|
|
|
function getVariantFallbacks($v) {
|
|
|
|
|
if( isset( $this->mVariantFallbacks[$v] ) ) {
|
|
|
|
|
return $this->mVariantFallbacks[$v];
|
|
|
|
|
}
|
|
|
|
|
return $this->mMainLanguageCode;
|
2005-04-15 14:12:39 +00:00
|
|
|
}
|
|
|
|
|
|
2005-08-15 19:27:58 +00:00
|
|
|
/**
|
2006-07-26 07:15:39 +00:00
|
|
|
* get preferred language variants.
|
|
|
|
|
* @param boolean $fromUser Get it from $wgUser's preferences
|
2008-06-26 03:00:34 +00:00
|
|
|
* @return string the preferred language code
|
|
|
|
|
* @access public
|
|
|
|
|
*/
|
2006-07-26 07:15:39 +00:00
|
|
|
function getPreferredVariant( $fromUser = true ) {
|
2007-01-01 17:20:19 +00:00
|
|
|
global $wgUser, $wgRequest, $wgVariantArticlePath, $wgDefaultLanguageVariant;
|
2005-08-15 19:27:58 +00:00
|
|
|
|
2005-04-15 14:12:39 +00:00
|
|
|
if($this->mPreferredVariant)
|
|
|
|
|
return $this->mPreferredVariant;
|
|
|
|
|
|
|
|
|
|
// see if the preference is set in the request
|
|
|
|
|
$req = $wgRequest->getText( 'variant' );
|
|
|
|
|
if( in_array( $req, $this->mVariants ) ) {
|
|
|
|
|
$this->mPreferredVariant = $req;
|
|
|
|
|
return $req;
|
|
|
|
|
}
|
|
|
|
|
|
2006-10-12 10:34:49 +00:00
|
|
|
// check the syntax /code/ArticleTitle
|
2006-12-14 02:16:49 +00:00
|
|
|
if($wgVariantArticlePath!=false && isset($_SERVER['SCRIPT_NAME'])){
|
|
|
|
|
// Note: SCRIPT_NAME probably won't hold the correct value if PHP is run as CGI
|
|
|
|
|
// (it will hold path to php.cgi binary), and might not exist on some very old PHP installations
|
|
|
|
|
$scriptBase = basename( $_SERVER['SCRIPT_NAME'] );
|
|
|
|
|
if(in_array($scriptBase,$this->mVariants)){
|
|
|
|
|
$this->mPreferredVariant = $scriptBase;
|
|
|
|
|
return $this->mPreferredVariant;
|
|
|
|
|
}
|
2006-10-12 10:34:49 +00:00
|
|
|
}
|
|
|
|
|
|
2005-08-15 19:27:58 +00:00
|
|
|
// get language variant preference from logged in users
|
2006-07-26 07:15:39 +00:00
|
|
|
// Don't call this on stub objects because that causes infinite
|
|
|
|
|
// recursion during initialisation
|
|
|
|
|
if( $fromUser && $wgUser->isLoggedIn() ) {
|
2005-04-15 14:12:39 +00:00
|
|
|
$this->mPreferredVariant = $wgUser->getOption('variant');
|
2005-07-05 05:21:53 +00:00
|
|
|
return $this->mPreferredVariant;
|
2005-04-15 14:12:39 +00:00
|
|
|
}
|
|
|
|
|
|
2007-01-01 17:20:19 +00:00
|
|
|
// see if default variant is globaly set
|
|
|
|
|
if($wgDefaultLanguageVariant != false && in_array( $wgDefaultLanguageVariant, $this->mVariants )){
|
|
|
|
|
$this->mPreferredVariant = $wgDefaultLanguageVariant;
|
|
|
|
|
return $this->mPreferredVariant;
|
|
|
|
|
}
|
|
|
|
|
|
2005-04-15 14:12:39 +00:00
|
|
|
# FIXME rewrite code for parsing http header. The current code
|
|
|
|
|
# is written specific for detecting zh- variants
|
|
|
|
|
if( !$this->mPreferredVariant ) {
|
2005-07-05 05:21:53 +00:00
|
|
|
// see if some supported language variant is set in the
|
|
|
|
|
// http header, but we don't set the mPreferredVariant
|
|
|
|
|
// variable in case this is called before the user's
|
|
|
|
|
// preference is loaded
|
|
|
|
|
$pv=$this->mMainLanguageCode;
|
2005-04-15 14:12:39 +00:00
|
|
|
if(array_key_exists('HTTP_ACCEPT_LANGUAGE', $_SERVER)) {
|
|
|
|
|
$header = str_replace( '_', '-', strtolower($_SERVER["HTTP_ACCEPT_LANGUAGE"]));
|
2006-11-06 17:46:58 +00:00
|
|
|
$zh = strstr($header, $pv.'-');
|
2005-04-15 14:12:39 +00:00
|
|
|
if($zh) {
|
2005-07-05 05:21:53 +00:00
|
|
|
$pv = substr($zh,0,5);
|
2005-04-15 14:12:39 +00:00
|
|
|
}
|
|
|
|
|
}
|
2007-01-01 17:20:19 +00:00
|
|
|
// don't try to return bad variant
|
|
|
|
|
if(in_array( $pv, $this->mVariants ))
|
|
|
|
|
return $pv;
|
2005-04-15 14:12:39 +00:00
|
|
|
}
|
2007-01-01 17:20:19 +00:00
|
|
|
|
|
|
|
|
return $this->mMainLanguageCode;
|
|
|
|
|
|
2005-04-15 14:12:39 +00:00
|
|
|
}
|
2008-06-26 03:00:34 +00:00
|
|
|
|
2005-04-15 14:12:39 +00:00
|
|
|
/**
|
2008-06-26 03:00:34 +00:00
|
|
|
* dictionary-based conversion
|
|
|
|
|
*
|
|
|
|
|
* @param string $text the text to be converted
|
|
|
|
|
* @param string $toVariant the target language code
|
|
|
|
|
* @return string the converted text
|
|
|
|
|
* @private
|
|
|
|
|
*/
|
2005-04-15 14:12:39 +00:00
|
|
|
function autoConvert($text, $toVariant=false) {
|
|
|
|
|
$fname="LanguageConverter::autoConvert";
|
2005-04-20 02:33:04 +00:00
|
|
|
|
2005-04-15 14:12:39 +00:00
|
|
|
wfProfileIn( $fname );
|
|
|
|
|
|
|
|
|
|
if(!$this->mTablesLoaded)
|
|
|
|
|
$this->loadTables();
|
|
|
|
|
|
2005-08-15 19:27:58 +00:00
|
|
|
if(!$toVariant)
|
2005-04-15 14:12:39 +00:00
|
|
|
$toVariant = $this->getPreferredVariant();
|
|
|
|
|
if(!in_array($toVariant, $this->mVariants))
|
|
|
|
|
return $text;
|
|
|
|
|
|
2006-01-24 18:36:45 +00:00
|
|
|
/* we convert everything except:
|
|
|
|
|
1. html markups (anything between < and >)
|
|
|
|
|
2. html entities
|
|
|
|
|
3. place holders created by the parser
|
|
|
|
|
*/
|
|
|
|
|
global $wgParser;
|
2008-07-04 15:01:41 +00:00
|
|
|
if (isset($wgParser) && $wgParser->UniqPrefix()!=''){
|
2006-01-24 18:36:45 +00:00
|
|
|
$marker = '|' . $wgParser->UniqPrefix() . '[\-a-zA-Z0-9]+';
|
2008-07-04 15:01:41 +00:00
|
|
|
} else
|
2006-01-24 18:36:45 +00:00
|
|
|
$marker = "";
|
2006-06-16 22:30:39 +00:00
|
|
|
|
|
|
|
|
// this one is needed when the text is inside an html markup
|
2006-09-20 10:22:12 +00:00
|
|
|
$htmlfix = '|<[^>]+$|^[^<>]*>';
|
2006-07-19 19:17:36 +00:00
|
|
|
|
2006-09-20 10:22:12 +00:00
|
|
|
// disable convert to variants between <code></code> tags
|
|
|
|
|
$codefix = '<code>.+?<\/code>|';
|
2006-12-26 12:19:45 +00:00
|
|
|
// disable convertsion of <script type="text/javascript"> ... </script>
|
|
|
|
|
$scriptfix = '<script.*?>.*?<\/script>|';
|
2008-07-04 15:01:41 +00:00
|
|
|
// disable conversion of <pre xxxx> ... </pre>
|
|
|
|
|
$prefix = '<pre.*?>.*?<\/pre>|';
|
2006-09-20 10:22:12 +00:00
|
|
|
|
2008-07-04 15:01:41 +00:00
|
|
|
$reg = '/'.$codefix . $scriptfix . $prefix . '<[^>]+>|&[a-zA-Z#][a-z0-9]+;' . $marker . $htmlfix . '/s';
|
2008-06-26 03:00:34 +00:00
|
|
|
|
2005-04-20 02:33:04 +00:00
|
|
|
$matches = preg_split($reg, $text, -1, PREG_SPLIT_OFFSET_CAPTURE);
|
|
|
|
|
|
2006-09-15 21:02:35 +00:00
|
|
|
$m = array_shift($matches);
|
2006-09-20 10:22:12 +00:00
|
|
|
|
2006-07-26 14:13:07 +00:00
|
|
|
$ret = $this->translate($m[0], $toVariant);
|
2005-04-20 02:33:04 +00:00
|
|
|
$mstart = $m[1]+strlen($m[0]);
|
|
|
|
|
foreach($matches as $m) {
|
|
|
|
|
$ret .= substr($text, $mstart, $m[1]-$mstart);
|
2006-07-26 14:13:07 +00:00
|
|
|
$ret .= $this->translate($m[0], $toVariant);
|
2005-04-20 02:33:04 +00:00
|
|
|
$mstart = $m[1] + strlen($m[0]);
|
2005-08-15 19:27:58 +00:00
|
|
|
}
|
2005-04-15 14:12:39 +00:00
|
|
|
wfProfileOut( $fname );
|
|
|
|
|
return $ret;
|
|
|
|
|
}
|
2005-08-15 19:27:58 +00:00
|
|
|
|
2006-07-26 14:13:07 +00:00
|
|
|
/**
|
|
|
|
|
* Translate a string to a variant
|
|
|
|
|
* Doesn't process markup or do any of that other stuff, for that use convert()
|
|
|
|
|
*
|
|
|
|
|
* @param string $text Text to convert
|
|
|
|
|
* @param string $variant Variant language code
|
|
|
|
|
* @return string Translated text
|
2008-07-04 15:01:41 +00:00
|
|
|
* @private
|
2006-07-26 14:13:07 +00:00
|
|
|
*/
|
|
|
|
|
function translate( $text, $variant ) {
|
2006-11-21 09:53:45 +00:00
|
|
|
wfProfileIn( __METHOD__ );
|
2006-07-26 14:13:07 +00:00
|
|
|
if( !$this->mTablesLoaded )
|
|
|
|
|
$this->loadTables();
|
2006-11-21 09:53:45 +00:00
|
|
|
$text = $this->mTables[$variant]->replace( $text );
|
|
|
|
|
wfProfileOut( __METHOD__ );
|
|
|
|
|
return $text;
|
2006-07-26 14:13:07 +00:00
|
|
|
}
|
|
|
|
|
|
2005-04-15 14:12:39 +00:00
|
|
|
/**
|
2008-06-26 03:00:34 +00:00
|
|
|
* convert text to all supported variants
|
|
|
|
|
*
|
|
|
|
|
* @param string $text the text to be converted
|
|
|
|
|
* @return array of string
|
|
|
|
|
* @public
|
|
|
|
|
*/
|
2006-07-19 20:13:39 +00:00
|
|
|
function autoConvertToAllVariants($text) {
|
2005-04-15 14:12:39 +00:00
|
|
|
$fname="LanguageConverter::autoConvertToAllVariants";
|
|
|
|
|
wfProfileIn( $fname );
|
|
|
|
|
if( !$this->mTablesLoaded )
|
|
|
|
|
$this->loadTables();
|
|
|
|
|
|
|
|
|
|
$ret = array();
|
|
|
|
|
foreach($this->mVariants as $variant) {
|
2006-07-26 14:13:07 +00:00
|
|
|
$ret[$variant] = $this->translate($text, $variant);
|
2005-04-15 14:12:39 +00:00
|
|
|
}
|
2006-09-20 10:22:12 +00:00
|
|
|
|
2005-04-15 14:12:39 +00:00
|
|
|
wfProfileOut( $fname );
|
|
|
|
|
return $ret;
|
|
|
|
|
}
|
|
|
|
|
|
2006-09-20 10:22:12 +00:00
|
|
|
/**
|
2008-06-26 03:00:34 +00:00
|
|
|
* convert link text to all supported variants
|
|
|
|
|
*
|
|
|
|
|
* @param string $text the text to be converted
|
|
|
|
|
* @return array of string
|
|
|
|
|
* @public
|
|
|
|
|
*/
|
2006-09-20 10:22:12 +00:00
|
|
|
function convertLinkToAllVariants($text) {
|
|
|
|
|
if( !$this->mTablesLoaded )
|
|
|
|
|
$this->loadTables();
|
|
|
|
|
|
|
|
|
|
$ret = array();
|
|
|
|
|
$tarray = explode($this->mMarkup['begin'], $text);
|
|
|
|
|
$tfirst = array_shift($tarray);
|
|
|
|
|
|
|
|
|
|
foreach($this->mVariants as $variant)
|
|
|
|
|
$ret[$variant] = $this->translate($tfirst,$variant);
|
|
|
|
|
|
|
|
|
|
foreach($tarray as $txt) {
|
|
|
|
|
$marked = explode($this->mMarkup['end'], $txt, 2);
|
|
|
|
|
|
|
|
|
|
foreach($this->mVariants as $variant){
|
|
|
|
|
$ret[$variant] .= $this->mMarkup['begin'].$marked[0].$this->mMarkup['end'];
|
|
|
|
|
if(array_key_exists(1, $marked))
|
|
|
|
|
$ret[$variant] .= $this->translate($marked[1],$variant);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
return $ret;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
2006-03-01 01:57:53 +00:00
|
|
|
/**
|
|
|
|
|
* Convert text using a parser object for context
|
2008-07-04 15:01:41 +00:00
|
|
|
* @public
|
2006-03-01 01:57:53 +00:00
|
|
|
*/
|
|
|
|
|
function parserConvert( $text, &$parser ) {
|
|
|
|
|
global $wgDisableLangConversion;
|
|
|
|
|
/* don't do anything if this is the conversion table */
|
2007-01-17 22:57:06 +00:00
|
|
|
if ( $parser->getTitle()->getNamespace() == NS_MEDIAWIKI &&
|
2006-09-20 10:22:12 +00:00
|
|
|
strpos($parser->mTitle->getText(), "Conversiontable") !== false )
|
2006-03-01 01:57:53 +00:00
|
|
|
{
|
|
|
|
|
return $text;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
if($wgDisableLangConversion)
|
|
|
|
|
return $text;
|
|
|
|
|
|
|
|
|
|
$text = $this->convert( $text );
|
|
|
|
|
$parser->mOutput->setTitleText( $this->mTitleDisplay );
|
|
|
|
|
return $text;
|
|
|
|
|
}
|
|
|
|
|
|
2008-07-04 15:01:41 +00:00
|
|
|
/**
|
|
|
|
|
* @access private
|
|
|
|
|
*/
|
2008-07-06 17:23:00 +00:00
|
|
|
function applyManualConv($convRule,$variant){
|
2008-06-26 03:00:34 +00:00
|
|
|
if(!$variant) $variant = $this->getPreferredVariant();
|
2008-07-06 17:23:00 +00:00
|
|
|
$rules = $convRule->getRules();
|
|
|
|
|
$flags = $convRule->getFlags();
|
|
|
|
|
list($bidtable, $unidtable) = $convRule->getConvTable();
|
2008-06-26 03:00:34 +00:00
|
|
|
|
|
|
|
|
$is_title_flag = in_array('T', $flags);
|
|
|
|
|
// use syntax -{T|zh:TitleZh;zh-tw:TitleTw}- for custom conversion in title
|
|
|
|
|
if($is_title_flag){
|
|
|
|
|
$this->mTitleFromFlag = true;
|
2008-07-06 17:23:00 +00:00
|
|
|
$this->mTitleDisplay = $convRule->getRulesTitle();
|
2008-06-26 03:00:34 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
if($this->mManualLevel[$variant]=='disable') return;
|
|
|
|
|
|
|
|
|
|
$is_remove_flag = !$is_title_flag && in_array('-', $flags);
|
|
|
|
|
$is_add_flag = !$is_remove_flag && in_array('+', $flags);
|
|
|
|
|
$is_bidMC = $this->mManualLevel[$variant]=='bidirectional';
|
|
|
|
|
$is_unidMC = $this->mManualLevel[$variant]=='unidirectional';
|
|
|
|
|
$vmarked=array();
|
|
|
|
|
|
|
|
|
|
foreach($this->mVariants as $v) {
|
|
|
|
|
/* for bidirectional array
|
|
|
|
|
fill in the missing variants, if any,
|
|
|
|
|
with fallbacks */
|
|
|
|
|
if($is_bidMC && !array_key_exists($v, $bidtable)) {
|
2008-07-06 17:23:00 +00:00
|
|
|
$vf = $convRule->getTextInBidtable($this->getVariantFallbacks($v) );
|
2008-06-26 03:00:34 +00:00
|
|
|
if($vf) $bidtable[$v] = $vf;
|
2007-01-03 14:37:15 +00:00
|
|
|
}
|
2008-06-26 03:00:34 +00:00
|
|
|
if($is_bidMC && array_key_exists($v,$bidtable)){
|
|
|
|
|
foreach($vmarked as $vo){
|
|
|
|
|
// use syntax:
|
|
|
|
|
// -{A|zh:WordZh;zh-tw:WordTw}- or -{+|zh:WordZh;zh-tw:WordTw}-
|
|
|
|
|
// to introduce a custom mapping between
|
|
|
|
|
// words WordZh and WordTw in the whole text
|
|
|
|
|
if($is_add_flag){
|
|
|
|
|
$this->mTables[$v]->setPair($bidtable[$vo], $bidtable[$v]);
|
|
|
|
|
$this->mTables[$vo]->setPair($bidtable[$v], $bidtable[$vo]);
|
|
|
|
|
}
|
|
|
|
|
// use syntax -{-|zh:WordZh;zh-tw:WordTw}- to remove a conversion
|
|
|
|
|
// words WordZh and WordTw in the whole text
|
|
|
|
|
if($is_remove_flag){
|
|
|
|
|
$this->mTables[$v]->removePair($bidtable[$vo]);
|
|
|
|
|
$this->mTables[$vo]->removePair($bidtable[$v]);
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
$vmarked[]=$v;
|
|
|
|
|
}
|
|
|
|
|
/*for unidirectional array
|
|
|
|
|
fill to convert tables */
|
|
|
|
|
if($is_unidMC && array_key_exists($v,$unidtable)){
|
|
|
|
|
if($is_add_flag)$this->mTables[$v]->mergeArray($unidtable[$v]);
|
|
|
|
|
if($is_remove_flag)$this->mTables[$v]->removeArray($unidtable[$v]);
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
2007-01-01 17:20:19 +00:00
|
|
|
|
2008-07-04 15:01:41 +00:00
|
|
|
/**
|
|
|
|
|
* convert title
|
|
|
|
|
* @private
|
|
|
|
|
*/
|
2008-06-26 03:00:34 +00:00
|
|
|
function convertTitle($text){
|
|
|
|
|
// check for __NOTC__ tag
|
|
|
|
|
if( !$this->mDoTitleConvert ) {
|
|
|
|
|
$this->mTitleDisplay = $text;
|
|
|
|
|
return $text;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// use the title from the T flag if any
|
|
|
|
|
if($this->mTitleFromFlag){
|
|
|
|
|
$this->mTitleFromFlag = false;
|
|
|
|
|
return $this->mTitleDisplay;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
global $wgRequest;
|
|
|
|
|
$isredir = $wgRequest->getText( 'redirect', 'yes' );
|
|
|
|
|
$action = $wgRequest->getText( 'action' );
|
|
|
|
|
if ( $isredir == 'no' || $action == 'edit' ) {
|
|
|
|
|
return $text;
|
|
|
|
|
} else {
|
|
|
|
|
$this->mTitleDisplay = $this->convert($text);
|
|
|
|
|
return $this->mTitleDisplay;
|
|
|
|
|
}
|
2007-01-01 17:20:19 +00:00
|
|
|
}
|
|
|
|
|
|
2005-04-15 14:12:39 +00:00
|
|
|
/**
|
|
|
|
|
* convert text to different variants of a language. the automatic
|
2005-08-15 19:27:58 +00:00
|
|
|
* conversion is done in autoConvert(). here we parse the text
|
|
|
|
|
* marked with -{}-, which specifies special conversions of the
|
2005-04-15 14:12:39 +00:00
|
|
|
* text that can not be accomplished in autoConvert()
|
|
|
|
|
*
|
|
|
|
|
* syntax of the markup:
|
|
|
|
|
* -{code1:text1;code2:text2;...}- or
|
2008-06-26 03:00:34 +00:00
|
|
|
* -{flags|code1:text1;code2:text2;...}- or
|
2005-04-15 14:12:39 +00:00
|
|
|
* -{text}- in which case no conversion should take place for text
|
2008-06-26 03:00:34 +00:00
|
|
|
*
|
|
|
|
|
* @param string $text text to be converted
|
|
|
|
|
* @param bool $isTitle whether this conversion is for the article title
|
|
|
|
|
* @return string converted text
|
|
|
|
|
* @access public
|
|
|
|
|
*/
|
2005-04-15 14:12:39 +00:00
|
|
|
function convert( $text , $isTitle=false) {
|
2008-06-26 03:00:34 +00:00
|
|
|
|
|
|
|
|
$mw =& MagicWord::get( 'notitleconvert' );
|
2005-04-15 14:12:39 +00:00
|
|
|
if( $mw->matchAndRemove( $text ) )
|
|
|
|
|
$this->mDoTitleConvert = false;
|
2008-06-26 03:00:34 +00:00
|
|
|
$mw =& MagicWord::get( 'nocontentconvert' );
|
2005-04-15 14:12:39 +00:00
|
|
|
if( $mw->matchAndRemove( $text ) ) {
|
|
|
|
|
$this->mDoContentConvert = false;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// no conversion if redirecting
|
2008-06-26 03:00:34 +00:00
|
|
|
$mw =& MagicWord::get( 'redirect' );
|
2005-04-15 14:12:39 +00:00
|
|
|
if( $mw->matchStart( $text ))
|
|
|
|
|
return $text;
|
|
|
|
|
|
2008-06-26 03:00:34 +00:00
|
|
|
// for title convertion
|
|
|
|
|
if ($isTitle) return $this->convertTitle($text);
|
2005-04-15 14:12:39 +00:00
|
|
|
|
|
|
|
|
$plang = $this->getPreferredVariant();
|
2005-04-20 02:33:04 +00:00
|
|
|
|
2005-04-15 14:12:39 +00:00
|
|
|
$tarray = explode($this->mMarkup['begin'], $text);
|
|
|
|
|
$tfirst = array_shift($tarray);
|
2007-01-02 22:59:11 +00:00
|
|
|
if($this->mDoContentConvert)
|
2008-06-26 03:00:34 +00:00
|
|
|
$text = $this->autoConvert($tfirst,$plang);
|
2007-01-02 22:59:11 +00:00
|
|
|
else
|
|
|
|
|
$text = $tfirst;
|
2008-06-26 03:00:34 +00:00
|
|
|
foreach($tarray as $txt) {
|
2006-04-29 23:24:23 +00:00
|
|
|
$marked = explode($this->mMarkup['end'], $txt, 2);
|
2005-04-20 02:33:04 +00:00
|
|
|
|
2007-01-01 17:20:19 +00:00
|
|
|
// strip the flags from syntax like -{T| ... }-
|
2008-07-06 17:23:00 +00:00
|
|
|
$crule = new ConverterRule($marked[0],
|
|
|
|
|
$this->mMarkup, $this->mFlags,
|
|
|
|
|
$this->mVariantNames,
|
|
|
|
|
$this->mDoContentConvert,
|
|
|
|
|
$this->mDoTitleConvert);
|
|
|
|
|
$crule->parseRules($plang,
|
|
|
|
|
$this->getVariantFallbacks($plang),
|
|
|
|
|
$this->mManualLevel[$plang]=='disable');
|
|
|
|
|
$text .= $crule->getRulesDisplay();
|
|
|
|
|
$this->applyManualConv($crule,$plang);
|
2007-01-01 17:20:19 +00:00
|
|
|
|
2007-01-02 22:59:11 +00:00
|
|
|
if(array_key_exists(1, $marked)){
|
|
|
|
|
if( $this->mDoContentConvert )
|
2008-06-26 03:00:34 +00:00
|
|
|
$text .= $this->autoConvert($marked[1],$plang);
|
2007-01-02 22:59:11 +00:00
|
|
|
else
|
|
|
|
|
$text .= $marked[1];
|
|
|
|
|
}
|
2005-04-15 14:12:39 +00:00
|
|
|
}
|
2005-08-15 19:27:58 +00:00
|
|
|
|
2005-04-15 14:12:39 +00:00
|
|
|
return $text;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/**
|
|
|
|
|
* if a language supports multiple variants, it is
|
|
|
|
|
* possible that non-existing link in one variant
|
2005-08-15 19:27:58 +00:00
|
|
|
* actually exists in another variant. this function
|
2005-04-15 14:12:39 +00:00
|
|
|
* tries to find it. See e.g. LanguageZh.php
|
|
|
|
|
*
|
|
|
|
|
* @param string $link the name of the link
|
|
|
|
|
* @param mixed $nt the title object of the link
|
|
|
|
|
* @return null the input parameters may be modified upon return
|
2008-06-26 03:00:34 +00:00
|
|
|
* @access public
|
2005-04-15 14:12:39 +00:00
|
|
|
*/
|
|
|
|
|
function findVariantLink( &$link, &$nt ) {
|
|
|
|
|
global $wgDisableLangConversion;
|
2006-12-11 23:33:27 +00:00
|
|
|
$linkBatch = new LinkBatch();
|
|
|
|
|
|
|
|
|
|
$ns=NS_MAIN;
|
|
|
|
|
|
2005-04-28 03:49:23 +00:00
|
|
|
if(is_object($nt))
|
|
|
|
|
$ns = $nt->getNamespace();
|
2006-09-20 10:22:12 +00:00
|
|
|
|
2005-04-15 14:12:39 +00:00
|
|
|
$variants = $this->autoConvertToAllVariants($link);
|
|
|
|
|
if($variants == false) //give up
|
|
|
|
|
return;
|
2006-12-11 23:33:27 +00:00
|
|
|
|
|
|
|
|
$titles = array();
|
|
|
|
|
|
2005-04-15 14:12:39 +00:00
|
|
|
foreach( $variants as $v ) {
|
2006-12-11 23:33:27 +00:00
|
|
|
if($v != $link){
|
|
|
|
|
$varnt = Title::newFromText( $v, $ns );
|
|
|
|
|
if(!is_null($varnt)){
|
|
|
|
|
$linkBatch->addObj($varnt);
|
|
|
|
|
$titles[]=$varnt;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// fetch all variants in single query
|
|
|
|
|
$linkBatch->execute();
|
|
|
|
|
|
|
|
|
|
foreach( $titles as $varnt ) {
|
|
|
|
|
if( $varnt->getArticleID() > 0 ) {
|
2005-04-15 14:12:39 +00:00
|
|
|
$nt = $varnt;
|
2005-04-28 03:49:23 +00:00
|
|
|
if( !$wgDisableLangConversion )
|
2005-04-15 14:12:39 +00:00
|
|
|
$link = $v;
|
|
|
|
|
break;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/**
|
2008-06-26 03:00:34 +00:00
|
|
|
* returns language specific hash options
|
|
|
|
|
*
|
|
|
|
|
* @access public
|
|
|
|
|
*/
|
2005-04-15 14:12:39 +00:00
|
|
|
function getExtraHashOptions() {
|
|
|
|
|
$variant = $this->getPreferredVariant();
|
|
|
|
|
return '!' . $variant ;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/**
|
2008-06-26 03:00:34 +00:00
|
|
|
* get title text as defined in the body of the article text
|
|
|
|
|
*
|
|
|
|
|
* @access public
|
|
|
|
|
*/
|
2005-04-15 14:12:39 +00:00
|
|
|
function getParsedTitle() {
|
|
|
|
|
return $this->mTitleDisplay;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/**
|
2008-06-26 03:00:34 +00:00
|
|
|
* a write lock to the cache
|
|
|
|
|
*
|
|
|
|
|
* @private
|
|
|
|
|
*/
|
2005-04-15 14:12:39 +00:00
|
|
|
function lockCache() {
|
|
|
|
|
global $wgMemc;
|
|
|
|
|
$success = false;
|
|
|
|
|
for($i=0; $i<30; $i++) {
|
|
|
|
|
if($success = $wgMemc->add($this->mCacheKey . "lock", 1, 10))
|
|
|
|
|
break;
|
|
|
|
|
sleep(1);
|
|
|
|
|
}
|
2005-08-15 19:27:58 +00:00
|
|
|
return $success;
|
2005-04-15 14:12:39 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/**
|
2008-06-26 03:00:34 +00:00
|
|
|
* unlock cache
|
|
|
|
|
*
|
|
|
|
|
* @private
|
|
|
|
|
*/
|
2005-04-15 14:12:39 +00:00
|
|
|
function unlockCache() {
|
|
|
|
|
global $wgMemc;
|
|
|
|
|
$wgMemc->delete($this->mCacheKey . "lock");
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
/**
|
2008-06-26 03:00:34 +00:00
|
|
|
* Load default conversion tables
|
|
|
|
|
* This method must be implemented in derived class
|
|
|
|
|
*
|
|
|
|
|
* @private
|
|
|
|
|
*/
|
2005-04-15 14:12:39 +00:00
|
|
|
function loadDefaultTables() {
|
|
|
|
|
$name = get_class($this);
|
2006-01-14 02:49:43 +00:00
|
|
|
wfDie("Must implement loadDefaultTables() method in class $name");
|
2005-04-15 14:12:39 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/**
|
2008-06-26 03:00:34 +00:00
|
|
|
* load conversion tables either from the cache or the disk
|
|
|
|
|
* @private
|
|
|
|
|
*/
|
2005-04-15 14:12:39 +00:00
|
|
|
function loadTables($fromcache=true) {
|
|
|
|
|
global $wgMemc;
|
|
|
|
|
if( $this->mTablesLoaded )
|
|
|
|
|
return;
|
2006-10-16 03:16:12 +00:00
|
|
|
wfProfileIn( __METHOD__ );
|
2005-04-15 14:12:39 +00:00
|
|
|
$this->mTablesLoaded = true;
|
2006-10-16 02:36:28 +00:00
|
|
|
$this->mTables = false;
|
2005-04-15 14:12:39 +00:00
|
|
|
if($fromcache) {
|
2006-10-16 03:16:12 +00:00
|
|
|
wfProfileIn( __METHOD__.'-cache' );
|
2005-04-15 14:12:39 +00:00
|
|
|
$this->mTables = $wgMemc->get( $this->mCacheKey );
|
2006-10-16 03:16:12 +00:00
|
|
|
wfProfileOut( __METHOD__.'-cache' );
|
2005-04-15 14:12:39 +00:00
|
|
|
}
|
2007-12-03 04:54:28 +00:00
|
|
|
if ( !$this->mTables || !isset( $this->mTables[self::CACHE_VERSION_KEY] ) ) {
|
2006-11-21 09:53:45 +00:00
|
|
|
wfProfileIn( __METHOD__.'-recache' );
|
2006-10-16 02:36:28 +00:00
|
|
|
// not in cache, or we need a fresh reload.
|
|
|
|
|
// we will first load the default tables
|
|
|
|
|
// then update them using things in MediaWiki:Zhconversiontable/*
|
|
|
|
|
$this->loadDefaultTables();
|
|
|
|
|
foreach($this->mVariants as $var) {
|
|
|
|
|
$cached = $this->parseCachedTable($var);
|
2006-11-21 09:53:45 +00:00
|
|
|
$this->mTables[$var]->mergeArray($cached);
|
2006-10-16 02:36:28 +00:00
|
|
|
}
|
2005-04-15 14:12:39 +00:00
|
|
|
|
2006-10-16 02:36:28 +00:00
|
|
|
$this->postLoadTables();
|
2007-12-03 04:54:28 +00:00
|
|
|
$this->mTables[self::CACHE_VERSION_KEY] = true;
|
2005-08-15 19:27:58 +00:00
|
|
|
|
2006-10-16 02:36:28 +00:00
|
|
|
if($this->lockCache()) {
|
|
|
|
|
$wgMemc->set($this->mCacheKey, $this->mTables, 43200);
|
|
|
|
|
$this->unlockCache();
|
|
|
|
|
}
|
2006-10-16 03:16:12 +00:00
|
|
|
wfProfileOut( __METHOD__.'-recache' );
|
2005-04-15 14:12:39 +00:00
|
|
|
}
|
2006-10-16 03:16:12 +00:00
|
|
|
wfProfileOut( __METHOD__ );
|
2006-07-26 14:13:07 +00:00
|
|
|
}
|
|
|
|
|
|
2005-04-15 14:12:39 +00:00
|
|
|
/**
|
2008-06-26 03:00:34 +00:00
|
|
|
* Hook for post processig after conversion tables are loaded
|
|
|
|
|
*
|
|
|
|
|
*/
|
2005-04-15 14:12:39 +00:00
|
|
|
function postLoadTables() {}
|
|
|
|
|
|
|
|
|
|
/**
|
2008-06-26 03:00:34 +00:00
|
|
|
* Reload the conversion tables
|
|
|
|
|
*
|
|
|
|
|
* @private
|
|
|
|
|
*/
|
2005-04-15 14:12:39 +00:00
|
|
|
function reloadTables() {
|
|
|
|
|
if($this->mTables)
|
|
|
|
|
unset($this->mTables);
|
|
|
|
|
$this->mTablesLoaded = false;
|
|
|
|
|
$this->loadTables(false);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
/**
|
2008-06-26 03:00:34 +00:00
|
|
|
* parse the conversion table stored in the cache
|
|
|
|
|
*
|
|
|
|
|
* the tables should be in blocks of the following form:
|
|
|
|
|
* -{
|
|
|
|
|
* word => word ;
|
|
|
|
|
* word => word ;
|
|
|
|
|
* ...
|
|
|
|
|
* }-
|
|
|
|
|
*
|
|
|
|
|
* to make the tables more manageable, subpages are allowed
|
|
|
|
|
* and will be parsed recursively if $recursive=true
|
|
|
|
|
*
|
2005-04-15 14:12:39 +00:00
|
|
|
*/
|
|
|
|
|
function parseCachedTable($code, $subpage='', $recursive=true) {
|
|
|
|
|
global $wgMessageCache;
|
|
|
|
|
static $parsed = array();
|
|
|
|
|
|
|
|
|
|
if(!is_object($wgMessageCache))
|
|
|
|
|
return array();
|
|
|
|
|
|
|
|
|
|
$key = 'Conversiontable/'.$code;
|
|
|
|
|
if($subpage)
|
|
|
|
|
$key .= '/' . $subpage;
|
|
|
|
|
|
|
|
|
|
if(array_key_exists($key, $parsed))
|
|
|
|
|
return array();
|
2005-08-15 19:27:58 +00:00
|
|
|
|
2008-07-05 15:39:10 +00:00
|
|
|
if ( strpos( $code, '/' ) === false ) {
|
|
|
|
|
$txt = $wgMessageCache->get( 'Conversiontable', true, $code );
|
|
|
|
|
} else {
|
|
|
|
|
$title = Title::makeTitleSafe( NS_MEDIAWIKI, "Conversiontable/$code" );
|
|
|
|
|
if ( $title && $title->exists() ) {
|
|
|
|
|
$article = new Article( $title );
|
|
|
|
|
$txt = $article->getContents();
|
|
|
|
|
} else {
|
|
|
|
|
$txt = '';
|
|
|
|
|
}
|
|
|
|
|
}
|
2005-04-15 14:12:39 +00:00
|
|
|
|
|
|
|
|
// get all subpage links of the form
|
|
|
|
|
// [[MediaWiki:conversiontable/zh-xx/...|...]]
|
|
|
|
|
$linkhead = $this->mLangObj->getNsText(NS_MEDIAWIKI) . ':Conversiontable';
|
|
|
|
|
$subs = explode('[[', $txt);
|
|
|
|
|
$sublinks = array();
|
|
|
|
|
foreach( $subs as $sub ) {
|
|
|
|
|
$link = explode(']]', $sub, 2);
|
|
|
|
|
if(count($link) != 2)
|
|
|
|
|
continue;
|
|
|
|
|
$b = explode('|', $link[0]);
|
|
|
|
|
$b = explode('/', trim($b[0]), 3);
|
|
|
|
|
if(count($b)==3)
|
|
|
|
|
$sublink = $b[2];
|
2005-08-15 19:27:58 +00:00
|
|
|
else
|
2005-04-15 14:12:39 +00:00
|
|
|
$sublink = '';
|
|
|
|
|
|
|
|
|
|
if($b[0] == $linkhead && $b[1] == $code) {
|
|
|
|
|
$sublinks[] = $sublink;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
// parse the mappings in this page
|
2005-04-20 02:33:04 +00:00
|
|
|
$blocks = explode($this->mMarkup['begin'], $txt);
|
2005-04-15 14:12:39 +00:00
|
|
|
array_shift($blocks);
|
2005-08-15 19:27:58 +00:00
|
|
|
$ret = array();
|
2005-04-15 14:12:39 +00:00
|
|
|
foreach($blocks as $block) {
|
2005-04-20 02:33:04 +00:00
|
|
|
$mappings = explode($this->mMarkup['end'], $block, 2);
|
2005-04-15 14:12:39 +00:00
|
|
|
$stripped = str_replace(array("'", '"', '*','#'), '', $mappings[0]);
|
|
|
|
|
$table = explode( ';', $stripped );
|
|
|
|
|
foreach( $table as $t ) {
|
|
|
|
|
$m = explode( '=>', $t );
|
|
|
|
|
if( count( $m ) != 2)
|
|
|
|
|
continue;
|
|
|
|
|
// trim any trailling comments starting with '//'
|
|
|
|
|
$tt = explode('//', $m[1], 2);
|
|
|
|
|
$ret[trim($m[0])] = trim($tt[0]);
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
$parsed[$key] = true;
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
// recursively parse the subpages
|
|
|
|
|
if($recursive) {
|
|
|
|
|
foreach($sublinks as $link) {
|
|
|
|
|
$s = $this->parseCachedTable($code, $link, $recursive);
|
|
|
|
|
$ret = array_merge($ret, $s);
|
|
|
|
|
}
|
|
|
|
|
}
|
2005-08-15 19:27:58 +00:00
|
|
|
|
2005-05-19 17:34:09 +00:00
|
|
|
if ($this->mUcfirst) {
|
|
|
|
|
foreach ($ret as $k => $v) {
|
2006-08-06 14:23:53 +00:00
|
|
|
$ret[Language::ucfirst($k)] = Language::ucfirst($v);
|
2005-05-19 17:34:09 +00:00
|
|
|
}
|
|
|
|
|
}
|
2005-04-15 14:12:39 +00:00
|
|
|
return $ret;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/**
|
|
|
|
|
* Enclose a string with the "no conversion" tag. This is used by
|
|
|
|
|
* various functions in the Parser
|
2005-08-15 19:27:58 +00:00
|
|
|
*
|
2005-04-15 14:12:39 +00:00
|
|
|
* @param string $text text to be tagged for no conversion
|
|
|
|
|
* @return string the tagged text
|
2008-07-04 15:01:41 +00:00
|
|
|
* @public
|
2008-06-26 03:00:34 +00:00
|
|
|
*/
|
2006-09-20 10:22:12 +00:00
|
|
|
function markNoConversion($text, $noParse=false) {
|
2005-04-20 02:33:04 +00:00
|
|
|
# don't mark if already marked
|
|
|
|
|
if(strpos($text, $this->mMarkup['begin']) ||
|
|
|
|
|
strpos($text, $this->mMarkup['end']))
|
|
|
|
|
return $text;
|
|
|
|
|
|
2008-06-26 03:00:34 +00:00
|
|
|
$ret = $this->mMarkup['begin'] .'R|'. $text . $this->mMarkup['end'];
|
2005-04-15 14:40:11 +00:00
|
|
|
return $ret;
|
2005-04-15 14:12:39 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/**
|
2005-08-15 19:27:58 +00:00
|
|
|
* convert the sorting key for category links. this should make different
|
2005-04-28 03:49:23 +00:00
|
|
|
* keys that are variants of each other map to the same key
|
2008-06-26 03:00:34 +00:00
|
|
|
*/
|
2005-04-28 03:49:23 +00:00
|
|
|
function convertCategoryKey( $key ) {
|
|
|
|
|
return $key;
|
|
|
|
|
}
|
|
|
|
|
/**
|
2008-06-26 03:00:34 +00:00
|
|
|
* hook to refresh the cache of conversion tables when
|
|
|
|
|
* MediaWiki:conversiontable* is updated
|
|
|
|
|
* @private
|
|
|
|
|
*/
|
2007-07-22 23:16:48 +00:00
|
|
|
function OnArticleSaveComplete($article, $user, $text, $summary, $isminor, $iswatch, $section, $flags, $revision) {
|
2005-04-15 14:12:39 +00:00
|
|
|
$titleobj = $article->getTitle();
|
2005-08-15 19:27:58 +00:00
|
|
|
if($titleobj->getNamespace() == NS_MEDIAWIKI) {
|
2005-04-15 14:12:39 +00:00
|
|
|
$title = $titleobj->getDBkey();
|
|
|
|
|
$t = explode('/', $title, 3);
|
|
|
|
|
$c = count($t);
|
|
|
|
|
if( $c > 1 && $t[0] == 'Conversiontable' ) {
|
|
|
|
|
if(in_array($t[1], $this->mVariants)) {
|
|
|
|
|
$this->reloadTables();
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
return true;
|
|
|
|
|
}
|
2006-09-20 10:22:12 +00:00
|
|
|
|
2006-12-11 23:33:27 +00:00
|
|
|
/**
|
|
|
|
|
* Armour rendered math against conversion
|
2007-01-03 14:37:15 +00:00
|
|
|
* Wrap math into rawoutput -{R| math }- syntax
|
2008-07-04 15:01:41 +00:00
|
|
|
* @public
|
2006-12-11 23:33:27 +00:00
|
|
|
*/
|
|
|
|
|
function armourMath($text){
|
2007-01-03 14:37:15 +00:00
|
|
|
$ret = $this->mMarkup['begin'] . 'R|' . $text . $this->mMarkup['end'];
|
|
|
|
|
return $ret;
|
2006-09-20 10:22:12 +00:00
|
|
|
}
|
2005-04-15 14:12:39 +00:00
|
|
|
}
|
2008-07-06 17:23:00 +00:00
|
|
|
|
|
|
|
|
/**
|
|
|
|
|
* @ingroup Language
|
|
|
|
|
* @author fdcn <fdcn64@gmail.com>
|
|
|
|
|
*/
|
|
|
|
|
class ConverterRule {
|
|
|
|
|
var $mText; // original text in -{text}-
|
|
|
|
|
var $mVariantNames;
|
|
|
|
|
var $mMarkup;
|
|
|
|
|
var $mRules;
|
|
|
|
|
var $mFlags;
|
|
|
|
|
var $mManualCodeError='<span style="color: red;">code error!</span>';
|
|
|
|
|
var $mDoTitleConvert=true, $mDoContentConvert=true;
|
|
|
|
|
var $ruleDisplay = '',$ruleTitle=false;
|
|
|
|
|
var $rules = '';// string $rule the text of the rule
|
|
|
|
|
var $flags = array();
|
|
|
|
|
var $bidtable = array();// array of the translation in each variant
|
|
|
|
|
var $unidtable = array();// array of the translation in each variant
|
|
|
|
|
|
|
|
|
|
/**
|
|
|
|
|
* Constructor
|
|
|
|
|
*
|
|
|
|
|
* @param string $text the text between -{ and }-
|
|
|
|
|
* @param array $markup the supported markup for conversion
|
|
|
|
|
* @param array $flags the supported flags for conversion
|
|
|
|
|
* @param array $variantNames the names list of supported language
|
|
|
|
|
* @param bool $doTitleConvert if do title convert
|
|
|
|
|
* @param bool $doContentConvert if do content convert
|
|
|
|
|
* @access public
|
|
|
|
|
*/
|
|
|
|
|
function __construct($text,$markup,$flags,$variantNames,
|
|
|
|
|
$doTitleConvert=true, $doContentConvert=true){
|
|
|
|
|
$this->mText = $text;
|
|
|
|
|
$this->mMarkup = $markup;
|
|
|
|
|
$this->mFlags = $flags;
|
|
|
|
|
$this->mVariantNames = $variantNames;
|
|
|
|
|
$this->mDoTitleConvert=$doTitleConvert;
|
|
|
|
|
$this->mDoContentConvert=$doContentConvert;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/**
|
|
|
|
|
* check if variants array in convert array
|
|
|
|
|
*
|
|
|
|
|
* @param string $variant Variant language code
|
|
|
|
|
* @return string Translated text
|
|
|
|
|
* @public
|
|
|
|
|
*/
|
|
|
|
|
function getTextInBidtable($variants){
|
|
|
|
|
if(is_string($variants)){ $variants=array($variants); }
|
|
|
|
|
if(!is_array($variants)) return false;
|
|
|
|
|
foreach ($variants as $variant){
|
|
|
|
|
if(array_key_exists($variant, $this->bidtable)){
|
|
|
|
|
return $this->bidtable[$variant];
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
return false;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/**
|
|
|
|
|
* Parse flags with syntax -{FLAG| ... }-
|
|
|
|
|
* @private
|
|
|
|
|
*/
|
|
|
|
|
function parseFlags(){
|
|
|
|
|
$flags = array();
|
|
|
|
|
$text = $this->mText;
|
|
|
|
|
|
|
|
|
|
// for multi-FLAGs
|
2008-07-07 01:12:15 +00:00
|
|
|
if(strlen($text) < 2 ) {
|
|
|
|
|
$this->flags = array( 'R' );
|
|
|
|
|
$this->rules = $text;
|
|
|
|
|
return;
|
|
|
|
|
}
|
2008-07-06 17:23:00 +00:00
|
|
|
|
|
|
|
|
$tt = explode($this->mMarkup['flagsep'], $text, 2);
|
|
|
|
|
|
|
|
|
|
if(count($tt) == 2) {
|
|
|
|
|
$f = explode($this->mMarkup['varsep'], $tt[0]);
|
|
|
|
|
foreach($f as $ff) {
|
|
|
|
|
$ff = trim($ff);
|
|
|
|
|
if(array_key_exists($ff, $this->mFlags) &&
|
|
|
|
|
!in_array($this->mFlags[$ff], $flags))
|
|
|
|
|
$flags[] = $this->mFlags[$ff];
|
|
|
|
|
}
|
|
|
|
|
$rules = $tt[1];
|
|
|
|
|
} else {
|
|
|
|
|
$rules = $text;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
if( !in_array('R',$flags) ){
|
|
|
|
|
//FIXME: may cause trouble here...
|
|
|
|
|
//strip since it interferes with the parsing, plus,
|
|
|
|
|
//all spaces should be stripped in this tag anyway.
|
|
|
|
|
$rules = str_replace(' ', '', $rules);
|
|
|
|
|
$rules = str_replace('=>','=>',$rules);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
//check flags
|
|
|
|
|
if( in_array('R',$flags) ){
|
|
|
|
|
$flags = array('R');// remove other flags
|
|
|
|
|
} elseif ( in_array('N',$flags) ){
|
|
|
|
|
$flags = array('N');// remove other flags
|
|
|
|
|
} elseif ( in_array('-',$flags) ){
|
|
|
|
|
$flags = array('-');// remove other flags
|
|
|
|
|
} elseif (count($flags)==1 && $flags[0]=='T'){
|
|
|
|
|
$flags[]='H';
|
|
|
|
|
} elseif ( in_array('H',$flags) ){
|
|
|
|
|
// replace A flag, and remove other flags except T
|
|
|
|
|
$temp=array('+','H');
|
|
|
|
|
if(in_array('T',$flags)) $temp[] = 'T';
|
|
|
|
|
if(in_array('D',$flags)) $temp[] = 'D';
|
|
|
|
|
$flags = $temp;
|
|
|
|
|
} else {
|
|
|
|
|
if ( in_array('A',$flags)) {
|
|
|
|
|
$flags[]='+';
|
|
|
|
|
$flags[]='S';
|
|
|
|
|
}
|
|
|
|
|
if ( in_array('D',$flags) )
|
|
|
|
|
$flags=array_diff($flags,array('S'));
|
|
|
|
|
}
|
|
|
|
|
if ( count($flags)==0 )
|
|
|
|
|
$flags = array('S');
|
|
|
|
|
$this->rules=$rules;
|
|
|
|
|
$this->flags=$flags;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/**
|
|
|
|
|
* generate conversion table
|
|
|
|
|
* @private
|
|
|
|
|
*/
|
|
|
|
|
function generateConvTable() {
|
|
|
|
|
$rules = $this->rules;
|
|
|
|
|
$flags = $this->flags;
|
|
|
|
|
$bidtable = array();
|
|
|
|
|
$unidtable = array();
|
|
|
|
|
$choice = explode($this->mMarkup['varsep'], $rules );
|
|
|
|
|
foreach($choice as $c) {
|
|
|
|
|
$v = explode($this->mMarkup['codesep'], $c);
|
|
|
|
|
if(count($v) != 2)
|
|
|
|
|
continue;// syntax error, skip
|
|
|
|
|
$to=trim($v[1]);
|
|
|
|
|
$v=trim($v[0]);
|
|
|
|
|
$u = explode($this->mMarkup['unidsep'], $v);
|
|
|
|
|
if(count($u) == 1) {
|
|
|
|
|
$bidtable[$v] = $to;
|
|
|
|
|
} else if(count($u) == 2){
|
|
|
|
|
$from=trim($u[0]);$v=trim($u[1]);
|
|
|
|
|
if( array_key_exists($v,$unidtable) && !is_array($unidtable[$v]) )
|
|
|
|
|
$unidtable[$v]=array($from=>$to);
|
|
|
|
|
else
|
|
|
|
|
$unidtable[$v][$from]=$to;
|
|
|
|
|
}
|
|
|
|
|
// syntax error, pass
|
|
|
|
|
if (!array_key_exists($v,$this->mVariantNames))
|
|
|
|
|
return;
|
|
|
|
|
}
|
|
|
|
|
$this->bidtable = $bidtable;
|
|
|
|
|
$this->unidtable = $unidtable;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/**
|
|
|
|
|
* @private
|
|
|
|
|
*/
|
|
|
|
|
function getRulesDesc(){
|
|
|
|
|
$text='';
|
|
|
|
|
foreach($this->bidtable as $k => $v)
|
|
|
|
|
$text .= $this->mVariantNames[$k].':'.$v.';';
|
|
|
|
|
foreach($this->unidtable as $k => $a)
|
|
|
|
|
foreach($a as $from=>$to)
|
|
|
|
|
$text.=$from.'⇒'.$this->mVariantNames[$k].':'.$to.';';
|
|
|
|
|
return $text;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/**
|
|
|
|
|
* Parse rules conversion
|
|
|
|
|
* @private
|
|
|
|
|
*/
|
|
|
|
|
function getRuleConvertedStr($variant,$variantFallbacks,
|
|
|
|
|
$doConvert,$isMCDisable=false){
|
|
|
|
|
$bidtable = $this->bidtable;
|
|
|
|
|
$unidtable = $this->unidtable;
|
|
|
|
|
|
|
|
|
|
if( count($bidtable) + count($unidtable) == 0 ){
|
|
|
|
|
return $this->rules;
|
|
|
|
|
} elseif ($doConvert){// the text converted
|
|
|
|
|
// display current variant in bidirectional array
|
|
|
|
|
$disp = $this->getTextInBidtable($variant);
|
|
|
|
|
// or display current variant in fallbacks
|
|
|
|
|
if(!$disp)
|
|
|
|
|
$disp = $this->getTextInBidtable($variantFallbacks);
|
|
|
|
|
// or display current variant in unidirectional array
|
|
|
|
|
if(!$disp && array_key_exists($variant,$unidtable)){
|
|
|
|
|
$disp = array_values($unidtable[$variant]);
|
|
|
|
|
$disp = $disp[0];
|
|
|
|
|
}
|
|
|
|
|
// or display frist text under disable manual convert
|
|
|
|
|
if(!$disp && $isMCDisable) {
|
|
|
|
|
if(count($bidtable)>0){
|
|
|
|
|
$disp = array_values($bidtable);
|
|
|
|
|
$disp = $disp[0];
|
|
|
|
|
} else {
|
|
|
|
|
$disp = array_values($unidtable);
|
|
|
|
|
$disp = array_values($disp[0]);
|
|
|
|
|
$disp = $disp[0];
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
return $disp;
|
|
|
|
|
} else {// no convert
|
|
|
|
|
return $this->rules;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
/**
|
|
|
|
|
* Parse rules and flags
|
|
|
|
|
* @public
|
|
|
|
|
*/
|
|
|
|
|
function parseRules($variant,$variantFallbacks,$isMCDisable=false){
|
|
|
|
|
$this->parseFlags();
|
|
|
|
|
$this->generateConvTable();
|
|
|
|
|
|
|
|
|
|
$rules = $this->rules;
|
|
|
|
|
$flags = $this->flags;
|
|
|
|
|
|
|
|
|
|
if(count($this->bidtable)==0 && count($this->unidtable)==0
|
|
|
|
|
&& !in_array('N',$flags) && !in_array('T',$flags) )
|
2008-07-07 01:12:15 +00:00
|
|
|
{
|
|
|
|
|
$flags = array('R');
|
|
|
|
|
}
|
2008-07-06 17:23:00 +00:00
|
|
|
|
|
|
|
|
if( in_array('R',$flags) ) {
|
|
|
|
|
// if we don't do content convert, still strip the -{}- tags
|
|
|
|
|
$this->ruleDisplay = $rules;
|
|
|
|
|
} elseif ( in_array('N',$flags) ){
|
|
|
|
|
// proces N flag: output current variant name
|
|
|
|
|
$this->ruleDisplay = $this->mVariantNames[trim($rules)];
|
|
|
|
|
} elseif ( in_array('D',$flags) ){
|
|
|
|
|
// proces D flag: output rules description
|
|
|
|
|
$this->ruleDisplay = $this->getRulesDesc();
|
|
|
|
|
} elseif ( in_array('H',$flags) || in_array('-',$flags) ) {
|
|
|
|
|
// proces H,- flag or T only: output nothing
|
|
|
|
|
$this->ruleDisplay = '';
|
|
|
|
|
} elseif ( in_array('S',$flags) ){
|
|
|
|
|
$this->ruleDisplay = $this->getRuleConvertedStr(
|
|
|
|
|
$variant,$variantFallbacks,
|
|
|
|
|
$this->mDoContentConvert,$isMCDisable);
|
|
|
|
|
} else {
|
|
|
|
|
$this->ruleDisplay= $this->mManualCodeError;
|
|
|
|
|
}
|
|
|
|
|
// proces T flag : output nothing
|
|
|
|
|
if ( in_array('T',$flags) ) {
|
|
|
|
|
$this->ruleTitle = $this->getRuleConvertedStr(
|
|
|
|
|
$variant,$variantFallbacks,
|
|
|
|
|
$this->mDoTitleConvert,$isMCDisable);
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/**
|
|
|
|
|
* get display text on markup -{...}-
|
|
|
|
|
* @param string $variant the current variant
|
|
|
|
|
* @public
|
|
|
|
|
*/
|
|
|
|
|
function getRulesDisplay(){
|
|
|
|
|
return $this->ruleDisplay;
|
|
|
|
|
}
|
|
|
|
|
/**
|
|
|
|
|
* get converted title
|
|
|
|
|
* @param string $variant the current variant
|
|
|
|
|
* @public
|
|
|
|
|
*/
|
|
|
|
|
function getRulesTitle(){
|
|
|
|
|
return $this->ruleTitle;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/**
|
|
|
|
|
* get conversion table ( bidirectional and unidirectional conversion table )
|
|
|
|
|
* @public
|
|
|
|
|
*/
|
|
|
|
|
function getConvTable(){
|
|
|
|
|
return array($this->bidtable, $this->unidtable);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/**
|
|
|
|
|
* get conversion rules string
|
|
|
|
|
* @public
|
|
|
|
|
*/
|
|
|
|
|
function getRules(){
|
|
|
|
|
return $this->rules;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/**
|
|
|
|
|
* get conversion flags
|
|
|
|
|
* @public
|
|
|
|
|
*/
|
|
|
|
|
function getFlags(){
|
|
|
|
|
return $this->flags;
|
|
|
|
|
}
|
|
|
|
|
}
|