MessageFormatterFactory
An injectable service interface for message formatting, somewhat narrowed compared to Message. Only the text format is implemented in this framework so far, with getTextFormatter() returning a formatter that converts to the text format. Other formatters could be added to MessageFormatterFactory. Bug: T226598 Change-Id: Id053074c1dbcb692e8309fdca602f94a385bca0c
This commit is contained in:
parent
3bb3c8b0ae
commit
09cd8eb080
16 changed files with 923 additions and 0 deletions
|
|
@ -134,6 +134,7 @@ class AutoLoader {
|
|||
'MediaWiki\\Edit\\' => __DIR__ . '/edit/',
|
||||
'MediaWiki\\EditPage\\' => __DIR__ . '/editpage/',
|
||||
'MediaWiki\\Linker\\' => __DIR__ . '/linker/',
|
||||
'MediaWiki\\Message\\' => __DIR__ . '/Message',
|
||||
'MediaWiki\\Permissions\\' => __DIR__ . '/Permissions/',
|
||||
'MediaWiki\\Preferences\\' => __DIR__ . '/preferences/',
|
||||
'MediaWiki\\Rest\\' => __DIR__ . '/Rest/',
|
||||
|
|
@ -143,6 +144,7 @@ class AutoLoader {
|
|||
'MediaWiki\\Sparql\\' => __DIR__ . '/sparql/',
|
||||
'MediaWiki\\Storage\\' => __DIR__ . '/Storage/',
|
||||
'MediaWiki\\Tidy\\' => __DIR__ . '/tidy/',
|
||||
'Wikimedia\\Message\\' => __DIR__ . '/libs/Message/',
|
||||
'Wikimedia\\ParamValidator\\' => __DIR__ . '/libs/ParamValidator/',
|
||||
'Wikimedia\\Services\\' => __DIR__ . '/libs/services/',
|
||||
];
|
||||
|
|
|
|||
|
|
@ -18,6 +18,7 @@ use MediaWiki\Block\BlockManager;
|
|||
use MediaWiki\Block\BlockRestrictionStore;
|
||||
use MediaWiki\FileBackend\FSFile\TempFSFileFactory;
|
||||
use MediaWiki\Http\HttpRequestFactory;
|
||||
use Wikimedia\Message\IMessageFormatterFactory;
|
||||
use MediaWiki\Page\MovePageFactory;
|
||||
use MediaWiki\Permissions\PermissionManager;
|
||||
use MediaWiki\Preferences\PreferencesFactory;
|
||||
|
|
@ -709,6 +710,14 @@ class MediaWikiServices extends ServiceContainer {
|
|||
return $this->getService( 'MessageCache' );
|
||||
}
|
||||
|
||||
/**
|
||||
* @since 1.34
|
||||
* @return IMessageFormatterFactory
|
||||
*/
|
||||
public function getMessageFormatterFactory() {
|
||||
return $this->getService( 'MessageFormatterFactory' );
|
||||
}
|
||||
|
||||
/**
|
||||
* @since 1.28
|
||||
* @return MimeAnalyzer
|
||||
|
|
|
|||
29
includes/Message/MessageFormatterFactory.php
Normal file
29
includes/Message/MessageFormatterFactory.php
Normal file
|
|
@ -0,0 +1,29 @@
|
|||
<?php
|
||||
|
||||
namespace MediaWiki\Message;
|
||||
|
||||
use Wikimedia\Message\IMessageFormatterFactory;
|
||||
use Wikimedia\Message\ITextFormatter;
|
||||
|
||||
/**
|
||||
* The MediaWiki-specific implementation of IMessageFormatterFactory
|
||||
*/
|
||||
class MessageFormatterFactory implements IMessageFormatterFactory {
|
||||
private $textFormatters = [];
|
||||
|
||||
/**
|
||||
* Required parameters may be added to this function without deprecation.
|
||||
* External callers should use MediaWikiServices::getMessageFormatterFactory().
|
||||
*
|
||||
* @internal
|
||||
*/
|
||||
public function __construct() {
|
||||
}
|
||||
|
||||
public function getTextFormatter( $langCode ): ITextFormatter {
|
||||
if ( !isset( $this->textFormatters[$langCode] ) ) {
|
||||
$this->textFormatters[$langCode] = new TextFormatter( $langCode );
|
||||
}
|
||||
return $this->textFormatters[$langCode];
|
||||
}
|
||||
}
|
||||
74
includes/Message/TextFormatter.php
Normal file
74
includes/Message/TextFormatter.php
Normal file
|
|
@ -0,0 +1,74 @@
|
|||
<?php
|
||||
|
||||
namespace MediaWiki\Message;
|
||||
|
||||
use Wikimedia\Message\ITextFormatter;
|
||||
use Wikimedia\Message\ListParam;
|
||||
use Wikimedia\Message\MessageParam;
|
||||
use Wikimedia\Message\MessageValue;
|
||||
use Wikimedia\Message\ParamType;
|
||||
use Message;
|
||||
|
||||
/**
|
||||
* The MediaWiki-specific implementation of ITextFormatter
|
||||
*/
|
||||
class TextFormatter implements ITextFormatter {
|
||||
/** @var string */
|
||||
private $langCode;
|
||||
|
||||
/**
|
||||
* Construct a TextFormatter.
|
||||
*
|
||||
* The type signature may change without notice as dependencies are added
|
||||
* to the constructor. External callers should use
|
||||
* MediaWikiServices::getMessageFormatterFactory()
|
||||
*
|
||||
* @internal
|
||||
*/
|
||||
public function __construct( $langCode ) {
|
||||
$this->langCode = $langCode;
|
||||
}
|
||||
|
||||
/**
|
||||
* Allow the Message class to be mocked in tests by constructing objects in
|
||||
* a protected method.
|
||||
*
|
||||
* @internal
|
||||
* @param string $key
|
||||
* @return Message
|
||||
*/
|
||||
protected function createMessage( $key ) {
|
||||
return new Message( $key );
|
||||
}
|
||||
|
||||
public function getLangCode() {
|
||||
return $this->langCode;
|
||||
}
|
||||
|
||||
private static function convertParam( MessageParam $param ) {
|
||||
if ( $param instanceof ListParam ) {
|
||||
$convertedElements = [];
|
||||
foreach ( $param->getValue() as $element ) {
|
||||
$convertedElements[] = self::convertParam( $element );
|
||||
}
|
||||
return Message::listParam( $convertedElements, $param->getListType() );
|
||||
} elseif ( $param instanceof MessageParam ) {
|
||||
if ( $param->getType() === ParamType::TEXT ) {
|
||||
return $param->getValue();
|
||||
} else {
|
||||
return [ $param->getType() => $param->getValue() ];
|
||||
}
|
||||
} else {
|
||||
throw new \InvalidArgumentException( 'Invalid message parameter type' );
|
||||
}
|
||||
}
|
||||
|
||||
public function format( MessageValue $mv ) {
|
||||
$message = $this->createMessage( $mv->getKey() );
|
||||
foreach ( $mv->getParams() as $param ) {
|
||||
$message->params( self::convertParam( $param ) );
|
||||
}
|
||||
$message->inLanguage( $this->langCode );
|
||||
return $message->text();
|
||||
}
|
||||
}
|
||||
11
includes/Rest/LocalizedHttpException.php
Normal file
11
includes/Rest/LocalizedHttpException.php
Normal file
|
|
@ -0,0 +1,11 @@
|
|||
<?php
|
||||
|
||||
namespace MediaWiki\Rest;
|
||||
|
||||
use Wikimedia\Message\MessageValue;
|
||||
|
||||
class LocalizedHttpException extends HttpException {
|
||||
public function __construct( MessageValue $message, $code = 500 ) {
|
||||
parent::__construct( 'Localized exception with key ' . $message->getKey(), $code );
|
||||
}
|
||||
}
|
||||
|
|
@ -52,6 +52,8 @@ use MediaWiki\Linker\LinkRenderer;
|
|||
use MediaWiki\Linker\LinkRendererFactory;
|
||||
use MediaWiki\Logger\LoggerFactory;
|
||||
use MediaWiki\MediaWikiServices;
|
||||
use Wikimedia\Message\IMessageFormatterFactory;
|
||||
use MediaWiki\Message\MessageFormatterFactory;
|
||||
use MediaWiki\Page\MovePageFactory;
|
||||
use MediaWiki\Permissions\PermissionManager;
|
||||
use MediaWiki\Preferences\PreferencesFactory;
|
||||
|
|
@ -350,6 +352,11 @@ return [
|
|||
);
|
||||
},
|
||||
|
||||
'MessageFormatterFactory' =>
|
||||
function ( MediaWikiServices $services ) : IMessageFormatterFactory {
|
||||
return new MessageFormatterFactory();
|
||||
},
|
||||
|
||||
'MimeAnalyzer' => function ( MediaWikiServices $services ) : MimeAnalyzer {
|
||||
$logger = LoggerFactory::getInstance( 'Mime' );
|
||||
$mainConfig = $services->getMainConfig();
|
||||
|
|
|
|||
18
includes/libs/Message/IMessageFormatterFactory.php
Normal file
18
includes/libs/Message/IMessageFormatterFactory.php
Normal file
|
|
@ -0,0 +1,18 @@
|
|||
<?php
|
||||
|
||||
namespace Wikimedia\Message;
|
||||
|
||||
/**
|
||||
* A simple factory providing a message formatter for a given language code.
|
||||
*
|
||||
* @see ITextFormatter
|
||||
*/
|
||||
interface IMessageFormatterFactory {
|
||||
/**
|
||||
* Get a text message formatter for a given language.
|
||||
*
|
||||
* @param string $langCode The language code
|
||||
* @return ITextFormatter
|
||||
*/
|
||||
public function getTextFormatter( $langCode ): ITextFormatter;
|
||||
}
|
||||
43
includes/libs/Message/ITextFormatter.php
Normal file
43
includes/libs/Message/ITextFormatter.php
Normal file
|
|
@ -0,0 +1,43 @@
|
|||
<?php
|
||||
|
||||
namespace Wikimedia\Message;
|
||||
|
||||
/**
|
||||
* ITextFormatter is a simplified interface to the Message class. It converts
|
||||
* MessageValue message specifiers to localized text in a certain language.
|
||||
*
|
||||
* MessageValue supports message keys, and parameters with a wide variety of
|
||||
* types. It does not expose any details of how messages are retrieved from
|
||||
* storage or what format they are stored in.
|
||||
*
|
||||
* Thus, TextFormatter supports single message keys, but not the concept of
|
||||
* presence or absence of a key from storage. So it does not support
|
||||
* fallback sequences of multiple keys.
|
||||
*
|
||||
* The caller cannot modify the details of message translation, such as which
|
||||
* of multiple sources the message is taken from. Any such flags may be injected
|
||||
* into the factory constructor.
|
||||
*
|
||||
* Implementations of TextFormatter are not required to perfectly format
|
||||
* any message in any language. Implementations should make a best effort to
|
||||
* produce human-readable text.
|
||||
*
|
||||
* @package MediaWiki\MessageFormatter
|
||||
*/
|
||||
interface ITextFormatter {
|
||||
/**
|
||||
* Get the internal language code in which format() is
|
||||
* @return string
|
||||
*/
|
||||
function getLangCode();
|
||||
|
||||
/**
|
||||
* Convert a MessageValue to text.
|
||||
*
|
||||
* The result is not safe for use as raw HTML.
|
||||
*
|
||||
* @param MessageValue $message
|
||||
* @return string
|
||||
*/
|
||||
function format( MessageValue $message );
|
||||
}
|
||||
52
includes/libs/Message/ListParam.php
Normal file
52
includes/libs/Message/ListParam.php
Normal file
|
|
@ -0,0 +1,52 @@
|
|||
<?php
|
||||
|
||||
namespace Wikimedia\Message;
|
||||
|
||||
/**
|
||||
* The class for list parameters
|
||||
*/
|
||||
class ListParam extends MessageParam {
|
||||
private $listType;
|
||||
|
||||
/**
|
||||
* @param string $listType One of the ListType constants:
|
||||
* - ListType::COMMA: A comma-separated list
|
||||
* - ListType::SEMICOLON: A semicolon-separated list
|
||||
* - ListType::PIPE: A pipe-separated list
|
||||
* - ListType::TEXT: A natural language list, separated by commas and
|
||||
* the word "and".
|
||||
* @param (MessageParam|string)[] $elements An array of parameters
|
||||
*/
|
||||
public function __construct( $listType, array $elements ) {
|
||||
$this->type = ParamType::LIST;
|
||||
$this->listType = $listType;
|
||||
$this->value = [];
|
||||
foreach ( $elements as $element ) {
|
||||
if ( $element instanceof MessageParam ) {
|
||||
$this->value[] = $element;
|
||||
} elseif ( is_scalar( $element ) ) {
|
||||
$this->value[] = new TextParam( ParamType::TEXT, $element );
|
||||
} else {
|
||||
throw new \InvalidArgumentException(
|
||||
'ListParam elements must be MessageParam or scalar' );
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the type of the list
|
||||
*
|
||||
* @return string One of the ListType constants
|
||||
*/
|
||||
public function getListType() {
|
||||
return $this->listType;
|
||||
}
|
||||
|
||||
public function dump() {
|
||||
$contents = '';
|
||||
foreach ( $this->value as $element ) {
|
||||
$contents .= $element->dump();
|
||||
}
|
||||
return "<{$this->type} listType=\"{$this->listType}\">$contents</{$this->type}>";
|
||||
}
|
||||
}
|
||||
22
includes/libs/Message/ListType.php
Normal file
22
includes/libs/Message/ListType.php
Normal file
|
|
@ -0,0 +1,22 @@
|
|||
<?php
|
||||
|
||||
namespace Wikimedia\Message;
|
||||
|
||||
/**
|
||||
* The constants used to specify list types. The values of the constants are an
|
||||
* unstable implementation detail and correspond to the names of the list types
|
||||
* in the Message class.
|
||||
*/
|
||||
class ListType {
|
||||
/** A comma-separated list */
|
||||
const COMMA = 'comma';
|
||||
|
||||
/** A semicolon-separated list */
|
||||
const SEMICOLON = 'semicolon';
|
||||
|
||||
/** A pipe-separated list */
|
||||
const PIPE = 'pipe';
|
||||
|
||||
/** A natural-language list separated by "and" */
|
||||
const AND = 'text';
|
||||
}
|
||||
36
includes/libs/Message/MessageParam.php
Normal file
36
includes/libs/Message/MessageParam.php
Normal file
|
|
@ -0,0 +1,36 @@
|
|||
<?php
|
||||
|
||||
namespace Wikimedia\Message;
|
||||
|
||||
/**
|
||||
* The base class for message parameters.
|
||||
*/
|
||||
abstract class MessageParam {
|
||||
protected $type;
|
||||
protected $value;
|
||||
|
||||
/**
|
||||
* Get the type of the parameter.
|
||||
*
|
||||
* @return string One of the ParamType constants
|
||||
*/
|
||||
public function getType() {
|
||||
return $this->type;
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the input value of the parameter
|
||||
*
|
||||
* @return int|float|string|array
|
||||
*/
|
||||
public function getValue() {
|
||||
return $this->value;
|
||||
}
|
||||
|
||||
/**
|
||||
* Dump the object for testing/debugging
|
||||
*
|
||||
* @return string
|
||||
*/
|
||||
abstract public function dump();
|
||||
}
|
||||
258
includes/libs/Message/MessageValue.php
Normal file
258
includes/libs/Message/MessageValue.php
Normal file
|
|
@ -0,0 +1,258 @@
|
|||
<?php
|
||||
|
||||
namespace Wikimedia\Message;
|
||||
|
||||
/**
|
||||
* A MessageValue holds a key and an array of parameters
|
||||
*/
|
||||
class MessageValue {
|
||||
/** @var string */
|
||||
private $key;
|
||||
|
||||
/** @var MessageParam[] */
|
||||
private $params;
|
||||
|
||||
/**
|
||||
* @param string $key
|
||||
* @param array $params Each element of the parameter array
|
||||
* may be either a MessageParam or a scalar. If it is a scalar, it is
|
||||
* converted to a parameter of type TEXT.
|
||||
*/
|
||||
public function __construct( $key, $params = [] ) {
|
||||
$this->key = $key;
|
||||
$this->params = [];
|
||||
$this->params( ...$params );
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the message key
|
||||
*
|
||||
* @return string
|
||||
*/
|
||||
public function getKey() {
|
||||
return $this->key;
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the parameter array
|
||||
*
|
||||
* @return MessageParam[]
|
||||
*/
|
||||
public function getParams() {
|
||||
return $this->params;
|
||||
}
|
||||
|
||||
/**
|
||||
* Chainable mutator which adds text parameters and MessageParam parameters
|
||||
*
|
||||
* @param mixed ...$values Scalar or MessageParam values
|
||||
* @return MessageValue
|
||||
*/
|
||||
public function params( ...$values ) {
|
||||
foreach ( $values as $value ) {
|
||||
if ( $value instanceof MessageParam ) {
|
||||
$this->params[] = $value;
|
||||
} else {
|
||||
$this->params[] = new TextParam( ParamType::TEXT, $value );
|
||||
}
|
||||
}
|
||||
return $this;
|
||||
}
|
||||
|
||||
/**
|
||||
* Chainable mutator which adds text parameters with a common type
|
||||
*
|
||||
* @param string $type One of the ParamType constants
|
||||
* @param mixed ...$values Scalar values
|
||||
* @return MessageValue
|
||||
*/
|
||||
public function textParamsOfType( $type, ...$values ) {
|
||||
foreach ( $values as $value ) {
|
||||
$this->params[] = new TextParam( $type, $value );
|
||||
}
|
||||
return $this;
|
||||
}
|
||||
|
||||
/**
|
||||
* Chainable mutator which adds list parameters with a common type
|
||||
*
|
||||
* @param string $listType One of the ListType constants
|
||||
* @param array ...$values Each value should be an array of list items.
|
||||
* @return MessageValue
|
||||
*/
|
||||
public function listParamsOfType( $listType, ...$values ) {
|
||||
foreach ( $values as $value ) {
|
||||
$this->params[] = new ListParam( $listType, $value );
|
||||
}
|
||||
return $this;
|
||||
}
|
||||
|
||||
/**
|
||||
* Chainable mutator which adds parameters of type text.
|
||||
*
|
||||
* @param string ...$values
|
||||
* @return MessageValue
|
||||
*/
|
||||
public function textParams( ...$values ) {
|
||||
return $this->textParamsOfType( ParamType::TEXT, ...$values );
|
||||
}
|
||||
|
||||
/**
|
||||
* Chainable mutator which adds numeric parameters
|
||||
*
|
||||
* @param mixed ...$values
|
||||
* @return MessageValue
|
||||
*/
|
||||
public function numParams( ...$values ) {
|
||||
return $this->textParamsOfType( ParamType::NUM, ...$values );
|
||||
}
|
||||
|
||||
/**
|
||||
* Chainable mutator which adds parameters which are a duration specified
|
||||
* in seconds. This is similar to timePeriodParams() except that the result
|
||||
* will be more verbose.
|
||||
*
|
||||
* @param int|float ...$values
|
||||
* @return MessageValue
|
||||
*/
|
||||
public function longDurationParams( ...$values ) {
|
||||
return $this->textParamsOfType( ParamType::DURATION_LONG, ...$values );
|
||||
}
|
||||
|
||||
/**
|
||||
* Chainable mutator which adds parameters which are a time period in seconds.
|
||||
* This is similar to durationParams() except that the result will be more
|
||||
* compact.
|
||||
*
|
||||
* @param int|float ...$values
|
||||
* @return MessageValue
|
||||
*/
|
||||
public function shortDurationParams( ...$values ) {
|
||||
return $this->textParamsOfType( ParamType::DURATION_SHORT, ...$values );
|
||||
}
|
||||
|
||||
/**
|
||||
* Chainable mutator which adds parameters which are an expiry timestamp
|
||||
* as used in the MediaWiki database schema.
|
||||
*
|
||||
* @param string ...$values
|
||||
* @return MessageValue
|
||||
*/
|
||||
public function expiryParams( ...$values ) {
|
||||
return $this->textParamsOfType( ParamType::EXPIRY, ...$values );
|
||||
}
|
||||
|
||||
/**
|
||||
* Chainable mutator which adds parameters which are a number of bytes.
|
||||
*
|
||||
* @param int ...$values
|
||||
* @return MessageValue
|
||||
*/
|
||||
public function sizeParams( ...$values ) {
|
||||
return $this->textParamsOfType( ParamType::SIZE, ...$values );
|
||||
}
|
||||
|
||||
/**
|
||||
* Chainable mutator which adds parameters which are a number of bits per
|
||||
* second.
|
||||
*
|
||||
* @param int|float ...$values
|
||||
* @return MessageValue
|
||||
*/
|
||||
public function bitrateParams( ...$values ) {
|
||||
return $this->textParamsOfType( ParamType::BITRATE, ...$values );
|
||||
}
|
||||
|
||||
/**
|
||||
* Chainable mutator which adds parameters of type "raw".
|
||||
*
|
||||
* @param mixed ...$values
|
||||
* @return MessageValue
|
||||
*/
|
||||
public function rawParams( ...$values ) {
|
||||
return $this->textParamsOfType( ParamType::RAW, ...$values );
|
||||
}
|
||||
|
||||
/**
|
||||
* Chainable mutator which adds parameters of type "plaintext".
|
||||
*/
|
||||
public function plaintextParams( ...$values ) {
|
||||
return $this->textParamsOfType( ParamType::PLAINTEXT, ...$values );
|
||||
}
|
||||
|
||||
/**
|
||||
* Chainable mutator which adds comma lists. Each comma list is an array of
|
||||
* list elements, and each list element is either a MessageParam or a
|
||||
* string. String parameters are converted to parameters of type "text".
|
||||
*
|
||||
* The list parameters thus created are formatted as a comma-separated list,
|
||||
* or some local equivalent.
|
||||
*
|
||||
* @param (MessageParam|string)[] ...$values
|
||||
* @return MessageValue
|
||||
*/
|
||||
public function commaListParams( ...$values ) {
|
||||
return $this->listParamsOfType( ListType::COMMA, ...$values );
|
||||
}
|
||||
|
||||
/**
|
||||
* Chainable mutator which adds semicolon lists. Each semicolon list is an
|
||||
* array of list elements, and each list element is either a MessageParam
|
||||
* or a string. String parameters are converted to parameters of type
|
||||
* "text".
|
||||
*
|
||||
* The list parameters thus created are formatted as a semicolon-separated
|
||||
* list, or some local equivalent.
|
||||
*
|
||||
* @param (MessageParam|string)[] ...$values
|
||||
* @return MessageValue
|
||||
*/
|
||||
public function semicolonListParams( ...$values ) {
|
||||
return $this->listParamsOfType( ListType::SEMICOLON, ...$values );
|
||||
}
|
||||
|
||||
/**
|
||||
* Chainable mutator which adds pipe lists. Each pipe list is an array of
|
||||
* list elements, and each list element is either a MessageParam or a
|
||||
* string. String parameters are converted to parameters of type "text".
|
||||
*
|
||||
* The list parameters thus created are formatted as a pipe ("|") -separated
|
||||
* list, or some local equivalent.
|
||||
*
|
||||
* @param (MessageParam|string)[] ...$values
|
||||
* @return MessageValue
|
||||
*/
|
||||
public function pipeListParams( ...$values ) {
|
||||
return $this->listParamsOfType( ListType::PIPE, ...$values );
|
||||
}
|
||||
|
||||
/**
|
||||
* Chainable mutator which adds text lists. Each text list is an array of
|
||||
* list elements, and each list element is either a MessageParam or a
|
||||
* string. String parameters are converted to parameters of type "text".
|
||||
*
|
||||
* The list parameters thus created, when formatted, are joined as in natural
|
||||
* language. In English, this means a comma-separated list, with the last
|
||||
* two elements joined with "and".
|
||||
*
|
||||
* @param (MessageParam|string)[] ...$values
|
||||
* @return MessageValue
|
||||
*/
|
||||
public function textListParams( ...$values ) {
|
||||
return $this->listParamsOfType( ListType::AND, ...$values );
|
||||
}
|
||||
|
||||
/**
|
||||
* Dump the object for testing/debugging
|
||||
*
|
||||
* @return string
|
||||
*/
|
||||
public function dump() {
|
||||
$contents = '';
|
||||
foreach ( $this->params as $param ) {
|
||||
$contents .= $param->dump();
|
||||
}
|
||||
return '<message key="' . htmlspecialchars( $this->key ) . '">' .
|
||||
$contents . '</message>';
|
||||
}
|
||||
}
|
||||
47
includes/libs/Message/ParamType.php
Normal file
47
includes/libs/Message/ParamType.php
Normal file
|
|
@ -0,0 +1,47 @@
|
|||
<?php
|
||||
|
||||
namespace Wikimedia\Message;
|
||||
|
||||
/**
|
||||
* The constants used to specify parameter types. The values of the constants
|
||||
* are an unstable implementation detail, and correspond to the names of the
|
||||
* parameter types in the Message class.
|
||||
*/
|
||||
class ParamType {
|
||||
/** A simple text parameter */
|
||||
const TEXT = 'text';
|
||||
|
||||
/** A number, to be formatted using local digits and separators */
|
||||
const NUM = 'num';
|
||||
|
||||
/** A number of seconds, to be formatted as natural language text. */
|
||||
const DURATION_LONG = 'duration';
|
||||
|
||||
/** A number of seconds, to be formatted in an abbreviated way. */
|
||||
const DURATION_SHORT = 'timeperiod';
|
||||
|
||||
/**
|
||||
* An expiry time for a block. The input is either a timestamp in one
|
||||
* of the formats accepted by the Wikimedia\Timestamp library, or
|
||||
* "infinity" for an infinite block.
|
||||
*/
|
||||
const EXPIRY = 'expiry';
|
||||
|
||||
/** A number of bytes. */
|
||||
const SIZE = 'size';
|
||||
|
||||
/** A number of bits per second. */
|
||||
const BITRATE = 'bitrate';
|
||||
|
||||
/** The list type (ListParam) */
|
||||
const LIST = 'list';
|
||||
|
||||
/**
|
||||
* A text parameter which is substituted after preprocessing, and so is
|
||||
* not available to the preprocessor and cannot be modified by it.
|
||||
*/
|
||||
const RAW = 'raw';
|
||||
|
||||
/** Reserved for future use. */
|
||||
const PLAINTEXT = 'plaintext';
|
||||
}
|
||||
37
includes/libs/Message/TextParam.php
Normal file
37
includes/libs/Message/TextParam.php
Normal file
|
|
@ -0,0 +1,37 @@
|
|||
<?php
|
||||
|
||||
namespace Wikimedia\Message;
|
||||
|
||||
class TextParam extends MessageParam {
|
||||
/**
|
||||
* Construct a text parameter
|
||||
*
|
||||
* @param string $type May be one of:
|
||||
* - ParamType::TEXT: A simple text parameter
|
||||
* - ParamType::NUM: A number, to be formatted using local digits and
|
||||
* separators
|
||||
* - ParamType::DURATION_LONG: A number of seconds, to be formatted as natural
|
||||
* language text.
|
||||
* - ParamType::DURATION_SHORT: A number of seconds, to be formatted in an
|
||||
* abbreviated way.
|
||||
* - ParamType::EXPIRY: An expiry time for a block. The input is either
|
||||
* a timestamp in one of the formats accepted by the Wikimedia\Timestamp
|
||||
* library, or "infinity" for an infinite block.
|
||||
* - ParamType::SIZE: A number of bytes.
|
||||
* - ParamType::BITRATE: A number of bits per second.
|
||||
* - ParamType::RAW: A text parameter which is substituted after
|
||||
* preprocessing, and so is not available to the preprocessor and cannot
|
||||
* be modified by it.
|
||||
* - ParamType::PLAINTEXT: Reserved for future use.
|
||||
*
|
||||
* @param string|int|float $value
|
||||
*/
|
||||
public function __construct( $type, $value ) {
|
||||
$this->type = $type;
|
||||
$this->value = $value;
|
||||
}
|
||||
|
||||
public function dump() {
|
||||
return "<{$this->type}>" . htmlspecialchars( $this->value ) . "</{$this->type}>";
|
||||
}
|
||||
}
|
||||
59
tests/phpunit/includes/Message/TextFormatterTest.php
Normal file
59
tests/phpunit/includes/Message/TextFormatterTest.php
Normal file
|
|
@ -0,0 +1,59 @@
|
|||
<?php
|
||||
|
||||
namespace MediaWiki\Tests\Message;
|
||||
|
||||
use MediaWiki\Message\TextFormatter;
|
||||
use MediaWikiTestCase;
|
||||
use Message;
|
||||
use Wikimedia\Message\MessageValue;
|
||||
use Wikimedia\Message\ParamType;
|
||||
use Wikimedia\Message\TextParam;
|
||||
|
||||
/**
|
||||
* @covers \MediaWiki\Message\TextFormatter
|
||||
* @covers \Wikimedia\Message\MessageValue
|
||||
* @covers \Wikimedia\Message\ListParam
|
||||
* @covers \Wikimedia\Message\TextParam
|
||||
* @covers \Wikimedia\Message\MessageParam
|
||||
*/
|
||||
class TextFormatterTest extends MediaWikiTestCase {
|
||||
private function createTextFormatter( $langCode ) {
|
||||
return new class( $langCode ) extends TextFormatter {
|
||||
public function __construct( $langCode ) {
|
||||
parent::__construct( $langCode );
|
||||
}
|
||||
|
||||
protected function createMessage( $key ) {
|
||||
return new FakeMessage( $key );
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
public function testGetLangCode() {
|
||||
$formatter = $this->createTextFormatter( 'fr' );
|
||||
$this->assertSame( 'fr', $formatter->getLangCode() );
|
||||
}
|
||||
|
||||
public function testFormatBitrate() {
|
||||
$formatter = $this->createTextFormatter( 'en' );
|
||||
$mv = ( new MessageValue( 'test' ) )->bitrateParams( 100, 200 );
|
||||
$result = $formatter->format( $mv );
|
||||
$this->assertSame( 'test 100 bps 200 bps', $result );
|
||||
}
|
||||
|
||||
public function testFormatList() {
|
||||
$formatter = $this->createTextFormatter( 'en' );
|
||||
$mv = ( new MessageValue( 'test' ) )->commaListParams( [
|
||||
'a',
|
||||
new TextParam( ParamType::BITRATE, 100 ),
|
||||
] );
|
||||
$result = $formatter->format( $mv );
|
||||
$this->assertSame( 'test a, 100 bps $2', $result );
|
||||
}
|
||||
}
|
||||
|
||||
class FakeMessage extends Message {
|
||||
public function fetchMessage() {
|
||||
return "{$this->getKey()} $1 $2";
|
||||
}
|
||||
}
|
||||
219
tests/phpunit/includes/libs/Message/MessageValueTest.php
Normal file
219
tests/phpunit/includes/libs/Message/MessageValueTest.php
Normal file
|
|
@ -0,0 +1,219 @@
|
|||
<?php
|
||||
|
||||
namespace Wikimedia\Tests\Message;
|
||||
|
||||
use Wikimedia\Message\ListType;
|
||||
use Wikimedia\Message\MessageValue;
|
||||
use Wikimedia\Message\ParamType;
|
||||
use Wikimedia\Message\TextParam;
|
||||
use MediaWikiTestCase;
|
||||
|
||||
/**
|
||||
* @covers \Wikimedia\Message\MessageValue
|
||||
* @covers \Wikimedia\Message\ListParam
|
||||
* @covers \Wikimedia\Message\TextParam
|
||||
* @covers \Wikimedia\Message\MessageParam
|
||||
*/
|
||||
class MessageValueTest extends MediaWikiTestCase {
|
||||
public static function provideConstruct() {
|
||||
return [
|
||||
[
|
||||
[],
|
||||
'<message key="key"></message>',
|
||||
],
|
||||
[
|
||||
[ 'a' ],
|
||||
'<message key="key"><text>a</text></message>'
|
||||
],
|
||||
[
|
||||
[ new TextParam( ParamType::BITRATE, 100 ) ],
|
||||
'<message key="key"><bitrate>100</bitrate></message>'
|
||||
],
|
||||
];
|
||||
}
|
||||
|
||||
/** @dataProvider provideConstruct */
|
||||
public function testConstruct( $input, $expected ) {
|
||||
$mv = new MessageValue( 'key', $input );
|
||||
$this->assertSame( $expected, $mv->dump() );
|
||||
}
|
||||
|
||||
public function testGetKey() {
|
||||
$mv = new MessageValue( 'key' );
|
||||
$this->assertSame( 'key', $mv->getKey() );
|
||||
}
|
||||
|
||||
public function testParams() {
|
||||
$mv = new MessageValue( 'key' );
|
||||
$mv->params( 1, 'x' );
|
||||
$mv2 = $mv->params( new TextParam( ParamType::BITRATE, 100 ) );
|
||||
$this->assertSame(
|
||||
'<message key="key"><text>1</text><text>x</text><bitrate>100</bitrate></message>',
|
||||
$mv->dump() );
|
||||
$this->assertSame( $mv, $mv2 );
|
||||
}
|
||||
|
||||
public function testTextParamsOfType() {
|
||||
$mv = new MessageValue( 'key' );
|
||||
$mv2 = $mv->textParamsOfType( ParamType::BITRATE, 1, 2 );
|
||||
$this->assertSame( '<message key="key">' .
|
||||
'<bitrate>1</bitrate><bitrate>2</bitrate>' .
|
||||
'</message>',
|
||||
$mv->dump() );
|
||||
$this->assertSame( $mv, $mv2 );
|
||||
}
|
||||
|
||||
public function testListParamsOfType() {
|
||||
$mv = new MessageValue( 'key' );
|
||||
$mv2 = $mv->listParamsOfType( ListType::COMMA, [ 'a' ], [ 'b', 'c' ] );
|
||||
$this->assertSame( '<message key="key">' .
|
||||
'<list listType="comma"><text>a</text></list>' .
|
||||
'<list listType="comma"><text>b</text><text>c</text></list>' .
|
||||
'</message>',
|
||||
$mv->dump() );
|
||||
$this->assertSame( $mv, $mv2 );
|
||||
}
|
||||
|
||||
public function testTextParams() {
|
||||
$mv = new MessageValue( 'key' );
|
||||
$mv2 = $mv->textParams( 'a', 'b' );
|
||||
$this->assertSame( '<message key="key">' .
|
||||
'<text>a</text>' .
|
||||
'<text>b</text>' .
|
||||
'</message>',
|
||||
$mv->dump() );
|
||||
$this->assertSame( $mv, $mv2 );
|
||||
}
|
||||
|
||||
public function testNumParams() {
|
||||
$mv = new MessageValue( 'key' );
|
||||
$mv2 = $mv->numParams( 1, 2 );
|
||||
$this->assertSame( '<message key="key">' .
|
||||
'<num>1</num>' .
|
||||
'<num>2</num>' .
|
||||
'</message>',
|
||||
$mv->dump() );
|
||||
$this->assertSame( $mv, $mv2 );
|
||||
}
|
||||
|
||||
public function testLongDurationParams() {
|
||||
$mv = new MessageValue( 'key' );
|
||||
$mv2 = $mv->longDurationParams( 1, 2 );
|
||||
$this->assertSame( '<message key="key">' .
|
||||
'<duration>1</duration>' .
|
||||
'<duration>2</duration>' .
|
||||
'</message>',
|
||||
$mv->dump() );
|
||||
$this->assertSame( $mv, $mv2 );
|
||||
}
|
||||
|
||||
public function testShortDurationParams() {
|
||||
$mv = new MessageValue( 'key' );
|
||||
$mv2 = $mv->shortDurationParams( 1, 2 );
|
||||
$this->assertSame( '<message key="key">' .
|
||||
'<timeperiod>1</timeperiod>' .
|
||||
'<timeperiod>2</timeperiod>' .
|
||||
'</message>',
|
||||
$mv->dump() );
|
||||
$this->assertSame( $mv, $mv2 );
|
||||
}
|
||||
|
||||
public function testExpiryParams() {
|
||||
$mv = new MessageValue( 'key' );
|
||||
$mv2 = $mv->expiryParams( 1, 2 );
|
||||
$this->assertSame( '<message key="key">' .
|
||||
'<expiry>1</expiry>' .
|
||||
'<expiry>2</expiry>' .
|
||||
'</message>',
|
||||
$mv->dump() );
|
||||
$this->assertSame( $mv, $mv2 );
|
||||
}
|
||||
|
||||
public function testSizeParams() {
|
||||
$mv = new MessageValue( 'key' );
|
||||
$mv2 = $mv->sizeParams( 1, 2 );
|
||||
$this->assertSame( '<message key="key">' .
|
||||
'<size>1</size>' .
|
||||
'<size>2</size>' .
|
||||
'</message>',
|
||||
$mv->dump() );
|
||||
$this->assertSame( $mv, $mv2 );
|
||||
}
|
||||
|
||||
public function testBitrateParams() {
|
||||
$mv = new MessageValue( 'key' );
|
||||
$mv2 = $mv->bitrateParams( 1, 2 );
|
||||
$this->assertSame( '<message key="key">' .
|
||||
'<bitrate>1</bitrate>' .
|
||||
'<bitrate>2</bitrate>' .
|
||||
'</message>',
|
||||
$mv->dump() );
|
||||
$this->assertSame( $mv, $mv2 );
|
||||
}
|
||||
|
||||
public function testRawParams() {
|
||||
$mv = new MessageValue( 'key' );
|
||||
$mv2 = $mv->rawParams( 1, 2 );
|
||||
$this->assertSame( '<message key="key">' .
|
||||
'<raw>1</raw>' .
|
||||
'<raw>2</raw>' .
|
||||
'</message>',
|
||||
$mv->dump() );
|
||||
$this->assertSame( $mv, $mv2 );
|
||||
}
|
||||
|
||||
public function testPlaintextParams() {
|
||||
$mv = new MessageValue( 'key' );
|
||||
$mv2 = $mv->plaintextParams( 1, 2 );
|
||||
$this->assertSame( '<message key="key">' .
|
||||
'<plaintext>1</plaintext>' .
|
||||
'<plaintext>2</plaintext>' .
|
||||
'</message>',
|
||||
$mv->dump() );
|
||||
$this->assertSame( $mv, $mv2 );
|
||||
}
|
||||
|
||||
public function testCommaListParams() {
|
||||
$mv = new MessageValue( 'key' );
|
||||
$mv2 = $mv->commaListParams( [ 'a', 'b' ] );
|
||||
$this->assertSame( '<message key="key">' .
|
||||
'<list listType="comma">' .
|
||||
'<text>a</text><text>b</text>' .
|
||||
'</list></message>',
|
||||
$mv->dump() );
|
||||
$this->assertSame( $mv, $mv2 );
|
||||
}
|
||||
|
||||
public function tesSemicolonListParams() {
|
||||
$mv = new MessageValue( 'key' );
|
||||
$mv2 = $mv->semicolonListParams( [ 'a', 'b' ] );
|
||||
$this->assertSame( '<message key="key">' .
|
||||
'<list listType="semicolon">' .
|
||||
'<text>a</text><text>b</text>' .
|
||||
'</list></message>',
|
||||
$mv->dump() );
|
||||
$this->assertSame( $mv, $mv2 );
|
||||
}
|
||||
|
||||
public function testPipeListParams() {
|
||||
$mv = new MessageValue( 'key' );
|
||||
$mv2 = $mv->pipeListParams( [ 'a', 'b' ] );
|
||||
$this->assertSame( '<message key="key">' .
|
||||
'<list listType="pipe">' .
|
||||
'<text>a</text><text>b</text>' .
|
||||
'</list></message>',
|
||||
$mv->dump() );
|
||||
$this->assertSame( $mv, $mv2 );
|
||||
}
|
||||
|
||||
public function testTextListParams() {
|
||||
$mv = new MessageValue( 'key' );
|
||||
$mv2 = $mv->textListParams( [ 'a', 'b' ] );
|
||||
$this->assertSame( '<message key="key">' .
|
||||
'<list listType="text">' .
|
||||
'<text>a</text><text>b</text>' .
|
||||
'</list></message>',
|
||||
$mv->dump() );
|
||||
$this->assertSame( $mv, $mv2 );
|
||||
}
|
||||
}
|
||||
Loading…
Reference in a new issue