Page Menu
Home
WickedGov Phorge
Search
Configure Global Search
Log In
Files
F5960495
ConverterRule.php
No One
Temporary
Actions
Download File
Edit File
Delete File
View Transforms
Subscribe
Flag For Later
Award Token
Size
14 KB
Referenced Files
None
Subscribers
None
ConverterRule.php
View Options
<?php
/**
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License along
* with this program; if not, write to the Free Software Foundation, Inc.,
* 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
* http://www.gnu.org/copyleft/gpl.html
*
* @file
* @author fdcn <fdcn64@gmail.com>, PhiLiP <philip.npc@gmail.com>
*/
namespace
MediaWiki\Language
;
use
MediaWiki\Logger\LoggerFactory
;
use
StringUtils
;
/**
* The rules used for language conversion, this processes the rules
* extracted by Parser from the `-{ }-` wikitext syntax.
*
* @ingroup Language
*/
class
ConverterRule
{
/**
* @var string original text in -{text}-
*/
public
$mText
;
/**
* @var LanguageConverter
*/
public
$mConverter
;
/** @var string|false */
public
$mRuleDisplay
=
''
;
/** @var string|false */
public
$mRuleTitle
=
false
;
/**
* @var string the text of the rules
*/
public
$mRules
=
''
;
/** @var string */
public
$mRulesAction
=
'none'
;
/** @var array */
public
$mFlags
=
[];
/** @var array */
public
$mVariantFlags
=
[];
/** @var array */
public
$mConvTable
=
[];
/**
* @var array of the translation in each variant
*/
public
$mBidtable
=
[];
/**
* @var array of the translation in each variant
*/
public
$mUnidtable
=
[];
/**
* @param string $text The text between -{ and }-
* @param LanguageConverter $converter
*/
public
function
__construct
(
$text
,
LanguageConverter
$converter
)
{
$this
->
mText
=
$text
;
$this
->
mConverter
=
$converter
;
}
/**
* Check if the variant array is in the convert array.
*
* @param array|string $variants Variant language code
* @return string|false Translated text
*/
public
function
getTextInBidtable
(
$variants
)
{
$variants
=
(
array
)
$variants
;
if
(
!
$variants
)
{
return
false
;
}
foreach
(
$variants
as
$variant
)
{
if
(
isset
(
$this
->
mBidtable
[
$variant
]
)
)
{
return
$this
->
mBidtable
[
$variant
];
}
}
return
false
;
}
/**
* Parse flags with syntax -{FLAG| ... }-
*/
private
function
parseFlags
()
{
$text
=
$this
->
mText
;
$flags
=
[];
$variantFlags
=
[];
$sepPos
=
strpos
(
$text
,
'|'
);
if
(
$sepPos
!==
false
)
{
$validFlags
=
$this
->
mConverter
->
getFlags
();
$f
=
StringUtils
::
explode
(
';'
,
substr
(
$text
,
0
,
$sepPos
)
);
foreach
(
$f
as
$ff
)
{
$ff
=
trim
(
$ff
);
if
(
isset
(
$validFlags
[
$ff
]
)
)
{
$flags
[
$validFlags
[
$ff
]]
=
true
;
}
}
$text
=
strval
(
substr
(
$text
,
$sepPos
+
1
)
);
}
if
(
!
$flags
)
{
$flags
[
'S'
]
=
true
;
}
elseif
(
isset
(
$flags
[
'R'
]
)
)
{
// remove other flags
$flags
=
[
'R'
=>
true
];
}
elseif
(
isset
(
$flags
[
'N'
]
)
)
{
// remove other flags
$flags
=
[
'N'
=>
true
];
}
elseif
(
isset
(
$flags
[
'-'
]
)
)
{
// remove other flags
$flags
=
[
'-'
=>
true
];
}
elseif
(
count
(
$flags
)
===
1
&&
isset
(
$flags
[
'T'
]
)
)
{
$flags
[
'H'
]
=
true
;
}
elseif
(
isset
(
$flags
[
'H'
]
)
)
{
// replace A flag, and remove other flags except T
$temp
=
[
'+'
=>
true
,
'H'
=>
true
];
if
(
isset
(
$flags
[
'T'
]
)
)
{
$temp
[
'T'
]
=
true
;
}
if
(
isset
(
$flags
[
'D'
]
)
)
{
$temp
[
'D'
]
=
true
;
}
$flags
=
$temp
;
}
else
{
if
(
isset
(
$flags
[
'A'
]
)
)
{
$flags
[
'+'
]
=
true
;
$flags
[
'S'
]
=
true
;
}
if
(
isset
(
$flags
[
'D'
]
)
)
{
unset
(
$flags
[
'S'
]
);
}
// try to find flags like "zh-hans", "zh-hant"
// allow syntaxes like "-{zh-hans;zh-hant|XXXX}-"
$variantFlags
=
array_intersect
(
array_keys
(
$flags
),
$this
->
mConverter
->
getVariants
()
);
if
(
$variantFlags
)
{
$variantFlags
=
array_fill_keys
(
$variantFlags
,
true
);
$flags
=
[];
}
}
$this
->
mVariantFlags
=
$variantFlags
;
$this
->
mRules
=
$text
;
$this
->
mFlags
=
$flags
;
}
/**
* Generate conversion table.
*/
private
function
parseRules
()
{
$rules
=
$this
->
mRules
;
$bidtable
=
[];
$unidtable
=
[];
$varsep_pattern
=
$this
->
mConverter
->
getVarSeparatorPattern
();
// Split text according to $varsep_pattern, but ignore semicolons from HTML entities
$rules
=
preg_replace
(
'/(&[#a-zA-Z0-9]+);/'
,
"$1
\x
01"
,
$rules
);
$choice
=
preg_split
(
$varsep_pattern
,
$rules
);
// @phan-suppress-next-line PhanTypeComparisonFromArray
if
(
$choice
===
false
)
{
$error
=
preg_last_error
();
$errorText
=
preg_last_error_msg
();
LoggerFactory
::
getInstance
(
'parser'
)->
warning
(
'ConverterRule preg_split error: {code} {errorText}'
,
[
'code'
=>
$error
,
'errorText'
=>
$errorText
]
);
$choice
=
[];
}
$choice
=
str_replace
(
"
\x
01"
,
';'
,
$choice
);
foreach
(
$choice
as
$c
)
{
$v
=
explode
(
':'
,
$c
,
2
);
if
(
count
(
$v
)
!==
2
)
{
// syntax error, skip
continue
;
}
$to
=
trim
(
$v
[
1
]
);
$v
=
trim
(
$v
[
0
]
);
$u
=
explode
(
'=>'
,
$v
,
2
);
$vv
=
$this
->
mConverter
->
validateVariant
(
$v
);
// if $to is empty (which is also used as $from in bidtable),
// strtr() could return a wrong result.
if
(
count
(
$u
)
===
1
&&
$to
!==
''
&&
$vv
)
{
$bidtable
[
$vv
]
=
$to
;
}
elseif
(
count
(
$u
)
===
2
)
{
$from
=
trim
(
$u
[
0
]
);
$v
=
trim
(
$u
[
1
]
);
$vv
=
$this
->
mConverter
->
validateVariant
(
$v
);
// if $from is empty, strtr() could return a wrong result.
if
(
array_key_exists
(
$vv
,
$unidtable
)
&&
!
is_array
(
$unidtable
[
$vv
]
)
&&
$from
!==
''
&&
$vv
)
{
$unidtable
[
$vv
]
=
[
$from
=>
$to
];
}
elseif
(
$from
!==
''
&&
$vv
)
{
$unidtable
[
$vv
][
$from
]
=
$to
;
}
}
// syntax error, pass
if
(
!
isset
(
$this
->
mConverter
->
getVariantNames
()[
$vv
]
)
)
{
$bidtable
=
[];
$unidtable
=
[];
break
;
}
}
$this
->
mBidtable
=
$bidtable
;
$this
->
mUnidtable
=
$unidtable
;
}
/**
* @return string
*/
private
function
getRulesDesc
()
{
$codesep
=
$this
->
mConverter
->
getDescCodeSeparator
();
$varsep
=
$this
->
mConverter
->
getDescVarSeparator
();
$text
=
''
;
foreach
(
$this
->
mBidtable
as
$k
=>
$v
)
{
$text
.=
$this
->
mConverter
->
getVariantNames
()[
$k
]
.
"$codesep$v$varsep"
;
}
foreach
(
$this
->
mUnidtable
as
$k
=>
$a
)
{
foreach
(
$a
as
$from
=>
$to
)
{
$text
.=
$from
.
'⇒'
.
$this
->
mConverter
->
getVariantNames
()[
$k
]
.
"$codesep$to$varsep"
;
}
}
return
$text
;
}
/**
* Parse rules conversion.
*
* @param string $variant
*
* @return string
*/
private
function
getRuleConvertedStr
(
$variant
)
{
$bidtable
=
$this
->
mBidtable
;
$unidtable
=
$this
->
mUnidtable
;
if
(
count
(
$bidtable
)
+
count
(
$unidtable
)
===
0
)
{
return
$this
->
mRules
;
}
// display current variant in bidirectional array
$disp
=
$this
->
getTextInBidtable
(
$variant
);
// or display current variant in fallbacks
if
(
$disp
===
false
)
{
$disp
=
$this
->
getTextInBidtable
(
$this
->
mConverter
->
getVariantFallbacks
(
$variant
)
);
}
// or display current variant in unidirectional array
if
(
$disp
===
false
&&
array_key_exists
(
$variant
,
$unidtable
)
)
{
$disp
=
array_values
(
$unidtable
[
$variant
]
)[
0
];
}
// or display first text under disable manual convert
if
(
$disp
===
false
&&
$this
->
mConverter
->
getManualLevel
()[
$variant
]
===
'disable'
)
{
if
(
count
(
$bidtable
)
>
0
)
{
$disp
=
array_values
(
$bidtable
)[
0
];
}
else
{
$disp
=
array_values
(
array_values
(
$unidtable
)[
0
]
)[
0
];
}
}
return
$disp
;
}
/**
* Similar to getRuleConvertedStr(), but this prefers to use MediaWiki\Title\Title;
* use original page title if $variant === $this->mConverter->getMainCode(),
* and may return false in this case (so this title conversion rule
* will be ignored and the original title is shown).
*
* @since 1.22
* @param string $variant The variant code to display page title in
* @return string|false The converted title or false if just page name
*/
private
function
getRuleConvertedTitle
(
$variant
)
{
if
(
$variant
===
$this
->
mConverter
->
getMainCode
()
)
{
// If a string targeting exactly this variant is set,
// use it. Otherwise, just return false, so the real
// page name can be shown (and because variant === main,
// there'll be no further automatic conversion).
$disp
=
$this
->
getTextInBidtable
(
$variant
);
if
(
$disp
)
{
return
$disp
;
}
if
(
array_key_exists
(
$variant
,
$this
->
mUnidtable
)
)
{
$disp
=
array_values
(
$this
->
mUnidtable
[
$variant
]
)[
0
];
}
// Assigned above or still false.
return
$disp
;
}
return
$this
->
getRuleConvertedStr
(
$variant
);
}
/**
* Generate conversion table for all text.
*/
private
function
generateConvTable
()
{
// Special case optimisation
if
(
!
$this
->
mBidtable
&&
!
$this
->
mUnidtable
)
{
$this
->
mConvTable
=
[];
return
;
}
$bidtable
=
$this
->
mBidtable
;
$unidtable
=
$this
->
mUnidtable
;
$manLevel
=
$this
->
mConverter
->
getManualLevel
();
$vmarked
=
[];
foreach
(
$this
->
mConverter
->
getVariants
()
as
$v
)
{
/* for bidirectional array
fill in the missing variants, if any,
with fallbacks */
if
(
!
isset
(
$bidtable
[
$v
]
)
)
{
$variantFallbacks
=
$this
->
mConverter
->
getVariantFallbacks
(
$v
);
$vf
=
$this
->
getTextInBidtable
(
$variantFallbacks
);
if
(
$vf
)
{
$bidtable
[
$v
]
=
$vf
;
}
}
if
(
isset
(
$bidtable
[
$v
]
)
)
{
foreach
(
$vmarked
as
$vo
)
{
// use syntax: -{A|zh:WordZh;zh-tw:WordTw}-
// or -{H|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
(
$manLevel
[
$v
]
===
'bidirectional'
)
{
$this
->
mConvTable
[
$v
][
$bidtable
[
$vo
]]
=
$bidtable
[
$v
];
}
if
(
$manLevel
[
$vo
]
===
'bidirectional'
)
{
$this
->
mConvTable
[
$vo
][
$bidtable
[
$v
]]
=
$bidtable
[
$vo
];
}
}
$vmarked
[]
=
$v
;
}
/* for unidirectional array fill to convert tables */
if
(
(
$manLevel
[
$v
]
===
'bidirectional'
||
$manLevel
[
$v
]
===
'unidirectional'
)
&&
isset
(
$unidtable
[
$v
]
)
)
{
if
(
isset
(
$this
->
mConvTable
[
$v
]
)
)
{
$this
->
mConvTable
[
$v
]
=
$unidtable
[
$v
]
+
$this
->
mConvTable
[
$v
];
}
else
{
$this
->
mConvTable
[
$v
]
=
$unidtable
[
$v
];
}
}
}
}
/**
* Parse rules and flags.
* @param string|null $variant Variant language code
*/
public
function
parse
(
$variant
=
null
)
{
if
(
!
$variant
)
{
$variant
=
$this
->
mConverter
->
getPreferredVariant
();
}
$this
->
parseFlags
();
$flags
=
$this
->
mFlags
;
// convert to specified variant
// syntax: -{zh-hans;zh-hant[;...]|<text to convert>}-
if
(
$this
->
mVariantFlags
)
{
// check if current variant in flags
if
(
isset
(
$this
->
mVariantFlags
[
$variant
]
)
)
{
// then convert <text to convert> to current language
$this
->
mRules
=
$this
->
mConverter
->
autoConvert
(
$this
->
mRules
,
$variant
);
}
else
{
// if the current variant is not in flags,
// then we check its fallback variants.
$variantFallbacks
=
$this
->
mConverter
->
getVariantFallbacks
(
$variant
);
if
(
is_array
(
$variantFallbacks
)
)
{
foreach
(
$variantFallbacks
as
$variantFallback
)
{
// if current variant's fallback exist in flags
if
(
isset
(
$this
->
mVariantFlags
[
$variantFallback
]
)
)
{
// then convert <text to convert> to fallback language
$this
->
mRules
=
$this
->
mConverter
->
autoConvert
(
$this
->
mRules
,
$variantFallback
);
break
;
}
}
}
}
$this
->
mFlags
=
$flags
=
[
'R'
=>
true
];
}
if
(
!
isset
(
$flags
[
'R'
]
)
&&
!
isset
(
$flags
[
'N'
]
)
)
{
// decode => HTML entities modified by Sanitizer::internalRemoveHtmlTags
$this
->
mRules
=
str_replace
(
'=>'
,
'=>'
,
$this
->
mRules
);
$this
->
parseRules
();
}
$rules
=
$this
->
mRules
;
if
(
!
$this
->
mBidtable
&&
!
$this
->
mUnidtable
)
{
if
(
isset
(
$flags
[
'+'
]
)
||
isset
(
$flags
[
'-'
]
)
)
{
// fill all variants if the text in -{A/H/-|text}- is non-empty but without rules
if
(
$rules
!==
''
)
{
foreach
(
$this
->
mConverter
->
getVariants
()
as
$v
)
{
$this
->
mBidtable
[
$v
]
=
$rules
;
}
}
}
elseif
(
!
isset
(
$flags
[
'N'
]
)
&&
!
isset
(
$flags
[
'T'
]
)
)
{
$this
->
mFlags
=
$flags
=
[
'R'
=>
true
];
}
}
$this
->
mRuleDisplay
=
false
;
foreach
(
$flags
as
$flag
=>
$unused
)
{
switch
(
$flag
)
{
case
'R'
:
// if we don't do content convert, still strip the -{}- tags
$this
->
mRuleDisplay
=
$rules
;
break
;
case
'N'
:
// process N flag: output current variant name
$ruleVar
=
trim
(
$rules
);
$this
->
mRuleDisplay
=
$this
->
mConverter
->
getVariantNames
()[
$ruleVar
]
??
''
;
break
;
case
'D'
:
// process D flag: output rules description
$this
->
mRuleDisplay
=
$this
->
getRulesDesc
();
break
;
case
'H'
:
// process H,- flag or T only: output nothing
$this
->
mRuleDisplay
=
''
;
break
;
case
'-'
:
$this
->
mRulesAction
=
'remove'
;
$this
->
mRuleDisplay
=
''
;
break
;
case
'+'
:
$this
->
mRulesAction
=
'add'
;
$this
->
mRuleDisplay
=
''
;
break
;
case
'S'
:
$this
->
mRuleDisplay
=
$this
->
getRuleConvertedStr
(
$variant
);
break
;
case
'T'
:
$this
->
mRuleTitle
=
$this
->
getRuleConvertedTitle
(
$variant
);
$this
->
mRuleDisplay
=
''
;
break
;
default
:
// ignore unknown flags (but see error-case below)
}
}
if
(
$this
->
mRuleDisplay
===
false
)
{
$this
->
mRuleDisplay
=
'<span class="error">'
.
wfMessage
(
'converter-manual-rule-error'
)->
inContentLanguage
()->
escaped
()
.
'</span>'
;
}
$this
->
generateConvTable
();
}
/**
* Checks if there are conversion rules.
* @return bool
*/
public
function
hasRules
()
{
return
$this
->
mRules
!==
''
;
}
/**
* Get display text on markup -{...}-
* @return string
*/
public
function
getDisplay
()
{
return
$this
->
mRuleDisplay
;
}
/**
* Get converted title.
* @return string|false
*/
public
function
getTitle
()
{
return
$this
->
mRuleTitle
;
}
/**
* Return how to deal with conversion rules.
* @return string
*/
public
function
getRulesAction
()
{
return
$this
->
mRulesAction
;
}
/**
* Get conversion table. (bidirectional and unidirectional
* conversion table)
* @return array
*/
public
function
getConvTable
()
{
return
$this
->
mConvTable
;
}
/**
* Get conversion rules string.
* @return string
*/
public
function
getRules
()
{
return
$this
->
mRules
;
}
/**
* Get conversion flags.
* @return array
*/
public
function
getFlags
()
{
return
$this
->
mFlags
;
}
}
/** @deprecated class alias since 1.43 */
class_alias
(
ConverterRule
::
class
,
'ConverterRule'
);
File Metadata
Details
Attached
Mime Type
text/x-php
Expires
Sat, Oct 3, 07:21 (2 w, 13 h ago)
Storage Engine
local-disk
Storage Format
Raw Data
Storage Handle
af/91/d1de47feb9c304e7f109bef50120
Default Alt Text
ConverterRule.php (14 KB)
Attached To
Mode
rMWPROD MediaWiki Production
Attached
Detach File
Event Timeline
Log In to Comment