162 const FORMAT_PLAIN =
'plain';
164 const FORMAT_BLOCK_PARSE =
'block-parse';
166 const FORMAT_PARSE =
'parse';
168 const FORMAT_TEXT =
'text';
170 const FORMAT_ESCAPED =
'escaped';
176 protected static $listTypeMap = [
177 'comma' =>
'commaList',
178 'semicolon' =>
'semicolonList',
179 'pipe' =>
'pipeList',
180 'text' =>
'listToText',
189 protected $interface =
true;
196 protected $language =
false;
207 protected $keysToTry;
212 protected $parameters = [];
218 protected $format =
'parse';
223 protected $useDatabase =
true;
249 public function __construct( $key,
$params = [],
Language $language =
null ) {
252 throw new InvalidArgumentException(
253 '$params must be empty if $key is a MessageSpecifier'
257 $key = $key->getKey();
260 if ( !is_string( $key ) && !is_array( $key ) ) {
261 throw new InvalidArgumentException(
'$key must be a string or an array' );
264 $this->keysToTry = (
array)$key;
266 if ( empty( $this->keysToTry ) ) {
267 throw new InvalidArgumentException(
'$key must not be an empty list' );
270 $this->
key = reset( $this->keysToTry );
272 $this->parameters = array_values(
$params );
275 $this->
language = $language ?:
false;
285 'interface' => $this->interface,
288 'keysToTry' => $this->keysToTry,
289 'parameters' => $this->parameters,
290 'format' => $this->format,
291 'useDatabase' => $this->useDatabase,
292 'titlestr' => $this->
title ? $this->
title->getFullText() :
null,
303 if ( !is_array(
$data ) ) {
304 throw new InvalidArgumentException( __METHOD__ .
': Invalid serialized data' );
307 $this->
interface =
$data['interface'];
309 $this->keysToTry =
$data[
'keysToTry'];
310 $this->parameters =
$data[
'parameters'];
312 $this->useDatabase =
$data[
'useDatabase'];
315 if ( isset(
$data[
'titlestr'] ) ) {
317 } elseif ( isset(
$data[
'title'] ) &&
$data[
'title'] instanceof
Title ) {
331 public function isMultiKey() {
332 return count( $this->keysToTry ) > 1;
341 public function getKeysToTry() {
342 return $this->keysToTry;
356 public function getKey() {
368 return $this->parameters;
379 public function getFormat() {
381 return $this->format;
391 public function getLanguage() {
408 public static function newFromKey( $key ) {
411 return new self( $key,
$params );
427 public static function newFromSpecifier(
$value ) {
429 if ( is_array(
$value ) ) {
434 if (
$value instanceof Message ) {
437 $message =
new Message(
$value );
438 } elseif ( is_string(
$value ) ) {
441 throw new InvalidArgumentException( __METHOD__ .
': invalid argument type '
460 public static function newFallbackSequence( ) {
461 $keys = func_get_args();
462 if ( func_num_args() == 1 ) {
463 if ( is_array(
$keys[0] ) ) {
471 return new self(
$keys );
484 public function getTitle() {
487 $contLang = MediaWikiServices::getInstance()->getContentLanguage();
488 $lang = $this->getLanguage();
491 !
$lang->equals( $contLang )
492 && in_array( $this->
key, (
array)$wgForceUIMsgAsContentMsg )
511 public function params( ) {
512 $args = func_get_args();
519 if (
$args[0] === [] ) {
523 if ( is_int( $key ) ) {
531 $this->parameters = array_merge( $this->parameters, array_values(
$args ) );
548 public function rawParams( ) {
554 $this->parameters[] = self::rawParam( $param );
570 public function numParams( ) {
576 $this->parameters[] = self::numParam( $param );
592 public function durationParams( ) {
598 $this->parameters[] = self::durationParam( $param );
614 public function expiryParams( ) {
620 $this->parameters[] = self::expiryParam( $param );
636 public function timeperiodParams( ) {
642 $this->parameters[] = self::timeperiodParam( $param );
658 public function sizeParams( ) {
664 $this->parameters[] = self::sizeParam( $param );
680 public function bitrateParams( ) {
686 $this->parameters[] = self::bitrateParam( $param );
704 public function plaintextParams( ) {
710 $this->parameters[] = self::plaintextParam( $param );
725 $this->inLanguage(
$context->getLanguage() );
727 $this->
interface =
true;
743 public function inLanguage(
$lang ) {
744 $previousLanguage = $this->language;
748 } elseif ( is_string(
$lang ) ) {
755 $type = gettype(
$lang );
757 .
"passed a String or Language object; $type given"
761 if ( $this->
language !== $previousLanguage ) {
765 $this->
interface =
false;
778 public function inContentLanguage() {
780 if ( in_array( $this->
key, (
array)$wgForceUIMsgAsContentMsg ) ) {
784 $this->inLanguage( MediaWikiServices::getInstance()->getContentLanguage() );
798 public function setInterfaceMessageFlag( $interface ) {
799 $this->
interface = (bool)$interface;
812 public function useDatabase( $useDatabase ) {
813 $this->useDatabase = (bool)$useDatabase;
856 public function toString( $format =
null ) {
857 if ( $format ===
null ) {
858 $ex =
new LogicException( __METHOD__ .
' using implicit format: ' . $this->
format );
860 $ex->getMessage(), [
'exception' => $ex,
'format' => $this->format,
'key' => $this->key ] );
861 $format = $this->format;
863 $string = $this->fetchMessage();
865 if ( $string ===
false ) {
873 return 'â§¼' . htmlspecialchars( $this->
key ) .
'â§½';
876 # Replace $* with a list of parameters for &uselang=qqx.
877 if ( strpos( $string,
'$*' ) !==
false ) {
879 if ( $this->parameters !== [] ) {
880 $paramlist =
': $' . implode(
', $', range( 1,
count( $this->parameters ) ) );
882 $string = str_replace(
'$*', $paramlist, $string );
885 # Replace parameters before text parsing
886 $string = $this->replaceParameters( $string,
'before', $format );
888 # Maybe transform using the full parser
889 if ( $format === self::FORMAT_PARSE ) {
890 $string = $this->parseText( $string );
891 $string = Parser::stripOuterParagraph( $string );
892 } elseif ( $format === self::FORMAT_BLOCK_PARSE ) {
893 $string = $this->parseText( $string );
894 } elseif ( $format === self::FORMAT_TEXT ) {
895 $string = $this->transformText( $string );
896 } elseif ( $format === self::FORMAT_ESCAPED ) {
897 $string = $this->transformText( $string );
898 $string = htmlspecialchars( $string, ENT_QUOTES,
'UTF-8',
false );
901 # Raw parameter replacement
902 $string = $this->replaceParameters( $string,
'after', $format );
916 public function __toString() {
921 return $this->toString( self::FORMAT_PARSE );
922 }
catch ( Exception $ex ) {
924 trigger_error(
"Exception caught in " . __METHOD__ .
" (message " . $this->
key .
"): "
925 . $ex, E_USER_WARNING );
926 }
catch ( Exception $ex ) {
930 return 'â§¼' . htmlspecialchars( $this->
key ) .
'â§½';
941 public function parse() {
942 $this->
format = self::FORMAT_PARSE;
943 return $this->toString( self::FORMAT_PARSE );
953 public function text() {
954 $this->
format = self::FORMAT_TEXT;
955 return $this->toString( self::FORMAT_TEXT );
965 public function plain() {
966 $this->
format = self::FORMAT_PLAIN;
967 return $this->toString( self::FORMAT_PLAIN );
977 public function parseAsBlock() {
978 $this->
format = self::FORMAT_BLOCK_PARSE;
979 return $this->toString( self::FORMAT_BLOCK_PARSE );
990 public function escaped() {
991 $this->
format = self::FORMAT_ESCAPED;
992 return $this->toString( self::FORMAT_ESCAPED );
1002 public function exists() {
1003 return $this->fetchMessage() !==
false;
1014 public function isBlank() {
1015 $message = $this->fetchMessage();
1016 return $message ===
false || $message ===
'';
1026 public function isDisabled() {
1027 $message = $this->fetchMessage();
1028 return $message ===
false || $message ===
'' || $message ===
'-';
1038 public static function rawParam( $raw ) {
1039 return [
'raw' => $raw ];
1049 public static function numParam( $num ) {
1050 return [
'num' => $num ];
1060 public static function durationParam( $duration ) {
1061 return [
'duration' => $duration ];
1071 public static function expiryParam( $expiry ) {
1072 return [
'expiry' => $expiry ];
1082 public static function timeperiodParam( $period ) {
1083 return [
'period' => $period ];
1093 public static function sizeParam( $size ) {
1094 return [
'size' => $size ];
1104 public static function bitrateParam( $bitrate ) {
1105 return [
'bitrate' => $bitrate ];
1115 public static function plaintextParam( $plaintext ) {
1116 return [
'plaintext' => $plaintext ];
1126 public static function listParam(
array $list,
$type =
'text' ) {
1127 if ( !isset( self::$listTypeMap[
$type] ) ) {
1128 throw new InvalidArgumentException(
1129 "Invalid type '$type'. Known types are: " . implode(
', ', array_keys( self::$listTypeMap ) )
1132 return [
'list' => $list,
'type' =>
$type ];
1146 protected function replaceParameters( $message,
$type, $format ) {
1151 $marker = $format === self::FORMAT_ESCAPED ?
'$' :
'$\'"';
1152 $replacementKeys = [];
1153 foreach ( $this->parameters
as $n => $param ) {
1154 list( $paramType,
$value ) = $this->extractParam( $param, $format );
1155 if (
$type ===
'before' ) {
1156 if ( $paramType ===
'before' ) {
1157 $replacementKeys[
'$' . ( $n + 1 )] =
$value;
1164 $replacementKeys[
'$' . ( $n + 1 )] = $marker . ( $n + 1 );
1166 } elseif ( $paramType ===
'after' ) {
1167 $replacementKeys[$marker . ( $n + 1 )] =
$value;
1170 return strtr( $message, $replacementKeys );
1183 protected function extractParam( $param, $format ) {
1184 if ( is_array( $param ) ) {
1185 if ( isset( $param[
'raw'] ) ) {
1186 return [
'after', $param[
'raw'] ];
1187 } elseif ( isset( $param[
'num'] ) ) {
1190 return [
'before', $this->getLanguage()->formatNum( $param[
'num'] ) ];
1191 } elseif ( isset( $param[
'duration'] ) ) {
1192 return [
'before', $this->getLanguage()->formatDuration( $param[
'duration'] ) ];
1193 } elseif ( isset( $param[
'expiry'] ) ) {
1194 return [
'before', $this->getLanguage()->formatExpiry( $param[
'expiry'] ) ];
1195 } elseif ( isset( $param[
'period'] ) ) {
1196 return [
'before', $this->getLanguage()->formatTimePeriod( $param[
'period'] ) ];
1197 } elseif ( isset( $param[
'size'] ) ) {
1198 return [
'before', $this->getLanguage()->formatSize( $param[
'size'] ) ];
1199 } elseif ( isset( $param[
'bitrate'] ) ) {
1200 return [
'before', $this->getLanguage()->formatBitrate( $param[
'bitrate'] ) ];
1201 } elseif ( isset( $param[
'plaintext'] ) ) {
1202 return [
'after', $this->formatPlaintext( $param[
'plaintext'], $format ) ];
1203 } elseif ( isset( $param[
'list'] ) ) {
1204 return $this->formatListParam( $param[
'list'], $param[
'type'], $format );
1206 if ( !is_scalar( $param ) ) {
1210 'Invalid parameter for message "{msgkey}": {param}',
1212 'exception' =>
new Exception,
1213 'msgkey' => $this->
getKey(),
1214 'param' => htmlspecialchars( $param ),
1218 return [
'before',
'[INVALID]' ];
1220 } elseif ( $param instanceof Message ) {
1222 $msg = clone $param;
1223 if ( $msg->language !== $this->language || $msg->useDatabase !== $this->useDatabase ) {
1225 $msg->message =
null;
1227 $msg->interface = $this->interface;
1228 $msg->language = $this->language;
1229 $msg->useDatabase = $this->useDatabase;
1233 if ( $format ===
'block-parse' ) {
1236 $msg->format = $format;
1241 return [
'after', $msg->toString( $format ) ];
1243 return [
'before', $param ];
1256 protected function parseText( $string ) {
1262 $this->getLanguage()
1267 'enableSectionEditLinks' =>
false,
1286 protected function transformText( $string ) {
1290 $this->getLanguage(),
1303 protected function fetchMessage() {
1304 if ( $this->
message ===
null ) {
1307 foreach ( $this->keysToTry
as $key ) {
1308 $message =
$cache->get( $key, $this->useDatabase, $this->getLanguage() );
1309 if ( $message !==
false && $message !==
'' ) {
1319 return $this->message;
1334 protected function formatPlaintext( $plaintext, $format ) {
1335 switch ( $format ) {
1336 case self::FORMAT_TEXT:
1337 case self::FORMAT_PLAIN:
1340 case self::FORMAT_PARSE:
1341 case self::FORMAT_BLOCK_PARSE:
1342 case self::FORMAT_ESCAPED:
1344 return htmlspecialchars( $plaintext, ENT_QUOTES );
1356 protected function formatListParam(
array $params, $listType, $format ) {
1357 if ( !isset( self::$listTypeMap[$listType] ) ) {
1358 $warning =
'Invalid list type for message "' . $this->
getKey() .
'": '
1359 . htmlspecialchars( $listType )
1361 trigger_error( $warning, E_USER_WARNING );
1363 wfDebugLog(
'Bug58676', $warning .
"\n" .
$e->getTraceAsString() );
1364 return [
'before',
'[INVALID]' ];
1366 $func = self::$listTypeMap[$listType];
1370 return [
'before', $this->getLanguage()->$func( [] ) ];
1379 $types[
$type] =
true;
1381 $vars[] =
'$' . ( $n + 1 );
1386 if (
count( $types ) === 1 ) {
1387 return [
key( $types ), $this->getLanguage()->$func( $list ) ];
1393 $vars = $this->getLanguage()->$func(
$vars );