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.
+ * Converts MessageValue message specifiers to localized plain text in a certain language.
*
* 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
namespace Wikimedia\Message;
/**
- * The class for list parameters
+ * Value object representing a message parameter that consists of a list of values.
+ *
+ * Message parameter classes are pure value objects and are safely newable.
*/
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
+ * @param string $listType One of the ListType constants.
+ * @param (MessageParam|MessageValue|string|int|float)[] $elements Values in the list.
+ * Values that are not instances of MessageParam are wrapped using ParamType::TEXT.
*/
public function __construct( $listType, array $elements ) {
$this->type = ParamType::LIST;
if ( $element instanceof MessageParam ) {
$this->value[] = $element;
} elseif ( is_scalar( $element ) ) {
- $this->value[] = new TextParam( ParamType::TEXT, $element );
+ $this->value[] = new ScalarParam( ParamType::TEXT, $element );
} else {
throw new \InvalidArgumentException(
'ListParam elements must be MessageParam or scalar' );
/**
* 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.
+ * unstable implementation detail.
*/
class ListType {
/** A comma-separated list */
namespace Wikimedia\Message;
/**
- * The base class for message parameters.
+ * Value object representing a message parameter that consists of a list of values.
+ *
+ * Message parameter classes are pure value objects and are safely newable.
*/
abstract class MessageParam {
protected $type;
/**
* Get the input value of the parameter
*
- * @return int|float|string|array
+ * @return mixed
*/
public function getValue() {
return $this->value;
namespace Wikimedia\Message;
/**
- * A MessageValue holds a key and an array of parameters
+ * Value object representing a message for i18n.
+ *
+ * A MessageValue holds a key and an array of parameters. It can be converted
+ * to a string in a particular language using formatters obtained from an
+ * IMessageFormatterFactory.
+ *
+ * MessageValues are pure value objects and are safely newable.
*/
class MessageValue {
/** @var string */
/**
* @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.
+ * @param (MessageParam|MessageValue|string|int|float)[] $params Values that are not instances
+ * of MessageParam are wrapped using ParamType::TEXT.
*/
public function __construct( $key, $params = [] ) {
$this->key = $key;
/**
* Chainable mutator which adds text parameters and MessageParam parameters
*
- * @param mixed ...$values Scalar or MessageParam values
+ * @param MessageParam|MessageValue|string|int|float ...$values
* @return MessageValue
*/
public function params( ...$values ) {
if ( $value instanceof MessageParam ) {
$this->params[] = $value;
} else {
- $this->params[] = new TextParam( ParamType::TEXT, $value );
+ $this->params[] = new ScalarParam( 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
+ * @param MessageValue|string|int|float ...$values Scalar values
* @return MessageValue
*/
public function textParamsOfType( $type, ...$values ) {
foreach ( $values as $value ) {
- $this->params[] = new TextParam( $type, $value );
+ $this->params[] = new ScalarParam( $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.
+ * @param (MessageParam|MessageValue|string|int|float)[] ...$values Each value
+ * is an array of items suitable to pass as $params to ListParam::__construct()
* @return MessageValue
*/
public function listParamsOfType( $listType, ...$values ) {
}
/**
- * Chainable mutator which adds parameters of type text.
+ * Chainable mutator which adds parameters of type text (ParamType::TEXT).
*
- * @param string ...$values
+ * @param MessageValue|string|int|float ...$values
* @return MessageValue
*/
public function textParams( ...$values ) {
}
/**
- * Chainable mutator which adds numeric parameters
+ * Chainable mutator which adds numeric parameters (ParamType::NUM).
*
- * @param mixed ...$values
+ * @param int|float ...$values
* @return MessageValue
*/
public function numParams( ...$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.
+ * in seconds (ParamType::DURATION_LONG).
+ *
+ * This is similar to shorDurationParams() except that the result will be
+ * more verbose.
*
* @param int|float ...$values
* @return MessageValue
}
/**
- * Chainable mutator which adds parameters which are a time period in seconds.
- * This is similar to durationParams() except that the result will be more
+ * Chainable mutator which adds parameters which are a duration specified
+ * in seconds (ParamType::DURATION_SHORT).
+ *
+ * This is similar to longDurationParams() except that the result will be more
* compact.
*
* @param int|float ...$values
}
/**
- * Chainable mutator which adds parameters which are an expiry timestamp
- * as used in the MediaWiki database schema.
+ * Chainable mutator which adds parameters which are an expiry timestamp (ParamType::EXPIRY).
*
- * @param string ...$values
+ * @param string ...$values Timestamp as accepted by the Wikimedia\Timestamp library,
+ * or "infinity"
* @return MessageValue
*/
public function expiryParams( ...$values ) {
}
/**
- * Chainable mutator which adds parameters which are a number of bytes.
+ * Chainable mutator which adds parameters which are a number of bytes (ParamType::SIZE).
*
* @param int ...$values
* @return MessageValue
/**
* Chainable mutator which adds parameters which are a number of bits per
- * second.
+ * second (ParamType::BITRATE).
*
* @param int|float ...$values
* @return MessageValue
}
/**
- * Chainable mutator which adds parameters of type "raw".
+ * Chainable mutator which adds "raw" parameters (ParamType::RAW).
*
- * @param mixed ...$values
+ * Raw parameters are substituted after formatter processing. The caller is responsible
+ * for ensuring that the value will be safe for the intended output format, and
+ * documenting what that intended output format is.
+ *
+ * @param string ...$values
* @return MessageValue
*/
public function rawParams( ...$values ) {
}
/**
- * Chainable mutator which adds parameters of type "plaintext".
+ * Chainable mutator which adds plaintext parameters (ParamType::PLAINTEXT).
+ *
+ * Plaintext parameters are substituted after formatter processing. The value
+ * will be escaped by the formatter as appropriate for the target output format
+ * so as to be represented as plain text rather than as any sort of markup.
+ *
+ * @param string ...$values
+ * @return MessageValue
*/
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".
+ * Chainable mutator which adds comma lists (ListType::COMMA).
*
* The list parameters thus created are formatted as a comma-separated list,
* or some local equivalent.
*
- * @param (MessageParam|string)[] ...$values
+ * @param (MessageParam|MessageValue|string|int|float)[] ...$values Each value
+ * is an array of items suitable to pass as $params to ListParam::__construct()
* @return MessageValue
*/
public function commaListParams( ...$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".
+ * Chainable mutator which adds semicolon lists (ListType::SEMICOLON).
*
* The list parameters thus created are formatted as a semicolon-separated
* list, or some local equivalent.
*
- * @param (MessageParam|string)[] ...$values
+ * @param (MessageParam|MessageValue|string|int|float)[] ...$values Each value
+ * is an array of items suitable to pass as $params to ListParam::__construct()
* @return MessageValue
*/
public function semicolonListParams( ...$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".
+ * Chainable mutator which adds pipe lists (ListType::PIPE).
*
* The list parameters thus created are formatted as a pipe ("|") -separated
* list, or some local equivalent.
*
- * @param (MessageParam|string)[] ...$values
+ * @param (MessageParam|MessageValue|string|int|float)[] ...$values Each value
+ * is an array of items suitable to pass as $params to ListParam::__construct()
* @return MessageValue
*/
public function pipeListParams( ...$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".
+ * Chainable mutator which adds natural-language lists (ListType::AND).
*
* The list parameters thus created, when formatted, are joined as in natural
* language. In English, this means a comma-separated list, with the last
/**
* 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.
+ * are an unstable implementation detail.
+ *
+ * Unless otherwise noted, these should be used with an instance of ScalarParam.
*/
class ParamType {
- /** A simple text parameter */
+ /** A simple text string or another MessageValue, not otherwise formatted. */
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. */
+ /**
+ * A number of seconds, to be formatted as natural language text.
+ * The value will be output exactly.
+ */
const DURATION_LONG = 'duration';
- /** A number of seconds, to be formatted in an abbreviated way. */
+ /**
+ * A number of seconds, to be formatted as natural language text in an abbreviated way.
+ * The output will be rounded to an appropriate magnitude.
+ */
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.
+ * An expiry time.
+ *
+ * The input is either a timestamp in one of the formats accepted by the
+ * Wikimedia\Timestamp library, or "infinity" if the thing doesn't expire.
+ *
+ * The output is a date and time in local format, or a string representing
+ * an "infinite" expiry.
*/
const EXPIRY = 'expiry';
- /** A number of bytes. */
+ /** A number of bytes. The output will be rounded to an appropriate magnitude. */
const SIZE = 'size';
- /** A number of bits per second. */
+ /** A number of bits per second. The output will be rounded to an appropriate magnitude. */
const BITRATE = 'bitrate';
- /** The list type (ListParam) */
+ /** A list of values. Must be used with 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.
+ * A text parameter which is substituted after formatter processing.
+ *
+ * The creator of the parameter and message is responsible for ensuring
+ * that the value will be safe for the intended output format, and
+ * documenting what that intended output format is.
*/
const RAW = 'raw';
- /** Reserved for future use. */
+ /**
+ * A text parameter which is substituted after formatter processing.
+ * The output will be escaped as appropriate for the output format so
+ * as to represent plain text rather than any sort of markup.
+ */
const PLAINTEXT = 'plaintext';
}
--- /dev/null
+Wikimedia Internationalization Library
+======================================
+
+This library provides interfaces and value objects for internationalization (i18n)
+of applications in PHP.
+
+It is based on the i18n code used in MediaWiki, and is also intended to be
+compatible with [jQuery.i18n], a JavaScript i18n library.
+
+Concepts
+--------
+
+Any text string that is needed in an application is a **message**. This might
+be something like a button label, a sentence, or a longer text. Each message is
+assigned a **message key**, which is used as the identifier in code.
+
+Each message is translated into various languages, each represented by a
+**language code**. The message's text (as translated into each language) can
+contain **placeholders**, which represents a place in the message where a
+**parameter** is to be inserted, and **formatting commands**. It might be plain
+text other than these placeholders and formatting commands, or it might be in a
+**markup language** such as wikitext or Markdown.
+
+A **formatter** is used to convert the message key and parameters into a text
+representation in a particular language and **output format**.
+
+The library itself imposes few restrictions on all of these concepts; this
+document contains recommendations to help various implementations operate in
+compatible ways.
+
+Usage
+-----
+
+<pre lang="php">
+use Wikimedia\Message\MessageValue;
+use Wikimedia\Message\MessageParam;
+use Wikimedia\Message\ParamType;
+
+// Constructor interface
+$message = new MessageValue( 'message-key', [
+ 'parameter',
+ new MessageValue( 'another-message' ),
+ new MessageParam( ParamType::NUM, 12345 ),
+] );
+
+// Fluent interface
+$message = ( new MessageValue( 'message-key' ) )
+ ->params( 'parameter', new MessageValue( 'another-message' ) )
+ ->numParams( 12345 );
+
+// Formatting
+$messageFormatter = $serviceContainter->get( 'MessageFormatterFactory' )->getTextFormatter( 'de' );
+$output = $messageFormatter->format( $message );
+</pre>
+
+Class Overview
+--------------
+
+### Messages
+
+Messages and their parameters are represented by newable value objects.
+
+**MessageValue** represents an instance of a message, holding the key and any
+parameters. It is mutable in that parameters can be added to the object after
+creation.
+
+**MessageParam** is an abstract value class representing a parameter to a message.
+It has a type (using constants defined in the **ParamType** class) and a value. It
+has two implementations:
+
+- **ScalarParam** represents a single-valued parameter, such as a text string, a
+ number, or another message.
+- **ListParam** represents a list of values, which will be joined together with
+ appropriate separators. It has a "list type" (using constants defined in the
+ **ListType** class) defining the desired separators.
+
+### Formatters
+
+A formatter for a particular language is obtained from an implementation of
+**IMessageFormatterFactory**. No implementation of this interface is provided by
+this library. If an environment needs its formatters to vary behavior on things
+other than the language code, for example selecting among multiple sources of
+messages or markup language used for processing message texts, it should define
+a MessageFormatterFactoryFactory of some sort to provide appropriate
+IMessageFormatterFactory implementations.
+
+There is no one base interface for all formatters; the intent is that type
+hinting will ensure that the formatter being used will produce output in the
+expected output format. The defined output formats are:
+
+- **ITextFormatter** produces plain text output.
+
+No implementation of these interfaces are provided by this library.
+
+Formatter implementations are expected to perform the following procedure to
+generate the output string:
+
+1. Fetch the message's translation in the formatter's language. Details of this
+ fetching are unspecified here.
+ - If no translation is found in the formatter's language, it should attempt
+ to fall back to appropriate other languages. Details of the fallback are
+ unspecified here.
+ - If no translation can be found in any fallback language, a string should
+ be returned that indicates at minimum the message key that was unable to
+ be found.
+2. Replace placeholders with parameter values.
+ - Note that placeholders must not be replaced recursively. That is, if a
+ parameter's value contains text that looks like a placeholder, it must not
+ be replaced as if it really were a placeholder.
+ - Certain types of parameters are not substituted directly at this stage.
+ Instead their placeholders must be replaced with an opaque representation
+ that will not be misinterpreted during later stages.
+ - Parameters of type RAW or PLAINTEXT
+ - TEXT parameters with a MessageValue as the value
+ - LIST parameters with any late-substituted value as one of their values.
+3. Process any formatting commands.
+4. Process the source markup language to produce a string in the desired output
+ format. This may be a no-op, and may be combined with the previous step if
+ the markup language implements compatible formatting commands.
+5. Replace any opaque representations from step 2 with the actual values of
+ the corresponding parameters.
+
+Guidelines for Interoperability
+-------------------------------
+
+Besides allowing for libraries to safely supply their own translations for
+every app using them, and apps to easily use libraries' translations instead of
+having to retranslate everything, following these guidelines will also help
+open source projects use [translatewiki.net] for crowdsourced volunteer
+translation into many languages.
+
+### Language codes
+
+[BCP 47] language tags should be used for language codes. If a supplied
+language tag is not recognized, at minimum the corresponding tag with all
+optional subtags stripped should be tried as a fallback.
+
+All messages must have a translation in English (code "en"). All languages
+should fall back to English as a last resort.
+
+The English translations should use `{{PLURAL:...}}` and `{{GENDER:...}}` even
+when English doesn't make a grammatical distinction, to signal to translators
+that plural/gender support is available.
+
+Language code "qqq" is reserved for documenting messages. Documentation should
+describe the context in which the message is used and the values of all
+parameters used with the message. Generally this is written in English.
+Attempting to obtain a message formatter for "qqq" should return one for "en"
+instead.
+
+Language code "qqx" is reserved for debugging. Rather than retrieving
+translations from some underlying storage, every key should act as if it were
+translated as something `(key-name: $1, $2, $3)` with the number of
+placeholders depending on how many parameters are included in the
+MessageValue.
+
+### Message keys
+
+Message keys intended for use with external implementations should follow
+certain guidelines for interoperability:
+
+- Keys should be restricted to the regular expression `/^[a-z][a-z0-9-]*$/`.
+ That is, it should consist of lowercase ASCII letters, numbers, and hyphen
+ only, and should begin with a letter.
+- Keys should be prefixed to help avoid collisions. For example, a library
+ named "ApplePicker" should prefix its message keys with "applepicker-".
+- Common values needing translation, such as names of months and weekdays,
+ should not be prefixed by each library. Libraries needing these should use
+ keys from the [Common Locale Data Repository][CLDR] and document this
+ requirement, and environments should provide these messages.
+
+### Message format
+
+Placeholders are represented by `$1`, `$2`, `$3`, and so on. Text like `$100`
+is interpreted as a placeholder for parameter 100 if 100 or more parameters
+were supplied, as a placeholder for parameter 10 followed by text "0" if
+between ten and 99 parameters were supplied, and as a placeholder for parameter
+1 followed by text "00" if between one and nine parameters were supplied.
+
+All formatting commands look like `{{NAME:$value1|$value2|$value3|...}}`. Braces
+are to be balanced, e.g. `{{NAME:foo|{{bar|baz}}}}` has $value1 as "foo" and
+$value2 as "{{bar|baz}}". The name is always case-insensitive.
+
+Anything syntactically resembling a placeholder or formatting command that does
+not correspond to an actual paramter or known command should be left unchanged
+for processing by the markup language processor.
+
+Libraries providing messages for use by externally-defined formatters should
+generally assume no markup language will be applied, and should avoid
+constructs used by common markup languages unless they also make sense when
+read as plain text.
+
+### Formatting commands
+
+The following formatting commands should be supported.
+
+#### PLURAL
+
+`{{PLURAL:$count|$formA|$formB|...}}` is used to produce plurals.
+
+$count is a number, which may have been formatted with ParamType::NUM.
+
+The number of forms and which count corresponds to which form depend on the
+language, for example English uses `{{PLURAL:$1|one|other}}` while Arabic uses
+`{{PLURAL:$1|zero|one|two|few|many|other}}`. Details are defined in
+[CLDR][CLDR plurals].
+
+It is not possible to "skip" positions while still suppling later ones. If too
+few values are supplied, the final form is repeated for subsequent positions.
+
+If there is an explicit plural form to be given for a specific number, it may
+be specified with syntax like `{{PLURAL:$1|one egg|$1 eggs|12=a dozen eggs}}`.
+
+#### GENDER
+
+`{{GENDER:$name|$masculine|$feminine|$unspecified}}` is used to handle
+grammatical gender, typically when messages refer to user accounts.
+
+This supports three grammatical genders: "male", "female", and a third option
+for cases where the gender is unspecified, unknown, or neither male nor female.
+It does not attempt to handle animate-inanimate or [T-V] distinctions.
+
+$name is a user account name or other similar identifier. If the name given
+does not correspond to any known user account, it should probably use the
+$unspecified gender.
+
+If $feminine and/or $unspecified is not specified, the value of $masculine
+is normally used in its place.
+
+#### GRAMMAR
+
+`{{GRAMMAR:$form|$term}}` converts a term to an appropriate grammatical form.
+
+If no mapping for $term to $form exists, $term should be returned unchanged.
+
+See [jQuery.i18n § Grammar][jQuery.i18n grammar] for details.
+
+#### BIDI
+
+`{{BIDI:$text}}` applies directional isolation to the wrapped text, to attempt
+to avoid errors where directionally-neutral characters are wrongly displayed
+when between LTR and RTL content.
+
+This should output U+202A (left-to-right embedding) or U+202B (right-to-left
+embedding) before the text, depending on the directionality of the first
+strongly-directional character in $text, and U+202C (pop directional
+formatting) after, or do something equivalent for the target output format.
+
+### Supplying translations
+
+Code intending its messages to be used by externally-defined formatters should
+supply the translations as described by
+[jQuery.i18n § Message File Format][jQuery.i18n file format].
+
+In brief, the base directory of the library should contain a directory named
+"i18n". This directory should contain JSON files named by code such as
+"en.json", "de.json", "qqq.json", each with contents like:
+
+```json
+{
+ "@metadata": {
+ "authors": [
+ "Alice",
+ "Bob",
+ "Carol",
+ "David"
+ ],
+ "last-updated": "2012-09-21"
+ },
+ "appname-title": "Example Application",
+ "appname-sub-title": "An example application",
+ "appname-header-introduction": "Introduction",
+ "appname-about": "About this application",
+ "appname-footer": "Footer text"
+}
+```
+
+Formatter implementations should be able to consume message data supplied in
+this format, either directly via registration of i18n directories to check or
+by providing tooling to incorporate it during a build step.
+
+
+---
+[jQuery.i18n]: https://github.com/wikimedia/jquery.i18n
+[BCP 47]: https://tools.ietf.org/rfc/bcp/bcp47.txt
+[CLDR]: http://cldr.unicode.org/
+[CLDR plurals]: https://www.unicode.org/cldr/charts/latest/supplemental/language_plural_rules.html
+[jQuery.i18n grammar]: https://github.com/wikimedia/jquery.i18n#grammar
+[jQuery.i18n file format]: https://github.com/wikimedia/jquery.i18n#message-file-format
+[translatewiki.net]: https://translatewiki.net/wiki/Translating:New_project
+[T-V]: https://en.wikipedia.org/wiki/T%E2%80%93V_distinction
--- /dev/null
+<?php
+
+namespace Wikimedia\Message;
+
+/**
+ * Value object representing a message parameter holding a single value.
+ *
+ * Message parameter classes are pure value objects and are safely newable.
+ */
+class ScalarParam extends MessageParam {
+ /**
+ * Construct a text parameter
+ *
+ * @param string $type One of the ParamType constants.
+ * @param string|int|float|MessageValue $value
+ */
+ public function __construct( $type, $value ) {
+ $this->type = $type;
+ $this->value = $value;
+ }
+
+ public function dump() {
+ if ( $this->value instanceof MessageValue ) {
+ $contents = $this->value->dump();
+ } else {
+ $contents = htmlspecialchars( $this->value );
+ }
+ return "<{$this->type}>" . $contents . "</{$this->type}>";
+ }
+}
+++ /dev/null
-<?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}>";
- }
-}
use Message;
use Wikimedia\Message\MessageValue;
use Wikimedia\Message\ParamType;
-use Wikimedia\Message\TextParam;
+use Wikimedia\Message\ScalarParam;
/**
* @covers \MediaWiki\Message\TextFormatter
* @covers \Wikimedia\Message\MessageValue
* @covers \Wikimedia\Message\ListParam
- * @covers \Wikimedia\Message\TextParam
+ * @covers \Wikimedia\Message\ScalarParam
* @covers \Wikimedia\Message\MessageParam
*/
class TextFormatterTest extends MediaWikiTestCase {
$formatter = $this->createTextFormatter( 'en' );
$mv = ( new MessageValue( 'test' ) )->commaListParams( [
'a',
- new TextParam( ParamType::BITRATE, 100 ),
+ new ScalarParam( ParamType::BITRATE, 100 ),
] );
$result = $formatter->format( $mv );
$this->assertSame( 'test a, 100 bps $2', $result );
use Wikimedia\Message\ListType;
use Wikimedia\Message\MessageValue;
use Wikimedia\Message\ParamType;
-use Wikimedia\Message\TextParam;
+use Wikimedia\Message\ScalarParam;
use MediaWikiTestCase;
/**
* @covers \Wikimedia\Message\MessageValue
* @covers \Wikimedia\Message\ListParam
- * @covers \Wikimedia\Message\TextParam
+ * @covers \Wikimedia\Message\ScalarParam
* @covers \Wikimedia\Message\MessageParam
*/
class MessageValueTest extends MediaWikiTestCase {
'<message key="key"><text>a</text></message>'
],
[
- [ new TextParam( ParamType::BITRATE, 100 ) ],
+ [ new ScalarParam( ParamType::BITRATE, 100 ) ],
'<message key="key"><bitrate>100</bitrate></message>'
],
];
public function testParams() {
$mv = new MessageValue( 'key' );
$mv->params( 1, 'x' );
- $mv2 = $mv->params( new TextParam( ParamType::BITRATE, 100 ) );
+ $mv2 = $mv->params( new ScalarParam( ParamType::BITRATE, 100 ) );
$this->assertSame(
'<message key="key"><text>1</text><text>x</text><bitrate>100</bitrate></message>',
$mv->dump() );
public function testTextParams() {
$mv = new MessageValue( 'key' );
- $mv2 = $mv->textParams( 'a', 'b' );
+ $mv2 = $mv->textParams( 'a', 'b', new MessageValue( 'key2' ) );
$this->assertSame( '<message key="key">' .
'<text>a</text>' .
'<text>b</text>' .
+ '<text><message key="key2"></message></text>' .
'</message>',
$mv->dump() );
$this->assertSame( $mv, $mv2 );