John Du Hart <john@compwhizii.net> <johnduhart@users.mediawiki.org>
John Erling Blad <john.blad@wikimedia.de>
Jon Harald Søby <jhsoby@gmail.com> <jhsoby@users.mediawiki.org>
+Jon Harald Søby <jhsoby@gmail.com>
Jon Robson <jrobson@wikimedia.org>
Jon Robson <jrobson@wikimedia.org> <jdlrobson@gmail.com>
Juliusz Gonera <jgonera@gmail.com>
Marko Obrovac <mobrovac@wikimedia.org>
Markus Glaser <glaser@hallowelt.biz>
Markus Glaser <glaser@hallowelt.biz> <mglaser@users.mediawiki.org>
+Martin Urbanec <martin.urbanec@wikimedia.cz>
Matt Johnston <mattj@emazestudios.com> <mattj@users.mediawiki.org>
Matthew Britton <hugglegurch@gmail.com> <gurch@users.mediawiki.org>
Matthew Bowker <matthewrbowker.bugs@gmail.com>
];
$cfg['suppress_issue_types'] = array_merge( $cfg['suppress_issue_types'], [
- // approximate error count: 18
- "PhanAccessMethodInternal",
- // approximate error count: 17
- "PhanCommentParamOnEmptyParamList",
- // approximate error count: 29
- "PhanCommentParamWithoutRealParam",
- // approximate error count: 2
- "PhanCompatibleNegativeStringOffset",
- // approximate error count: 21
- "PhanParamReqAfterOpt",
- // approximate error count: 26
- "PhanParamSignatureMismatch",
- // approximate error count: 4
- "PhanParamSignatureMismatchInternal",
- // approximate error count: 127
- "PhanParamTooMany",
- // approximate error count: 2
- "PhanTraitParentReference",
- // approximate error count: 30
- "PhanTypeArraySuspicious",
- // approximate error count: 27
- "PhanTypeArraySuspiciousNullable",
- // approximate error count: 26
- "PhanTypeComparisonFromArray",
- // approximate error count: 63
- "PhanTypeInvalidDimOffset",
- // approximate error count: 7
- "PhanTypeInvalidLeftOperandOfIntegerOp",
- // approximate error count: 2
- "PhanTypeInvalidRightOperandOfIntegerOp",
- // approximate error count: 154
- "PhanTypeMismatchArgument",
- // approximate error count: 27
- "PhanTypeMismatchArgumentInternal",
- // approximate error count: 2
- "PhanTypeMismatchDimEmpty",
- // approximate error count: 27
- "PhanTypeMismatchDimFetch",
- // approximate error count: 10
- "PhanTypeMismatchForeach",
- // approximate error count: 77
- "PhanTypeMismatchProperty",
- // approximate error count: 84
- "PhanTypeMismatchReturn",
- // approximate error count: 12
- "PhanTypeObjectUnsetDeclaredProperty",
- // approximate error count: 9
- "PhanTypeSuspiciousNonTraversableForeach",
- // approximate error count: 3
- "PhanTypeSuspiciousStringExpression",
+ // approximate error count: 19
+ "PhanParamReqAfterOpt", // False positives with nullables, ref phan issue #3159
+ // approximate error count: 110
+ "PhanParamTooMany", // False positives with variargs. Unsuppress after dropping HHVM
+
// approximate error count: 22
+ "PhanAccessMethodInternal",
+ // approximate error count: 36
"PhanUndeclaredConstant",
- // approximate error count: 3
- "PhanUndeclaredInvokeInCallable",
- // approximate error count: 237
- "PhanUndeclaredMethod",
- // approximate error count: 846
+ // approximate error count: 60
+ "PhanTypeMismatchArgument",
+ // approximate error count: 752
"PhanUndeclaredProperty",
- // approximate error count: 2
- "PhanUndeclaredVariableAssignOp",
- // approximate error count: 55
- "PhanUndeclaredVariableDim",
] );
$cfg['ignore_undeclared_variables_in_global_scope'] = true;
-$cfg['globals_type_map']['IP'] = 'string';
+$cfg['globals_type_map'] = array_merge( $cfg['globals_type_map'], [
+ 'IP' => 'string',
+ 'wgGalleryOptions' => 'array',
+ 'wgDummyLanguageCodes' => 'string[]',
+ 'wgNamespaceProtection' => 'array<string,string|string[]>',
+ 'wgNamespaceAliases' => 'array<string,int>',
+ 'wgLockManagers' => 'array[]',
+ 'wgForeignFileRepos' => 'array[]',
+ 'wgDefaultUserOptions' => 'array',
+ 'wgSkipSkins' => 'string[]',
+ 'wgLogTypes' => 'string[]',
+ 'wgLogNames' => 'array<string,string>',
+ 'wgLogHeaders' => 'array<string,string>',
+ 'wgLogActionsHandlers' => 'array<string,class-string>',
+ 'wgPasswordPolicy' => 'array<string,array<string,string|array>>',
+ 'wgVirtualRestConfig' => 'array<string,array>',
+ 'wgWANObjectCaches' => 'array[]',
+ 'wgLocalInterwikis' => 'string[]',
+] );
return $cfg;
--- /dev/null
+<?php
+// These stubs were generated by the phan stub generator.
+// @phan-stub-for-extension dom@20031129
+
+namespace {
+class DOMAttr extends \DOMNode {
+
+ // properties
+ public $name;
+ public $ownerElement;
+ public $schemaTypeInfo;
+ public $specified;
+ public $value;
+
+ // methods
+ public function isId() {}
+ public function __construct($name, $value = null) {}
+}
+
+class DOMCdataSection extends \DOMText {
+
+ // methods
+ public function __construct($value) {}
+}
+
+class DOMCharacterData extends \DOMNode {
+
+ // properties
+ public $data;
+ public $length;
+
+ // methods
+ public function substringData($offset, $count) {}
+ public function appendData($arg) {}
+ public function insertData($offset, $arg) {}
+ public function deleteData($offset, $count) {}
+ public function replaceData($offset, $count, $arg) {}
+}
+
+class DOMComment extends \DOMCharacterData {
+
+ // methods
+ public function __construct($value = null) {}
+}
+
+class DOMConfiguration {
+
+ // methods
+ public function setParameter($name, $value) {}
+ public function getParameter($name = null) {}
+ public function canSetParameter($name = null, $value = null) {}
+}
+
+class DOMDocument extends \DOMNode {
+
+ // properties
+ public $actualEncoding;
+ public $config;
+ public $doctype;
+ public $documentElement;
+ public $documentURI;
+ public $encoding;
+ public $formatOutput;
+ public $implementation;
+ public $preserveWhiteSpace;
+ public $recover;
+ public $resolveExternals;
+ public $standalone;
+ public $strictErrorChecking;
+ public $substituteEntities;
+ public $validateOnParse;
+ public $version;
+ public $xmlEncoding;
+ public $xmlStandalone;
+ public $xmlVersion;
+
+ // methods
+ public function createElement($tagName, $value = null) {}
+ public function createDocumentFragment() {}
+ public function createTextNode($data) {}
+ public function createComment($data) {}
+ public function createCDATASection($data) {}
+ public function createProcessingInstruction($target, $data) {}
+ public function createAttribute($name) {}
+ public function createEntityReference($name) {}
+ public function getElementsByTagName($tagName) {}
+ public function importNode(\DOMNode $importedNode, $deep) {}
+ public function createElementNS($namespaceURI, $qualifiedName, $value = null) {}
+ public function createAttributeNS($namespaceURI, $qualifiedName) {}
+ public function getElementsByTagNameNS($namespaceURI, $localName) {}
+ public function getElementById($elementId) {}
+ public function adoptNode(\DOMNode $source) {}
+ public function normalizeDocument() {}
+ public function renameNode(\DOMNode $node, $namespaceURI, $qualifiedName) {}
+ public function load($source, $options = null) {}
+ public function save($file) {}
+ public function loadXML($source, $options = null) {}
+ public function saveXML(\DOMNode $node = null, $options = null) {}
+ public function __construct($version = null, $encoding = null) {}
+ public function validate() {}
+ public function xinclude($options = null) {}
+ public function loadHTML($source, $options = null) {}
+ public function loadHTMLFile($source, $options = null) {}
+ public function saveHTML() {}
+ public function saveHTMLFile($file) {}
+ public function schemaValidate($filename) {}
+ public function schemaValidateSource($source) {}
+ public function relaxNGValidate($filename) {}
+ public function relaxNGValidateSource($source) {}
+ public function registerNodeClass($baseClass, $extendedClass) {}
+}
+
+class DOMDocumentFragment extends \DOMNode {
+
+ // properties
+ public $name;
+
+ // methods
+ public function __construct() {}
+ public function appendXML($data) {}
+}
+
+class DOMDocumentType extends \DOMNode {
+
+ // properties
+ public $entities;
+ public $internalSubset;
+ public $name;
+ public $notations;
+ public $publicId;
+ public $systemId;
+}
+
+class DOMDomError {
+}
+
+class DOMElement extends \DOMNode {
+
+ // properties
+ public $schemaTypeInfo;
+ public $tagName;
+
+ // methods
+ public function getAttribute($name) {}
+ public function setAttribute($name, $value) {}
+ public function removeAttribute($name) {}
+ public function getAttributeNode($name) {}
+ public function setAttributeNode(\DOMAttr $newAttr) {}
+ public function removeAttributeNode(\DOMAttr $oldAttr) {}
+ public function getElementsByTagName($name) {}
+ public function getAttributeNS($namespaceURI, $localName) {}
+ public function setAttributeNS($namespaceURI, $qualifiedName, $value) {}
+ public function removeAttributeNS($namespaceURI, $localName) {}
+ public function getAttributeNodeNS($namespaceURI, $localName) {}
+ public function setAttributeNodeNS(\DOMAttr $newAttr) {}
+ public function getElementsByTagNameNS($namespaceURI, $localName) {}
+ public function hasAttribute($name) {}
+ public function hasAttributeNS($namespaceURI, $localName) {}
+ public function setIdAttribute($name, $isId) {}
+ public function setIdAttributeNS($namespaceURI, $localName, $isId) {}
+ public function setIdAttributeNode(\DOMAttr $attr, $isId) {}
+ public function __construct($name, $value = null, $uri = null) {}
+}
+
+class DOMEntity extends \DOMNode {
+
+ // properties
+ public $actualEncoding;
+ public $encoding;
+ public $notationName;
+ public $publicId;
+ public $systemId;
+ public $version;
+}
+
+class DOMEntityReference extends \DOMNode {
+
+ // properties
+ public $name;
+
+ // methods
+ public function __construct($name) {}
+}
+
+class DOMErrorHandler {
+
+ // methods
+ public function handleError(\DOMDomError $error) {}
+}
+
+final class DOMException extends \Exception {
+
+ // properties
+ public $code;
+ protected $message;
+ protected $file;
+ protected $line;
+}
+
+class DOMImplementation {
+
+ // properties
+ public $name;
+
+ // methods
+ public function getFeature($feature, $version) {}
+ public function hasFeature() {}
+ public function createDocumentType($qualifiedName, $publicId, $systemId) {}
+ public function createDocument($namespaceURI, $qualifiedName, \DOMDocumentType $docType) {}
+}
+
+class DOMImplementationList {
+
+ // methods
+ public function item($index) {}
+}
+
+class DOMImplementationSource {
+
+ // methods
+ public function getDomimplementation($features) {}
+ public function getDomimplementations($features) {}
+}
+
+class DOMLocator {
+}
+
+class DOMNameList {
+
+ // methods
+ public function getName($index) {}
+ public function getNamespaceURI($index) {}
+}
+
+class DOMNameSpaceNode {
+}
+
+class DOMNamedNodeMap implements \Traversable, \Countable {
+
+ // properties
+ public $length;
+
+ // methods
+ public function getNamedItem($name) {}
+ public function setNamedItem(\DOMNode $arg) {}
+ public function removeNamedItem($name = null) {}
+ public function item($index = null) {}
+ public function getNamedItemNS($namespaceURI = null, $localName = null) {}
+ public function setNamedItemNS(\DOMNode $arg = null) {}
+ public function removeNamedItemNS($namespaceURI = null, $localName = null) {}
+ public function count() {}
+}
+
+class DOMNode {
+
+ // properties
+ public $attributes;
+ public $baseURI;
+ public $childNodes;
+ public $firstChild;
+ public $lastChild;
+ public $localName;
+ public $namespaceURI;
+ public $nextSibling;
+ public $nodeName;
+ public $nodeType;
+ public $nodeValue;
+ public $ownerDocument;
+ public $parentNode;
+ public $prefix;
+ public $previousSibling;
+ public $textContent;
+
+ // methods
+ public function insertBefore(\DOMNode $newChild, \DOMNode $refChild = null) {}
+ public function replaceChild(\DOMNode $newChild, \DOMNode $oldChild) {}
+ public function removeChild(\DOMNode $oldChild) {}
+ public function appendChild(\DOMNode $newChild) {}
+ public function hasChildNodes() {}
+ public function cloneNode($deep = null) {}
+ public function normalize() {}
+ public function isSupported($feature, $version) {}
+ public function hasAttributes() {}
+ public function compareDocumentPosition(\DOMNode $other) {}
+ public function isSameNode(\DOMNode $other) {}
+ public function lookupPrefix($namespaceURI) {}
+ public function isDefaultNamespace($namespaceURI) {}
+ public function lookupNamespaceUri($prefix) {}
+ public function isEqualNode(\DOMNode $arg) {}
+ public function getFeature($feature, $version) {}
+ public function setUserData($key, $data, $handler) {}
+ public function getUserData($key) {}
+ public function getNodePath() {}
+ public function getLineNo() {}
+ public function C14N($exclusive = null, $with_comments = null, array $xpath = null, array $ns_prefixes = null) {}
+ public function C14NFile($uri, $exclusive = null, $with_comments = null, array $xpath = null, array $ns_prefixes = null) {}
+}
+
+class DOMNodeList implements \Traversable, \Countable {
+
+ // properties
+ public $length;
+
+ // methods
+ public function item($index) {}
+ public function count() {}
+}
+
+class DOMNotation extends \DOMNode {
+
+ // properties
+ public $publicId;
+ public $systemId;
+}
+
+class DOMProcessingInstruction extends \DOMNode {
+
+ // properties
+ public $data;
+ public $target;
+
+ // methods
+ public function __construct($name, $value = null) {}
+}
+
+class DOMStringExtend {
+
+ // methods
+ public function findOffset16($offset32) {}
+ public function findOffset32($offset16) {}
+}
+
+class DOMStringList {
+
+ // methods
+ public function item($index) {}
+}
+
+class DOMText extends \DOMCharacterData {
+
+ // properties
+ public $wholeText;
+
+ // methods
+ public function splitText($offset) {}
+ public function isWhitespaceInElementContent() {}
+ public function isElementContentWhitespace() {}
+ public function replaceWholeText($content) {}
+ public function __construct($value = null) {}
+}
+
+class DOMTypeinfo {
+}
+
+class DOMUserDataHandler {
+
+ // methods
+ public function handle() {}
+}
+
+class DOMXPath {
+
+ // properties
+ public $document;
+
+ // methods
+ public function __construct(\DOMDocument $doc) {}
+ public function registerNamespace($prefix, $uri) {}
+ public function query($expr, \DOMNode $context = null, $registerNodeNS = null) {}
+ public function evaluate($expr, \DOMNode $context = null, $registerNodeNS = null) {}
+ public function registerPhpFunctions() {}
+}
+
+function dom_import_simplexml($node) {}
+const DOMSTRING_SIZE_ERR = 2;
+const DOM_HIERARCHY_REQUEST_ERR = 3;
+const DOM_INDEX_SIZE_ERR = 1;
+const DOM_INUSE_ATTRIBUTE_ERR = 10;
+const DOM_INVALID_ACCESS_ERR = 15;
+const DOM_INVALID_CHARACTER_ERR = 5;
+const DOM_INVALID_MODIFICATION_ERR = 13;
+const DOM_INVALID_STATE_ERR = 11;
+const DOM_NAMESPACE_ERR = 14;
+const DOM_NOT_FOUND_ERR = 8;
+const DOM_NOT_SUPPORTED_ERR = 9;
+const DOM_NO_DATA_ALLOWED_ERR = 6;
+const DOM_NO_MODIFICATION_ALLOWED_ERR = 7;
+const DOM_PHP_ERR = 0;
+const DOM_SYNTAX_ERR = 12;
+const DOM_VALIDATION_ERR = 16;
+const DOM_WRONG_DOCUMENT_ERR = 4;
+const XML_ATTRIBUTE_CDATA = 1;
+const XML_ATTRIBUTE_DECL_NODE = 16;
+const XML_ATTRIBUTE_ENTITY = 6;
+const XML_ATTRIBUTE_ENUMERATION = 9;
+const XML_ATTRIBUTE_ID = 2;
+const XML_ATTRIBUTE_IDREF = 3;
+const XML_ATTRIBUTE_IDREFS = 4;
+const XML_ATTRIBUTE_NMTOKEN = 7;
+const XML_ATTRIBUTE_NMTOKENS = 8;
+const XML_ATTRIBUTE_NODE = 2;
+const XML_ATTRIBUTE_NOTATION = 10;
+const XML_CDATA_SECTION_NODE = 4;
+const XML_COMMENT_NODE = 8;
+const XML_DOCUMENT_FRAG_NODE = 11;
+const XML_DOCUMENT_NODE = 9;
+const XML_DOCUMENT_TYPE_NODE = 10;
+const XML_DTD_NODE = 14;
+const XML_ELEMENT_DECL_NODE = 15;
+const XML_ELEMENT_NODE = 1;
+const XML_ENTITY_DECL_NODE = 17;
+const XML_ENTITY_NODE = 6;
+const XML_ENTITY_REF_NODE = 5;
+const XML_HTML_DOCUMENT_NODE = 13;
+const XML_LOCAL_NAMESPACE = 18;
+const XML_NAMESPACE_DECL_NODE = 18;
+const XML_NOTATION_NODE = 12;
+const XML_PI_NODE = 7;
+const XML_TEXT_NODE = 3;
+}
--- /dev/null
+<?php
+// These stubs were generated by the phan stub generator.
+// @phan-stub-for-extension intl@7.3.4
+
+namespace {
+class Collator {
+
+ // constants
+ const DEFAULT_VALUE = -1;
+ const PRIMARY = 0;
+ const SECONDARY = 1;
+ const TERTIARY = 2;
+ const DEFAULT_STRENGTH = 2;
+ const QUATERNARY = 3;
+ const IDENTICAL = 15;
+ const OFF = 16;
+ const ON = 17;
+ const SHIFTED = 20;
+ const NON_IGNORABLE = 21;
+ const LOWER_FIRST = 24;
+ const UPPER_FIRST = 25;
+ const FRENCH_COLLATION = 0;
+ const ALTERNATE_HANDLING = 1;
+ const CASE_FIRST = 2;
+ const CASE_LEVEL = 3;
+ const NORMALIZATION_MODE = 4;
+ const STRENGTH = 5;
+ const HIRAGANA_QUATERNARY_MODE = 6;
+ const NUMERIC_COLLATION = 7;
+ const SORT_REGULAR = 0;
+ const SORT_STRING = 1;
+ const SORT_NUMERIC = 2;
+
+ // properties
+ public $name;
+
+ // methods
+ public function __construct($arg1) {}
+ public static function create($arg1) {}
+ public function compare($arg1, $arg2) {}
+ public function sort(array &$arr, $flags = null) {}
+ public function sortWithSortKeys(array &$arr) {}
+ public function asort(array &$arr, $flags = null) {}
+ public function getAttribute($arg1) {}
+ public function setAttribute($arg1, $arg2) {}
+ public function getStrength() {}
+ public function setStrength($arg1) {}
+ public function getLocale($arg1) {}
+ public function getErrorCode() {}
+ public function getErrorMessage() {}
+ public function getSortKey($arg1) {}
+}
+
+class IntlBreakIterator implements \Traversable {
+
+ // constants
+ const DONE = -1;
+ const WORD_NONE = 0;
+ const WORD_NONE_LIMIT = 100;
+ const WORD_NUMBER = 100;
+ const WORD_NUMBER_LIMIT = 200;
+ const WORD_LETTER = 200;
+ const WORD_LETTER_LIMIT = 300;
+ const WORD_KANA = 300;
+ const WORD_KANA_LIMIT = 400;
+ const WORD_IDEO = 400;
+ const WORD_IDEO_LIMIT = 500;
+ const LINE_SOFT = 0;
+ const LINE_SOFT_LIMIT = 100;
+ const LINE_HARD = 100;
+ const LINE_HARD_LIMIT = 200;
+ const SENTENCE_TERM = 0;
+ const SENTENCE_TERM_LIMIT = 100;
+ const SENTENCE_SEP = 100;
+ const SENTENCE_SEP_LIMIT = 200;
+
+ // methods
+ private function __construct() {}
+ public static function createWordInstance($locale = null) {}
+ public static function createLineInstance($locale = null) {}
+ public static function createCharacterInstance($locale = null) {}
+ public static function createSentenceInstance($locale = null) {}
+ public static function createTitleInstance($locale = null) {}
+ public static function createCodePointInstance() {}
+ public function getText() {}
+ public function setText($text) {}
+ public function first() {}
+ public function last() {}
+ public function previous() {}
+ public function next($offset = null) {}
+ public function current() {}
+ public function following($offset) {}
+ public function preceding($offset) {}
+ public function isBoundary($offset) {}
+ public function getLocale($locale_type) {}
+ public function getPartsIterator($key_type = null) {}
+ public function getErrorCode() {}
+ public function getErrorMessage() {}
+}
+
+class IntlCalendar {
+
+ // constants
+ const FIELD_ERA = 0;
+ const FIELD_YEAR = 1;
+ const FIELD_MONTH = 2;
+ const FIELD_WEEK_OF_YEAR = 3;
+ const FIELD_WEEK_OF_MONTH = 4;
+ const FIELD_DATE = 5;
+ const FIELD_DAY_OF_YEAR = 6;
+ const FIELD_DAY_OF_WEEK = 7;
+ const FIELD_DAY_OF_WEEK_IN_MONTH = 8;
+ const FIELD_AM_PM = 9;
+ const FIELD_HOUR = 10;
+ const FIELD_HOUR_OF_DAY = 11;
+ const FIELD_MINUTE = 12;
+ const FIELD_SECOND = 13;
+ const FIELD_MILLISECOND = 14;
+ const FIELD_ZONE_OFFSET = 15;
+ const FIELD_DST_OFFSET = 16;
+ const FIELD_YEAR_WOY = 17;
+ const FIELD_DOW_LOCAL = 18;
+ const FIELD_EXTENDED_YEAR = 19;
+ const FIELD_JULIAN_DAY = 20;
+ const FIELD_MILLISECONDS_IN_DAY = 21;
+ const FIELD_IS_LEAP_MONTH = 22;
+ const FIELD_FIELD_COUNT = 23;
+ const FIELD_DAY_OF_MONTH = 5;
+ const DOW_SUNDAY = 1;
+ const DOW_MONDAY = 2;
+ const DOW_TUESDAY = 3;
+ const DOW_WEDNESDAY = 4;
+ const DOW_THURSDAY = 5;
+ const DOW_FRIDAY = 6;
+ const DOW_SATURDAY = 7;
+ const DOW_TYPE_WEEKDAY = 0;
+ const DOW_TYPE_WEEKEND = 1;
+ const DOW_TYPE_WEEKEND_OFFSET = 2;
+ const DOW_TYPE_WEEKEND_CEASE = 3;
+ const WALLTIME_FIRST = 1;
+ const WALLTIME_LAST = 0;
+ const WALLTIME_NEXT_VALID = 2;
+
+ // methods
+ private function __construct() {}
+ public static function createInstance($timeZone = null, $locale = null) {}
+ public static function getKeywordValuesForLocale($key, $locale, $commonlyUsed) {}
+ public static function getNow() {}
+ public static function getAvailableLocales() {}
+ public function get($field) {}
+ public function getTime() {}
+ public function setTime($date) {}
+ public function add($field, $amount) {}
+ public function setTimeZone($timeZone) {}
+ public function after(\IntlCalendar $calendar) {}
+ public function before(\IntlCalendar $calendar) {}
+ public function set($fieldOrYear, $valueOrMonth, $dayOfMonth = null, $hour = null, $minute = null, $second = null) {}
+ public function roll($field, $amountOrUpOrDown) {}
+ public function clear($field = null) {}
+ public function fieldDifference($when, $field) {}
+ public function getActualMaximum($field) {}
+ public function getActualMinimum($field) {}
+ public function getDayOfWeekType($dayOfWeek) {}
+ public function getFirstDayOfWeek() {}
+ public function getGreatestMinimum($field) {}
+ public function getLeastMaximum($field) {}
+ public function getLocale($localeType) {}
+ public function getMaximum($field) {}
+ public function getMinimalDaysInFirstWeek() {}
+ public function getMinimum($field) {}
+ public function getTimeZone() {}
+ public function getType() {}
+ public function getWeekendTransition($dayOfWeek) {}
+ public function inDaylightTime() {}
+ public function isEquivalentTo(\IntlCalendar $calendar) {}
+ public function isLenient() {}
+ public function isSet($field) {}
+ public function isWeekend($date = null) {}
+ public function setFirstDayOfWeek($dayOfWeek) {}
+ public function setLenient($isLenient) {}
+ public function setMinimalDaysInFirstWeek($numberOfDays) {}
+ public function equals(\IntlCalendar $calendar) {}
+ public function getRepeatedWallTimeOption() {}
+ public function getSkippedWallTimeOption() {}
+ public function setRepeatedWallTimeOption($wallTimeOption) {}
+ public function setSkippedWallTimeOption($wallTimeOption) {}
+ public static function fromDateTime($dateTime) {}
+ public function toDateTime() {}
+ public function getErrorCode() {}
+ public function getErrorMessage() {}
+}
+
+class IntlChar {
+
+ // constants
+ const UNICODE_VERSION = '11.0';
+ const CODEPOINT_MIN = 0;
+ const CODEPOINT_MAX = 1114111;
+ const NO_NUMERIC_VALUE = -123456789.0;
+ const PROPERTY_ALPHABETIC = 0;
+ const PROPERTY_BINARY_START = 0;
+ const PROPERTY_ASCII_HEX_DIGIT = 1;
+ const PROPERTY_BIDI_CONTROL = 2;
+ const PROPERTY_BIDI_MIRRORED = 3;
+ const PROPERTY_DASH = 4;
+ const PROPERTY_DEFAULT_IGNORABLE_CODE_POINT = 5;
+ const PROPERTY_DEPRECATED = 6;
+ const PROPERTY_DIACRITIC = 7;
+ const PROPERTY_EXTENDER = 8;
+ const PROPERTY_FULL_COMPOSITION_EXCLUSION = 9;
+ const PROPERTY_GRAPHEME_BASE = 10;
+ const PROPERTY_GRAPHEME_EXTEND = 11;
+ const PROPERTY_GRAPHEME_LINK = 12;
+ const PROPERTY_HEX_DIGIT = 13;
+ const PROPERTY_HYPHEN = 14;
+ const PROPERTY_ID_CONTINUE = 15;
+ const PROPERTY_ID_START = 16;
+ const PROPERTY_IDEOGRAPHIC = 17;
+ const PROPERTY_IDS_BINARY_OPERATOR = 18;
+ const PROPERTY_IDS_TRINARY_OPERATOR = 19;
+ const PROPERTY_JOIN_CONTROL = 20;
+ const PROPERTY_LOGICAL_ORDER_EXCEPTION = 21;
+ const PROPERTY_LOWERCASE = 22;
+ const PROPERTY_MATH = 23;
+ const PROPERTY_NONCHARACTER_CODE_POINT = 24;
+ const PROPERTY_QUOTATION_MARK = 25;
+ const PROPERTY_RADICAL = 26;
+ const PROPERTY_SOFT_DOTTED = 27;
+ const PROPERTY_TERMINAL_PUNCTUATION = 28;
+ const PROPERTY_UNIFIED_IDEOGRAPH = 29;
+ const PROPERTY_UPPERCASE = 30;
+ const PROPERTY_WHITE_SPACE = 31;
+ const PROPERTY_XID_CONTINUE = 32;
+ const PROPERTY_XID_START = 33;
+ const PROPERTY_CASE_SENSITIVE = 34;
+ const PROPERTY_S_TERM = 35;
+ const PROPERTY_VARIATION_SELECTOR = 36;
+ const PROPERTY_NFD_INERT = 37;
+ const PROPERTY_NFKD_INERT = 38;
+ const PROPERTY_NFC_INERT = 39;
+ const PROPERTY_NFKC_INERT = 40;
+ const PROPERTY_SEGMENT_STARTER = 41;
+ const PROPERTY_PATTERN_SYNTAX = 42;
+ const PROPERTY_PATTERN_WHITE_SPACE = 43;
+ const PROPERTY_POSIX_ALNUM = 44;
+ const PROPERTY_POSIX_BLANK = 45;
+ const PROPERTY_POSIX_GRAPH = 46;
+ const PROPERTY_POSIX_PRINT = 47;
+ const PROPERTY_POSIX_XDIGIT = 48;
+ const PROPERTY_CASED = 49;
+ const PROPERTY_CASE_IGNORABLE = 50;
+ const PROPERTY_CHANGES_WHEN_LOWERCASED = 51;
+ const PROPERTY_CHANGES_WHEN_UPPERCASED = 52;
+ const PROPERTY_CHANGES_WHEN_TITLECASED = 53;
+ const PROPERTY_CHANGES_WHEN_CASEFOLDED = 54;
+ const PROPERTY_CHANGES_WHEN_CASEMAPPED = 55;
+ const PROPERTY_CHANGES_WHEN_NFKC_CASEFOLDED = 56;
+ const PROPERTY_BINARY_LIMIT = 65;
+ const PROPERTY_BIDI_CLASS = 4096;
+ const PROPERTY_INT_START = 4096;
+ const PROPERTY_BLOCK = 4097;
+ const PROPERTY_CANONICAL_COMBINING_CLASS = 4098;
+ const PROPERTY_DECOMPOSITION_TYPE = 4099;
+ const PROPERTY_EAST_ASIAN_WIDTH = 4100;
+ const PROPERTY_GENERAL_CATEGORY = 4101;
+ const PROPERTY_JOINING_GROUP = 4102;
+ const PROPERTY_JOINING_TYPE = 4103;
+ const PROPERTY_LINE_BREAK = 4104;
+ const PROPERTY_NUMERIC_TYPE = 4105;
+ const PROPERTY_SCRIPT = 4106;
+ const PROPERTY_HANGUL_SYLLABLE_TYPE = 4107;
+ const PROPERTY_NFD_QUICK_CHECK = 4108;
+ const PROPERTY_NFKD_QUICK_CHECK = 4109;
+ const PROPERTY_NFC_QUICK_CHECK = 4110;
+ const PROPERTY_NFKC_QUICK_CHECK = 4111;
+ const PROPERTY_LEAD_CANONICAL_COMBINING_CLASS = 4112;
+ const PROPERTY_TRAIL_CANONICAL_COMBINING_CLASS = 4113;
+ const PROPERTY_GRAPHEME_CLUSTER_BREAK = 4114;
+ const PROPERTY_SENTENCE_BREAK = 4115;
+ const PROPERTY_WORD_BREAK = 4116;
+ const PROPERTY_BIDI_PAIRED_BRACKET_TYPE = 4117;
+ const PROPERTY_INT_LIMIT = 4121;
+ const PROPERTY_GENERAL_CATEGORY_MASK = 8192;
+ const PROPERTY_MASK_START = 8192;
+ const PROPERTY_MASK_LIMIT = 8193;
+ const PROPERTY_NUMERIC_VALUE = 12288;
+ const PROPERTY_DOUBLE_START = 12288;
+ const PROPERTY_DOUBLE_LIMIT = 12289;
+ const PROPERTY_AGE = 16384;
+ const PROPERTY_STRING_START = 16384;
+ const PROPERTY_BIDI_MIRRORING_GLYPH = 16385;
+ const PROPERTY_CASE_FOLDING = 16386;
+ const PROPERTY_ISO_COMMENT = 16387;
+ const PROPERTY_LOWERCASE_MAPPING = 16388;
+ const PROPERTY_NAME = 16389;
+ const PROPERTY_SIMPLE_CASE_FOLDING = 16390;
+ const PROPERTY_SIMPLE_LOWERCASE_MAPPING = 16391;
+ const PROPERTY_SIMPLE_TITLECASE_MAPPING = 16392;
+ const PROPERTY_SIMPLE_UPPERCASE_MAPPING = 16393;
+ const PROPERTY_TITLECASE_MAPPING = 16394;
+ const PROPERTY_UNICODE_1_NAME = 16395;
+ const PROPERTY_UPPERCASE_MAPPING = 16396;
+ const PROPERTY_BIDI_PAIRED_BRACKET = 16397;
+ const PROPERTY_STRING_LIMIT = 16398;
+ const PROPERTY_SCRIPT_EXTENSIONS = 28672;
+ const PROPERTY_OTHER_PROPERTY_START = 28672;
+ const PROPERTY_OTHER_PROPERTY_LIMIT = 28673;
+ const PROPERTY_INVALID_CODE = -1;
+ const CHAR_CATEGORY_UNASSIGNED = 0;
+ const CHAR_CATEGORY_GENERAL_OTHER_TYPES = 0;
+ const CHAR_CATEGORY_UPPERCASE_LETTER = 1;
+ const CHAR_CATEGORY_LOWERCASE_LETTER = 2;
+ const CHAR_CATEGORY_TITLECASE_LETTER = 3;
+ const CHAR_CATEGORY_MODIFIER_LETTER = 4;
+ const CHAR_CATEGORY_OTHER_LETTER = 5;
+ const CHAR_CATEGORY_NON_SPACING_MARK = 6;
+ const CHAR_CATEGORY_ENCLOSING_MARK = 7;
+ const CHAR_CATEGORY_COMBINING_SPACING_MARK = 8;
+ const CHAR_CATEGORY_DECIMAL_DIGIT_NUMBER = 9;
+ const CHAR_CATEGORY_LETTER_NUMBER = 10;
+ const CHAR_CATEGORY_OTHER_NUMBER = 11;
+ const CHAR_CATEGORY_SPACE_SEPARATOR = 12;
+ const CHAR_CATEGORY_LINE_SEPARATOR = 13;
+ const CHAR_CATEGORY_PARAGRAPH_SEPARATOR = 14;
+ const CHAR_CATEGORY_CONTROL_CHAR = 15;
+ const CHAR_CATEGORY_FORMAT_CHAR = 16;
+ const CHAR_CATEGORY_PRIVATE_USE_CHAR = 17;
+ const CHAR_CATEGORY_SURROGATE = 18;
+ const CHAR_CATEGORY_DASH_PUNCTUATION = 19;
+ const CHAR_CATEGORY_START_PUNCTUATION = 20;
+ const CHAR_CATEGORY_END_PUNCTUATION = 21;
+ const CHAR_CATEGORY_CONNECTOR_PUNCTUATION = 22;
+ const CHAR_CATEGORY_OTHER_PUNCTUATION = 23;
+ const CHAR_CATEGORY_MATH_SYMBOL = 24;
+ const CHAR_CATEGORY_CURRENCY_SYMBOL = 25;
+ const CHAR_CATEGORY_MODIFIER_SYMBOL = 26;
+ const CHAR_CATEGORY_OTHER_SYMBOL = 27;
+ const CHAR_CATEGORY_INITIAL_PUNCTUATION = 28;
+ const CHAR_CATEGORY_FINAL_PUNCTUATION = 29;
+ const CHAR_CATEGORY_CHAR_CATEGORY_COUNT = 30;
+ const CHAR_DIRECTION_LEFT_TO_RIGHT = 0;
+ const CHAR_DIRECTION_RIGHT_TO_LEFT = 1;
+ const CHAR_DIRECTION_EUROPEAN_NUMBER = 2;
+ const CHAR_DIRECTION_EUROPEAN_NUMBER_SEPARATOR = 3;
+ const CHAR_DIRECTION_EUROPEAN_NUMBER_TERMINATOR = 4;
+ const CHAR_DIRECTION_ARABIC_NUMBER = 5;
+ const CHAR_DIRECTION_COMMON_NUMBER_SEPARATOR = 6;
+ const CHAR_DIRECTION_BLOCK_SEPARATOR = 7;
+ const CHAR_DIRECTION_SEGMENT_SEPARATOR = 8;
+ const CHAR_DIRECTION_WHITE_SPACE_NEUTRAL = 9;
+ const CHAR_DIRECTION_OTHER_NEUTRAL = 10;
+ const CHAR_DIRECTION_LEFT_TO_RIGHT_EMBEDDING = 11;
+ const CHAR_DIRECTION_LEFT_TO_RIGHT_OVERRIDE = 12;
+ const CHAR_DIRECTION_RIGHT_TO_LEFT_ARABIC = 13;
+ const CHAR_DIRECTION_RIGHT_TO_LEFT_EMBEDDING = 14;
+ const CHAR_DIRECTION_RIGHT_TO_LEFT_OVERRIDE = 15;
+ const CHAR_DIRECTION_POP_DIRECTIONAL_FORMAT = 16;
+ const CHAR_DIRECTION_DIR_NON_SPACING_MARK = 17;
+ const CHAR_DIRECTION_BOUNDARY_NEUTRAL = 18;
+ const CHAR_DIRECTION_FIRST_STRONG_ISOLATE = 19;
+ const CHAR_DIRECTION_LEFT_TO_RIGHT_ISOLATE = 20;
+ const CHAR_DIRECTION_RIGHT_TO_LEFT_ISOLATE = 21;
+ const CHAR_DIRECTION_POP_DIRECTIONAL_ISOLATE = 22;
+ const CHAR_DIRECTION_CHAR_DIRECTION_COUNT = 23;
+ const BLOCK_CODE_NO_BLOCK = 0;
+ const BLOCK_CODE_BASIC_LATIN = 1;
+ const BLOCK_CODE_LATIN_1_SUPPLEMENT = 2;
+ const BLOCK_CODE_LATIN_EXTENDED_A = 3;
+ const BLOCK_CODE_LATIN_EXTENDED_B = 4;
+ const BLOCK_CODE_IPA_EXTENSIONS = 5;
+ const BLOCK_CODE_SPACING_MODIFIER_LETTERS = 6;
+ const BLOCK_CODE_COMBINING_DIACRITICAL_MARKS = 7;
+ const BLOCK_CODE_GREEK = 8;
+ const BLOCK_CODE_CYRILLIC = 9;
+ const BLOCK_CODE_ARMENIAN = 10;
+ const BLOCK_CODE_HEBREW = 11;
+ const BLOCK_CODE_ARABIC = 12;
+ const BLOCK_CODE_SYRIAC = 13;
+ const BLOCK_CODE_THAANA = 14;
+ const BLOCK_CODE_DEVANAGARI = 15;
+ const BLOCK_CODE_BENGALI = 16;
+ const BLOCK_CODE_GURMUKHI = 17;
+ const BLOCK_CODE_GUJARATI = 18;
+ const BLOCK_CODE_ORIYA = 19;
+ const BLOCK_CODE_TAMIL = 20;
+ const BLOCK_CODE_TELUGU = 21;
+ const BLOCK_CODE_KANNADA = 22;
+ const BLOCK_CODE_MALAYALAM = 23;
+ const BLOCK_CODE_SINHALA = 24;
+ const BLOCK_CODE_THAI = 25;
+ const BLOCK_CODE_LAO = 26;
+ const BLOCK_CODE_TIBETAN = 27;
+ const BLOCK_CODE_MYANMAR = 28;
+ const BLOCK_CODE_GEORGIAN = 29;
+ const BLOCK_CODE_HANGUL_JAMO = 30;
+ const BLOCK_CODE_ETHIOPIC = 31;
+ const BLOCK_CODE_CHEROKEE = 32;
+ const BLOCK_CODE_UNIFIED_CANADIAN_ABORIGINAL_SYLLABICS = 33;
+ const BLOCK_CODE_OGHAM = 34;
+ const BLOCK_CODE_RUNIC = 35;
+ const BLOCK_CODE_KHMER = 36;
+ const BLOCK_CODE_MONGOLIAN = 37;
+ const BLOCK_CODE_LATIN_EXTENDED_ADDITIONAL = 38;
+ const BLOCK_CODE_GREEK_EXTENDED = 39;
+ const BLOCK_CODE_GENERAL_PUNCTUATION = 40;
+ const BLOCK_CODE_SUPERSCRIPTS_AND_SUBSCRIPTS = 41;
+ const BLOCK_CODE_CURRENCY_SYMBOLS = 42;
+ const BLOCK_CODE_COMBINING_MARKS_FOR_SYMBOLS = 43;
+ const BLOCK_CODE_LETTERLIKE_SYMBOLS = 44;
+ const BLOCK_CODE_NUMBER_FORMS = 45;
+ const BLOCK_CODE_ARROWS = 46;
+ const BLOCK_CODE_MATHEMATICAL_OPERATORS = 47;
+ const BLOCK_CODE_MISCELLANEOUS_TECHNICAL = 48;
+ const BLOCK_CODE_CONTROL_PICTURES = 49;
+ const BLOCK_CODE_OPTICAL_CHARACTER_RECOGNITION = 50;
+ const BLOCK_CODE_ENCLOSED_ALPHANUMERICS = 51;
+ const BLOCK_CODE_BOX_DRAWING = 52;
+ const BLOCK_CODE_BLOCK_ELEMENTS = 53;
+ const BLOCK_CODE_GEOMETRIC_SHAPES = 54;
+ const BLOCK_CODE_MISCELLANEOUS_SYMBOLS = 55;
+ const BLOCK_CODE_DINGBATS = 56;
+ const BLOCK_CODE_BRAILLE_PATTERNS = 57;
+ const BLOCK_CODE_CJK_RADICALS_SUPPLEMENT = 58;
+ const BLOCK_CODE_KANGXI_RADICALS = 59;
+ const BLOCK_CODE_IDEOGRAPHIC_DESCRIPTION_CHARACTERS = 60;
+ const BLOCK_CODE_CJK_SYMBOLS_AND_PUNCTUATION = 61;
+ const BLOCK_CODE_HIRAGANA = 62;
+ const BLOCK_CODE_KATAKANA = 63;
+ const BLOCK_CODE_BOPOMOFO = 64;
+ const BLOCK_CODE_HANGUL_COMPATIBILITY_JAMO = 65;
+ const BLOCK_CODE_KANBUN = 66;
+ const BLOCK_CODE_BOPOMOFO_EXTENDED = 67;
+ const BLOCK_CODE_ENCLOSED_CJK_LETTERS_AND_MONTHS = 68;
+ const BLOCK_CODE_CJK_COMPATIBILITY = 69;
+ const BLOCK_CODE_CJK_UNIFIED_IDEOGRAPHS_EXTENSION_A = 70;
+ const BLOCK_CODE_CJK_UNIFIED_IDEOGRAPHS = 71;
+ const BLOCK_CODE_YI_SYLLABLES = 72;
+ const BLOCK_CODE_YI_RADICALS = 73;
+ const BLOCK_CODE_HANGUL_SYLLABLES = 74;
+ const BLOCK_CODE_HIGH_SURROGATES = 75;
+ const BLOCK_CODE_HIGH_PRIVATE_USE_SURROGATES = 76;
+ const BLOCK_CODE_LOW_SURROGATES = 77;
+ const BLOCK_CODE_PRIVATE_USE_AREA = 78;
+ const BLOCK_CODE_PRIVATE_USE = 78;
+ const BLOCK_CODE_CJK_COMPATIBILITY_IDEOGRAPHS = 79;
+ const BLOCK_CODE_ALPHABETIC_PRESENTATION_FORMS = 80;
+ const BLOCK_CODE_ARABIC_PRESENTATION_FORMS_A = 81;
+ const BLOCK_CODE_COMBINING_HALF_MARKS = 82;
+ const BLOCK_CODE_CJK_COMPATIBILITY_FORMS = 83;
+ const BLOCK_CODE_SMALL_FORM_VARIANTS = 84;
+ const BLOCK_CODE_ARABIC_PRESENTATION_FORMS_B = 85;
+ const BLOCK_CODE_SPECIALS = 86;
+ const BLOCK_CODE_HALFWIDTH_AND_FULLWIDTH_FORMS = 87;
+ const BLOCK_CODE_OLD_ITALIC = 88;
+ const BLOCK_CODE_GOTHIC = 89;
+ const BLOCK_CODE_DESERET = 90;
+ const BLOCK_CODE_BYZANTINE_MUSICAL_SYMBOLS = 91;
+ const BLOCK_CODE_MUSICAL_SYMBOLS = 92;
+ const BLOCK_CODE_MATHEMATICAL_ALPHANUMERIC_SYMBOLS = 93;
+ const BLOCK_CODE_CJK_UNIFIED_IDEOGRAPHS_EXTENSION_B = 94;
+ const BLOCK_CODE_CJK_COMPATIBILITY_IDEOGRAPHS_SUPPLEMENT = 95;
+ const BLOCK_CODE_TAGS = 96;
+ const BLOCK_CODE_CYRILLIC_SUPPLEMENT = 97;
+ const BLOCK_CODE_CYRILLIC_SUPPLEMENTARY = 97;
+ const BLOCK_CODE_TAGALOG = 98;
+ const BLOCK_CODE_HANUNOO = 99;
+ const BLOCK_CODE_BUHID = 100;
+ const BLOCK_CODE_TAGBANWA = 101;
+ const BLOCK_CODE_MISCELLANEOUS_MATHEMATICAL_SYMBOLS_A = 102;
+ const BLOCK_CODE_SUPPLEMENTAL_ARROWS_A = 103;
+ const BLOCK_CODE_SUPPLEMENTAL_ARROWS_B = 104;
+ const BLOCK_CODE_MISCELLANEOUS_MATHEMATICAL_SYMBOLS_B = 105;
+ const BLOCK_CODE_SUPPLEMENTAL_MATHEMATICAL_OPERATORS = 106;
+ const BLOCK_CODE_KATAKANA_PHONETIC_EXTENSIONS = 107;
+ const BLOCK_CODE_VARIATION_SELECTORS = 108;
+ const BLOCK_CODE_SUPPLEMENTARY_PRIVATE_USE_AREA_A = 109;
+ const BLOCK_CODE_SUPPLEMENTARY_PRIVATE_USE_AREA_B = 110;
+ const BLOCK_CODE_LIMBU = 111;
+ const BLOCK_CODE_TAI_LE = 112;
+ const BLOCK_CODE_KHMER_SYMBOLS = 113;
+ const BLOCK_CODE_PHONETIC_EXTENSIONS = 114;
+ const BLOCK_CODE_MISCELLANEOUS_SYMBOLS_AND_ARROWS = 115;
+ const BLOCK_CODE_YIJING_HEXAGRAM_SYMBOLS = 116;
+ const BLOCK_CODE_LINEAR_B_SYLLABARY = 117;
+ const BLOCK_CODE_LINEAR_B_IDEOGRAMS = 118;
+ const BLOCK_CODE_AEGEAN_NUMBERS = 119;
+ const BLOCK_CODE_UGARITIC = 120;
+ const BLOCK_CODE_SHAVIAN = 121;
+ const BLOCK_CODE_OSMANYA = 122;
+ const BLOCK_CODE_CYPRIOT_SYLLABARY = 123;
+ const BLOCK_CODE_TAI_XUAN_JING_SYMBOLS = 124;
+ const BLOCK_CODE_VARIATION_SELECTORS_SUPPLEMENT = 125;
+ const BLOCK_CODE_ANCIENT_GREEK_MUSICAL_NOTATION = 126;
+ const BLOCK_CODE_ANCIENT_GREEK_NUMBERS = 127;
+ const BLOCK_CODE_ARABIC_SUPPLEMENT = 128;
+ const BLOCK_CODE_BUGINESE = 129;
+ const BLOCK_CODE_CJK_STROKES = 130;
+ const BLOCK_CODE_COMBINING_DIACRITICAL_MARKS_SUPPLEMENT = 131;
+ const BLOCK_CODE_COPTIC = 132;
+ const BLOCK_CODE_ETHIOPIC_EXTENDED = 133;
+ const BLOCK_CODE_ETHIOPIC_SUPPLEMENT = 134;
+ const BLOCK_CODE_GEORGIAN_SUPPLEMENT = 135;
+ const BLOCK_CODE_GLAGOLITIC = 136;
+ const BLOCK_CODE_KHAROSHTHI = 137;
+ const BLOCK_CODE_MODIFIER_TONE_LETTERS = 138;
+ const BLOCK_CODE_NEW_TAI_LUE = 139;
+ const BLOCK_CODE_OLD_PERSIAN = 140;
+ const BLOCK_CODE_PHONETIC_EXTENSIONS_SUPPLEMENT = 141;
+ const BLOCK_CODE_SUPPLEMENTAL_PUNCTUATION = 142;
+ const BLOCK_CODE_SYLOTI_NAGRI = 143;
+ const BLOCK_CODE_TIFINAGH = 144;
+ const BLOCK_CODE_VERTICAL_FORMS = 145;
+ const BLOCK_CODE_NKO = 146;
+ const BLOCK_CODE_BALINESE = 147;
+ const BLOCK_CODE_LATIN_EXTENDED_C = 148;
+ const BLOCK_CODE_LATIN_EXTENDED_D = 149;
+ const BLOCK_CODE_PHAGS_PA = 150;
+ const BLOCK_CODE_PHOENICIAN = 151;
+ const BLOCK_CODE_CUNEIFORM = 152;
+ const BLOCK_CODE_CUNEIFORM_NUMBERS_AND_PUNCTUATION = 153;
+ const BLOCK_CODE_COUNTING_ROD_NUMERALS = 154;
+ const BLOCK_CODE_SUNDANESE = 155;
+ const BLOCK_CODE_LEPCHA = 156;
+ const BLOCK_CODE_OL_CHIKI = 157;
+ const BLOCK_CODE_CYRILLIC_EXTENDED_A = 158;
+ const BLOCK_CODE_VAI = 159;
+ const BLOCK_CODE_CYRILLIC_EXTENDED_B = 160;
+ const BLOCK_CODE_SAURASHTRA = 161;
+ const BLOCK_CODE_KAYAH_LI = 162;
+ const BLOCK_CODE_REJANG = 163;
+ const BLOCK_CODE_CHAM = 164;
+ const BLOCK_CODE_ANCIENT_SYMBOLS = 165;
+ const BLOCK_CODE_PHAISTOS_DISC = 166;
+ const BLOCK_CODE_LYCIAN = 167;
+ const BLOCK_CODE_CARIAN = 168;
+ const BLOCK_CODE_LYDIAN = 169;
+ const BLOCK_CODE_MAHJONG_TILES = 170;
+ const BLOCK_CODE_DOMINO_TILES = 171;
+ const BLOCK_CODE_SAMARITAN = 172;
+ const BLOCK_CODE_UNIFIED_CANADIAN_ABORIGINAL_SYLLABICS_EXTENDED = 173;
+ const BLOCK_CODE_TAI_THAM = 174;
+ const BLOCK_CODE_VEDIC_EXTENSIONS = 175;
+ const BLOCK_CODE_LISU = 176;
+ const BLOCK_CODE_BAMUM = 177;
+ const BLOCK_CODE_COMMON_INDIC_NUMBER_FORMS = 178;
+ const BLOCK_CODE_DEVANAGARI_EXTENDED = 179;
+ const BLOCK_CODE_HANGUL_JAMO_EXTENDED_A = 180;
+ const BLOCK_CODE_JAVANESE = 181;
+ const BLOCK_CODE_MYANMAR_EXTENDED_A = 182;
+ const BLOCK_CODE_TAI_VIET = 183;
+ const BLOCK_CODE_MEETEI_MAYEK = 184;
+ const BLOCK_CODE_HANGUL_JAMO_EXTENDED_B = 185;
+ const BLOCK_CODE_IMPERIAL_ARAMAIC = 186;
+ const BLOCK_CODE_OLD_SOUTH_ARABIAN = 187;
+ const BLOCK_CODE_AVESTAN = 188;
+ const BLOCK_CODE_INSCRIPTIONAL_PARTHIAN = 189;
+ const BLOCK_CODE_INSCRIPTIONAL_PAHLAVI = 190;
+ const BLOCK_CODE_OLD_TURKIC = 191;
+ const BLOCK_CODE_RUMI_NUMERAL_SYMBOLS = 192;
+ const BLOCK_CODE_KAITHI = 193;
+ const BLOCK_CODE_EGYPTIAN_HIEROGLYPHS = 194;
+ const BLOCK_CODE_ENCLOSED_ALPHANUMERIC_SUPPLEMENT = 195;
+ const BLOCK_CODE_ENCLOSED_IDEOGRAPHIC_SUPPLEMENT = 196;
+ const BLOCK_CODE_CJK_UNIFIED_IDEOGRAPHS_EXTENSION_C = 197;
+ const BLOCK_CODE_MANDAIC = 198;
+ const BLOCK_CODE_BATAK = 199;
+ const BLOCK_CODE_ETHIOPIC_EXTENDED_A = 200;
+ const BLOCK_CODE_BRAHMI = 201;
+ const BLOCK_CODE_BAMUM_SUPPLEMENT = 202;
+ const BLOCK_CODE_KANA_SUPPLEMENT = 203;
+ const BLOCK_CODE_PLAYING_CARDS = 204;
+ const BLOCK_CODE_MISCELLANEOUS_SYMBOLS_AND_PICTOGRAPHS = 205;
+ const BLOCK_CODE_EMOTICONS = 206;
+ const BLOCK_CODE_TRANSPORT_AND_MAP_SYMBOLS = 207;
+ const BLOCK_CODE_ALCHEMICAL_SYMBOLS = 208;
+ const BLOCK_CODE_CJK_UNIFIED_IDEOGRAPHS_EXTENSION_D = 209;
+ const BLOCK_CODE_ARABIC_EXTENDED_A = 210;
+ const BLOCK_CODE_ARABIC_MATHEMATICAL_ALPHABETIC_SYMBOLS = 211;
+ const BLOCK_CODE_CHAKMA = 212;
+ const BLOCK_CODE_MEETEI_MAYEK_EXTENSIONS = 213;
+ const BLOCK_CODE_MEROITIC_CURSIVE = 214;
+ const BLOCK_CODE_MEROITIC_HIEROGLYPHS = 215;
+ const BLOCK_CODE_MIAO = 216;
+ const BLOCK_CODE_SHARADA = 217;
+ const BLOCK_CODE_SORA_SOMPENG = 218;
+ const BLOCK_CODE_SUNDANESE_SUPPLEMENT = 219;
+ const BLOCK_CODE_TAKRI = 220;
+ const BLOCK_CODE_BASSA_VAH = 221;
+ const BLOCK_CODE_CAUCASIAN_ALBANIAN = 222;
+ const BLOCK_CODE_COPTIC_EPACT_NUMBERS = 223;
+ const BLOCK_CODE_COMBINING_DIACRITICAL_MARKS_EXTENDED = 224;
+ const BLOCK_CODE_DUPLOYAN = 225;
+ const BLOCK_CODE_ELBASAN = 226;
+ const BLOCK_CODE_GEOMETRIC_SHAPES_EXTENDED = 227;
+ const BLOCK_CODE_GRANTHA = 228;
+ const BLOCK_CODE_KHOJKI = 229;
+ const BLOCK_CODE_KHUDAWADI = 230;
+ const BLOCK_CODE_LATIN_EXTENDED_E = 231;
+ const BLOCK_CODE_LINEAR_A = 232;
+ const BLOCK_CODE_MAHAJANI = 233;
+ const BLOCK_CODE_MANICHAEAN = 234;
+ const BLOCK_CODE_MENDE_KIKAKUI = 235;
+ const BLOCK_CODE_MODI = 236;
+ const BLOCK_CODE_MRO = 237;
+ const BLOCK_CODE_MYANMAR_EXTENDED_B = 238;
+ const BLOCK_CODE_NABATAEAN = 239;
+ const BLOCK_CODE_OLD_NORTH_ARABIAN = 240;
+ const BLOCK_CODE_OLD_PERMIC = 241;
+ const BLOCK_CODE_ORNAMENTAL_DINGBATS = 242;
+ const BLOCK_CODE_PAHAWH_HMONG = 243;
+ const BLOCK_CODE_PALMYRENE = 244;
+ const BLOCK_CODE_PAU_CIN_HAU = 245;
+ const BLOCK_CODE_PSALTER_PAHLAVI = 246;
+ const BLOCK_CODE_SHORTHAND_FORMAT_CONTROLS = 247;
+ const BLOCK_CODE_SIDDHAM = 248;
+ const BLOCK_CODE_SINHALA_ARCHAIC_NUMBERS = 249;
+ const BLOCK_CODE_SUPPLEMENTAL_ARROWS_C = 250;
+ const BLOCK_CODE_TIRHUTA = 251;
+ const BLOCK_CODE_WARANG_CITI = 252;
+ const BLOCK_CODE_COUNT = 292;
+ const BLOCK_CODE_INVALID_CODE = -1;
+ const BPT_NONE = 0;
+ const BPT_OPEN = 1;
+ const BPT_CLOSE = 2;
+ const BPT_COUNT = 3;
+ const EA_NEUTRAL = 0;
+ const EA_AMBIGUOUS = 1;
+ const EA_HALFWIDTH = 2;
+ const EA_FULLWIDTH = 3;
+ const EA_NARROW = 4;
+ const EA_WIDE = 5;
+ const EA_COUNT = 6;
+ const UNICODE_CHAR_NAME = 0;
+ const UNICODE_10_CHAR_NAME = 1;
+ const EXTENDED_CHAR_NAME = 2;
+ const CHAR_NAME_ALIAS = 3;
+ const CHAR_NAME_CHOICE_COUNT = 4;
+ const SHORT_PROPERTY_NAME = 0;
+ const LONG_PROPERTY_NAME = 1;
+ const PROPERTY_NAME_CHOICE_COUNT = 2;
+ const DT_NONE = 0;
+ const DT_CANONICAL = 1;
+ const DT_COMPAT = 2;
+ const DT_CIRCLE = 3;
+ const DT_FINAL = 4;
+ const DT_FONT = 5;
+ const DT_FRACTION = 6;
+ const DT_INITIAL = 7;
+ const DT_ISOLATED = 8;
+ const DT_MEDIAL = 9;
+ const DT_NARROW = 10;
+ const DT_NOBREAK = 11;
+ const DT_SMALL = 12;
+ const DT_SQUARE = 13;
+ const DT_SUB = 14;
+ const DT_SUPER = 15;
+ const DT_VERTICAL = 16;
+ const DT_WIDE = 17;
+ const DT_COUNT = 18;
+ const JT_NON_JOINING = 0;
+ const JT_JOIN_CAUSING = 1;
+ const JT_DUAL_JOINING = 2;
+ const JT_LEFT_JOINING = 3;
+ const JT_RIGHT_JOINING = 4;
+ const JT_TRANSPARENT = 5;
+ const JT_COUNT = 6;
+ const JG_NO_JOINING_GROUP = 0;
+ const JG_AIN = 1;
+ const JG_ALAPH = 2;
+ const JG_ALEF = 3;
+ const JG_BEH = 4;
+ const JG_BETH = 5;
+ const JG_DAL = 6;
+ const JG_DALATH_RISH = 7;
+ const JG_E = 8;
+ const JG_FEH = 9;
+ const JG_FINAL_SEMKATH = 10;
+ const JG_GAF = 11;
+ const JG_GAMAL = 12;
+ const JG_HAH = 13;
+ const JG_TEH_MARBUTA_GOAL = 14;
+ const JG_HAMZA_ON_HEH_GOAL = 14;
+ const JG_HE = 15;
+ const JG_HEH = 16;
+ const JG_HEH_GOAL = 17;
+ const JG_HETH = 18;
+ const JG_KAF = 19;
+ const JG_KAPH = 20;
+ const JG_KNOTTED_HEH = 21;
+ const JG_LAM = 22;
+ const JG_LAMADH = 23;
+ const JG_MEEM = 24;
+ const JG_MIM = 25;
+ const JG_NOON = 26;
+ const JG_NUN = 27;
+ const JG_PE = 28;
+ const JG_QAF = 29;
+ const JG_QAPH = 30;
+ const JG_REH = 31;
+ const JG_REVERSED_PE = 32;
+ const JG_SAD = 33;
+ const JG_SADHE = 34;
+ const JG_SEEN = 35;
+ const JG_SEMKATH = 36;
+ const JG_SHIN = 37;
+ const JG_SWASH_KAF = 38;
+ const JG_SYRIAC_WAW = 39;
+ const JG_TAH = 40;
+ const JG_TAW = 41;
+ const JG_TEH_MARBUTA = 42;
+ const JG_TETH = 43;
+ const JG_WAW = 44;
+ const JG_YEH = 45;
+ const JG_YEH_BARREE = 46;
+ const JG_YEH_WITH_TAIL = 47;
+ const JG_YUDH = 48;
+ const JG_YUDH_HE = 49;
+ const JG_ZAIN = 50;
+ const JG_FE = 51;
+ const JG_KHAPH = 52;
+ const JG_ZHAIN = 53;
+ const JG_BURUSHASKI_YEH_BARREE = 54;
+ const JG_FARSI_YEH = 55;
+ const JG_NYA = 56;
+ const JG_ROHINGYA_YEH = 57;
+ const JG_MANICHAEAN_ALEPH = 58;
+ const JG_MANICHAEAN_AYIN = 59;
+ const JG_MANICHAEAN_BETH = 60;
+ const JG_MANICHAEAN_DALETH = 61;
+ const JG_MANICHAEAN_DHAMEDH = 62;
+ const JG_MANICHAEAN_FIVE = 63;
+ const JG_MANICHAEAN_GIMEL = 64;
+ const JG_MANICHAEAN_HETH = 65;
+ const JG_MANICHAEAN_HUNDRED = 66;
+ const JG_MANICHAEAN_KAPH = 67;
+ const JG_MANICHAEAN_LAMEDH = 68;
+ const JG_MANICHAEAN_MEM = 69;
+ const JG_MANICHAEAN_NUN = 70;
+ const JG_MANICHAEAN_ONE = 71;
+ const JG_MANICHAEAN_PE = 72;
+ const JG_MANICHAEAN_QOPH = 73;
+ const JG_MANICHAEAN_RESH = 74;
+ const JG_MANICHAEAN_SADHE = 75;
+ const JG_MANICHAEAN_SAMEKH = 76;
+ const JG_MANICHAEAN_TAW = 77;
+ const JG_MANICHAEAN_TEN = 78;
+ const JG_MANICHAEAN_TETH = 79;
+ const JG_MANICHAEAN_THAMEDH = 80;
+ const JG_MANICHAEAN_TWENTY = 81;
+ const JG_MANICHAEAN_WAW = 82;
+ const JG_MANICHAEAN_YODH = 83;
+ const JG_MANICHAEAN_ZAYIN = 84;
+ const JG_STRAIGHT_WAW = 85;
+ const JG_COUNT = 102;
+ const GCB_OTHER = 0;
+ const GCB_CONTROL = 1;
+ const GCB_CR = 2;
+ const GCB_EXTEND = 3;
+ const GCB_L = 4;
+ const GCB_LF = 5;
+ const GCB_LV = 6;
+ const GCB_LVT = 7;
+ const GCB_T = 8;
+ const GCB_V = 9;
+ const GCB_SPACING_MARK = 10;
+ const GCB_PREPEND = 11;
+ const GCB_REGIONAL_INDICATOR = 12;
+ const GCB_COUNT = 18;
+ const WB_OTHER = 0;
+ const WB_ALETTER = 1;
+ const WB_FORMAT = 2;
+ const WB_KATAKANA = 3;
+ const WB_MIDLETTER = 4;
+ const WB_MIDNUM = 5;
+ const WB_NUMERIC = 6;
+ const WB_EXTENDNUMLET = 7;
+ const WB_CR = 8;
+ const WB_EXTEND = 9;
+ const WB_LF = 10;
+ const WB_MIDNUMLET = 11;
+ const WB_NEWLINE = 12;
+ const WB_REGIONAL_INDICATOR = 13;
+ const WB_HEBREW_LETTER = 14;
+ const WB_SINGLE_QUOTE = 15;
+ const WB_DOUBLE_QUOTE = 16;
+ const WB_COUNT = 23;
+ const SB_OTHER = 0;
+ const SB_ATERM = 1;
+ const SB_CLOSE = 2;
+ const SB_FORMAT = 3;
+ const SB_LOWER = 4;
+ const SB_NUMERIC = 5;
+ const SB_OLETTER = 6;
+ const SB_SEP = 7;
+ const SB_SP = 8;
+ const SB_STERM = 9;
+ const SB_UPPER = 10;
+ const SB_CR = 11;
+ const SB_EXTEND = 12;
+ const SB_LF = 13;
+ const SB_SCONTINUE = 14;
+ const SB_COUNT = 15;
+ const LB_UNKNOWN = 0;
+ const LB_AMBIGUOUS = 1;
+ const LB_ALPHABETIC = 2;
+ const LB_BREAK_BOTH = 3;
+ const LB_BREAK_AFTER = 4;
+ const LB_BREAK_BEFORE = 5;
+ const LB_MANDATORY_BREAK = 6;
+ const LB_CONTINGENT_BREAK = 7;
+ const LB_CLOSE_PUNCTUATION = 8;
+ const LB_COMBINING_MARK = 9;
+ const LB_CARRIAGE_RETURN = 10;
+ const LB_EXCLAMATION = 11;
+ const LB_GLUE = 12;
+ const LB_HYPHEN = 13;
+ const LB_IDEOGRAPHIC = 14;
+ const LB_INSEPARABLE = 15;
+ const LB_INSEPERABLE = 15;
+ const LB_INFIX_NUMERIC = 16;
+ const LB_LINE_FEED = 17;
+ const LB_NONSTARTER = 18;
+ const LB_NUMERIC = 19;
+ const LB_OPEN_PUNCTUATION = 20;
+ const LB_POSTFIX_NUMERIC = 21;
+ const LB_PREFIX_NUMERIC = 22;
+ const LB_QUOTATION = 23;
+ const LB_COMPLEX_CONTEXT = 24;
+ const LB_SURROGATE = 25;
+ const LB_SPACE = 26;
+ const LB_BREAK_SYMBOLS = 27;
+ const LB_ZWSPACE = 28;
+ const LB_NEXT_LINE = 29;
+ const LB_WORD_JOINER = 30;
+ const LB_H2 = 31;
+ const LB_H3 = 32;
+ const LB_JL = 33;
+ const LB_JT = 34;
+ const LB_JV = 35;
+ const LB_CLOSE_PARENTHESIS = 36;
+ const LB_CONDITIONAL_JAPANESE_STARTER = 37;
+ const LB_HEBREW_LETTER = 38;
+ const LB_REGIONAL_INDICATOR = 39;
+ const LB_COUNT = 43;
+ const NT_NONE = 0;
+ const NT_DECIMAL = 1;
+ const NT_DIGIT = 2;
+ const NT_NUMERIC = 3;
+ const NT_COUNT = 4;
+ const HST_NOT_APPLICABLE = 0;
+ const HST_LEADING_JAMO = 1;
+ const HST_VOWEL_JAMO = 2;
+ const HST_TRAILING_JAMO = 3;
+ const HST_LV_SYLLABLE = 4;
+ const HST_LVT_SYLLABLE = 5;
+ const HST_COUNT = 6;
+ const FOLD_CASE_DEFAULT = 0;
+ const FOLD_CASE_EXCLUDE_SPECIAL_I = 1;
+
+ // methods
+ public static function chr($codepoint) {}
+ public static function ord($character) {}
+ public static function hasBinaryProperty($codepoint, $property) {}
+ public static function isUAlphabetic($codepoint) {}
+ public static function isULowercase($codepoint) {}
+ public static function isUUppercase($codepoint) {}
+ public static function isUWhiteSpace($codepoint) {}
+ public static function getIntPropertyValue($codepoint, $property) {}
+ public static function getIntPropertyMinValue($property) {}
+ public static function getIntPropertyMaxValue($property) {}
+ public static function getNumericValue($codepoint) {}
+ public static function islower($codepoint) {}
+ public static function isupper($codepoint) {}
+ public static function istitle($codepoint) {}
+ public static function isdigit($codepoint) {}
+ public static function isalpha($codepoint) {}
+ public static function isalnum($codepoint) {}
+ public static function isxdigit($codepoint) {}
+ public static function ispunct($codepoint) {}
+ public static function isgraph($codepoint) {}
+ public static function isblank($codepoint) {}
+ public static function isdefined($codepoint) {}
+ public static function isspace($codepoint) {}
+ public static function isJavaSpaceChar($codepoint) {}
+ public static function isWhitespace($codepoint) {}
+ public static function iscntrl($codepoint) {}
+ public static function isISOControl($codepoint) {}
+ public static function isprint($codepoint) {}
+ public static function isbase($codepoint) {}
+ public static function charDirection($codepoint) {}
+ public static function isMirrored($codepoint) {}
+ public static function charMirror($codepoint) {}
+ public static function getBidiPairedBracket($codepoint) {}
+ public static function charType($codepoint) {}
+ public static function enumCharTypes($callback = null) {}
+ public static function getCombiningClass($codepoint) {}
+ public static function charDigitValue($codepoint) {}
+ public static function getBlockCode($codepoint) {}
+ public static function charName($codepoint, $nameChoice = null) {}
+ public static function charFromName($characterName, $nameChoice = null) {}
+ public static function enumCharNames($start, $limit, $callback, $nameChoice = null) {}
+ public static function getPropertyName($property, $nameChoice = null) {}
+ public static function getPropertyEnum($alias) {}
+ public static function getPropertyValueName($property, $value, $nameChoice = null) {}
+ public static function getPropertyValueEnum($property, $name) {}
+ public static function isIDStart($codepoint) {}
+ public static function isIDPart($codepoint) {}
+ public static function isIDIgnorable($codepoint) {}
+ public static function isJavaIDStart($codepoint) {}
+ public static function isJavaIDPart($codepoint) {}
+ public static function tolower($codepoint) {}
+ public static function toupper($codepoint) {}
+ public static function totitle($codepoint) {}
+ public static function foldCase($codepoint, $options = null) {}
+ public static function digit($codepoint, $radix = null) {}
+ public static function forDigit($digit, $radix = null) {}
+ public static function charAge($codepoint) {}
+ public static function getUnicodeVersion() {}
+ public static function getFC_NFKC_Closure($codepoint) {}
+}
+
+class IntlCodePointBreakIterator extends \IntlBreakIterator {
+
+ // constants
+ const DONE = -1;
+ const WORD_NONE = 0;
+ const WORD_NONE_LIMIT = 100;
+ const WORD_NUMBER = 100;
+ const WORD_NUMBER_LIMIT = 200;
+ const WORD_LETTER = 200;
+ const WORD_LETTER_LIMIT = 300;
+ const WORD_KANA = 300;
+ const WORD_KANA_LIMIT = 400;
+ const WORD_IDEO = 400;
+ const WORD_IDEO_LIMIT = 500;
+ const LINE_SOFT = 0;
+ const LINE_SOFT_LIMIT = 100;
+ const LINE_HARD = 100;
+ const LINE_HARD_LIMIT = 200;
+ const SENTENCE_TERM = 0;
+ const SENTENCE_TERM_LIMIT = 100;
+ const SENTENCE_SEP = 100;
+ const SENTENCE_SEP_LIMIT = 200;
+
+ // methods
+ public function getLastCodePoint() {}
+}
+
+class IntlDateFormatter {
+
+ // constants
+ const FULL = 0;
+ const LONG = 1;
+ const MEDIUM = 2;
+ const SHORT = 3;
+ const NONE = -1;
+ const GREGORIAN = 1;
+ const TRADITIONAL = 0;
+
+ // methods
+ public function __construct($locale, $datetype, $timetype, $timezone = null, $calendar = null, $pattern = null) {}
+ public static function create($locale, $datetype, $timetype, $timezone = null, $calendar = null, $pattern = null) {}
+ public function getDateType() {}
+ public function getTimeType() {}
+ public function getCalendar() {}
+ public function getCalendarObject() {}
+ public function setCalendar($which) {}
+ public function getTimeZoneId() {}
+ public function getTimeZone() {}
+ public function setTimeZone($zone) {}
+ public function setPattern($pattern) {}
+ public function getPattern() {}
+ public function getLocale() {}
+ public function setLenient($lenient) {}
+ public function isLenient() {}
+ public function format($args = null, $array = null) {}
+ public static function formatObject($object, $format = null, $locale = null) {}
+ public function parse($string, &$position = null) {}
+ public function localtime($string, &$position = null) {}
+ public function getErrorCode() {}
+ public function getErrorMessage() {}
+}
+
+class IntlException extends \Exception {
+
+ // properties
+ protected $message;
+ protected $code;
+ protected $file;
+ protected $line;
+}
+
+class IntlGregorianCalendar extends \IntlCalendar {
+
+ // constants
+ const FIELD_ERA = 0;
+ const FIELD_YEAR = 1;
+ const FIELD_MONTH = 2;
+ const FIELD_WEEK_OF_YEAR = 3;
+ const FIELD_WEEK_OF_MONTH = 4;
+ const FIELD_DATE = 5;
+ const FIELD_DAY_OF_YEAR = 6;
+ const FIELD_DAY_OF_WEEK = 7;
+ const FIELD_DAY_OF_WEEK_IN_MONTH = 8;
+ const FIELD_AM_PM = 9;
+ const FIELD_HOUR = 10;
+ const FIELD_HOUR_OF_DAY = 11;
+ const FIELD_MINUTE = 12;
+ const FIELD_SECOND = 13;
+ const FIELD_MILLISECOND = 14;
+ const FIELD_ZONE_OFFSET = 15;
+ const FIELD_DST_OFFSET = 16;
+ const FIELD_YEAR_WOY = 17;
+ const FIELD_DOW_LOCAL = 18;
+ const FIELD_EXTENDED_YEAR = 19;
+ const FIELD_JULIAN_DAY = 20;
+ const FIELD_MILLISECONDS_IN_DAY = 21;
+ const FIELD_IS_LEAP_MONTH = 22;
+ const FIELD_FIELD_COUNT = 23;
+ const FIELD_DAY_OF_MONTH = 5;
+ const DOW_SUNDAY = 1;
+ const DOW_MONDAY = 2;
+ const DOW_TUESDAY = 3;
+ const DOW_WEDNESDAY = 4;
+ const DOW_THURSDAY = 5;
+ const DOW_FRIDAY = 6;
+ const DOW_SATURDAY = 7;
+ const DOW_TYPE_WEEKDAY = 0;
+ const DOW_TYPE_WEEKEND = 1;
+ const DOW_TYPE_WEEKEND_OFFSET = 2;
+ const DOW_TYPE_WEEKEND_CEASE = 3;
+ const WALLTIME_FIRST = 1;
+ const WALLTIME_LAST = 0;
+ const WALLTIME_NEXT_VALID = 2;
+
+ // methods
+ public function __construct($timeZoneOrYear = null, $localeOrMonth = null, $dayOfMonth = null, $hour = null, $minute = null, $second = null) {}
+ public function setGregorianChange($date) {}
+ public function getGregorianChange() {}
+ public function isLeapYear($year) {}
+}
+
+class IntlIterator implements \Iterator, \Traversable {
+
+ // methods
+ public function current() {}
+ public function key() {}
+ public function next() {}
+ public function rewind() {}
+ public function valid() {}
+}
+
+class IntlPartsIterator extends \IntlIterator {
+
+ // constants
+ const KEY_SEQUENTIAL = 0;
+ const KEY_LEFT = 1;
+ const KEY_RIGHT = 2;
+
+ // methods
+ public function getBreakIterator() {}
+}
+
+class IntlRuleBasedBreakIterator extends \IntlBreakIterator {
+
+ // constants
+ const DONE = -1;
+ const WORD_NONE = 0;
+ const WORD_NONE_LIMIT = 100;
+ const WORD_NUMBER = 100;
+ const WORD_NUMBER_LIMIT = 200;
+ const WORD_LETTER = 200;
+ const WORD_LETTER_LIMIT = 300;
+ const WORD_KANA = 300;
+ const WORD_KANA_LIMIT = 400;
+ const WORD_IDEO = 400;
+ const WORD_IDEO_LIMIT = 500;
+ const LINE_SOFT = 0;
+ const LINE_SOFT_LIMIT = 100;
+ const LINE_HARD = 100;
+ const LINE_HARD_LIMIT = 200;
+ const SENTENCE_TERM = 0;
+ const SENTENCE_TERM_LIMIT = 100;
+ const SENTENCE_SEP = 100;
+ const SENTENCE_SEP_LIMIT = 200;
+
+ // methods
+ public function __construct($rules, $areCompiled = null) {}
+ public function getRules() {}
+ public function getRuleStatus() {}
+ public function getRuleStatusVec() {}
+ public function getBinaryRules() {}
+}
+
+class IntlTimeZone {
+
+ // constants
+ const DISPLAY_SHORT = 1;
+ const DISPLAY_LONG = 2;
+ const DISPLAY_SHORT_GENERIC = 3;
+ const DISPLAY_LONG_GENERIC = 4;
+ const DISPLAY_SHORT_GMT = 5;
+ const DISPLAY_LONG_GMT = 6;
+ const DISPLAY_SHORT_COMMONLY_USED = 7;
+ const DISPLAY_GENERIC_LOCATION = 8;
+ const TYPE_ANY = 0;
+ const TYPE_CANONICAL = 1;
+ const TYPE_CANONICAL_LOCATION = 2;
+
+ // methods
+ private function __construct() {}
+ public static function createTimeZone($zoneId) {}
+ public static function fromDateTimeZone($zoneId) {}
+ public static function createDefault() {}
+ public static function getGMT() {}
+ public static function getUnknown() {}
+ public static function createEnumeration($countryOrRawOffset = null) {}
+ public static function countEquivalentIDs($zoneId) {}
+ public static function createTimeZoneIDEnumeration($zoneType, $region = null, $rawOffset = null) {}
+ public static function getCanonicalID($zoneId, &$isSystemID = null) {}
+ public static function getRegion($zoneId) {}
+ public static function getTZDataVersion() {}
+ public static function getEquivalentID($zoneId, $index) {}
+ public function getID() {}
+ public function useDaylightTime() {}
+ public function getOffset($date, $local, &$rawOffset, &$dstOffset) {}
+ public function getRawOffset() {}
+ public function hasSameRules(\IntlTimeZone $otherTimeZone) {}
+ public function getDisplayName($isDaylight = null, $style = null, $locale = null) {}
+ public function getDSTSavings() {}
+ public function toDateTimeZone() {}
+ public function getErrorCode() {}
+ public function getErrorMessage() {}
+ public static function getWindowsID($timezone) {}
+ public static function getIDForWindowsID($timezone, $region = null) {}
+}
+
+class Locale {
+
+ // constants
+ const ACTUAL_LOCALE = 0;
+ const VALID_LOCALE = 1;
+ const DEFAULT_LOCALE = NULL;
+ const LANG_TAG = 'language';
+ const EXTLANG_TAG = 'extlang';
+ const SCRIPT_TAG = 'script';
+ const REGION_TAG = 'region';
+ const VARIANT_TAG = 'variant';
+ const GRANDFATHERED_LANG_TAG = 'grandfathered';
+ const PRIVATE_TAG = 'private';
+
+ // properties
+ public $name;
+
+ // methods
+ public static function getDefault() {}
+ public static function setDefault($locale) {}
+ public static function getPrimaryLanguage($locale) {}
+ public static function getScript($locale) {}
+ public static function getRegion($locale) {}
+ public static function getKeywords($locale) {}
+ public static function getDisplayScript($locale, $in_locale = null) {}
+ public static function getDisplayRegion($locale, $in_locale = null) {}
+ public static function getDisplayName($locale, $in_locale = null) {}
+ public static function getDisplayLanguage($locale, $in_locale = null) {}
+ public static function getDisplayVariant($locale, $in_locale = null) {}
+ public static function composeLocale($subtags) {}
+ public static function parseLocale($locale) {}
+ public static function getAllVariants($locale) {}
+ public static function filterMatches($langtag, $locale, $canonicalize = null) {}
+ public static function lookup($langtag, $locale, $canonicalize = null, $default = null) {}
+ public static function canonicalize($locale) {}
+ public static function acceptFromHttp($header) {}
+}
+
+class MessageFormatter {
+
+ // methods
+ public function __construct($locale, $pattern) {}
+ public static function create($locale, $pattern) {}
+ public function format($args) {}
+ public static function formatMessage($locale, $pattern, $args) {}
+ public function parse($source) {}
+ public static function parseMessage($locale, $pattern, $args) {}
+ public function setPattern($pattern) {}
+ public function getPattern() {}
+ public function getLocale() {}
+ public function getErrorCode() {}
+ public function getErrorMessage() {}
+}
+
+class Normalizer {
+
+ // constants
+ const NONE = 2;
+ const FORM_D = 4;
+ const NFD = 4;
+ const FORM_KD = 8;
+ const NFKD = 8;
+ const FORM_C = 16;
+ const NFC = 16;
+ const FORM_KC = 32;
+ const NFKC = 32;
+ const FORM_KC_CF = 48;
+ const NFKC_CF = 48;
+
+ // properties
+ public $name;
+
+ // methods
+ public static function normalize($input, $form = null) {}
+ public static function isNormalized($input, $form = null) {}
+ public static function getRawDecomposition($input) {}
+}
+
+class NumberFormatter {
+
+ // constants
+ const PATTERN_DECIMAL = 0;
+ const DECIMAL = 1;
+ const CURRENCY = 2;
+ const PERCENT = 3;
+ const SCIENTIFIC = 4;
+ const SPELLOUT = 5;
+ const ORDINAL = 6;
+ const DURATION = 7;
+ const PATTERN_RULEBASED = 9;
+ const IGNORE = 0;
+ const DEFAULT_STYLE = 1;
+ const ROUND_CEILING = 0;
+ const ROUND_FLOOR = 1;
+ const ROUND_DOWN = 2;
+ const ROUND_UP = 3;
+ const ROUND_HALFEVEN = 4;
+ const ROUND_HALFDOWN = 5;
+ const ROUND_HALFUP = 6;
+ const PAD_BEFORE_PREFIX = 0;
+ const PAD_AFTER_PREFIX = 1;
+ const PAD_BEFORE_SUFFIX = 2;
+ const PAD_AFTER_SUFFIX = 3;
+ const PARSE_INT_ONLY = 0;
+ const GROUPING_USED = 1;
+ const DECIMAL_ALWAYS_SHOWN = 2;
+ const MAX_INTEGER_DIGITS = 3;
+ const MIN_INTEGER_DIGITS = 4;
+ const INTEGER_DIGITS = 5;
+ const MAX_FRACTION_DIGITS = 6;
+ const MIN_FRACTION_DIGITS = 7;
+ const FRACTION_DIGITS = 8;
+ const MULTIPLIER = 9;
+ const GROUPING_SIZE = 10;
+ const ROUNDING_MODE = 11;
+ const ROUNDING_INCREMENT = 12;
+ const FORMAT_WIDTH = 13;
+ const PADDING_POSITION = 14;
+ const SECONDARY_GROUPING_SIZE = 15;
+ const SIGNIFICANT_DIGITS_USED = 16;
+ const MIN_SIGNIFICANT_DIGITS = 17;
+ const MAX_SIGNIFICANT_DIGITS = 18;
+ const LENIENT_PARSE = 19;
+ const POSITIVE_PREFIX = 0;
+ const POSITIVE_SUFFIX = 1;
+ const NEGATIVE_PREFIX = 2;
+ const NEGATIVE_SUFFIX = 3;
+ const PADDING_CHARACTER = 4;
+ const CURRENCY_CODE = 5;
+ const DEFAULT_RULESET = 6;
+ const PUBLIC_RULESETS = 7;
+ const DECIMAL_SEPARATOR_SYMBOL = 0;
+ const GROUPING_SEPARATOR_SYMBOL = 1;
+ const PATTERN_SEPARATOR_SYMBOL = 2;
+ const PERCENT_SYMBOL = 3;
+ const ZERO_DIGIT_SYMBOL = 4;
+ const DIGIT_SYMBOL = 5;
+ const MINUS_SIGN_SYMBOL = 6;
+ const PLUS_SIGN_SYMBOL = 7;
+ const CURRENCY_SYMBOL = 8;
+ const INTL_CURRENCY_SYMBOL = 9;
+ const MONETARY_SEPARATOR_SYMBOL = 10;
+ const EXPONENTIAL_SYMBOL = 11;
+ const PERMILL_SYMBOL = 12;
+ const PAD_ESCAPE_SYMBOL = 13;
+ const INFINITY_SYMBOL = 14;
+ const NAN_SYMBOL = 15;
+ const SIGNIFICANT_DIGIT_SYMBOL = 16;
+ const MONETARY_GROUPING_SEPARATOR_SYMBOL = 17;
+ const TYPE_DEFAULT = 0;
+ const TYPE_INT32 = 1;
+ const TYPE_INT64 = 2;
+ const TYPE_DOUBLE = 3;
+ const TYPE_CURRENCY = 4;
+
+ // properties
+ public $name;
+
+ // methods
+ public function __construct($locale, $style, $pattern = null) {}
+ public static function create($locale, $style, $pattern = null) {}
+ public function format($num, $type = null) {}
+ public function parse($string, $type = null, &$position = null) {}
+ public function formatCurrency($num, $currency) {}
+ public function parseCurrency($string, &$currency, &$position = null) {}
+ public function setAttribute($attr, $value) {}
+ public function getAttribute($attr) {}
+ public function setTextAttribute($attr, $value) {}
+ public function getTextAttribute($attr) {}
+ public function setSymbol($attr, $symbol) {}
+ public function getSymbol($attr) {}
+ public function setPattern($pattern) {}
+ public function getPattern() {}
+ public function getLocale($type = null) {}
+ public function getErrorCode() {}
+ public function getErrorMessage() {}
+}
+
+class ResourceBundle implements \Traversable {
+
+ // methods
+ public function __construct($locale, $bundlename, $fallback = null) {}
+ public static function create($locale, $bundlename, $fallback = null) {}
+ public function get($index, $fallback = null) {}
+ public function count() {}
+ public static function getLocales($bundlename) {}
+ public function getErrorCode() {}
+ public function getErrorMessage() {}
+}
+
+class Spoofchecker {
+
+ // constants
+ const SINGLE_SCRIPT_CONFUSABLE = 1;
+ const MIXED_SCRIPT_CONFUSABLE = 2;
+ const WHOLE_SCRIPT_CONFUSABLE = 4;
+ const ANY_CASE = 8;
+ const SINGLE_SCRIPT = 16;
+ const INVISIBLE = 32;
+ const CHAR_LIMIT = 64;
+ const ASCII = 268435456;
+ const HIGHLY_RESTRICTIVE = 805306368;
+ const MODERATELY_RESTRICTIVE = 1073741824;
+ const MINIMALLY_RESTRICTIVE = 1342177280;
+ const UNRESTRICTIVE = 1610612736;
+ const SINGLE_SCRIPT_RESTRICTIVE = 536870912;
+
+ // methods
+ public function __construct() {}
+ public function isSuspicious($text, &$error = null) {}
+ public function areConfusable($s1, $s2, &$error = null) {}
+ public function setAllowedLocales($locale_list) {}
+ public function setChecks($checks) {}
+ public function setRestrictionLevel($level) {}
+}
+
+class Transliterator {
+
+ // constants
+ const FORWARD = 0;
+ const REVERSE = 1;
+
+ // properties
+ public $id;
+
+ // methods
+ private function __construct() {}
+ public static function create($id, $direction = null) {}
+ public static function createFromRules($rules, $direction = null) {}
+ public function createInverse() {}
+ public static function listIDs() {}
+ public function transliterate($subject, $start = null, $end = null) {}
+ public function getErrorCode() {}
+ public function getErrorMessage() {}
+}
+
+class UConverter {
+
+ // constants
+ const REASON_UNASSIGNED = 0;
+ const REASON_ILLEGAL = 1;
+ const REASON_IRREGULAR = 2;
+ const REASON_RESET = 3;
+ const REASON_CLOSE = 4;
+ const REASON_CLONE = 5;
+ const UNSUPPORTED_CONVERTER = -1;
+ const SBCS = 0;
+ const DBCS = 1;
+ const MBCS = 2;
+ const LATIN_1 = 3;
+ const UTF8 = 4;
+ const UTF16_BigEndian = 5;
+ const UTF16_LittleEndian = 6;
+ const UTF32_BigEndian = 7;
+ const UTF32_LittleEndian = 8;
+ const EBCDIC_STATEFUL = 9;
+ const ISO_2022 = 10;
+ const LMBCS_1 = 11;
+ const LMBCS_2 = 12;
+ const LMBCS_3 = 13;
+ const LMBCS_4 = 14;
+ const LMBCS_5 = 15;
+ const LMBCS_6 = 16;
+ const LMBCS_8 = 17;
+ const LMBCS_11 = 18;
+ const LMBCS_16 = 19;
+ const LMBCS_17 = 20;
+ const LMBCS_18 = 21;
+ const LMBCS_19 = 22;
+ const LMBCS_LAST = 22;
+ const HZ = 23;
+ const SCSU = 24;
+ const ISCII = 25;
+ const US_ASCII = 26;
+ const UTF7 = 27;
+ const BOCU1 = 28;
+ const UTF16 = 29;
+ const UTF32 = 30;
+ const CESU8 = 31;
+ const IMAP_MAILBOX = 32;
+
+ // methods
+ public function __construct($destination_encoding = null, $source_encoding = null) {}
+ public function setSourceEncoding($encoding) {}
+ public function setDestinationEncoding($encoding) {}
+ public function getSourceEncoding() {}
+ public function getDestinationEncoding() {}
+ public function getSourceType() {}
+ public function getDestinationType() {}
+ public function getSubstChars() {}
+ public function setSubstChars($chars) {}
+ public function toUCallback($reason, $source, $codeUnits, &$error) {}
+ public function fromUCallback($reason, $source, $codePoint, &$error) {}
+ public function convert($str, $reverse = null) {}
+ public static function transcode($str, $toEncoding, $fromEncoding, array $options = null) {}
+ public function getErrorCode() {}
+ public function getErrorMessage() {}
+ public static function reasonText($reason = null) {}
+ public static function getAvailable() {}
+ public static function getAliases($name) {}
+ public static function getStandards() {}
+}
+
+function collator_asort(\Collator $object, array &$arr, $sort_flags = null) {}
+function collator_compare(\Collator $object, $arg1, $arg2) {}
+function collator_create($arg1) {}
+function collator_get_attribute(\Collator $object, $arg1) {}
+function collator_get_error_code(\Collator $object) {}
+function collator_get_error_message(\Collator $object) {}
+function collator_get_locale(\Collator $object, $arg1) {}
+function collator_get_sort_key(\Collator $object, $arg1) {}
+function collator_get_strength(\Collator $object) {}
+function collator_set_attribute(\Collator $object, $arg1, $arg2) {}
+function collator_set_strength(\Collator $object, $arg1) {}
+function collator_sort(\Collator $object, array &$arr, $sort_flags = null) {}
+function collator_sort_with_sort_keys(\Collator $coll, array &$arr) {}
+function datefmt_create($locale, $date_type, $time_type, $timezone_str = null, $calendar = null, $pattern = null) {}
+function datefmt_format($args = null, $array = null) {}
+function datefmt_format_object($object, $format = null, $locale = null) {}
+function datefmt_get_calendar($mf) {}
+function datefmt_get_calendar_object($mf) {}
+function datefmt_get_datetype($mf) {}
+function datefmt_get_error_code($nf) {}
+function datefmt_get_error_message($coll) {}
+function datefmt_get_locale($mf) {}
+function datefmt_get_pattern($mf) {}
+function datefmt_get_timetype($mf) {}
+function datefmt_get_timezone($mf) {}
+function datefmt_get_timezone_id($mf) {}
+function datefmt_is_lenient($mf) {}
+function datefmt_localtime($formatter, $string, &$position = null) {}
+function datefmt_parse($formatter, $string, &$position = null) {}
+function datefmt_set_calendar($mf, $calendar) {}
+function datefmt_set_lenient($mf) {}
+function datefmt_set_pattern($mf, $pattern) {}
+function datefmt_set_timezone($mf, $timezone) {}
+function grapheme_extract($arg1, $arg2, $arg3 = null, $arg4 = null, &$arg5 = null) {}
+function grapheme_stripos($haystack, $needle, $offset = null) {}
+function grapheme_stristr($haystack, $needle, $before_needle = null) {}
+function grapheme_strlen($string) {}
+function grapheme_strpos($haystack, $needle, $offset = null) {}
+function grapheme_strripos($haystack, $needle, $offset = null) {}
+function grapheme_strrpos($haystack, $needle, $offset = null) {}
+function grapheme_strstr($haystack, $needle, $before_needle = null) {}
+function grapheme_substr($string, $start, $length = null) {}
+function idn_to_ascii($domain, $option = null, $variant = null, &$idn_info = null) {}
+function idn_to_utf8($domain, $option = null, $variant = null, &$idn_info = null) {}
+function intl_error_name($arg1) {}
+function intl_get_error_code() {}
+function intl_get_error_message() {}
+function intl_is_failure($arg1) {}
+function intlcal_add(\IntlCalendar $calendar, $field, $amount) {}
+function intlcal_after(\IntlCalendar $calendar, \IntlCalendar $otherCalendar) {}
+function intlcal_before(\IntlCalendar $calendar, \IntlCalendar $otherCalendar) {}
+function intlcal_clear(\IntlCalendar $calendar, $field = null) {}
+function intlcal_create_instance($timeZone = null, $locale = null) {}
+function intlcal_equals(\IntlCalendar $calendar, \IntlCalendar $otherCalendar) {}
+function intlcal_field_difference(\IntlCalendar $calendar, $when, $field) {}
+function intlcal_from_date_time($dateTime) {}
+function intlcal_get(\IntlCalendar $calendar, $field) {}
+function intlcal_get_actual_maximum(\IntlCalendar $calendar, $field) {}
+function intlcal_get_actual_minimum(\IntlCalendar $calendar, $field) {}
+function intlcal_get_available_locales() {}
+function intlcal_get_day_of_week_type(\IntlCalendar $calendar, $dayOfWeek) {}
+function intlcal_get_error_code(\IntlCalendar $calendar) {}
+function intlcal_get_error_message(\IntlCalendar $calendar) {}
+function intlcal_get_first_day_of_week(\IntlCalendar $calendar) {}
+function intlcal_get_greatest_minimum(\IntlCalendar $calendar, $field) {}
+function intlcal_get_keyword_values_for_locale($key, $locale, $commonlyUsed) {}
+function intlcal_get_least_maximum(\IntlCalendar $calendar, $field) {}
+function intlcal_get_locale(\IntlCalendar $calendar, $localeType) {}
+function intlcal_get_maximum(\IntlCalendar $calendar, $field) {}
+function intlcal_get_minimal_days_in_first_week(\IntlCalendar $calendar) {}
+function intlcal_get_minimum(\IntlCalendar $calendar, $field) {}
+function intlcal_get_now() {}
+function intlcal_get_repeated_wall_time_option(\IntlCalendar $calendar) {}
+function intlcal_get_skipped_wall_time_option(\IntlCalendar $calendar) {}
+function intlcal_get_time(\IntlCalendar $calendar) {}
+function intlcal_get_time_zone(\IntlCalendar $calendar) {}
+function intlcal_get_type(\IntlCalendar $calendar) {}
+function intlcal_get_weekend_transition(\IntlCalendar $calendar, $dayOfWeek) {}
+function intlcal_in_daylight_time(\IntlCalendar $calendar) {}
+function intlcal_is_equivalent_to(\IntlCalendar $calendar, \IntlCalendar $otherCalendar) {}
+function intlcal_is_lenient(\IntlCalendar $calendar) {}
+function intlcal_is_set(\IntlCalendar $calendar, $field) {}
+function intlcal_is_weekend(\IntlCalendar $calendar, $date = null) {}
+function intlcal_roll(\IntlCalendar $calendar, $field, $amountOrUpOrDown = null) {}
+function intlcal_set(\IntlCalendar $calendar, $fieldOrYear, $valueOrMonth, $dayOfMonth = null, $hour = null, $minute = null, $second = null) {}
+function intlcal_set_first_day_of_week(\IntlCalendar $calendar, $dayOfWeek) {}
+function intlcal_set_lenient(\IntlCalendar $calendar, $isLenient) {}
+function intlcal_set_minimal_days_in_first_week(\IntlCalendar $calendar, $numberOfDays) {}
+function intlcal_set_repeated_wall_time_option(\IntlCalendar $calendar, $wallTimeOption) {}
+function intlcal_set_skipped_wall_time_option(\IntlCalendar $calendar, $wallTimeOption) {}
+function intlcal_set_time(\IntlCalendar $calendar, $date) {}
+function intlcal_set_time_zone(\IntlCalendar $calendar, $timeZone) {}
+function intlcal_to_date_time(\IntlCalendar $calendar) {}
+function intlgregcal_create_instance($timeZoneOrYear = null, $localeOrMonth = null, $dayOfMonth = null, $hour = null, $minute = null, $second = null) {}
+function intlgregcal_get_gregorian_change(\IntlGregorianCalendar $calendar) {}
+function intlgregcal_is_leap_year(\IntlGregorianCalendar $calendar, $year) {}
+function intlgregcal_set_gregorian_change(\IntlGregorianCalendar $calendar, $date) {}
+function intltz_count_equivalent_ids($zoneId) {}
+function intltz_create_default() {}
+function intltz_create_enumeration($countryOrRawOffset = null) {}
+function intltz_create_time_zone($zoneId) {}
+function intltz_create_time_zone_id_enumeration($zoneType, $region = null, $rawOffset = null) {}
+function intltz_from_date_time_zone(\DateTimeZone $dateTimeZone) {}
+function intltz_get_canonical_id($zoneId, &$isSystemID = null) {}
+function intltz_get_display_name(\IntlTimeZone $timeZone, $isDaylight = null, $style = null, $locale = null) {}
+function intltz_get_dst_savings(\IntlTimeZone $timeZone) {}
+function intltz_get_equivalent_id($zoneId, $index) {}
+function intltz_get_error_code(\IntlTimeZone $timeZone) {}
+function intltz_get_error_message(\IntlTimeZone $timeZone) {}
+function intltz_get_gmt() {}
+function intltz_get_id(\IntlTimeZone $timeZone) {}
+function intltz_get_offset(\IntlTimeZone $timeZone, $date, $local, &$rawOffset, &$dstOffset) {}
+function intltz_get_raw_offset(\IntlTimeZone $timeZone) {}
+function intltz_get_region($zoneId) {}
+function intltz_get_tz_data_version() {}
+function intltz_get_unknown() {}
+function intltz_has_same_rules(\IntlTimeZone $timeZone, \IntlTimeZone $otherTimeZone = null) {}
+function intltz_to_date_time_zone(\IntlTimeZone $timeZone) {}
+function intltz_use_daylight_time(\IntlTimeZone $timeZone) {}
+function locale_accept_from_http($arg1) {}
+function locale_canonicalize($arg1) {}
+function locale_compose($arg1) {}
+function locale_filter_matches($langtag, $locale, $canonicalize = null) {}
+function locale_get_all_variants($arg1) {}
+function locale_get_default() {}
+function locale_get_display_language($locale, $in_locale = null) {}
+function locale_get_display_name($locale, $in_locale = null) {}
+function locale_get_display_region($locale, $in_locale = null) {}
+function locale_get_display_script($locale, $in_locale = null) {}
+function locale_get_display_variant($locale, $in_locale = null) {}
+function locale_get_keywords($arg1) {}
+function locale_get_primary_language($arg1) {}
+function locale_get_region($arg1) {}
+function locale_get_script($arg1) {}
+function locale_lookup($langtag, $locale, $canonicalize = null, $def = null) {}
+function locale_parse($arg1) {}
+function locale_set_default($arg1) {}
+function msgfmt_create($locale, $pattern) {}
+function msgfmt_format($nf, $args) {}
+function msgfmt_format_message($locale, $pattern, $args) {}
+function msgfmt_get_error_code($nf) {}
+function msgfmt_get_error_message($coll) {}
+function msgfmt_get_locale($mf) {}
+function msgfmt_get_pattern($mf) {}
+function msgfmt_parse($nf, $source) {}
+function msgfmt_parse_message($locale, $pattern, $source) {}
+function msgfmt_set_pattern($mf, $pattern) {}
+function normalizer_get_raw_decomposition($input) {}
+function normalizer_is_normalized($input, $form = null) {}
+function normalizer_normalize($input, $form = null) {}
+function numfmt_create($locale, $style, $pattern = null) {}
+function numfmt_format($nf, $num, $type = null) {}
+function numfmt_format_currency($nf, $num, $currency) {}
+function numfmt_get_attribute($nf, $attr) {}
+function numfmt_get_error_code($nf) {}
+function numfmt_get_error_message($nf) {}
+function numfmt_get_locale($nf, $type = null) {}
+function numfmt_get_pattern($nf) {}
+function numfmt_get_symbol($nf, $attr) {}
+function numfmt_get_text_attribute($nf, $attr) {}
+function numfmt_parse($formatter, $string, $type = null, &$position = null) {}
+function numfmt_parse_currency($formatter, $string, &$currency, &$position = null) {}
+function numfmt_set_attribute($nf, $attr, $value) {}
+function numfmt_set_pattern($nf, $pattern) {}
+function numfmt_set_symbol($nf, $attr, $symbol) {}
+function numfmt_set_text_attribute($nf, $attr, $value) {}
+function resourcebundle_count($bundle) {}
+function resourcebundle_create($locale, $bundlename, $fallback = null) {}
+function resourcebundle_get($bundle, $index, $fallback = null) {}
+function resourcebundle_get_error_code($bundle) {}
+function resourcebundle_get_error_message($bundle) {}
+function resourcebundle_locales($bundlename) {}
+function transliterator_create($id, $direction = null) {}
+function transliterator_create_from_rules($rules, $direction = null) {}
+function transliterator_create_inverse(\Transliterator $orig_trans) {}
+function transliterator_get_error_code(\Transliterator $trans) {}
+function transliterator_get_error_message(\Transliterator $trans) {}
+function transliterator_list_ids() {}
+function transliterator_transliterate($trans, $subject, $start = null, $end = null) {}
+const GRAPHEME_EXTR_COUNT = 0;
+const GRAPHEME_EXTR_MAXBYTES = 1;
+const GRAPHEME_EXTR_MAXCHARS = 2;
+const IDNA_ALLOW_UNASSIGNED = 1;
+const IDNA_CHECK_BIDI = 4;
+const IDNA_CHECK_CONTEXTJ = 8;
+const IDNA_DEFAULT = 0;
+const IDNA_ERROR_BIDI = 2048;
+const IDNA_ERROR_CONTEXTJ = 4096;
+const IDNA_ERROR_DISALLOWED = 128;
+const IDNA_ERROR_DOMAIN_NAME_TOO_LONG = 4;
+const IDNA_ERROR_EMPTY_LABEL = 1;
+const IDNA_ERROR_HYPHEN_3_4 = 32;
+const IDNA_ERROR_INVALID_ACE_LABEL = 1024;
+const IDNA_ERROR_LABEL_HAS_DOT = 512;
+const IDNA_ERROR_LABEL_TOO_LONG = 2;
+const IDNA_ERROR_LEADING_COMBINING_MARK = 64;
+const IDNA_ERROR_LEADING_HYPHEN = 8;
+const IDNA_ERROR_PUNYCODE = 256;
+const IDNA_ERROR_TRAILING_HYPHEN = 16;
+const IDNA_NONTRANSITIONAL_TO_ASCII = 16;
+const IDNA_NONTRANSITIONAL_TO_UNICODE = 32;
+const IDNA_USE_STD3_RULES = 2;
+const INTL_ICU_DATA_VERSION = '63.1';
+const INTL_ICU_VERSION = '63.1';
+const INTL_IDNA_VARIANT_2003 = 0;
+const INTL_IDNA_VARIANT_UTS46 = 1;
+const INTL_MAX_LOCALE_LEN = 156;
+const ULOC_ACTUAL_LOCALE = 0;
+const ULOC_VALID_LOCALE = 1;
+const U_AMBIGUOUS_ALIAS_WARNING = -122;
+const U_BAD_VARIABLE_DEFINITION = 65536;
+const U_BRK_ASSIGN_ERROR = 66053;
+const U_BRK_ERROR_LIMIT = 66062;
+const U_BRK_ERROR_START = 66048;
+const U_BRK_HEX_DIGITS_EXPECTED = 66049;
+const U_BRK_INIT_ERROR = 66058;
+const U_BRK_INTERNAL_ERROR = 66048;
+const U_BRK_MALFORMED_RULE_TAG = 66061;
+const U_BRK_MISMATCHED_PAREN = 66055;
+const U_BRK_NEW_LINE_IN_QUOTED_STRING = 66056;
+const U_BRK_RULE_EMPTY_SET = 66059;
+const U_BRK_RULE_SYNTAX = 66051;
+const U_BRK_SEMICOLON_EXPECTED = 66050;
+const U_BRK_UNCLOSED_SET = 66052;
+const U_BRK_UNDEFINED_VARIABLE = 66057;
+const U_BRK_UNRECOGNIZED_OPTION = 66060;
+const U_BRK_VARIABLE_REDFINITION = 66054;
+const U_BUFFER_OVERFLOW_ERROR = 15;
+const U_CE_NOT_FOUND_ERROR = 21;
+const U_COLLATOR_VERSION_MISMATCH = 28;
+const U_DIFFERENT_UCA_VERSION = -121;
+const U_ENUM_OUT_OF_SYNC_ERROR = 25;
+const U_ERROR_LIMIT = 66818;
+const U_ERROR_WARNING_LIMIT = -119;
+const U_ERROR_WARNING_START = -128;
+const U_FILE_ACCESS_ERROR = 4;
+const U_FMT_PARSE_ERROR_LIMIT = 65812;
+const U_FMT_PARSE_ERROR_START = 65792;
+const U_IDNA_ACE_PREFIX_ERROR = 66564;
+const U_IDNA_CHECK_BIDI_ERROR = 66562;
+const U_IDNA_DOMAIN_NAME_TOO_LONG_ERROR = 66568;
+const U_IDNA_ERROR_LIMIT = 66569;
+const U_IDNA_ERROR_START = 66560;
+const U_IDNA_LABEL_TOO_LONG_ERROR = 66566;
+const U_IDNA_PROHIBITED_ERROR = 66560;
+const U_IDNA_STD3_ASCII_RULES_ERROR = 66563;
+const U_IDNA_UNASSIGNED_ERROR = 66561;
+const U_IDNA_VERIFICATION_ERROR = 66565;
+const U_IDNA_ZERO_LENGTH_LABEL_ERROR = 66567;
+const U_ILLEGAL_ARGUMENT_ERROR = 1;
+const U_ILLEGAL_CHARACTER = 65567;
+const U_ILLEGAL_CHAR_FOUND = 12;
+const U_ILLEGAL_CHAR_IN_SEGMENT = 65564;
+const U_ILLEGAL_ESCAPE_SEQUENCE = 18;
+const U_ILLEGAL_PAD_POSITION = 65800;
+const U_INDEX_OUTOFBOUNDS_ERROR = 8;
+const U_INTERNAL_PROGRAM_ERROR = 5;
+const U_INTERNAL_TRANSLITERATOR_ERROR = 65568;
+const U_INVALID_CHAR_FOUND = 10;
+const U_INVALID_FORMAT_ERROR = 3;
+const U_INVALID_FUNCTION = 65570;
+const U_INVALID_ID = 65569;
+const U_INVALID_PROPERTY_PATTERN = 65561;
+const U_INVALID_RBT_SYNTAX = 65560;
+const U_INVALID_STATE_ERROR = 27;
+const U_INVALID_TABLE_FILE = 14;
+const U_INVALID_TABLE_FORMAT = 13;
+const U_INVARIANT_CONVERSION_ERROR = 26;
+const U_MALFORMED_EXPONENTIAL_PATTERN = 65795;
+const U_MALFORMED_PRAGMA = 65562;
+const U_MALFORMED_RULE = 65537;
+const U_MALFORMED_SET = 65538;
+const U_MALFORMED_SYMBOL_REFERENCE = 65539;
+const U_MALFORMED_UNICODE_ESCAPE = 65540;
+const U_MALFORMED_VARIABLE_DEFINITION = 65541;
+const U_MALFORMED_VARIABLE_REFERENCE = 65542;
+const U_MEMORY_ALLOCATION_ERROR = 7;
+const U_MESSAGE_PARSE_ERROR = 6;
+const U_MISMATCHED_SEGMENT_DELIMITERS = 65543;
+const U_MISPLACED_ANCHOR_START = 65544;
+const U_MISPLACED_COMPOUND_FILTER = 65558;
+const U_MISPLACED_CURSOR_OFFSET = 65545;
+const U_MISPLACED_QUANTIFIER = 65546;
+const U_MISSING_OPERATOR = 65547;
+const U_MISSING_RESOURCE_ERROR = 2;
+const U_MISSING_SEGMENT_CLOSE = 65548;
+const U_MULTIPLE_ANTE_CONTEXTS = 65549;
+const U_MULTIPLE_COMPOUND_FILTERS = 65559;
+const U_MULTIPLE_CURSORS = 65550;
+const U_MULTIPLE_DECIMAL_SEPARATORS = 65793;
+const U_MULTIPLE_DECIMAL_SEPERATORS = 65793;
+const U_MULTIPLE_EXPONENTIAL_SYMBOLS = 65794;
+const U_MULTIPLE_PAD_SPECIFIERS = 65798;
+const U_MULTIPLE_PERCENT_SYMBOLS = 65796;
+const U_MULTIPLE_PERMILL_SYMBOLS = 65797;
+const U_MULTIPLE_POST_CONTEXTS = 65551;
+const U_NO_SPACE_AVAILABLE = 20;
+const U_NO_WRITE_PERMISSION = 30;
+const U_PARSE_ERROR = 9;
+const U_PARSE_ERROR_LIMIT = 65571;
+const U_PARSE_ERROR_START = 65536;
+const U_PATTERN_SYNTAX_ERROR = 65799;
+const U_PRIMARY_TOO_LONG_ERROR = 22;
+const U_REGEX_BAD_ESCAPE_SEQUENCE = 66307;
+const U_REGEX_BAD_INTERVAL = 66312;
+const U_REGEX_ERROR_LIMIT = 66326;
+const U_REGEX_ERROR_START = 66304;
+const U_REGEX_INTERNAL_ERROR = 66304;
+const U_REGEX_INVALID_BACK_REF = 66314;
+const U_REGEX_INVALID_FLAG = 66315;
+const U_REGEX_INVALID_STATE = 66306;
+const U_REGEX_LOOK_BEHIND_LIMIT = 66316;
+const U_REGEX_MAX_LT_MIN = 66313;
+const U_REGEX_MISMATCHED_PAREN = 66310;
+const U_REGEX_NUMBER_TOO_BIG = 66311;
+const U_REGEX_PROPERTY_SYNTAX = 66308;
+const U_REGEX_RULE_SYNTAX = 66305;
+const U_REGEX_SET_CONTAINS_STRING = 66317;
+const U_REGEX_UNIMPLEMENTED = 66309;
+const U_RESOURCE_TYPE_MISMATCH = 17;
+const U_RULE_MASK_ERROR = 65557;
+const U_SAFECLONE_ALLOCATED_WARNING = -126;
+const U_SORT_KEY_TOO_SHORT_WARNING = -123;
+const U_STANDARD_ERROR_LIMIT = 31;
+const U_STATE_OLD_WARNING = -125;
+const U_STATE_TOO_OLD_ERROR = 23;
+const U_STRINGPREP_CHECK_BIDI_ERROR = 66562;
+const U_STRINGPREP_PROHIBITED_ERROR = 66560;
+const U_STRINGPREP_UNASSIGNED_ERROR = 66561;
+const U_STRING_NOT_TERMINATED_WARNING = -124;
+const U_TOO_MANY_ALIASES_ERROR = 24;
+const U_TRAILING_BACKSLASH = 65552;
+const U_TRUNCATED_CHAR_FOUND = 11;
+const U_UNCLOSED_SEGMENT = 65563;
+const U_UNDEFINED_SEGMENT_REFERENCE = 65553;
+const U_UNDEFINED_VARIABLE = 65554;
+const U_UNEXPECTED_TOKEN = 65792;
+const U_UNMATCHED_BRACES = 65801;
+const U_UNQUOTED_SPECIAL = 65555;
+const U_UNSUPPORTED_ATTRIBUTE = 65803;
+const U_UNSUPPORTED_ERROR = 16;
+const U_UNSUPPORTED_ESCAPE_SEQUENCE = 19;
+const U_UNSUPPORTED_PROPERTY = 65802;
+const U_UNTERMINATED_QUOTE = 65556;
+const U_USELESS_COLLATOR_ERROR = 29;
+const U_USING_DEFAULT_WARNING = -127;
+const U_USING_FALLBACK_WARNING = -128;
+const U_VARIABLE_RANGE_EXHAUSTED = 65565;
+const U_VARIABLE_RANGE_OVERLAP = 65566;
+const U_ZERO_ERROR = 0;
+}
}
public function stop() {
}
- public function getLog() {
+ public function getLog() : ExcimerLog {
}
public function flush() {
}
}
function formatCollapsed() {
}
+ /**
+ * @return array[]
+ */
function aggregateByFunction() {
}
+ /**
+ * @return int
+ */
function getEventCount() {
}
function current() {
*/
public function send( $recipients, array $headers, $body ) {
}
+ /**
+ * @return string
+ */
+ public function getMessage() {
+ }
}
class Mail_smtp extends Mail {
* Jaska Zedlik
* Jason Richey
* Jayprakash12345
-* jeblad
* Jeff Hobson
* Jeff Janes
* jeff303
* Jerome Jamnicky
* Jesús Martínez Novo
* jhobs
-* jhsoby
* Jiabao
* Jidanni
* Jimmy Collins
cache: true
},
all: [
- '**/*.js{,on}',
+ '**/*.{js,json}',
'!docs/**',
'!node_modules/**',
'!resources/lib/**',
Starting with MediaWiki 1.2.0, it's possible to install and configure the wiki
"in-place", as long as you have the necessary prerequisites available.
-Required software:
-* Web server with PHP 7.0.0 or HHVM 3.18.5 or higher.
+Required software as of MediaWiki 1.34.0:
+
+* Web server with PHP 7.0.13 or higher, plus the following extesnsions:
+** ctype
+** dom
+** fileinfo
+** iconv
+** json
+** mbstring
+** xml
* A SQL server, the following types are supported
** MySQL 5.5.8 or higher
** PostgreSQL 9.2 or higher
* $wgDebugPrintHttpHeaders - The default of including HTTP headers in the
debug log channel is no longer configurable. The debug log itself remains
configurable via $wgDebugLogFile.
+* $wgMsgCacheExpiry - The MessageCache uses 24 hours as the expiry for values
+ stored in WANObjectCache. This is no longer configurable.
* $wgPasswordSalt – This setting, used for migrating exceptionally old, insecure
password setups and deprecated since 1.24, is now removed.
* $wgDBOracleDRCP - If you must use persistent connections, set DBO_PERSISTENT
in the 'flags' field for servers in $wgDBServers (or $wgLBFactoryConf).
+* $wgMemCachedDebug - Set the cache "debug" field in $wgObjectCaches instead.
=== New user-facing features in 1.34 ===
* Special:Mute has been added as a quick way for users to block unwanted emails
([[Special:NewSection/Test]] redirects to creating a new section in "Test").
Otherwise, it displays a basic interface to allow the end user to specify
the target manually.
+* (T220447) Special:Contributions/newbies has been removed for performance and
+ usefulness reasons. Use Special:RecentChanges?userExpLevel=newcomer instead.
+* Special:NewFiles/newbies has been removed for performance and usefulness
+ reasons. Use Special:RecentChanges?userExpLevel=newcomer&namespace=6 instead.
=== New developer features in 1.34 ===
* The ImgAuthModifyHeaders hook was added to img_auth.php to allow modification
* The UserIsBlockedFrom hook is only called if a block is found first, and
should only be used to unblock a blocked user.
* …
-* Language::$dataCache has been removed (without prior deprecation, for
- practical reasons). Use MediaWikiServices instead to get a LocalisationCache.
=== Deprecations in 1.34 ===
* The MWNamespace class is deprecated. Use NamespaceInfo.
* ResourceLoaderContext::getConfig and ResourceLoaderContext::getLogger have
been deprecated. Inside ResourceLoaderModule subclasses, use the local methods
instead. Elsewhere, use the methods from the ResourceLoader class.
+* The Profiler::setTemplated and Profiler::getTemplated methods have been
+ deprecated. Use Profiler::setAllowOutput and Profiler::getAllowOutput
+ instead.
* The Preprocessor_DOM implementation has been deprecated. It will be
removed in a future release. Use the Preprocessor_Hash implementation
instead.
* Constructing MovePage directly is deprecated. Use MovePageFactory.
* TempFSFile::factory() has been deprecated. Use TempFSFileFactory instead.
* wfIsBadImage() is deprecated. Use the BadFileLookup service instead.
-* Language::getLocalisationCache() is deprecated. Use MediaWikiServices.
-* The following Language methods are deprecated: isSupportedLanguage,
- isValidCode, isValidBuiltInCode, isKnownLanguageTag, fetchLanguageNames,
- fetchLanguageName, getFileName, getMessagesFileName, getJsonMessagesFileName.
- Use the new LanguageNameUtils class instead. (Note that fetchLanguageName(s)
- are called getLanguageName(s) in the new class.)
+* Building a new SearchResult is hard-deprecated, always call
+ SearchResult::newFromTitle(). This class is being refactored into an abstract
+ class. If you extend this class please be sure to override all its methods
+ or extend RevisionSearchResult.
+* Skin::getSkinNameMessages() is deprecated and no longer used.
=== Other changes in 1.34 ===
* …
== Compatibility ==
MediaWiki 1.34 requires PHP 7.0.13 or later. Although HHVM 3.18.5 or later is
supported, it is generally advised to use PHP 7.0.13 or later for long term
-support.
+support. It also requires the following PHP extensions:
+
+* ctype
+* dom
+* fileinfo
+* iconv
+* json
+* mbstring
+* xml
MySQL/MariaDB is the recommended DBMS. PostgreSQL or SQLite can also be used,
but support for them is somewhat less mature.
'ConvertExtensionToRegistration' => __DIR__ . '/maintenance/convertExtensionToRegistration.php',
'ConvertLinks' => __DIR__ . '/maintenance/convertLinks.php',
'ConvertUserOptions' => __DIR__ . '/maintenance/convertUserOptions.php',
- 'ConverterRule' => __DIR__ . '/languages/ConverterRule.php',
+ 'ConverterRule' => __DIR__ . '/includes/language/ConverterRule.php',
'Cookie' => __DIR__ . '/includes/libs/Cookie.php',
'CookieJar' => __DIR__ . '/includes/libs/CookieJar.php',
'CopyFileBackend' => __DIR__ . '/maintenance/copyFileBackend.php',
'MediaWiki\\Diff\\ComplexityException' => __DIR__ . '/includes/diff/ComplexityException.php',
'MediaWiki\\Diff\\WordAccumulator' => __DIR__ . '/includes/diff/WordAccumulator.php',
'MediaWiki\\FileBackend\\FSFile\\TempFSFileFactory' => __DIR__ . '/includes/libs/filebackend/fsfile/TempFSFileFactory.php',
+ 'MediaWiki\\FileBackend\\LockManager\\LockManagerGroupFactory' => __DIR__ . '/includes/filebackend/lockmanager/LockManagerGroupFactory.php',
'MediaWiki\\HeaderCallback' => __DIR__ . '/includes/HeaderCallback.php',
'MediaWiki\\Http\\HttpRequestFactory' => __DIR__ . '/includes/http/HttpRequestFactory.php',
'MediaWiki\\Installer\\InstallException' => __DIR__ . '/includes/installer/InstallException.php',
'MediaWiki\\Languages\\Data\\CrhExceptions' => __DIR__ . '/languages/data/CrhExceptions.php',
'MediaWiki\\Languages\\Data\\Names' => __DIR__ . '/languages/data/Names.php',
'MediaWiki\\Languages\\Data\\ZhConversion' => __DIR__ . '/languages/data/ZhConversion.php',
- 'MediaWiki\\Languages\\LanguageNameUtils' => __DIR__ . '/includes/language/LanguageNameUtils.php',
'MediaWiki\\Logger\\ConsoleLogger' => __DIR__ . '/includes/debug/logger/ConsoleLogger.php',
'MediaWiki\\Logger\\ConsoleSpi' => __DIR__ . '/includes/debug/logger/ConsoleSpi.php',
'MediaWiki\\Logger\\LegacyLogger' => __DIR__ . '/includes/debug/logger/LegacyLogger.php',
'NullStatsdDataFactory' => __DIR__ . '/includes/libs/stats/NullStatsdDataFactory.php',
'NumericUppercaseCollation' => __DIR__ . '/includes/collation/NumericUppercaseCollation.php',
'OOUIHTMLForm' => __DIR__ . '/includes/htmlform/OOUIHTMLForm.php',
- 'ORAField' => __DIR__ . '/includes/db/ORAField.php',
- 'ORAResult' => __DIR__ . '/includes/db/ORAResult.php',
'ObjectCache' => __DIR__ . '/includes/objectcache/ObjectCache.php',
'OldChangesList' => __DIR__ . '/includes/changes/OldChangesList.php',
'OldLocalFile' => __DIR__ . '/includes/filerepo/file/OldLocalFile.php',
'RevisionItemBase' => __DIR__ . '/includes/revisionlist/RevisionItemBase.php',
'RevisionList' => __DIR__ . '/includes/revisionlist/RevisionList.php',
'RevisionListBase' => __DIR__ . '/includes/revisionlist/RevisionListBase.php',
+ 'RevisionSearchResult' => __DIR__ . '/includes/search/RevisionSearchResult.php',
+ 'RevisionSearchResultTrait' => __DIR__ . '/includes/search/RevisionSearchResultTrait.php',
'RiffExtractor' => __DIR__ . '/includes/libs/RiffExtractor.php',
'RightsLogFormatter' => __DIR__ . '/includes/logging/RightsLogFormatter.php',
'RollbackAction' => __DIR__ . '/includes/actions/RollbackAction.php',
'SearchResult' => __DIR__ . '/includes/search/SearchResult.php',
'SearchResultSet' => __DIR__ . '/includes/search/SearchResultSet.php',
'SearchResultSetTrait' => __DIR__ . '/includes/search/SearchResultSetTrait.php',
+ 'SearchResultTrait' => __DIR__ . '/includes/search/SearchResultTrait.php',
'SearchSqlite' => __DIR__ . '/includes/search/SearchSqlite.php',
'SearchSuggestion' => __DIR__ . '/includes/search/SearchSuggestion.php',
'SearchSuggestionSet' => __DIR__ . '/includes/search/SearchSuggestionSet.php',
'UncategorizedTemplatesPage' => __DIR__ . '/includes/specials/SpecialUncategorizedtemplates.php',
'Undelete' => __DIR__ . '/maintenance/undelete.php',
'UnifiedDiffFormatter' => __DIR__ . '/includes/diff/UnifiedDiffFormatter.php',
+ 'UnknownContent' => __DIR__ . '/includes/content/UnknownContent.php',
+ 'UnknownContentHandler' => __DIR__ . '/includes/content/UnknownContentHandler.php',
'UnlistedSpecialPage' => __DIR__ . '/includes/specialpage/UnlistedSpecialPage.php',
'UnprotectAction' => __DIR__ . '/includes/actions/UnprotectAction.php',
'UnregisteredLocalFile' => __DIR__ . '/includes/filerepo/file/UnregisteredLocalFile.php',
+ 'UnsupportedSlotDiffRenderer' => __DIR__ . '/includes/diff/UnsupportedSlotDiffRenderer.php',
'UnusedCategoriesPage' => __DIR__ . '/includes/specials/SpecialUnusedcategories.php',
'UnusedimagesPage' => __DIR__ . '/includes/specials/SpecialUnusedimages.php',
'UnusedtemplatesPage' => __DIR__ . '/includes/specials/SpecialUnusedtemplates.php',
'Wikimedia\\Rdbms\\LoadMonitorMySQL' => __DIR__ . '/includes/libs/rdbms/loadmonitor/LoadMonitorMySQL.php',
'Wikimedia\\Rdbms\\LoadMonitorNull' => __DIR__ . '/includes/libs/rdbms/loadmonitor/LoadMonitorNull.php',
'Wikimedia\\Rdbms\\MaintainableDBConnRef' => __DIR__ . '/includes/libs/rdbms/database/MaintainableDBConnRef.php',
- 'Wikimedia\\Rdbms\\MssqlBlob' => __DIR__ . '/includes/libs/rdbms/encasing/MssqlBlob.php',
- 'Wikimedia\\Rdbms\\MssqlField' => __DIR__ . '/includes/libs/rdbms/field/MssqlField.php',
- 'Wikimedia\\Rdbms\\MssqlResultWrapper' => __DIR__ . '/includes/libs/rdbms/database/resultwrapper/MssqlResultWrapper.php',
'Wikimedia\\Rdbms\\MySQLField' => __DIR__ . '/includes/libs/rdbms/field/MySQLField.php',
'Wikimedia\\Rdbms\\MySQLMasterPos' => __DIR__ . '/includes/libs/rdbms/database/position/MySQLMasterPos.php',
'Wikimedia\\Rdbms\\NextSequenceValue' => __DIR__ . '/includes/libs/rdbms/database/utils/NextSequenceValue.php',
"composer/semver": "1.5.0",
"cssjanus/cssjanus": "1.3.0",
"ext-ctype": "*",
+ "ext-dom": "*",
"ext-fileinfo": "*",
"ext-iconv": "*",
"ext-json": "*",
* PostgreSQL
* SQLite
-* Oracle
-* MSSQL
More information can be found about each of these databases (known issues,
level of support, extra configuration) in the "databases" subdirectory in
cleared by: Language::loadLocalisation()
Message Cache:
- backend: $wgMessageCacheType
- key: $wgDBname:messages, $wgDBname:messages-hash, $wgDBname:messages-status
- ex: wikidb:messages, wikidb:messages-hash, wikidb:messages-status
- stores: an array where the keys are DB keys and the values are messages
- set in: wfMessage(), Article::editUpdates() and Title::moveTo()
- expiry: $wgMsgCacheExpiry
- cleared by: nothing
+ See MessageCache.php.
Newtalk:
key: $wgDBname:newtalk:ip:$ip
'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/',
'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/',
];
$dbw->lockForUpdate( 'category', [ 'cat_title' => $this->mName ], __METHOD__ );
// Lock all the `categorylinks` records and gaps for this category;
- // this is a separate query due to postgres/oracle limitations
+ // this is a separate query due to postgres limitations
$dbw->selectRowCount(
[ 'categorylinks', 'page' ],
'*',
* See LockManager::__construct() for more details.
* Additional parameters are specific to the lock manager class used.
* These settings should be global to all wikis.
- *
- * When using DBLockManager, the 'dbsByBucket' map can reference 'localDBMaster' as
- * a peer database in each bucket. This will result in an extra connection to the domain
- * that the LockManager services, which must also be a valid wiki ID.
*/
$wgLockManagers = [];
* $wgTiffThumbnailType = [ 'jpg', 'image/jpeg' ];
* @endcode
*/
-$wgTiffThumbnailType = false;
+$wgTiffThumbnailType = [];
/**
* If rendered thumbnail files are older than this timestamp, they
*/
$wgSessionPbkdf2Iterations = 10001;
-/**
- * If enabled, will send MemCached debugging information to $wgDebugLogFile
- */
-$wgMemCachedDebug = false;
-
/**
* The list of MemCached servers and port numbers
*/
'store' => 'detect',
'storeClass' => false,
'storeDirectory' => false,
- 'storeServer' => [],
- 'forceRecache' => false,
'manualRecache' => false,
];
*/
$wgUseDatabaseMessages = true;
-/**
- * Expiry time for the message cache key
- */
-$wgMsgCacheExpiry = 86400;
-
/**
* Maximum entry size in the message cache, in bytes
*/
# $wgGroupPermissions['sysop']['deletelogentry'] = true;
# $wgGroupPermissions['sysop']['deleterevision'] = true;
// To hide usernames from users and Sysops
-# $wgGroupPermissions['suppress']['hideuser'] = true;
+$wgGroupPermissions['suppress']['hideuser'] = true;
// To hide revisions/log items from users and Sysops
-# $wgGroupPermissions['suppress']['suppressrevision'] = true;
+$wgGroupPermissions['suppress']['suppressrevision'] = true;
// To view revisions/log items hidden from users and Sysops
-# $wgGroupPermissions['suppress']['viewsuppressed'] = true;
+$wgGroupPermissions['suppress']['viewsuppressed'] = true;
// For private suppression log access
-# $wgGroupPermissions['suppress']['suppressionlog'] = true;
+$wgGroupPermissions['suppress']['suppressionlog'] = true;
+// Basic rights for revision delete
+$wgGroupPermissions['suppress']['deleterevision'] = true;
+$wgGroupPermissions['suppress']['deletelogentry'] = true;
/**
* The developer group is deprecated, but can be activated if need be
/**
* List of Days options to list in the Special:Recentchanges and
* Special:Recentchangeslinked pages.
+ *
+ * @see ChangesListSpecialPage::getLinkDays
*/
$wgRCLinkDays = [ 1, 3, 7, 14, 30 ];
# checking, etc.
if ( $this->formtype == 'initial' || $this->firsttime ) {
if ( $this->initialiseForm() === false ) {
- $out = $this->context->getOutput();
- if ( $out->getRedirect() === '' ) { // mcrundo hack redirects, don't override it
- $this->noSuchSectionPage();
- }
return;
}
* @return string|null
*/
protected function importContentFormData( &$request ) {
- return; // Don't do anything, EditPage already extracted wpTextbox1
+ return null; // Don't do anything, EditPage already extracted wpTextbox1
}
/**
$content = $this->getContentObject( false ); # TODO: track content object?!
if ( $content === false ) {
+ $out = $this->context->getOutput();
+ if ( $out->getRedirect() === '' ) { // mcrundo hack redirects, don't override it
+ $this->noSuchSectionPage();
+ }
return false;
}
+
+ if ( !$this->isSupportedContentModel( $content->getModel() ) ) {
+ $modelMsg = $this->getContext()->msg( 'content-model-' . $content->getModel() );
+ $modelName = $modelMsg->exists() ? $modelMsg->text() : $content->getModel();
+
+ $out = $this->context->getOutput();
+ $out->showErrorPage(
+ 'modeleditnotsupported-title',
+ 'modeleditnotsupported-text',
+ $modelName
+ );
+ return false;
+ }
+
$this->textbox1 = $this->toEditText( $content );
$user = $this->context->getUser();
* - 'legacy-name' (optional): short name for backwards-compatibility
* @param array $checked Array of checkbox name (matching the 'legacy-name') => bool,
* where bool indicates the checked status of the checkbox
- * @return array
+ * @return array[]
*/
public function getCheckboxesDefinition( $checked ) {
$checkboxes = [];
/**
* @return array
+ * @suppress PhanParamSignatureMismatch
*/
public function getValues() {
return $this->data;
* Really delete the file
*
* @param Title &$title
- * @param File &$file
+ * @param LocalFile &$file
* @param string &$oldimage Archive name
* @param string $reason Reason of the deletion
* @param bool $suppress Whether to mark all deleted versions as restricted
if ( $oldimage ) {
$page = null;
$status = $file->deleteOld( $oldimage, $reason, $suppress, $user );
- if ( $status->ok ) {
+ if ( $status->isOK() ) {
// Need to do a log item
$logComment = wfMessage( 'deletedrevision', $oldimage )->inContentLanguage()->text();
if ( trim( $reason ) != '' ) {
$logEntry->setPerformer( $user );
$logEntry->setTarget( $title );
$logEntry->setComment( $logComment );
- $logEntry->setTags( $tags );
+ $logEntry->addTags( $tags );
$logid = $logEntry->insert();
$logEntry->publish( $logid );
$logEntry->setPerformer( $user );
$logEntry->setTarget( clone $title );
$logEntry->setComment( $reason );
- $logEntry->setTags( $tags );
+ $logEntry->addTags( $tags );
$logid = $logEntry->insert();
$dbw->onTransactionPreCommitOrIdle(
function () use ( $logEntry, $logid ) {
$wgOut->enableOOUI();
+ $fields = [];
+
+ $fields[] = new OOUI\LabelWidget( [ 'label' => new OOUI\HtmlSnippet(
+ $this->prepareMessage( 'filedelete-intro' ) ) ]
+ );
+
$options = Xml::listDropDownOptions(
$wgOut->msg( 'filedelete-reason-dropdown' )->inContentLanguage()->text(),
[ 'other' => $wgOut->msg( 'filedelete-reason-otherlist' )->inContentLanguage()->text() ]
);
$options = Xml::listDropDownOptionsOoui( $options );
- $fields[] = new OOUI\LabelWidget( [ 'label' => new OOUI\HtmlSnippet(
- $this->prepareMessage( 'filedelete-intro' ) ) ]
- );
-
$fields[] = new OOUI\FieldLayout(
new OOUI\DropdownInputWidget( [
'name' => 'wpDeleteReasonList',
// Don't share DB, storage, or memcached connections
MediaWikiServices::resetChildProcessServices();
FileBackendGroup::destroySingleton();
- LockManagerGroup::destroySingletons();
JobQueueGroup::destroySingletons();
ObjectCache::clear();
RedisConnectionPool::destroySingletons();
if ( isset( $ctx['forwarded_for'] ) ||
isset( $ctx['client_ip'] ) ||
isset( $ctx['from'] ) ) {
+ // @phan-suppress-next-line PhanTypeArraySuspiciousNullable
$ctx['proxy'] = $_SERVER['REMOTE_ADDR'];
}
* including errors from limit.sh
* - profileMethod: By default this function will profile based on the calling
* method. Set this to a string for an alternative method to profile from
+ * @phan-param array{duplicateStderr?:bool,profileMethod?:string} $options
*
* @return string Collected stdout as a string
* @deprecated since 1.30 use class MediaWiki\Shell\Shell
}
$includeStderr = isset( $options['duplicateStderr'] ) && $options['duplicateStderr'];
+ // @phan-suppress-next-line PhanTypeInvalidDimOffset
$profileMethod = $options['profileMethod'] ?? wfGetCaller();
try {
* @param array $options Associative array of options:
* 'php': The path to the php executable
* 'wrapper': Path to a PHP wrapper to handle the maintenance script
+ * @phan-param array{php?:string,wrapper?:string} $options
* @return string
*/
function wfShellWikiCmd( $script, array $parameters = [], array $options = [] ) {
// Give site config file a chance to run the script in a wrapper.
// The caller may likely want to call wfBasename() on $script.
Hooks::run( 'wfShellWikiCmd', [ &$script, &$parameters, &$options ] );
+ // @phan-suppress-next-line PhanTypeInvalidDimOffset
$cmd = [ $options['php'] ?? $wgPhpCli ];
if ( isset( $options['wrapper'] ) ) {
$cmd[] = $options['wrapper'];
$result = unpack( $format, $data );
Wikimedia\restoreWarnings();
+ // @phan-suppress-next-line PhanTypeComparisonFromArray Phan issue #3160
if ( $result === false ) {
// If it cannot extract the packed data.
throw new MWException( "unpack could not unpack binary data" );
// The constant prefix is smaller than el_index_60, so we use a LIKE
// for a prefix search.
return [
- "{$p}_index_60" . $db->buildLike( [ $index, $db->anyString() ] ),
+ "{$p}_index_60" . $db->buildLike( $index, $db->anyString() ),
"{$p}_index" . $db->buildLike( $like ),
];
}
*/
public static function makeLikeArray( $filterEntry, $protocol = 'http://' ) {
$db = wfGetDB( DB_REPLICA );
+ $like = [];
$target = $protocol . $filterEntry;
$bits = wfParseUrl( $target );
if ( $label == '' ) {
$label = $title->getPrefixedText();
}
- $encLabel = htmlspecialchars( $label );
+ $repoGroup = MediaWikiServices::getInstance()->getRepoGroup();
$currentExists = $time
- && MediaWikiServices::getInstance()->getRepoGroup()->findFile( $title ) !== false;
+ && $repoGroup->findFile( $title ) !== false;
if ( ( $wgUploadMissingFileUrl || $wgUploadNavigationUrl || $wgEnableUploads )
&& !$currentExists
) {
- $redir = RepoGroup::singleton()->getLocalRepo()->checkRedirect( $title );
-
- if ( $redir ) {
- // We already know it's a redirect, so mark it
- // accordingly
+ if ( $repoGroup->getLocalRepo()->checkRedirect( $title ) ) {
+ // We already know it's a redirect, so mark it accordingly
return self::link(
$title,
- $encLabel,
+ htmlspecialchars( $label ),
[ 'class' => 'mw-redirect' ],
wfCgiToArray( $query ),
[ 'known', 'noclasses' ]
);
}
- $href = self::getUploadUrl( $title, $query );
-
- return '<a href="' . htmlspecialchars( $href ) . '" class="new" title="' .
- htmlspecialchars( $title->getPrefixedText(), ENT_QUOTES ) . '">' .
- $encLabel . '</a>';
+ return Html::element( 'a', [
+ 'href' => self::getUploadUrl( $title, $query ),
+ 'class' => 'new',
+ 'title' => $title->getPrefixedText()
+ ], $label );
}
- return self::link( $title, $encLabel, [], wfCgiToArray( $query ), [ 'known', 'noclasses' ] );
+ return self::link(
+ $title,
+ htmlspecialchars( $label ),
+ [],
+ wfCgiToArray( $query ),
+ [ 'known', 'noclasses' ]
+ );
}
/**
}
$userTalkPage = new TitleValue( NS_USER_TALK, strtr( $userText, ' ', '_' ) );
- $moreLinkAttribs['class'] = 'mw-usertoollinks-talk';
+ $moreLinkAttribs = [ 'class' => 'mw-usertoollinks-talk' ];
return self::link( $userTalkPage,
wfMessage( 'talkpagelinktext' )->escaped(),
}
$blockPage = SpecialPage::getTitleFor( 'Block', $userText );
- $moreLinkAttribs['class'] = 'mw-usertoollinks-block';
+ $moreLinkAttribs = [ 'class' => 'mw-usertoollinks-block' ];
return self::link( $blockPage,
wfMessage( 'blocklink' )->escaped(),
}
$emailPage = SpecialPage::getTitleFor( 'Emailuser', $userText );
- $moreLinkAttribs['class'] = 'mw-usertoollinks-mail';
+ $moreLinkAttribs = [ 'class' => 'mw-usertoollinks-mail' ];
return self::link( $emailPage,
wfMessage( 'emaillink' )->escaped(),
$moreLinkAttribs
$services->getNamespaceInfo()->getCanonicalName( NS_MEDIA ), '/' );
$medians .= '|';
$medians .= preg_quote(
- MediaWikiServices::getInstance()->getContentLanguage()->getNsText( NS_MEDIA ),
+ $services->getContentLanguage()->getNsText( NS_MEDIA ),
'/'
) . '):';
}
if ( $match[1] !== false && $match[1] !== '' ) {
if ( preg_match(
- MediaWikiServices::getInstance()->getContentLanguage()->linkTrail(),
+ $services->getContentLanguage()->linkTrail(),
$match[3],
$submatch
) ) {
Title::newFromText( $linkTarget );
try {
- $target = MediaWikiServices::getInstance()->getTitleParser()->
+ $target = $services->getTitleParser()->
parseTitle( $linkTarget );
if ( $target->getText() == '' && !$target->isExternal()
Profiler::instance()->logDataPageOutputOnly();
} catch ( Exception $e ) {
// An error may already have been shown in run(), so just log it to be safe
- MWExceptionHandler::rollbackMasterChangesAndLog( $e );
+ MWExceptionHandler::logException( $e );
}
// Disable WebResponse setters for post-send processing (T191537).
use Hooks;
use IBufferingStatsdDataFactory;
use Liuggio\StatsdClient\Factory\StatsdDataFactoryInterface;
-use LocalisationCache;
use MediaWiki\Block\BlockManager;
use MediaWiki\Block\BlockRestrictionStore;
use MediaWiki\FileBackend\FSFile\TempFSFileFactory;
+use MediaWiki\FileBackend\LockManager\LockManagerGroupFactory;
use MediaWiki\Http\HttpRequestFactory;
-use MediaWiki\Languages\LanguageNameUtils;
+use Wikimedia\Message\IMessageFormatterFactory;
use MediaWiki\Page\MovePageFactory;
use MediaWiki\Permissions\PermissionManager;
use MediaWiki\Preferences\PreferencesFactory;
return $this->getService( 'InterwikiLookup' );
}
- /**
- * @since 1.34
- * @return LanguageNameUtils
- */
- public function getLanguageNameUtils() {
- return $this->getService( 'LanguageNameUtils' );
- }
-
/**
* @since 1.28
* @return LinkCache
return $this->getService( 'LinkRendererFactory' );
}
- /**
- * @since 1.34
- * @return LocalisationCache
- */
- public function getLocalisationCache() : LocalisationCache {
- return $this->getService( 'LocalisationCache' );
- }
-
/**
* @since 1.28
* @return \BagOStuff
return $this->getService( 'LocalServerObjectCache' );
}
+ /**
+ * @since 1.34
+ * @return LockManagerGroupFactory
+ */
+ public function getLockManagerGroupFactory() : LockManagerGroupFactory {
+ return $this->getService( 'LockManagerGroupFactory' );
+ }
+
/**
* @since 1.32
* @return MagicWordFactory
return $this->getService( 'MessageCache' );
}
+ /**
+ * @since 1.34
+ * @return IMessageFormatterFactory
+ */
+ public function getMessageFormatterFactory() {
+ return $this->getService( 'MessageFormatterFactory' );
+ }
+
/**
* @since 1.28
* @return MimeAnalyzer
--- /dev/null
+<?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];
+ }
+}
--- /dev/null
+<?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();
+ }
+}
$status = Status::newFatal( 'movepage-max-pages', $wgMaximumMovedPages );
$perTitleStatus[$oldSubpage->getPrefixedText()] = $status;
$topStatus->merge( $status );
- $topStatus->setOk( true );
+ $topStatus->setOK( true );
break;
}
}
$perTitleStatus[$oldSubpage->getPrefixedText()] = $status;
$topStatus->merge( $status );
- $topStatus->setOk( true );
+ $topStatus->setOK( true );
}
$topStatus->value = $perTitleStatus;
'4::oldtitle' => $this->oldTitle->getPrefixedText(),
] );
$logEntry->setRelations( [ 'pr_id' => $logRelationsValues ] );
- $logEntry->setTags( $changeTags );
+ $logEntry->addTags( $changeTags );
$logId = $logEntry->insert();
$logEntry->publish( $logId );
}
# Log the move
$logid = $logEntry->insert();
- $logEntry->setTags( $changeTags );
+ $logEntry->addTags( $changeTags );
$logEntry->publish( $logid );
return $nullRevision;
namespace MediaWiki\Navigation;
-use MediaWiki\Linker\LinkTarget;
-use MessageLocalizer;
use Html;
+use MessageLocalizer;
+use Title;
/**
* Helper class for generating prev/next links for paging.
+ * @todo Use LinkTarget instead of Title
*
* @since 1.34
*/
*/
private $messageLocalizer;
+ /**
+ * @param MessageLocalizer $messageLocalizer
+ */
public function __construct( MessageLocalizer $messageLocalizer ) {
$this->messageLocalizer = $messageLocalizer;
}
/**
* Generate (prev x| next x) (20|50|100...) type links for paging
*
- * @param LinkTarget $title LinkTarget object to link
+ * @param Title $title Title object to link
* @param int $offset
* @param int $limit
* @param array $query Optional URL query parameter string
* @param bool $atend Optional param for specified if this is the last page
* @return string
*/
- public function buildPrevNextNavigation( LinkTarget $title, $offset, $limit,
- array $query = [], $atend = false
+ public function buildPrevNextNavigation(
+ Title $title,
+ $offset,
+ $limit,
+ array $query = [],
+ $atend = false
) {
# Make 'previous' link
$prev = $this->messageLocalizer->msg( 'prevn' )->title( $title )
# Make links to set number of items per page
$numLinks = [];
+ // @phan-suppress-next-next-line PhanUndeclaredMethod
+ // @fixme MessageLocalizer doesn't have a getLanguage() method!
$lang = $this->messageLocalizer->getLanguage();
foreach ( [ 20, 50, 100, 250, 500 ] as $num ) {
$numLinks[] = $this->numLink( $title, $offset, $num, $query,
/**
* Helper function for buildPrevNextNavigation() that generates links
*
- * @param LinkTarget $title LinkTarget object to link
+ * @param Title $title Title object to link
* @param int $offset
* @param int $limit
* @param array $query Extra query parameters
* @param string $class Value of the "class" attribute of the link
* @return string HTML fragment
*/
- private function numLink( LinkTarget $title, $offset, $limit, array $query, $link,
+ private function numLink( Title $title, $offset, $limit, array $query, $link,
$tooltipMsg, $class
) {
$query = [ 'limit' => $limit, 'offset' => $offset ] + $query;
* @todo document
*/
class OutputPage extends ContextSource {
- /** @var array Should be private. Used with addMeta() which adds "<meta>" */
+ /** @var string[][] Should be private. Used with addMeta() which adds "<meta>" */
protected $mMetatags = [];
/** @var array */
* @param Title $t
*/
public function setTitle( Title $t ) {
+ // @phan-suppress-next-next-line PhanUndeclaredMethod
+ // @fixme Not all implementations of IContextSource have this method!
$this->getContext()->setTitle( $t );
}
* @param string $text Wikitext
* @param Title $title
* @param bool $linestart Is this the start of a line?
- * @param bool $tidy Whether to use tidy.
- * Setting this to false (or omitting it) is deprecated
- * since 1.32; all wikitext should be tidied.
* @param bool $interface Whether it is an interface message
* (for example disables conversion)
* @param string $wrapperClass if not empty, wraps the output in
* a `<div class="$wrapperClass">`
- * @private
*/
private function addWikiTextTitleInternal(
$text, Title $title, $linestart, $interface, $wrapperClass = null
$title = $this->getTitle();
$ns = $title->getNamespace();
- $nsInfo = MediaWikiServices::getInstance()->getNamespaceInfo();
+ $nsInfo = $services->getNamespaceInfo();
$canonicalNamespace = $nsInfo->exists( $ns )
? $nsInfo->getCanonicalName( $ns )
: $title->getNsText();
$vars['wgUserVariant'] = $contLang->getPreferredVariant();
}
// Same test as SkinTemplate
- $vars['wgIsProbablyEditable'] = $title->quickUserCan( 'edit', $user )
- && ( $title->exists() || $title->quickUserCan( 'create', $user ) );
+ $vars['wgIsProbablyEditable'] = $this->userCanEditOrCreate( $user, $title );
- $vars['wgRelevantPageIsProbablyEditable'] = $relevantTitle
- && $relevantTitle->quickUserCan( 'edit', $user )
- && ( $relevantTitle->exists() || $relevantTitle->quickUserCan( 'create', $user ) );
+ $vars['wgRelevantPageIsProbablyEditable'] = $relevantTitle &&
+ $this->userCanEditOrCreate( $user, $relevantTitle );
foreach ( $title->getRestrictionTypes() as $type ) {
// Following keys are set in $vars:
return true;
}
+ /**
+ * @param User $user
+ * @param LinkTarget $title
+ * @return bool
+ */
+ private function userCanEditOrCreate(
+ User $user,
+ LinkTarget $title
+ ) {
+ $pm = MediaWikiServices::getInstance()->getPermissionManager();
+ return $pm->quickUserCan( 'edit', $user, $title )
+ && ( $this->getTitle()->exists() ||
+ $pm->quickUserCan( 'create', $user, $title ) );
+ }
+
/**
* @return array Array in format "link name or number => 'link html'".
*/
# Universal edit button
if ( $config->get( 'UniversalEditButton' ) && $this->isArticleRelated() ) {
- $user = $this->getUser();
- if ( $this->getTitle()->quickUserCan( 'edit', $user )
- && ( $this->getTitle()->exists() ||
- $this->getTitle()->quickUserCan( 'create', $user ) )
- ) {
+ if ( $this->userCanEditOrCreate( $this->getUser(), $this->getTitle() ) ) {
// Original UniversalEditButton
$msg = $this->msg( 'edit' )->text();
$tags['universal-edit-button'] = Html::element( 'link', [
/** @var NamespaceInfo */
private $nsInfo;
- /** @var string[] Cached results of getAllRights() */
- private $allRights = false;
+ /** @var string[]|null Cached results of getAllRights() */
+ private $allRights;
/** @var string[][] Cached user rights */
private $usersRights = null;
return !count( $this->getPermissionErrorsInternal( $action, $user, $page, $rigor, true ) );
}
+ /**
+ * A convenience method for calling PermissionManager::userCan
+ * with PermissionManager::RIGOR_QUICK
+ *
+ * Suitable for use for nonessential UI controls in common cases, but
+ * _not_ for functional access control.
+ * May provide false positives, but should never provide a false negative.
+ *
+ * @see PermissionManager::userCan()
+ *
+ * @param string $action
+ * @param User $user
+ * @param LinkTarget $page
+ * @return bool
+ */
+ public function quickUserCan( $action, User $user, LinkTarget $page ) {
+ return $this->userCan( $action, $user, $page, self::RIGOR_QUICK );
+ }
+
/**
* Can $user perform $action on a page?
*
* Check permissions on special pages & namespaces
*
* @param string $action The action to check
- * @param User $user User to check
+ * @param UserIdentity $user User to check
* @param array $errors List of current errors
* @param string $rigor One of PermissionManager::RIGOR_ constants
* - RIGOR_QUICK : does cheap permission checks from replica DBs (usable for GUI creation)
*/
private function checkSpecialsAndNSPermissions(
$action,
- User $user,
+ UserIdentity $user,
$errors,
$rigor,
$short,
}
# Check $wgNamespaceProtection for restricted namespaces
- if ( $title->isNamespaceProtected( $user ) ) {
+ if ( $this->isNamespaceProtected( $title->getNamespace(), $user ) ) {
$ns = $title->getNamespace() == NS_MAIN ?
wfMessage( 'nstab-main' )->text() : $title->getNsText();
$errors[] = $title->getNamespace() == NS_MEDIAWIKI ?
* Check if user is allowed to make any action
*
* @param UserIdentity $user
- * // TODO: HHVM can't create mocks with variable params @param string ...$actions
+ * // TODO: HHVM bug T228695#5450847 @param string ...$actions
+ * @suppress PhanCommentParamWithoutRealParam
* @return bool True if user is allowed to perform *any* of the given actions
* @since 1.34
*/
* Check if user is allowed to make all actions
*
* @param UserIdentity $user
- * // TODO: HHVM can't create mocks with variable params @param string ...$actions
+ * // TODO: HHVM bug T228695#5450847 @param string ...$actions
+ * @suppress PhanCommentParamWithoutRealParam
* @return bool True if user is allowed to perform *all* of the given actions
* @since 1.34
*/
*/
public function getUserPermissions( UserIdentity $user ) {
$user = User::newFromIdentity( $user );
- if ( !isset( $this->usersRights[ $user->getId() ] ) ) {
- $this->usersRights[ $user->getId() ] = $this->getGroupPermissions(
+ $rightsCacheKey = $this->getRightsCacheKey( $user );
+ if ( !isset( $this->usersRights[ $rightsCacheKey ] ) ) {
+ $this->usersRights[ $rightsCacheKey ] = $this->getGroupPermissions(
$user->getEffectiveGroups()
);
- Hooks::run( 'UserGetRights', [ $user, &$this->usersRights[ $user->getId() ] ] );
+ Hooks::run( 'UserGetRights', [ $user, &$this->usersRights[ $rightsCacheKey ] ] );
// Deny any rights denied by the user's session, unless this
// endpoint has no sessions.
// FIXME: $user->getRequest().. need to be replaced with something else
$allowedRights = $user->getRequest()->getSession()->getAllowedUserRights();
if ( $allowedRights !== null ) {
- $this->usersRights[ $user->getId() ] = array_intersect(
- $this->usersRights[ $user->getId() ],
+ $this->usersRights[ $rightsCacheKey ] = array_intersect(
+ $this->usersRights[ $rightsCacheKey ],
$allowedRights
);
}
}
- Hooks::run( 'UserGetRightsRemove', [ $user, &$this->usersRights[ $user->getId() ] ] );
+ Hooks::run( 'UserGetRightsRemove', [ $user, &$this->usersRights[ $rightsCacheKey ] ] );
// Force reindexation of rights when a hook has unset one of them
- $this->usersRights[ $user->getId() ] = array_values(
- array_unique( $this->usersRights[ $user->getId() ] )
+ $this->usersRights[ $rightsCacheKey ] = array_values(
+ array_unique( $this->usersRights[ $rightsCacheKey ] )
);
if (
$user->getBlock()
) {
$anon = new User;
- $this->usersRights[ $user->getId() ] = array_intersect(
- $this->usersRights[ $user->getId() ],
+ $this->usersRights[ $rightsCacheKey ] = array_intersect(
+ $this->usersRights[ $rightsCacheKey ],
$this->getUserPermissions( $anon )
);
}
}
- $rights = $this->usersRights[ $user->getId() ];
+ $rights = $this->usersRights[ $rightsCacheKey ];
foreach ( $this->temporaryUserRights[ $user->getId() ] ?? [] as $overrides ) {
$rights = array_values( array_unique( array_merge( $rights, $overrides ) ) );
}
*/
public function invalidateUsersRightsCache( $user = null ) {
if ( $user !== null ) {
- if ( isset( $this->usersRights[ $user->getId() ] ) ) {
- unset( $this->usersRights[$user->getId()] );
+ $rightsCacheKey = $this->getRightsCacheKey( $user );
+ if ( isset( $this->usersRights[ $rightsCacheKey ] ) ) {
+ unset( $this->usersRights[ $rightsCacheKey ] );
}
} else {
$this->usersRights = null;
}
}
+ /**
+ * Gets a unique key for user rights cache.
+ * @param UserIdentity $user
+ * @return string
+ */
+ private function getRightsCacheKey( UserIdentity $user ) {
+ return $user->isRegistered() ? "u:{$user->getId()}" : "anon:{$user->getName()}";
+ }
+
/**
* Check, if the given group has the given permission
*
* @return string[] Array of permission names
*/
public function getAllPermissions() {
- if ( $this->allRights === false ) {
+ if ( $this->allRights === null ) {
if ( count( $this->options->get( 'AvailableRights' ) ) ) {
$this->allRights = array_unique( array_merge(
$this->coreRights,
return $this->allRights;
}
+ /**
+ * Determines if $user is unable to edit pages in namespace because it has been protected.
+ * @param $index
+ * @param UserIdentity $user
+ * @return bool
+ */
+ private function isNamespaceProtected( $index, UserIdentity $user ) {
+ $namespaceProtection = $this->options->get( 'NamespaceProtection' );
+ if ( isset( $namespaceProtection[$index] ) ) {
+ return !$this->userHasAllRights( $user, ...(array)$namespaceProtection[$index] );
+ }
+ return false;
+ }
+
/**
* Determine which restriction levels it makes sense to use in a namespace,
* optionally filtered by a user's rights.
if ( !defined( 'MW_PHPUNIT_TEST' ) ) {
throw new Exception( __METHOD__ . ' can not be called outside of tests' );
}
- $this->usersRights[ $user->getId() ] = is_array( $rights ) ? $rights : [ $rights ];
+ $this->usersRights[ $this->getRightsCacheKey( $user ) ] =
+ is_array( $rights ) ? $rights : [ $rights ];
}
}
*/
public function isConfiguredProxy( $ip ) {
// Quick check of known singular proxy servers
- if ( in_array( $ip, $this->proxyServers ) ) {
+ if ( in_array( $ip, $this->proxyServers, true ) ) {
return true;
}
namespace MediaWiki\Rest;
use ExtensionRegistry;
+use MediaWiki;
use MediaWiki\MediaWikiServices;
use MediaWiki\Rest\BasicAccess\MWBasicAuthorizer;
use RequestContext;
private $webResponse;
/** @var Router */
private $router;
+ /** @var RequestContext */
+ private $context;
public static function main() {
// URL safety checks
return;
}
+ $context = RequestContext::getMain();
+
// Set $wgTitle and the title in RequestContext, as in api.php
global $wgTitle;
$wgTitle = Title::makeTitle( NS_SPECIAL, 'Badtitle/rest.php' );
- RequestContext::getMain()->setTitle( $wgTitle );
+ $context->setTitle( $wgTitle );
$services = MediaWikiServices::getInstance();
$conf = $services->getMainConfig();
'cookiePrefix' => $conf->get( 'CookiePrefix' )
] );
- $authorizer = new MWBasicAuthorizer( RequestContext::getMain()->getUser(),
+ $authorizer = new MWBasicAuthorizer( $context->getUser(),
$services->getPermissionManager() );
global $IP;
);
$entryPoint = new self(
+ $context,
$request,
$wgRequest->response(),
$router );
$entryPoint->execute();
}
- public function __construct( RequestInterface $request, WebResponse $webResponse,
- Router $router
+ public function __construct( RequestContext $context, RequestInterface $request,
+ WebResponse $webResponse, Router $router
) {
+ $this->context = $context;
$this->request = $request;
$this->webResponse = $webResponse;
$this->router = $router;
}
public function execute() {
+ ob_start();
$response = $this->router->execute( $this->request );
$this->webResponse->header(
}
// Clear all errors that might have been displayed if display_errors=On
- ob_clean();
+ ob_end_clean();
$stream = $response->getBody();
$stream->rewind();
+
+ MediaWiki::preOutputCommit( $this->context );
+
if ( $stream instanceof CopyableStreamInterface ) {
$stream->copyToStream( fopen( 'php://output', 'w' ) );
} else {
echo $buffer;
}
}
+
+ $mw = new MediaWiki;
+ $mw->doPostOutputShutdown( 'fast' );
}
}
* better served by an HTTP header parsing library which provides the full
* parse tree.
*
- * @param string $name The header name
* @param string|string[] $value The input header value
* @return array
*/
--- /dev/null
+<?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 );
+ }
+}
*
* run() must be declared in the subclass. It cannot be declared as abstract
* here because it has a variable parameter list.
+ * @todo Declare it as abstract after dropping HHVM
*
* @package MediaWiki\Rest
*/
class SimpleHandler extends Handler {
public function execute() {
$params = array_values( $this->getRequest()->getPathParams() );
+ // @phan-suppress-next-line PhanUndeclaredMethod
return $this->run( ...$params );
}
}
*
* @since 1.31
* @since 1.32 Renamed from MediaWiki\Storage\MutableRevisionRecord
+ * @property MutableRevisionSlots $mSlots
*/
class MutableRevisionRecord extends RevisionRecord {
$slots = new MutableRevisionSlots();
parent::__construct( $title, $slots, $dbDomain );
-
- $this->mSlots = $slots; // redundant, but nice for static analysis
}
/**
* @param array $hints Hints given as an associative array. Known keys:
* - 'generate-html' => bool: Whether the caller is interested in output HTML (as opposed
* to just meta-data). Default is to generate HTML.
+ * @phan-param array{generate-html?:bool} $hints
*
* @return ParserOutput
*/
* @param array $hints Hints given as an associative array. Known keys:
* - 'generate-html' => bool: Whether the caller is interested in output HTML (as opposed
* to just meta-data). Default is to generate HTML.
+ * @phan-param array{generate-html?:bool} $hints
*
* @throws SuppressedDataException if the content is not accessible for the audience
* specified in the constructor.
* matched the $rev and $options. This mechanism is intended as a temporary stop-gap,
* for the time until caches have been changed to store RenderedRevision states instead
* of ParserOutput objects.
+ * @phan-param array{use-master?:bool,audience?:int,known-revision-output?:ParserOutput} $hints
*
* @return RenderedRevision|null The rendered revision, or null if the audience checks fails.
*/
throw new InvalidArgumentException( 'Mismatching wiki ID ' . $rev->getWikiId() );
}
+ // @phan-suppress-next-line PhanTypeInvalidDimOffset
$audience = $hints['audience']
?? ( $forUser ? RevisionRecord::FOR_THIS_USER : RevisionRecord::FOR_PUBLIC );
$options = ParserOptions::newCanonical( $forUser ?: 'canonical' );
}
+ // @phan-suppress-next-line PhanTypeInvalidDimOffset
$useMaster = $hints['use-master'] ?? false;
$dbIndex = $useMaster
}
private function getSpeculativeRevId( $dbIndex ) {
- // Use a fresh master connection in order to see the latest data, by avoiding
+ // Use a separate master connection in order to see the latest data, by avoiding
// stale data from REPEATABLE-READ snapshots.
- // HACK: But don't use a fresh connection in unit tests, since it would not have
- // the fake tables. This should be handled by the LoadBalancer!
- $flags = defined( 'MW_PHPUNIT_TEST' ) || $dbIndex === DB_REPLICA
- ? 0
- : ILoadBalancer::CONN_TRX_AUTOCOMMIT;
+ $flags = ILoadBalancer::CONN_TRX_AUTOCOMMIT;
$db = $this->loadBalancer->getConnectionRef( $dbIndex, [], $this->dbDomain, $flags );
}
private function getSpeculativePageId( $dbIndex ) {
- // Use a fresh master connection in order to see the latest data, by avoiding
+ // Use a separate master connection in order to see the latest data, by avoiding
// stale data from REPEATABLE-READ snapshots.
- // HACK: But don't use a fresh connection in unit tests, since it would not have
- // the fake tables. This should be handled by the LoadBalancer!
- $flags = defined( 'MW_PHPUNIT_TEST' ) || $dbIndex === DB_REPLICA
- ? 0
- : ILoadBalancer::CONN_TRX_AUTOCOMMIT;
+ $flags = ILoadBalancer::CONN_TRX_AUTOCOMMIT;
$db = $this->loadBalancer->getConnectionRef( $dbIndex, [], $this->dbDomain, $flags );
* - tables: (string[]) to include in the `$table` to `IDatabase->select()`
* - fields: (string[]) to include in the `$vars` to `IDatabase->select()`
* - joins: (array) to include in the `$join_conds` to `IDatabase->select()`
+ * @phan-return array{tables:string[],fields:string[],joins:array}
*/
public function getQueryInfo( $options = [] ) {
$ret = [
use MediaWiki\Config\ConfigRepository;
use MediaWiki\Config\ServiceOptions;
use MediaWiki\FileBackend\FSFile\TempFSFileFactory;
+use MediaWiki\FileBackend\LockManager\LockManagerGroupFactory;
use MediaWiki\Http\HttpRequestFactory;
use MediaWiki\Interwiki\ClassicInterwikiLookup;
use MediaWiki\Interwiki\InterwikiLookup;
-use MediaWiki\Languages\LanguageNameUtils;
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;
);
},
- 'LanguageNameUtils' => function ( MediaWikiServices $services ) : LanguageNameUtils {
- return new LanguageNameUtils( new ServiceOptions(
- LanguageNameUtils::$constructorOptions,
- $services->getMainConfig()
- ) );
- },
-
'LinkCache' => function ( MediaWikiServices $services ) : LinkCache {
return new LinkCache(
$services->getTitleFormatter(),
);
},
- 'LocalisationCache' => function ( MediaWikiServices $services ) : LocalisationCache {
- $conf = $services->getMainConfig()->get( 'LocalisationCacheConf' );
-
- $logger = LoggerFactory::getInstance( 'localisation' );
-
- // Figure out what class to use for the LCStore
- $storeArg = [];
- $storeArg['directory'] =
- $conf['storeDirectory'] ?? $services->getMainConfig()->get( 'CacheDirectory' );
-
- if ( !empty( $conf['storeClass'] ) ) {
- $storeClass = $conf['storeClass'];
- } elseif ( $conf['store'] === 'files' || $conf['store'] === 'file' ||
- ( $conf['store'] === 'detect' && $storeArg['directory'] )
- ) {
- $storeClass = LCStoreCDB::class;
- } elseif ( $conf['store'] === 'db' || $conf['store'] === 'detect' ) {
- $storeClass = LCStoreDB::class;
- $storeArg['server'] = $conf['storeServer'] ?? [];
- } elseif ( $conf['store'] === 'array' ) {
- $storeClass = LCStoreStaticArray::class;
- } else {
- throw new MWException(
- 'Please set $wgLocalisationCacheConf[\'store\'] to something sensible.'
- );
- }
- $logger->debug( "LocalisationCache: using store $storeClass" );
-
- return new $conf['class'](
- new ServiceOptions(
- LocalisationCache::$constructorOptions,
- // Two of the options are stored in $wgLocalisationCacheConf
- $conf,
- // In case someone set that config variable and didn't reset all keys, set defaults.
- [
- 'forceRecache' => false,
- 'manualRecache' => false,
- ],
- // Some other options come from config itself
- $services->getMainConfig()
- ),
- new $storeClass( $storeArg ),
- $logger,
- [ function () use ( $services ) {
- $services->getResourceLoader()->getMessageBlobStore()->clear();
- } ],
- $services->getLanguageNameUtils()
- );
- },
-
'LocalServerObjectCache' => function ( MediaWikiServices $services ) : BagOStuff {
$config = $services->getMainConfig();
$cacheId = \ObjectCache::detectLocalServerCache();
return \ObjectCache::newFromParams( $config->get( 'ObjectCaches' )[$cacheId] );
},
+ 'LockManagerGroupFactory' => function ( MediaWikiServices $services ) : LockManagerGroupFactory {
+ return new LockManagerGroupFactory(
+ WikiMap::getCurrentWikiDbDomain()->getId(),
+ $services->getMainConfig()->get( 'LockManagers' ),
+ $services->getDBLoadBalancerFactory()
+ );
+ },
+
'MagicWordFactory' => function ( MediaWikiServices $services ) : MagicWordFactory {
return new MagicWordFactory( $services->getContentLanguage() );
},
? $services->getLocalServerObjectCache()
: new EmptyBagOStuff(),
$mainConfig->get( 'UseDatabaseMessages' ),
- $mainConfig->get( 'MsgCacheExpiry' ),
$services->getContentLanguage()
);
},
+ 'MessageFormatterFactory' =>
+ function ( MediaWikiServices $services ) : IMessageFormatterFactory {
+ return new MessageFormatterFactory();
+ },
+
'MimeAnalyzer' => function ( MediaWikiServices $services ) : MimeAnalyzer {
$logger = LoggerFactory::getInstance( 'Mime' );
$mainConfig = $services->getMainConfig();
// Install a header callback
MediaWiki\HeaderCallback::register();
-// Set the encoding used by reading HTTP input, writing HTTP output.
+// Set the encoding used by PHP for reading HTTP input, and writing output.
// This is also the default for mbstring functions.
mb_internal_encoding( 'UTF-8' );
* Main setup
*/
-$fname = 'Setup.php';
-$ps_setup = Profiler::instance()->scopedProfileIn( $fname );
-
// Load queued extensions
ExtensionRegistry::getInstance()->loadFromQueue();
// Don't let any other extensions load
setlocale( LC_ALL, $wgShellLocale );
// Set various default paths sensibly...
-$ps_default = Profiler::instance()->scopedProfileIn( $fname . '-defaults' );
-
if ( $wgScript === false ) {
$wgScript = "$wgScriptPath/index.php";
}
unset( $repo ); // no global pollution; destroy reference
$rcMaxAgeDays = $wgRCMaxAge / ( 3600 * 24 );
-if ( $wgRCFilterByAge ) {
- // Trim down $wgRCLinkDays so that it only lists links which are valid
- // as determined by $wgRCMaxAge.
- // Note that we allow 1 link higher than the max for things like 56 days but a 60 day link.
- sort( $wgRCLinkDays );
-
- foreach ( $wgRCLinkDays as $i => $days ) {
- if ( $days >= $rcMaxAgeDays ) {
- array_splice( $wgRCLinkDays, $i + 1 );
- break;
- }
- }
-}
// Ensure that default user options are not invalid, since that breaks Special:Preferences
$wgDefaultUserOptions['rcdays'] = min(
$wgDefaultUserOptions['rcdays'],
if ( $wgLocalInterwiki ) {
// Hard deprecated in 1.34.
wfDeprecated( '$wgLocalInterwiki – use $wgLocalInterwikis instead', '1.23' );
+ // @phan-suppress-next-line PhanUndeclaredVariableDim
array_unshift( $wgLocalInterwikis, $wgLocalInterwiki );
}
$wgPHPSessionHandling = MW_NO_SESSION === 'warn' ? 'warn' : 'disable';
}
-Profiler::instance()->scopedProfileOut( $ps_default );
-
// Disable MWDebug for command line mode, this prevents MWDebug from eating up
// all the memory from logging SQL queries on maintenance scripts
global $wgCommandLineMode;
}
}
-$ps_default2 = Profiler::instance()->scopedProfileIn( $fname . '-defaults2' );
-
if ( $wgCanonicalServer === false ) {
$wgCanonicalServer = wfExpandUrl( $wgServer, PROTO_HTTP );
}
);
}
-Profiler::instance()->scopedProfileOut( $ps_default2 );
-
-$ps_misc = Profiler::instance()->scopedProfileIn( $fname . '-misc' );
-
// Raise the memory limit if it's too low
// Note, this makes use of wfDebug, and thus should not be before
// MWDebug::init() is called.
$wgMemc = ObjectCache::getLocalClusterInstance();
$messageMemc = wfGetMessageCacheStorage();
-wfDebugLog( 'caches',
- 'cluster: ' . get_class( $wgMemc ) .
- ', WAN: ' . ( $wgMainWANCache === CACHE_NONE ? 'CACHE_NONE' : $wgMainWANCache ) .
- ', stash: ' . $wgMainStash .
- ', message: ' . get_class( $messageMemc ) .
- ', session: ' . get_class( ObjectCache::getInstance( $wgSessionCacheType ) )
-);
-
-Profiler::instance()->scopedProfileOut( $ps_misc );
-
// Most of the config is out, some might want to run hooks here.
Hooks::run( 'SetupAfterCache' );
-$ps_globals = Profiler::instance()->scopedProfileIn( $fname . '-globals' );
-
/**
* @var Language $wgContLang
* @deprecated since 1.32, use the ContentLanguage service directly
*/
$wgTitle = null;
-Profiler::instance()->scopedProfileOut( $ps_globals );
-$ps_extensions = Profiler::instance()->scopedProfileIn( $fname . '-extensions' );
-
// Extension setup functions
// Entries should be added to this variable during the inclusion
// of the extension file. This allows the extension to perform
}
$wgFullyInitialised = true;
-
-Profiler::instance()->scopedProfileOut( $ps_extensions );
-Profiler::instance()->scopedProfileOut( $ps_setup );
namespace MediaWiki\Storage;
+use StatusValue;
+
/**
* Service for loading and storing data blobs.
*
*/
public function getBlob( $blobAddress, $queryFlags = 0 );
+ /**
+ * A batched version of BlobStore::getBlob.
+ *
+ * @param string[] $blobAddresses An array of blob addresses.
+ * @param int $queryFlags See IDBAccessObject.
+ * @throws BlobAccessException
+ * @return StatusValue A status with a map of blobAddress => binary blob data or null
+ * if fetching the blob has failed. Fetch failures errors are the
+ * warnings in the status object.
+ * @since 1.34
+ */
+ public function getBlobBatch( $blobAddresses, $queryFlags = 0 );
+
/**
* Stores an arbitrary blob of data and returns an address that can be used with
* getBlob() to retrieve the same blob of data,
* @return IDatabase
*/
private function getDBConnection( $index, $flags = 0 ) {
- return $this->loadBalancer->getConnection( $index, [], $this->domain, $flags );
+ return $this->loadBalancer->getConnectionRef( $index, [], $this->domain, $flags );
}
/**
if ( $id === null ) {
// RACE: $name was already in the db, probably just inserted, so load from master.
// Use DBO_TRX to avoid missing inserts due to other threads or REPEATABLE-READs.
- // ...but not during unit tests, because we need the fake DB tables of the default
- // connection.
- $connFlags = defined( 'MW_PHPUNIT_TEST' ) ? 0 : ILoadBalancer::CONN_TRX_AUTOCOMMIT;
- $table = $this->reloadMap( $connFlags );
+ $table = $this->reloadMap( ILoadBalancer::CONN_TRX_AUTOCOMMIT );
$searchResult = array_search( $name, $table, true );
if ( $searchResult === false ) {
// TODO: introduce something like an UnsavedRevisionFactory service instead!
/** @var MutableRevisionRecord $rev */
$rev = $this->derivedDataUpdater->getRevision();
+ '@phan-var MutableRevisionRecord $rev';
$rev->setPageId( $title->getArticleID() );
namespace MediaWiki\Storage;
+use AppendIterator;
use DBAccessObjectUtils;
use IDBAccessObject;
use IExpiringStore;
use InvalidArgumentException;
use Language;
use MWException;
+use StatusValue;
use WANObjectCache;
use ExternalStoreAccess;
use Wikimedia\Assert\Assert;
public function getBlob( $blobAddress, $queryFlags = 0 ) {
Assert::parameterType( 'string', $blobAddress, '$blobAddress' );
- // No negative caching; negative hits on text rows may be due to corrupted replica DBs
+ $error = null;
$blob = $this->cache->getWithSetCallback(
$this->getCacheKey( $blobAddress ),
$this->getCacheTTL(),
- function ( $unused, &$ttl, &$setOpts ) use ( $blobAddress, $queryFlags ) {
+ function ( $unused, &$ttl, &$setOpts ) use ( $blobAddress, $queryFlags, &$error ) {
// Ignore $setOpts; blobs are immutable and negatives are not cached
- return $this->fetchBlob( $blobAddress, $queryFlags );
+ list( $result, $errors ) = $this->fetchBlobs( [ $blobAddress ], $queryFlags );
+ // No negative caching; negative hits on text rows may be due to corrupted replica DBs
+ $error = $errors[$blobAddress] ?? null;
+ return $result[$blobAddress];
},
[ 'pcGroup' => self::TEXT_CACHE_GROUP, 'pcTTL' => IExpiringStore::TTL_PROC_LONG ]
);
- if ( $blob === false ) {
- throw new BlobAccessException( 'Failed to load blob from address ' . $blobAddress );
+ if ( $error ) {
+ throw new BlobAccessException( $error );
}
+ Assert::postcondition( is_string( $blob ), 'Blob must not be null' );
return $blob;
}
+ /**
+ * A batched version of BlobStore::getBlob.
+ *
+ * @param string[] $blobAddresses An array of blob addresses.
+ * @param int $queryFlags See IDBAccessObject.
+ * @throws BlobAccessException
+ * @return StatusValue A status with a map of blobAddress => binary blob data or null
+ * if fetching the blob has failed. Fetch failures errors are the
+ * warnings in the status object.
+ * @since 1.34
+ */
+ public function getBlobBatch( $blobAddresses, $queryFlags = 0 ) {
+ $errors = null;
+ $addressByCacheKey = $this->cache->makeMultiKeys(
+ $blobAddresses,
+ function ( $blobAddress ) {
+ return $this->getCacheKey( $blobAddress );
+ }
+ );
+ $blobsByCacheKey = $this->cache->getMultiWithUnionSetCallback(
+ $addressByCacheKey,
+ $this->getCacheTTL(),
+ function ( array $blobAddresses, array &$ttls, array &$setOpts ) use ( $queryFlags, &$errors ) {
+ // Ignore $setOpts; blobs are immutable and negatives are not cached
+ list( $result, $errors ) = $this->fetchBlobs( $blobAddresses, $queryFlags );
+ return $result;
+ },
+ [ 'pcGroup' => self::TEXT_CACHE_GROUP, 'pcTTL' => IExpiringStore::TTL_PROC_LONG ]
+ );
+
+ // Remap back to incoming blob addresses. The return value of the
+ // WANObjectCache::getMultiWithUnionSetCallback is keyed on the internal
+ // keys from WANObjectCache::makeMultiKeys, so we need to remap them
+ // before returning to the client.
+ $blobsByAddress = [];
+ foreach ( $blobsByCacheKey as $cacheKey => $blob ) {
+ $blobsByAddress[ $addressByCacheKey[ $cacheKey ] ] = $blob !== false ? $blob : null;
+ }
+
+ $result = StatusValue::newGood( $blobsByAddress );
+ if ( $errors ) {
+ foreach ( $errors as $error ) {
+ $result->warning( 'internalerror', $error );
+ }
+ }
+ return $result;
+ }
+
/**
* MCR migration note: this corresponds to Revision::fetchText
*
- * @param string $blobAddress
+ * @param string[] $blobAddresses
* @param int $queryFlags
*
* @throws BlobAccessException
- * @return string|false
- */
- private function fetchBlob( $blobAddress, $queryFlags ) {
- list( $schema, $id, ) = self::splitBlobAddress( $blobAddress );
+ * @return array [ $result, $errors ] A map of blob addresses to successfully fetched blobs
+ * or false if fetch failed, plus and array of errors
+ */
+ private function fetchBlobs( $blobAddresses, $queryFlags ) {
+ $textIdToBlobAddress = [];
+ $result = [];
+ $errors = [];
+ foreach ( $blobAddresses as $blobAddress ) {
+ list( $schema, $id ) = self::splitBlobAddress( $blobAddress );
+ //TODO: MCR: also support 'ex' schema with ExternalStore URLs, plus flags encoded in the URL!
+ if ( $schema === 'tt' ) {
+ $textId = intval( $id );
+ $textIdToBlobAddress[$textId] = $blobAddress;
+ } else {
+ $errors[$blobAddress] = "Unknown blob address schema: $schema";
+ $result[$blobAddress] = false;
+ continue;
+ }
- //TODO: MCR: also support 'ex' schema with ExternalStore URLs, plus flags encoded in the URL!
- if ( $schema === 'tt' ) {
- $textId = intval( $id );
- } else {
- // XXX: change to better exceptions! That makes migration more difficult, though.
- throw new BlobAccessException( "Unknown blob address schema: $schema" );
+ if ( !$textId || $id !== (string)$textId ) {
+ $errors[$blobAddress] = "Bad blob address: $blobAddress";
+ $result[$blobAddress] = false;
+ }
}
- if ( !$textId || $id !== (string)$textId ) {
- // XXX: change to better exceptions! That makes migration more difficult, though.
- throw new BlobAccessException( "Bad blob address: $blobAddress" );
+ $textIds = array_keys( $textIdToBlobAddress );
+ if ( !$textIds ) {
+ return [ $result, $errors ];
}
-
// Callers doing updates will pass in READ_LATEST as usual. Since the text/blob tables
// do not normally get rows changed around, set READ_LATEST_IMMUTABLE in those cases.
$queryFlags |= DBAccessObjectUtils::hasFlags( $queryFlags, self::READ_LATEST )
? self::READ_LATEST_IMMUTABLE
: 0;
-
list( $index, $options, $fallbackIndex, $fallbackOptions ) =
DBAccessObjectUtils::getDBOptions( $queryFlags );
-
// Text data is immutable; check replica DBs first.
- $row = $this->getDBConnection( $index )->selectRow(
+ $dbConnection = $this->getDBConnection( $index );
+ $rows = $dbConnection->select(
'text',
- [ 'old_text', 'old_flags' ],
- [ 'old_id' => $textId ],
+ [ 'old_id', 'old_text', 'old_flags' ],
+ [ 'old_id' => $textIds ],
__METHOD__,
$options
);
- // Fallback to DB_MASTER in some cases if the row was not found, using the appropriate
+ // Fallback to DB_MASTER in some cases if not all the rows were found, using the appropriate
// options, such as FOR UPDATE to avoid missing rows due to REPEATABLE-READ.
- if ( !$row && $fallbackIndex !== null ) {
- $row = $this->getDBConnection( $fallbackIndex )->selectRow(
+ if ( $dbConnection->numRows( $rows ) !== count( $textIds ) && $fallbackIndex !== null ) {
+ $fetchedTextIds = [];
+ foreach ( $rows as $row ) {
+ $fetchedTextIds[] = $row->old_id;
+ }
+ $missingTextIds = array_diff( $textIds, $fetchedTextIds );
+ $dbConnection = $this->getDBConnection( $fallbackIndex );
+ $rowsFromFallback = $dbConnection->select(
'text',
- [ 'old_text', 'old_flags' ],
- [ 'old_id' => $textId ],
+ [ 'old_id', 'old_text', 'old_flags' ],
+ [ 'old_id' => $missingTextIds ],
__METHOD__,
$fallbackOptions
);
+ $appendIterator = new AppendIterator();
+ $appendIterator->append( $rows );
+ $appendIterator->append( $rowsFromFallback );
+ $rows = $appendIterator;
}
- if ( !$row ) {
- wfWarn( __METHOD__ . ": No text row with ID $textId." );
- return false;
+ foreach ( $rows as $row ) {
+ $blobAddress = $textIdToBlobAddress[$row->old_id];
+ $blob = $this->expandBlob( $row->old_text, $row->old_flags, $blobAddress );
+ if ( $blob === false ) {
+ $errors[$blobAddress] = "Bad data in text row {$row->old_id}.";
+ }
+ $result[$blobAddress] = $blob;
}
- $blob = $this->expandBlob( $row->old_text, $row->old_flags, $blobAddress );
-
- if ( $blob === false ) {
- wfLogWarning( __METHOD__ . ": Bad data in text row $textId." );
- return false;
+ // If we're still missing some of the rows, set errors for missing blobs.
+ if ( count( $result ) !== count( $blobAddresses ) ) {
+ foreach ( $blobAddresses as $blobAddress ) {
+ if ( !isset( $result[$blobAddress ] ) ) {
+ $errors[$blobAddress] = "Unable to fetch blob at $blobAddress";
+ $result[$blobAddress] = false;
+ }
+ }
}
-
- return $blob;
+ return [ $result, $errors ];
}
/**
use MediaWiki\Linker\LinkRenderer;
use MediaWiki\Linker\LinkTarget;
+use MediaWiki\MediaWikiServices;
/**
* Handles formatting for the "templates used on this page"
* Return a link to the edit page, with the text
* saying "view source" if the user can't edit the page
*
- * @param Title $titleObj
+ * @param LinkTarget $titleObj
* @return string
*/
- private function buildEditLink( Title $titleObj ) {
- if ( $titleObj->quickUserCan( 'edit', $this->context->getUser() ) ) {
+ private function buildEditLink( LinkTarget $titleObj ) {
+ if ( MediaWikiServices::getInstance()->getPermissionManager()
+ ->quickUserCan( 'edit', $this->context->getUser(), $titleObj )
+ ) {
$linkMsg = 'editlink';
} else {
$linkMsg = 'viewsourcelink';
/** @var bool Whether a page has any subpages */
private $mHasSubpages;
- /** @var bool The (string) language code of the page's language and content code. */
- private $mPageLanguage = false;
+ /** @var array|null The (string) language code of the page's language and content code. */
+ private $mPageLanguage;
/** @var string|bool|null The page language code from the database, null if not saved in
* the database or false if not loaded, yet.
* @param int|int[] $namespaces,... The namespaces to check for
* @return bool
* @since 1.19
+ * @suppress PhanCommentParamOnEmptyParamList Cannot make variadic due to HHVM bug, T191668#5263929
*/
public function inNamespaces( /* ... */ ) {
$namespaces = func_get_args();
* Determines if $user is unable to edit this page because it has been protected
* by $wgNamespaceProtection.
*
+ * @deprecated since 1.34 Don't use this function in new code.
* @param User $user User object to check permissions
* @return bool
*/
}
$dbr = wfGetDB( DB_REPLICA );
- $conds['page_namespace'] = $this->mNamespace;
+ $conds = [ 'page_namespace' => $this->mNamespace ];
$conds[] = 'page_title ' . $dbr->buildLike( $this->mDbkeyform . '/', $dbr->anyString() );
$options = [];
if ( $limit > -1 ) {
$this->mLatestID = false;
$this->mContentModel = false;
$this->mEstimateRevisions = null;
- $this->mPageLanguage = false;
+ $this->mPageLanguage = null;
$this->mDbPageLanguage = false;
$this->mIsBigDeletion = null;
}
public static function capitalize( $text, $ns = NS_MAIN ) {
$services = MediaWikiServices::getInstance();
if ( $services->getNamespaceInfo()->isCapitalized( $ns ) ) {
- return MediaWikiServices::getInstance()->getContentLanguage()->ucfirst( $text );
+ return $services->getContentLanguage()->ucfirst( $text );
} else {
return $text;
}
// splitTitleString method, but the only implementation (MediaWikiTitleCodec) does
/** @var MediaWikiTitleCodec $titleCodec */
$titleCodec = MediaWikiServices::getInstance()->getTitleParser();
+ '@phan-var MediaWikiTitleCodec $titleCodec';
// MalformedTitleException can be thrown here
$parts = $titleCodec->splitTitleString( $this->mDbkeyform, $this->mDefaultNamespace );
$method = $auth ? 'moveSubpagesIfAllowed' : 'moveSubpages';
$result = $mp->$method( $wgUser, $reason, $createRedirect, $changeTags );
- if ( !$result->isOk() ) {
+ if ( !$result->isOK() ) {
return $result->getErrorsArray();
}
/**
* The TitleArray class only exists to provide the newFromResult method at pre-
* sent.
+ *
+ * @method int count()
*/
abstract class TitleArray implements Iterator {
/**
use MediaWiki\Session\Session;
use MediaWiki\Session\SessionId;
use MediaWiki\Session\SessionManager;
+use Wikimedia\AtEase\AtEase;
// The point of this class is to be a wrapper around super globals
// phpcs:disable MediaWiki.Usage.SuperGlobalsUsage.SuperGlobals
* @ingroup HTTP
*/
class WebRequest {
- protected $data, $headers = [];
+ /** @var array */
+ protected $data;
+ /** @var array */
+ protected $headers = [];
/**
* Flag to make WebRequest::getHeader return an array of values.
* @return array Any query arguments found in path matches.
*/
public static function getPathInfo( $want = 'all' ) {
- global $wgUsePathInfo;
// PATH_INFO is mangled due to https://bugs.php.net/bug.php?id=31892
// And also by Apache 2.x, double slashes are converted to single slashes.
// So we will use REQUEST_URI if possible.
- $matches = [];
- if ( !empty( $_SERVER['REQUEST_URI'] ) ) {
+ if ( isset( $_SERVER['REQUEST_URI'] ) ) {
// Slurp out the path portion to examine...
$url = $_SERVER['REQUEST_URI'];
if ( !preg_match( '!^https?://!', $url ) ) {
$url = 'http://unused' . $url;
}
- Wikimedia\suppressWarnings();
+ AtEase::suppressWarnings();
$a = parse_url( $url );
- Wikimedia\restoreWarnings();
- if ( $a ) {
- $path = $a['path'] ?? '';
-
- global $wgScript;
- if ( $path == $wgScript && $want !== 'all' ) {
- // Script inside a rewrite path?
- // Abort to keep from breaking...
- return $matches;
- }
+ AtEase::restoreWarnings();
+ if ( !$a ) {
+ return [];
+ }
+ $path = $a['path'] ?? '';
- $router = new PathRouter;
+ global $wgScript;
+ if ( $path == $wgScript && $want !== 'all' ) {
+ // Script inside a rewrite path?
+ // Abort to keep from breaking...
+ return [];
+ }
- // Raw PATH_INFO style
- $router->add( "$wgScript/$1" );
+ $router = new PathRouter;
- if ( isset( $_SERVER['SCRIPT_NAME'] )
- && preg_match( '/\.php/', $_SERVER['SCRIPT_NAME'] )
- ) {
- # Check for SCRIPT_NAME, we handle index.php explicitly
- # But we do have some other .php files such as img_auth.php
- # Don't let root article paths clober the parsing for them
- $router->add( $_SERVER['SCRIPT_NAME'] . "/$1" );
- }
-
- global $wgArticlePath;
- if ( $wgArticlePath ) {
- $router->add( $wgArticlePath );
- }
+ // Raw PATH_INFO style
+ $router->add( "$wgScript/$1" );
- global $wgActionPaths;
- if ( $wgActionPaths ) {
- $router->add( $wgActionPaths, [ 'action' => '$key' ] );
- }
+ if ( isset( $_SERVER['SCRIPT_NAME'] )
+ && strpos( $_SERVER['SCRIPT_NAME'], '.php' ) !== false
+ ) {
+ // Check for SCRIPT_NAME, we handle index.php explicitly
+ // But we do have some other .php files such as img_auth.php
+ // Don't let root article paths clober the parsing for them
+ $router->add( $_SERVER['SCRIPT_NAME'] . "/$1" );
+ }
- global $wgVariantArticlePath;
- if ( $wgVariantArticlePath ) {
- $router->add( $wgVariantArticlePath,
- [ 'variant' => '$2' ],
- [ '$2' => MediaWikiServices::getInstance()->getContentLanguage()->
- getVariants() ]
- );
- }
+ global $wgArticlePath;
+ if ( $wgArticlePath ) {
+ $router->add( $wgArticlePath );
+ }
- Hooks::run( 'WebRequestPathInfoRouter', [ $router ] );
+ global $wgActionPaths;
+ if ( $wgActionPaths ) {
+ $router->add( $wgActionPaths, [ 'action' => '$key' ] );
+ }
- $matches = $router->parse( $path );
+ global $wgVariantArticlePath;
+ if ( $wgVariantArticlePath ) {
+ $router->add( $wgVariantArticlePath,
+ [ 'variant' => '$2' ],
+ [ '$2' => MediaWikiServices::getInstance()->getContentLanguage()->
+ getVariants() ]
+ );
}
- } elseif ( $wgUsePathInfo ) {
- if ( isset( $_SERVER['ORIG_PATH_INFO'] ) && $_SERVER['ORIG_PATH_INFO'] != '' ) {
- // Mangled PATH_INFO
- // https://bugs.php.net/bug.php?id=31892
- // Also reported when ini_get('cgi.fix_pathinfo')==false
- $matches['title'] = substr( $_SERVER['ORIG_PATH_INFO'], 1 );
-
- } elseif ( isset( $_SERVER['PATH_INFO'] ) && $_SERVER['PATH_INFO'] != '' ) {
- // Regular old PATH_INFO yay
- $matches['title'] = substr( $_SERVER['PATH_INFO'], 1 );
+
+ Hooks::run( 'WebRequestPathInfoRouter', [ $router ] );
+
+ $matches = $router->parse( $path );
+ } else {
+ global $wgUsePathInfo;
+ $matches = [];
+ if ( $wgUsePathInfo ) {
+ if ( !empty( $_SERVER['ORIG_PATH_INFO'] ) ) {
+ // Mangled PATH_INFO
+ // https://bugs.php.net/bug.php?id=31892
+ // Also reported when ini_get('cgi.fix_pathinfo')==false
+ $matches['title'] = substr( $_SERVER['ORIG_PATH_INFO'], 1 );
+ } elseif ( !empty( $_SERVER['PATH_INFO'] ) ) {
+ // Regular old PATH_INFO yay
+ $matches['title'] = substr( $_SERVER['PATH_INFO'], 1 );
+ }
}
}
header( 'Cache-Control: no-cache' );
header( 'Content-Type: text/html; charset=utf-8' );
HttpStatus::header( 400 );
- $error = wfMessage( 'nonwrite-api-promise-error' )->escaped();
- $content = <<<EOT
+ $errorHtml = wfMessage( 'nonwrite-api-promise-error' )
+ ->useDatabase( false )
+ ->inContentLanguage()
+ ->escaped();
+ $content = <<<HTML
<!DOCTYPE html>
<html>
<head><meta charset="UTF-8" /></head>
<body>
-$error
+$errorHtml
</body>
</html>
-EOT;
+HTML;
header( 'Content-Length: ' . strlen( $content ) );
echo $content;
die();
* Get the wiki ID of a database domain
*
* This is like DatabaseDomain::getId() without encoding (for legacy reasons) and
- * without the schema if it is the generic installer default of "mediawiki"/"dbo"
+ * without the schema if it is the generic installer default of "mediawiki"
*
* @see $wgDBmwschema
* @see PostgresInstaller
- * @see MssqlInstaller
*
* @param string|DatabaseDomain $domain
* @return string
// the installer default then it is probably the case that the schema is the same for
// all wikis in the farm. Historically, any wiki farm had to make the database/prefix
// combination unique per wiki. Ommit the schema if it does not seem wiki specific.
- if ( !in_array( $domain->getSchema(), [ null, 'mediawiki', 'dbo' ], true ) ) {
+ if ( !in_array( $domain->getSchema(), [ null, 'mediawiki' ], true ) ) {
// This means a site admin may have specifically taylored the schemas.
// Domain IDs might use the form <DB>-<project>- or <DB>-<project>-<language>_,
// meaning that the schema portion must be accounted for to disambiguate wikis.
// Language in which the page content is (supposed to be) written
$pageLang = $title->getPageLanguage()->getCode();
- $permissionManager = MediaWikiServices::getInstance()->getPermissionManager();
+ $permissionManager = $services->getPermissionManager();
$pageLangHtml = $pageLang . ' - ' .
Language::fetchLanguageName( $pageLang, $lang->getCode() );
$this->useTransactionalTimeLimit();
$old = $this->getRequest()->getText( 'oldimage' );
+ /** @var LocalFile $localFile */
$localFile = $this->page->getFile();
+ '@phan-var LocalFile $localFile';
$oldFile = OldLocalFile::newFromArchiveName( $this->getTitle(), $localFile->getRepo(), $old );
$source = $localFile->getArchiveVirtualUrl( $old );
$tools = [];
# Rollback and undo links
- if ( $prevRev && $this->getTitle()->quickUserCan( 'edit', $user ) ) {
- if ( $latest && $this->getTitle()->quickUserCan( 'rollback', $user ) ) {
+
+ if ( $prevRev && $permissionManager->quickUserCan( 'edit', $user, $this->getTitle() ) ) {
+ if ( $latest && $permissionManager->quickUserCan( 'rollback',
+ $user, $this->getTitle() )
+ ) {
// Get a rollback link without the brackets
$rollbackLink = Linker::generateRollback(
$rev,
$undoTooltip = $latest
? [ 'title' => $this->msg( 'tooltip-undo' )->text() ]
: [];
- $undolink = MediaWikiServices::getInstance()->getLinkRenderer()->makeKnownLink(
+ $undolink = $this->getLinkRenderer()->makeKnownLink(
$this->getTitle(),
$this->msg( 'editundo' )->text(),
$undoTooltip,
) {
return $cur;
} else {
- return MediaWikiServices::getInstance()->getLinkRenderer()->makeKnownLink(
+ return $this->getLinkRenderer()->makeKnownLink(
$this->getTitle(),
new HtmlArmor( $cur ),
[],
return $last;
}
- $linkRenderer = MediaWikiServices::getInstance()->getLinkRenderer();
+ $linkRenderer = $this->getLinkRenderer();
if ( $next === 'unknown' ) {
# Next row probably exists but is unknown, use an oldid=prev link
return $linkRenderer->makeKnownLink(
/**
* Clean up a field array for output
- * @param ApiBase $module For context and parameters 'mergerequestfields'
- * and 'messageformat'
* @param array $fields
+ * @codingStandardsIgnoreStart
+ * @phan-param array{type:string,options:array,value:string,label:Message,help:Message,optional:bool,sensitive:bool,skippable:bool} $fields
+ * @codingStandardsIgnoreEnd
* @return array
*/
private function formatFields( array $fields ) {
/** @var array Maps extension paths to info arrays */
private static $extensionInfo = null;
- /** @var int[][][] Cache for self::filterIDs() */
+ /** @var stdClass[][] Cache for self::filterIDs() */
private static $filterIDsCache = [];
/** $var array Map of web UI block messages to corresponding API messages and codes */
$this->dieStatus( $this->errorArrayToStatus( $retval ) );
}
- list( $target, /*...*/ ) = SpecialBlock::getTargetAndType( $params['user'] );
+ $res = [];
+
$res['user'] = $params['user'];
+ list( $target, /*...*/ ) = SpecialBlock::getTargetAndType( $params['user'] );
$res['userID'] = $target instanceof User ? $target->getId() : 0;
$block = DatabaseBlock::newFromTarget( $target, null, true );
$pageObj = $this->getTitleOrPageId( $params, 'fromdbmaster' );
$titleObj = $pageObj->getTitle();
if ( !$pageObj->exists() &&
+ // @phan-suppress-next-line PhanUndeclaredMethod
!( $titleObj->getNamespace() == NS_FILE && self::canDeleteFile( $pageObj->getFile() ) )
) {
$this->dieWithError( 'apierror-missingtitle' );
) {
$title = $page->getTitle();
+ // @phan-suppress-next-line PhanUndeclaredMethod There's no right typehint for it
$file = $page->getFile();
if ( !self::canDeleteFile( $file ) ) {
return self::delete( $page, $user, $reason, $tags );
/** @var Title $newTitle */
foreach ( $titles as $id => $newTitle ) {
- if ( !isset( $titles[$id - 1] ) ) {
- $titles[$id - 1] = $oldTitle;
- }
+ $titles[ $id - 1 ] = $titles[ $id - 1 ] ?? $oldTitle;
$redirValues[] = [
'from' => $titles[$id - 1]->getPrefixedText(),
$status = $ep->attemptSave( $result );
$wgRequest = $oldRequest;
+ $r = [];
switch ( $status->value ) {
case EditPage::AS_HOOK_ERROR:
case EditPage::AS_HOOK_ERROR_EXPECTED:
* ApiResult.
* @since 1.25
* @ingroup API
+ * @phan-file-suppress PhanUndeclaredMethod Undeclared methods in IApiMessage
*/
class ApiErrorFormatter {
/** @var Title Dummy title to silence warnings from MessageCache::parse() */
$parser->startExternalParse( $titleObj, $options, Parser::OT_PREPROCESS );
$dom = $parser->preprocessToDom( $params['text'] );
if ( is_callable( [ $dom, 'saveXML' ] ) ) {
+ // @phan-suppress-next-line PhanUndeclaredMethod
$xml = $dom->saveXML();
} else {
+ // @phan-suppress-next-line PhanUndeclaredMethod
$xml = $dom->__toString();
}
if ( isset( $prop['parsetree'] ) ) {
' [' . $config->get( 'LanguageCode' ) . ']';
$feedUrl = SpecialPage::getTitleFor( 'Contributions', $params['user'] )->getFullURL();
- $target = 'newbies';
- if ( $params['user'] != 'newbies' ) {
- try {
- $target = $this->titleParser
- ->parseTitle( $params['user'], NS_USER )
- ->getText();
- } catch ( MalformedTitleException $e ) {
- $this->dieWithError(
- [ 'apierror-baduser', 'user', wfEscapeWikiText( $params['user'] ) ],
- 'baduser_' . $this->encodeParamName( 'user' )
- );
- }
+ try {
+ $target = $this->titleParser
+ ->parseTitle( $params['user'], NS_USER )
+ ->getText();
+ } catch ( MalformedTitleException $e ) {
+ $this->dieWithError(
+ [ 'apierror-baduser', 'user', wfEscapeWikiText( $params['user'] ) ],
+ 'baduser_' . $this->encodeParamName( 'user' )
+ );
}
$feed = new $feedClasses[$params['feedformat']] (
if ( $e instanceof ApiUsageException ) {
foreach ( $e->getStatusValue()->getErrors() as $error ) {
+ // @phan-suppress-next-line PhanUndeclaredMethod
$msg = ApiMessage::create( $error )
->inLanguage( $this->getLanguage() );
$errorTitle = $this->msg( 'api-feed-error-title', $msg->getApiCode() );
$tmpFile = MediaWikiServices::getInstance()->getTempFSFileFactory()
->newTempFSFile( 'rotate_', $ext );
$dstPath = $tmpFile->getPath();
+ // @phan-suppress-next-line PhanUndeclaredMethod
$err = $handler->rotate( $file, [
'srcPath' => $srcPath,
'dstPath' => $dstPath,
$comment = wfMessage(
'rotate-comment'
)->numParams( $rotation )->inContentLanguage()->text();
+ // @phan-suppress-next-line PhanUndeclaredMethod
$status = $file->upload(
$dstPath,
$comment,
* @param int $successCount
* @param array $pageInfo
* @return void
+ * @suppress PhanParamSignatureMismatch
*/
public function reportPage( $title, $foreignTitle, $revisionCount, $successCount, $pageInfo ) {
// Add a result entry
private $mModule;
private $mCacheMode = 'private';
+ /** @var array */
private $mCacheControl = [];
private $mParamsUsed = [];
private $mParamsSensitive = [];
* @param IContextSource|WebRequest|null $context If this is an instance of
* FauxRequest, errors are thrown and no printing occurs
* @param bool $enableWrite Should be set to true if the api may modify data
+ * @suppress PhanUndeclaredMethod
*/
public function __construct( $context = null, $enableWrite = false ) {
if ( $context === null ) {
* Trait to implement the IApiMessage interface for Message subclasses
* @since 1.27
* @ingroup API
+ * @phan-file-suppress PhanTraitParentReference
+ * @phan-file-suppress PhanUndeclaredMethod
*/
trait ApiMessageTrait {
}
$toTalk = $toTitle->getTalkPageIfDefined();
+ $repoGroup = MediaWikiServices::getInstance()->getRepoGroup();
if ( $toTitle->getNamespace() == NS_FILE
- && !RepoGroup::singleton()->getLocalRepo()->findFile( $toTitle )
- && MediaWikiServices::getInstance()->getRepoGroup()->findFile( $toTitle )
+ && !$repoGroup->getLocalRepo()->findFile( $toTitle )
+ && $repoGroup->findFile( $toTitle )
) {
if ( !$params['ignorewarnings'] &&
$this->getPermissionManager()->userHasRight( $user, 'reupload-shared' ) ) {
$mp = new MovePage( $fromTitle, $toTitle );
$result =
$mp->moveSubpagesIfAllowed( $this->getUser(), $reason, !$noredirect, $changeTags );
- if ( !$result->isOk() ) {
+ if ( !$result->isOK() ) {
// This means the whole thing failed
return [ 'errors' => $this->getErrorFormatter()->arrayFromStatus( $result ) ];
}
case 'xml':
$printer = $this->getMain()->createPrinterByName( 'xml' . $this->fm );
+ '@phan-var ApiFormatXML $printer';
$printer->setRootElement( 'SearchSuggestion' );
return $printer;
// Trim extracts, if necessary
$length = $this->getConfig()->get( 'OpenSearchDescriptionLength' );
foreach ( $results as &$r ) {
+ // @phan-suppress-next-line PhanTypeInvalidDimOffset
if ( is_string( $r['extract'] ) && !$r['extract trimmed'] ) {
$r['extract'] = self::trimExtract( $r['extract'], $length );
}
* @param string $search the search query
* @param array $params api request params
* @return array search results. Keys are integers.
+ * @phan-return array<array{title:Title,redirect_from:?Title,extract:false,extract_trimmed:false,image:false,url:string}>
+ * Note that phan annotations don't support keys containing a space.
*/
private function search( $search, array $params ) {
$searchEngine = $this->buildSearchEngine( $params );
if ( is_string( $r['extract'] ) && $r['extract'] !== '' ) {
$item['Description'] = $r['extract'];
}
+ // @phan-suppress-next-line PhanTypeArraySuspiciousNullable
if ( is_array( $r['image'] ) && isset( $r['image']['source'] ) ) {
$item['Image'] = array_intersect_key( $r['image'], $imageKeys );
}
private $mGeneratorData = []; // [ns][dbkey] => data array
private $mFakePageId = -1;
private $mCacheMode = 'public';
+ /** @var array */
private $mRequestedPageFields = [];
/** @var int */
private $mDefaultNamespace = NS_MAIN;
// Need gender information
if (
- MediaWikiServices::getInstance()->getNamespaceInfo()->
+ $services->getNamespaceInfo()->
hasGenderDistinction( $titleObj->getNamespace() )
) {
$usernames[] = $titleObj->getText();
$parser = MediaWikiServices::getInstance()->getParser();
$parser->startExternalParse( $titleObj, $popts, Parser::OT_PREPROCESS );
+ // @phan-suppress-next-line PhanUndeclaredMethod
$xml = $parser->preprocessToDom( $this->content->getText() )->__toString();
$result_array['parsetree'] = $xml;
$result_array[ApiResult::META_BC_SUBELEMENTS][] = 'parsetree';
// Filter modules based on continue parameter
$continuationManager = new ApiContinuationManager( $this, $allModules, $propModules );
$this->setContinuationManager( $continuationManager );
+ /** @var ApiQueryBase[] $modules */
$modules = $continuationManager->getRunModules();
+ '@phan-var ApiQueryBase[] $modules';
if ( !$continuationManager->isGeneratorDone() ) {
// Query modules may optimize data requests through the $this->getPageSet()
$cacheMode = $this->mPageSet->getCacheMode();
// Execute all unfinished modules
- /** @var ApiQueryBase $module */
foreach ( $modules as $module ) {
$params = $module->extractRequestParams();
$cacheMode = $this->mergeCacheMode(
$this->addJoinConds(
[ 'change_tag' => [ 'JOIN', [ 'ar_rev_id=ct_rev_id' ] ] ]
);
- $changeTagDefStore = MediaWikiServices::getInstance()->getChangeTagDefStore();
+ $changeTagDefStore = $services->getChangeTagDefStore();
try {
$this->addWhereFld( 'ct_tag_id', $changeTagDefStore->getId( $params['tag'] ) );
} catch ( NameTableAccessException $exception ) {
ApiBase::PARAM_ISMULTI => true,
],
'rights' => [
- ApiBase::PARAM_TYPE => User::getAllRights(),
+ ApiBase::PARAM_TYPE => $this->getPermissionManager()->getAllPermissions(),
ApiBase::PARAM_ISMULTI => true,
],
'prop' => [
*/
private $rootTitle;
- private $params, $cont, $redirect;
+ private $params;
+ /** @var array */
+ private $cont;
+ private $redirect;
private $bl_ns, $bl_from, $bl_from_ns, $bl_table, $bl_code, $bl_title, $bl_fields, $hasNS;
/**
}
if ( is_null( $resultPageSet ) ) {
- $a['pageid'] = (int)$row->page_id;
+ $a = [ 'pageid' => (int)$row->page_id ];
ApiQueryBase::addTitleInfo( $a, Title::makeTitle( $row->page_namespace, $row->page_title ) );
if ( $row->page_is_redirect ) {
$a['redirect'] = true;
/**
* @param ApiPageSet $resultPageSet
* @return void
+ * @suppress PhanTypeInvalidDimOffset
*/
private function run( $resultPageSet = null ) {
$this->params = $this->extractRequestParams( false );
$id = $restriction->getBlockId();
switch ( $restriction->getType() ) {
case 'page':
+ /** @var \MediaWiki\Block\Restriction\PageRestriction $restriction */
+ '@phan-var \MediaWiki\Block\Restriction\PageRestriction $restriction';
$value = [ 'id' => $restriction->getValue() ];
if ( $restriction->getTitle() ) {
self::addTitleInfo( $value, $restriction->getTitle() );
'cl_to' . $sort
] );
}
+ $this->addOption( 'LIMIT', $params['limit'] + 1 );
$res = $this->select( __METHOD__ );
public function getAllowedParams() {
$userGroups = User::getAllGroups();
- $userRights = User::getAllRights();
+ $userRights = $this->getPermissionManager()->getAllPermissions();
return [
'group' => [
if ( !isset( $pageMap[$row->ar_namespace][$row->ar_title] ) ) {
$pageID = $newPageID++;
$pageMap[$row->ar_namespace][$row->ar_title] = $pageID;
- $a['revisions'] = [ $rev ];
+ $a = [ 'revisions' => [ $rev ] ];
ApiResult::setIndexedTagName( $a['revisions'], 'rev' );
$title = Title::makeTitle( $row->ar_namespace, $row->ar_title );
ApiQueryBase::addTitleInfo( $a, $title );
$this->dieWithError( [ 'apierror-bad-badfilecontexttitle', $p ], 'invalid-title' );
}
} else {
- $badFileContextTitle = false;
+ $badFileContextTitle = null;
}
$pageIds = $this->getPageSet()->getGoodAndMissingTitlesByNamespace();
$vals['thumbmime'] = $mime;
}
} elseif ( $mto && $mto->isError() ) {
+ /** @var MediaTransformError $mto */
+ '@phan-var MediaTransformError $mto';
$vals['thumberror'] = $mto->toText();
}
}
// Thus there should be no issue with format=xml.
$format = new FormatMetadata;
$format->setSingleLanguage( !$opts['multilang'] );
+ // @phan-suppress-next-line PhanUndeclaredMethod
$format->getContext()->setLanguage( $opts['language'] );
$extmetaArray = $format->fetchExtendedMetadata( $file );
if ( $opts['extmetadatafilter'] ) {
}
if ( $archive && $file->isOld() ) {
+ /** @var OldLocalFile $file */
+ '@phan-var OldLocalFile $file';
$vals['archivename'] = $file->getArchiveName();
}
return $this->tokenFunctions;
}
+ /** @var string[] */
protected static $cachedTokens = [];
/**
if ( $this->fld_parsetree || ( $this->fld_content && $this->generateXML ) ) {
if ( $content->getModel() === CONTENT_MODEL_WIKITEXT ) {
+ /** @var WikitextContent $content */
+ '@phan-var WikitextContent $content';
$t = $content->getText(); # note: don't set $text
$parser = MediaWikiServices::getInstance()->getParser();
);
$dom = $parser->preprocessToDom( $t );
if ( is_callable( [ $dom, 'saveXML' ] ) ) {
+ // @phan-suppress-next-line PhanUndeclaredMethod
$xml = $dom->saveXML();
} else {
+ // @phan-suppress-next-line PhanUndeclaredMethod
$xml = $dom->__toString();
}
$vals['parsetree'] = $xml;
if ( $this->expandTemplates && !$this->parseContent ) {
if ( $content->getModel() === CONTENT_MODEL_WIKITEXT ) {
+ /** @var WikitextContent $content */
+ '@phan-var WikitextContent $content';
$text = $content->getText();
$text = MediaWikiServices::getInstance()->getParser()->preprocess(
const WL_UNREAD_LIMIT = 1000;
+ /** @var array */
private $params = [];
+ /** @var array */
private $prop = [];
public function __construct( ApiQuery $query, $moduleName ) {
}
}
- $fit = $result->addValue( [ 'query', $this->getModuleName() ],
- null, $data[$u] );
+ // @phan-suppress-next-line PhanTypeArraySuspiciousNullable
+ $fit = $result->addValue( [ 'query', $this->getModuleName() ], null, $data[$u] );
if ( !$fit ) {
if ( $useNames ) {
$this->setContinueEnumParameter( 'users',
return;
}
- // The user will abort the AJAX request by pressing "save", so ignore that
- ignore_user_abort( true );
-
if ( $user->pingLimiter( 'stashedit' ) ) {
$status = 'ratelimited';
} else {
$this->dieStatus( $this->errorArrayToStatus( $retval ) );
}
- $res['id'] = $block->getId();
$target = $block->getType() == DatabaseBlock::TYPE_AUTO ? '' : $block->getTarget();
- $res['user'] = $target instanceof User ? $target->getName() : $target;
- $res['userid'] = $target instanceof User ? $target->getId() : 0;
- $res['reason'] = $params['reason'];
+ $res = [
+ 'id' => $block->getId(),
+ 'user' => $target instanceof User ? $target->getName() : $target,
+ 'userid' => $target instanceof User ? $target->getId() : 0,
+ 'reason' => $params['reason']
+ ];
$this->getResult()->addValue( null, $this->getModuleName(), $res );
}
$this->setWatch( $params['watchlist'], $titleObj );
- $info['title'] = $titleObj->getPrefixedText();
- $info['revisions'] = (int)$retval[0];
- $info['fileversions'] = (int)$retval[1];
- $info['reason'] = $retval[2];
+ $info = [
+ 'title' => $titleObj->getPrefixedText(),
+ 'revisions' => (int)$retval[0],
+ 'fileversions' => (int)$retval[1],
+ 'reason' => $retval[2]
+ ];
$this->getResult()->addValue( null, $this->getModuleName(), $info );
}
}
// No errors, no warnings: do the upload
+ $result = [];
if ( $this->mParams['async'] ) {
$progress = UploadBase::getSessionStatus( $this->getUser(), $this->mParams['filekey'] );
if ( $progress && $progress['result'] === 'Poll' ) {
$form = $this->getUserRightsPage();
$form->setContext( $this->getContext() );
+ $r = [];
$r['user'] = $user->getName();
$r['userid'] = $user->getId();
list( $r['added'], $r['removed'] ) = $form->doSaveUserGroups(
$user = $this->getUser();
}
+ $r = [];
$validity = $user->checkPasswordValidity( $params['password'] );
$r['validity'] = $validity->isGood() ? 'Good' : ( $validity->isOK() ? 'Change' : 'Invalid' );
$messages = array_merge(
*
* @return array array containing available additional api param definitions.
* Empty if profiles are not supported by the searchEngine implementation.
+ * @suppress PhanTypeMismatchDimFetch
*/
private function buildProfileApiParam() {
$configs = $this->getSearchProfileParams();
if ( isset( $profile['desc-message'] ) ) {
$helpMessages[$profile['name']] = $profile['desc-message'];
}
+
if ( !empty( $profile['default'] ) ) {
$defaultProfile = $profile['name'];
}
"apiwarn-deprecation-missingparam": "نظرا لعدم تحديد <var>$1</var>; تم استخدام تنسيق قديم للإخراج، تم إيقاف هذا التنسيق، وسيتم دائما استخدام التنسيق الجديد في المستقبل.",
"apiwarn-deprecation-parameter": "تم إيقاف الوسيط <var>$1</var>.",
"apiwarn-deprecation-parse-headitems": "تم إيقاف <kbd>prop=headitems</kbd> منذ ميدياويكي 1.28; استخدم <kbd>prop=headhtml</kbd> عند إنشاء مستندات HTML جديدة، أو <kbd>prop=modules|jsconfigvars</kbd> عند تحديث مستند من جانب العميل.",
+ "apiwarn-deprecation-post-without-content-type": "تم تقديم طلب POST بدون عنوان <code>Content-Type</code>، هذا لا يعمل بشكل موثوق.",
"apiwarn-deprecation-purge-get": "تم إيقاف استخدام <kbd>action=purge</kbd> عبر GET; استخدم POST بدلا من ذلك.",
"apiwarn-deprecation-withreplacement": "تم إيقاف <kbd>$1</kbd>; الرجاء استخدام <kbd>$2</kbd> بدلا من ذلك.",
"apiwarn-difftohidden": "لا يمكنك إجراء مقارنة مع r$1: المحتوى مخفي.",
"apiwarn-deprecation-missingparam": "Comme <var>$1</var> n’a pas été spécifié, un format ancien a été utilisé pour la sortie. Ce format est obsolète, et dans le futur, le nouveau format sera toujours utilisé.",
"apiwarn-deprecation-parameter": "Le paramètre <var>$1</var> est désuet.",
"apiwarn-deprecation-parse-headitems": "<kbd>prop=headitems</kbd> est désuet depuis MédiaWiki 1.28. Utilisez <kbd>prop=headhtml</kbd> lors de la création de nouveaux documents HTML, ou <kbd>prop=modules|jsconfigvars</kbd> lors de la mise à jour d’un document côté client.",
+ "apiwarn-deprecation-post-without-content-type": "Une requête POST a été faite sans entête <code>Content-Type</code>. Cela ne fonctionne pas de façon fiable.",
"apiwarn-deprecation-purge-get": "L’utilisation de <kbd>action=purge</kbd> via un GET est désuète. Utiliser POST à la place.",
"apiwarn-deprecation-withreplacement": "<kbd>$1</kbd> est désuet. Veuillez utiliser <kbd>$2</kbd> à la place.",
"apiwarn-difftohidden": "Impossible de faire un diff avec r$1 : le contenu est masqué.",
"apihelp-compare-param-totitle": "Втор наслов за споредба.",
"apihelp-compare-param-toid": "Втора назнака на страница за споредба.",
"apihelp-compare-param-torev": "Бтора преработка за споредба.",
+ "apihelp-compare-param-topst": "Направи преобразување пред зачувување на <var>totext</var>.",
+ "apihelp-compare-paramvalue-prop-diff": "HTML на разликата.",
"apihelp-compare-example-1": "Дај разлика помеѓу преработките 1 и 2",
"apihelp-createaccount-summary": "Создај нова корисничка сметка.",
"apihelp-delete-summary": "Избриши страница.",
"apihelp-query+watchlistraw-param-dir": "Насока на исписот.",
"apihelp-revisiondelete-param-suppress": "Дали се притајуваат податоци од администраторите на ист начин како и за останатите.",
"apihelp-revisiondelete-param-tags": "Ознаки за примена врз ставката во дневникот на бришења.",
+ "apihelp-rollback-param-title": "Наслов на страницата што сакате да ја отповикате. Не може да се користи заедно со <var>$1pageid</var>.",
+ "apihelp-rollback-param-pageid": "Назнака на страницата што сакате да ја отповикате. Не може да се користи заедно со <var>$1title</var>.",
+ "apihelp-setpagelanguage-param-reason": "Причина за промената.",
"apihelp-stashedit-param-section": "Број на поднасловот. <kbd>0</kbd> за првиот, <kbd>new</kbd> за нов.",
"apihelp-stashedit-param-sectiontitle": "Назив за нов поднаслов.",
"apihelp-stashedit-param-text": "Содржина на страницата.",
"apihelp-stashedit-param-contentmodel": "Содржински модел на новата содржина.",
"apihelp-stashedit-param-contentformat": "Форматот за серијализација на содржината што се користи во вносниот текст.",
+ "apihelp-stashedit-param-summary": "Опис на промената.",
+ "apihelp-tag-summary": "Додавање или отстранување ознаки за промени од поединечни преработки или дневнички записи.",
"apihelp-tag-param-reason": "Причина за промената.",
"apihelp-unblock-summary": "Одблокирај корисник.",
"apihelp-unblock-param-user": "Корисничко име, IP-адреса или IP-опсег за одблокирање. Не може да се користи заедно со <var>$1id</var> или <var>$1userid</var>.",
"api-help-right-apihighlimits": "Употреба на повисоки ограничувања за приложни барања (бавни барања: $1; брзи барања: $2). Ограничувањата за бавни барања важат и за повеќевредносни параметри.",
"apierror-badgenerator-unknown": "Непознат <kbd>generator=$1</kbd>.",
"apierror-badquery": "Неважечко барање.",
+ "apierror-cannotviewtitle": "Не ви е дозволено да ја прегледате $1.",
+ "apierror-cantblock": "Немате дозвола за блокирање корисници.",
+ "apierror-cantchangecontentmodel": "Немате дозвола за менување содржинскиот модел на страница.",
+ "apierror-cantimport-upload": "Немате дозвола да увезувате подигнати страници.",
+ "apierror-cantimport": "Немате дозвола за увезуваање страници.",
"apierror-copyuploadbaddomain": "Подигањето преку URL не е дозволено од овој домен.",
"apierror-copyuploadbadurl": "Подигањето не е дозволено од оваа URL-адреса.",
"apierror-emptynewsection": "Создавањето на нови празни поднаслови не е дозволено.",
"apiwarn-deprecation-missingparam": "Foi usado um formato antigo para a saída, porque <var>$1</var> não foi especificado. Este formato foi descontinuado e de futuro será sempre usado o formato novo.",
"apiwarn-deprecation-parameter": "O parâmetro <var>$1</var> é obsoleto.",
"apiwarn-deprecation-parse-headitems": "<kbd>prop=headitems</kbd> está depreciado desde o MediaWiki 1.28. Use <kbd>prop=headhtml</kbd> quando for criar novos documentos HTML, ou <kbd>prop=modules|jsconfigvars</kbd> quando for atualizar um documento no lado do cliente.",
+ "apiwarn-deprecation-post-without-content-type": "Um pedido POST foi feito sem um cabeçalho <code>Content-Type</code>. Isto não funciona de forma fiável.",
"apiwarn-deprecation-purge-get": "O uso de <kbd>action=purge</kbd> via GET está obsoleto. Use o POST em vez disso.",
"apiwarn-deprecation-withreplacement": "<kbd>$1</kbd> está obsoleto. Por favor, use <kbd>$2</kbd> em vez.",
"apiwarn-difftohidden": "Não foi possível diferenciar r$1: o conteúdo está oculto.",
"apiwarn-deprecation-missingparam": "Foi usado um formato antigo para a saída, porque <var>$1</var> não foi especificado. Este formato foi descontinuado e de futuro será sempre usado o formato novo.",
"apiwarn-deprecation-parameter": "O parâmetro <var>$1</var> foi descontinuado.",
"apiwarn-deprecation-parse-headitems": "<kbd>prop=headitems</kbd> está obsoleto desde o MediaWiki 1.28. Use <kbd>prop=headhtml</kbd> ao criar novos documentos de HTML, ou <kbd>prop=modules|jsconfigvars</kbd> ao atualizar um documento no lado do cliente.",
+ "apiwarn-deprecation-post-without-content-type": "Um pedido POST foi feito sem um cabeçalho <code>Content-Type</code>. Isto não funciona de forma fiável.",
"apiwarn-deprecation-purge-get": "O uso de <kbd>action=purge</kbd> através de um GET foi descontinuado. Em substituição, use um POST.",
"apiwarn-deprecation-withreplacement": "<kbd>$1</kbd> foi descontinuado. Em substituição, use <kbd>$2</kbd>, por favor.",
"apiwarn-difftohidden": "Não foi possível criar uma lista das diferenças em relação à r$1: o conteúdo está ocultado.",
"apihelp-block-param-reblock": "Skriv över befintlig blockering om användaren redan är blockerad.",
"apihelp-block-param-watchuser": "Bevaka användarens eller IP-adressens användarsida och diskussionssida",
"apihelp-block-param-tags": "Ändra märken att tillämpa i blockloggens post.",
+ "apihelp-block-param-pagerestrictions": "Lista över titlar att blockera användaren från att redigera. Gäller endast när <var>partial</var> är \"true\".",
+ "apihelp-block-param-namespacerestrictions": "Lista över namnrymds-ID:n att blockera användaren från att redigera. Gäller endast när <var>partial</var> är \"true\".",
"apihelp-block-example-ip-simple": "Blockera IP-adressen <kbd>192.0.2.5</kbd> i tre dagar med motivationen <kbd>First strike</kbd>",
"apihelp-block-example-user-complex": "Blockera användare <kbd>Vandal</kbd> på obegränsad tid med motivationen <kbd>Vandalism</kbd>, och förhindra kontoskapande och e-post.",
"apihelp-changeauthenticationdata-summary": "Ändra autentiseringsdata för aktuell användare.",
"apihelp-query+blocks-paramvalue-prop-expiry": "Lägger till en tidsstämpel för när blockeringen går ut.",
"apihelp-query+blocks-paramvalue-prop-reason": "Lägger till de skäl som angetts för blockeringen.",
"apihelp-query+blocks-paramvalue-prop-range": "Lägger till intervallet av IP-adresser som berörs av blockeringen.",
+ "apihelp-query+blocks-paramvalue-prop-restrictions": "Lägger till partiella blockeringsbegränsningar om blockeringen inte gäller för hela webbplatsen.",
"apihelp-query+blocks-example-simple": "Lista blockeringar.",
"apihelp-query+blocks-example-users": "Lista blockeringar av användarna <kbd>Alice</kbd> och <kbd>Bob</kbd>.",
"apihelp-query+categories-summary": "Lista alla kategorier sidorna tillhör.",
"apierror-unknownformat": "Okänt format \"$1\".",
"apiwarn-compare-no-next": "Sidversion $2 är den senaste sidversionen av $1, det finns ingen sidversion för <kbd>torelative=next</kbd> att jämföra med.",
"apiwarn-compare-no-prev": "Sidversionen $2 är den tidigaste sidversion för $1, det finns ingen sidversion för <kbd>torelative=prev</kbd> att jämföra med.",
+ "apiwarn-deprecation-post-without-content-type": "En POST-begäran gjordes utan en <code>Content-Type</code> i sidhuvudet. Det fungerar inte ordentligt.",
"api-feed-error-title": "Fel ($1)"
}
"科劳",
"SolidBlock",
"神樂坂秀吉",
- "94rain"
+ "94rain",
+ "予弦"
]
},
"apihelp-main-extended-description": "<div class=\"hlist plainlinks api-main-links\">\n* [[mw:Special:MyLanguage/API:Main_page|文档]]\n* [[mw:Special:MyLanguage/API:FAQ|常见问题]]\n* [https://lists.wikimedia.org/mailman/listinfo/mediawiki-api 邮件列表]\n* [https://lists.wikimedia.org/mailman/listinfo/mediawiki-api-announce API公告]\n* [https://phabricator.wikimedia.org/maniphest/query/GebfyV4uCaLd/#R 程序错误与功能请求]\n</div>\n<strong>状态信息:</strong>MediaWiki API是一个成熟稳定的,不断受到支持和改进的界面。尽管我们尽力避免,但偶尔也需要作出重大更新;请订阅[https://lists.wikimedia.org/pipermail/mediawiki-api-announce/ mediawiki-api-announce 邮件列表]以便获得更新通知。\n\n<strong>错误请求:</strong>当API收到错误请求时,HTTP header将会返回一个包含\"MediaWiki-API-Error\"的值,随后header的值与error code将会送回并设置为相同的值。详细信息请参阅[[mw:Special:MyLanguage/API:Errors_and_warnings|API:错误与警告]]。\n\n<p class=\"mw-apisandbox-link\"><strong>测试中:</strong>测试API请求的易用性,请参见[[Special:ApiSandbox]]。</p>",
"apihelp-block-param-reblock": "如果该用户已被封禁,则覆盖已有的封禁。",
"apihelp-block-param-watchuser": "监视用户或该 IP 的用户页和讨论页。",
"apihelp-block-param-tags": "要在封禁日志中应用到实体的更改标签。",
+ "apihelp-block-param-partial": "封禁用户于特定页面或名字空间而不是整个站点。",
+ "apihelp-block-param-pagerestrictions": "阻止用户编辑的标题列表。仅在<var>partial</var>设置为true时适用。",
+ "apihelp-block-param-namespacerestrictions": "用于阻止用户编辑的名字空间ID列表。仅在<var>partial</var>设置为true时适用。",
"apihelp-block-example-ip-simple": "封禁IP地址<kbd>192.0.2.5</kbd>三天,原因<kbd>First strike</kbd>。",
"apihelp-block-example-user-complex": "无限期封禁用户<kbd>Vandal</kbd>,原因<kbd>Vandalism</kbd>,并阻止新账户创建和电子邮件发送。",
"apihelp-changeauthenticationdata-summary": "更改当前用户的身份验证数据。",
"apiwarn-deprecation-missingparam": "因為未指定 <var>$1</var>,輸出內容使用到過去舊有的格式。該格式已棄用,並且往後都只會使用新格式。",
"apiwarn-deprecation-parameter": "參數 <var>$1</var> 已棄用。",
"apiwarn-deprecation-parse-headitems": "<kbd>prop=headitems</kbd> 自 MediaWiki 的 1.28 版本後已被棄用。當建立新 HTML 文件時請使用 <kbd>prop=headhtml</kbd>,或是當更新文件客戶端時請使用 <kbd>prop=modules|jsconfigvars</kbd>。",
+ "apiwarn-deprecation-post-without-content-type": "POST 請求不需要 <code>Content-Type</code> 標頭,這會無法可靠運作。",
"apiwarn-deprecation-purge-get": "透過 GET 方式使用的 <kbd>action=purge</kbd> 已棄用,請以 POST 替代。",
"apiwarn-deprecation-withreplacement": "<kbd>$1</kbd> 已棄用,請改用 <kbd>$2</kbd>。",
"apiwarn-difftohidden": "無法對 r$1 比較差異:內容被隱蔵。",
* a 'password' field).
*
* @return array As above
+ * @phan-return array<string,array{type:string,options?:array,value?:string,label:Message,help:Message,optional?:bool,sensitive?:bool,skippable?:bool}>
*/
abstract public function getFieldInfo();
* @param AuthenticationRequest[] $reqs
* @return array
* @throws \UnexpectedValueException If fields cannot be merged
+ * @suppress PhanTypeInvalidDimOffset
*/
public static function mergeFieldInfo( array $reqs ) {
$merged = [];
}
$options['sensitive'] = !empty( $options['sensitive'] );
+ $type = $options['type'];
if ( !array_key_exists( $name, $merged ) ) {
$merged[$name] = $options;
- } elseif ( $merged[$name]['type'] !== $options['type'] ) {
+ } elseif ( $merged[$name]['type'] !== $type ) {
throw new \UnexpectedValueException( "Field type conflict for \"$name\", " .
- "\"{$merged[$name]['type']}\" vs \"{$options['type']}\""
+ "\"{$merged[$name]['type']}\" vs \"$type\""
);
} else {
if ( isset( $options['options'] ) ) {
public function __construct() {
/** @var SessionProvider $provider */
$provider = SessionManager::getGlobalSession()->getProvider();
+ '@phan-var SessionProvider $provider';
$this->expiration = $provider->getRememberUserDuration();
}
/**
* See documentation of $wgPasswordAttemptThrottle for format. Old (pre-1.27) format is not
* allowed here.
- * @var array
+ * @var array[]
* @see https://www.mediawiki.org/wiki/Manual:$wgPasswordAttemptThrottle
*/
protected $conditions;
continue;
}
- $throttleKey = $this->cache->makeGlobalKey( 'throttler', $this->type, $index, $ipKey, $userKey );
+ $throttleKey = $this->cache->makeGlobalKey(
+ 'throttler',
+ $this->type,
+ $index,
+ $ipKey,
+ $userKey
+ );
$throttleCount = $this->cache->get( $throttleKey );
-
- if ( !$throttleCount ) { // counter not started yet
- $this->cache->add( $throttleKey, 1, $expiry );
- } elseif ( $throttleCount < $count ) { // throttle limited not yet reached
- $this->cache->incr( $throttleKey );
- } else { // throttled
+ if ( $throttleCount && $throttleCount >= $count ) {
+ // Throttle limited reached
$this->logRejection( [
'throttle' => $this->type,
'index' => $index,
// @codeCoverageIgnoreEnd
] );
- return [
- 'throttleIndex' => $index,
- 'count' => $count,
- 'wait' => $expiry,
- ];
+ return [ 'throttleIndex' => $index, 'count' => $count, 'wait' => $expiry ];
+ } else {
+ $this->cache->incrWithInit( $throttleKey, $expiry, 1 );
}
}
+
return false;
}
/**
* Handles B/C for $wgPasswordAttemptThrottle.
* @param array $throttleConditions
- * @return array
+ * @return array[]
* @see $wgPasswordAttemptThrottle for structure
*/
protected static function normalizeThrottleConditions( $throttleConditions ) {
/**
* Create a new block with specified parameters on a user, IP or IP range.
*
- * @param array $options Parameters of the block:
- * address string|User Target user name, User object, IP address or IP range
- * by int User ID of the blocker
- * reason string Reason of the block
- * timestamp string The time at which the block comes into effect
- * byText string Username of the blocker (for foreign users)
- * hideName bool Hide the target user name
+ * @param array $options Parameters of the block, with supported options:
+ * - address: (string|User) Target user name, User object, IP address or IP range
+ * - by: (int) User ID of the blocker
+ * - reason: (string) Reason of the block
+ * - timestamp: (string) The time at which the block comes into effect
+ * - byText: (string) Username of the blocker (for foreign users)
+ * - hideName: (bool) Hide the target user name
*/
public function __construct( array $options = [] ) {
$defaults = [
* may be overridden according to global configs.
*
* @since 1.33
- * @param string $right Right to check
- * @return bool|null null if unrecognized right or unset property
+ * @param string $right
+ * @return bool|null The block applies to the right, or null if
+ * unsure (e.g. unrecognized right or unset property)
*/
public function appliesToRight( $right ) {
$config = RequestContext::getMain()->getConfig();
*/
public function getUserBlock( User $user, $fromReplica ) {
$isAnon = $user->getId() === 0;
+ $fromMaster = !$fromReplica;
// TODO: If $user is the current user, we should use the current request. Otherwise,
// we should not look for XFF or cookie blocks.
// User/IP blocking
// After this, $blocks is an array of blocks or an empty array
// TODO: remove dependency on DatabaseBlock
- $blocks = DatabaseBlock::newListFromTarget( $user, $ip, !$fromReplica );
+ $blocks = DatabaseBlock::newListFromTarget( $user, $ip, $fromMaster );
// Cookie blocking
$cookieBlock = $this->getBlockFromCookieValue( $user, $request );
$xff = array_map( 'trim', explode( ',', $xff ) );
$xff = array_diff( $xff, [ $ip ] );
// TODO: remove dependency on DatabaseBlock
- $xffblocks = DatabaseBlock::getBlocksForIPList( $xff, $isAnon, !$fromReplica );
+ $xffblocks = DatabaseBlock::getBlocksForIPList( $xff, $isAnon, $fromMaster );
$blocks = array_merge( $blocks, $xffblocks );
}
if ( $block instanceof SystemBlock ) {
$systemBlocks[] = $block;
} elseif ( $block->getType() === DatabaseBlock::TYPE_AUTO ) {
+ /** @var DatabaseBlock $block */
+ '@phan-var DatabaseBlock $block';
if ( !isset( $databaseBlocks[$block->getParentBlockId()] ) ) {
$databaseBlocks[$block->getParentBlockId()] = $block;
}
$block = DatabaseBlock::newFromID( $blockCookieId );
if (
$block instanceof DatabaseBlock &&
- $this->shouldApplyCookieBlock( $block, $user->isAnon() )
+ $this->shouldApplyCookieBlock( $block, !$user->isRegistered() )
) {
return $block;
}
/**
* Create a new block with specified parameters on a user, IP or IP range.
*
- * @param array $options Parameters of the block:
- * originalBlocks Block[] Blocks that this block is composed from
+ * @param array $options Parameters of the block, with options supported by
+ * `AbstractBlock::__construct`, and also:
+ * - originalBlocks: (Block[]) Blocks that this block is composed from
*/
public function __construct( array $options = [] ) {
parent::__construct( $options );
/**
* @inheritDoc
+ *
+ * Determines whether the CompositeBlock applies to a right by checking
+ * whether the original blocks apply to that right. Each block can report
+ * true (applies), false (does not apply) or null (unsure). Then:
+ * - If any original blocks apply, this block applies
+ * - If no original blocks apply but any are unsure, this block is unsure
+ * - If all blocks do not apply, this block does not apply
*/
public function appliesToRight( $right ) {
- return $this->methodReturnsValue( __FUNCTION__, true, $right );
+ $isUnsure = false;
+
+ foreach ( $this->originalBlocks as $block ) {
+ $appliesToRight = $block->appliesToRight( $right );
+
+ if ( $appliesToRight ) {
+ return true;
+ } elseif ( $appliesToRight === null ) {
+ $isUnsure = true;
+ }
+ }
+
+ return $isUnsure ? null : false;
}
/**
/**
* Create a new block with specified option parameters on a user, IP or IP range.
*
- * @param array $options Parameters of the block:
- * user int Override target user ID (for foreign users)
- * auto bool Is this an automatic block?
- * expiry string Timestamp of expiration of the block or 'infinity'
- * anonOnly bool Only disallow anonymous actions
- * createAccount bool Disallow creation of new accounts
- * enableAutoblock bool Enable automatic blocking
- * blockEmail bool Disallow sending emails
- * allowUsertalk bool Allow the target to edit its own talk page
- * sitewide bool Disallow editing all pages and all contribution
- * actions, except those specifically allowed by
- * other block flags
+ * @param array $options Parameters of the block, with options supported by
+ * `AbstractBlock::__construct`, and also:
+ * - user: (int) Override target user ID (for foreign users)
+ * - auto: (bool) Is this an automatic block?
+ * - expiry: (string) Timestamp of expiration of the block or 'infinity'
+ * - anonOnly: (bool) Only disallow anonymous actions
+ * - createAccount: (bool) Disallow creation of new accounts
+ * - enableAutoblock: (bool) Enable automatic blocking
+ * - blockEmail: (bool) Disallow sending emails
+ * - allowUsertalk: (bool) Allow the target to edit its own talk page
+ * - sitewide: (bool) Disallow editing all pages and all contribution actions,
+ * except those specifically allowed by other block flags
*
* @since 1.26 $options array
*/
* @inheritDoc
*/
public static function newFromRow( \stdClass $row ) {
+ /** @var self $restriction */
$restriction = parent::newFromRow( $row );
+ '@phan-var self $restriction';
// If the page_namespace and the page_title were provided, add the title to
// the restriction.
*
* @since 1.33
* @param \stdClass $row
- * @return self
+ * @return static
*/
public static function newFromRow( \stdClass $row );
/**
* Create a new block with specified parameters on a user, IP or IP range.
*
- * @param array $options Parameters of the block:
- * systemBlock string Indicate that this block is automatically
- * created by MediaWiki rather than being stored
- * in the database. Value is a string to return
- * from self::getSystemBlockType().
+ * @param array $options Parameters of the block, with options supported by
+ * `AbstractBlock::__construct`, and also:
+ * - systemBlock: (string) Indicate that this block is automatically created by
+ * MediaWiki rather than being stored in the database. Value is a string to
+ * return from self::getSystemBlockType().
*/
public function __construct( array $options = [] ) {
parent::__construct( $options );
$this->partitionCache = [];
$this->fullResultCache = [];
$this->wanCache->touchCheckKey( $this->makeCheckKey() );
- unset( $this->db );
+ $this->db = null;
}
/**
* @return IDatabase
*/
protected function getDB() {
- if ( !isset( $this->db ) ) {
+ if ( $this->db === null ) {
$this->db = wfGetDB( DB_REPLICA );
}
* Function that gets called when initialization is done.
*
* @since 1.20
- * @var callable
+ * @var callable|null
*/
- protected $onInitHandler = false;
+ protected $onInitHandler;
/**
* Elements to build a cache key with.
$this->hasCached = is_array( $cachedChunks );
$this->cachedChunks = $this->hasCached ? $cachedChunks : [];
- if ( $this->onInitHandler !== false ) {
+ if ( $this->onInitHandler !== null ) {
call_user_func( $this->onInitHandler, $this->hasCached );
}
}
*/
public function incrMissesRecent( WebRequest $request ) {
if ( mt_rand( 0, self::MISS_FACTOR - 1 ) == 0 ) {
- $cache = ObjectCache::getLocalClusterInstance();
# Get a large IP range that should include the user even if that
# person's IP address changes
$ip = $request->getIP();
if ( !IP::isValid( $ip ) ) {
return;
}
+
$ip = IP::isIPv6( $ip )
? IP::sanitizeRange( "$ip/32" )
: IP::sanitizeRange( "$ip/16" );
# Bail out if a request already came from this range...
+ $cache = ObjectCache::getLocalClusterInstance();
$key = $cache->makeKey( static::class, 'attempt', $this->mType, $this->mKey, $ip );
- if ( $cache->get( $key ) ) {
+ if ( !$cache->add( $key, 1, self::MISS_TTL_SEC ) ) {
return; // possibly the same user
}
- $cache->set( $key, 1, self::MISS_TTL_SEC );
# Increment the number of cache misses...
- $key = $this->cacheMissKey( $cache );
- if ( $cache->get( $key ) === false ) {
- $cache->set( $key, 1, self::MISS_TTL_SEC );
- } else {
- $cache->incr( $key );
- }
+ $cache->incrWithInit( $this->cacheMissKey( $cache ), self::MISS_TTL_SEC );
}
}
/** How long memcached locks last */
const LOCK_TTL = 30;
+ /**
+ * Lifetime for cache, for keys stored in $wanCache, in seconds.
+ * @var int
+ */
+ const WAN_TTL = IExpiringStore::TTL_DAY;
+
/**
* Process cache of loaded messages that are defined in MediaWiki namespace
*
*/
protected $mDisable;
- /**
- * Lifetime for cache, used by object caching.
- * Set on construction, see __construct().
- */
- protected $mExpiry;
-
/**
* Message cache has its own parser which it uses to transform messages
* @var ParserOptions
* @param BagOStuff $clusterCache
* @param BagOStuff $serverCache
* @param bool $useDB Whether to look for message overrides (e.g. MediaWiki: pages)
- * @param int $expiry Lifetime for cache. @see $mExpiry.
* @param Language|null $contLang Content language of site
*/
public function __construct(
BagOStuff $clusterCache,
BagOStuff $serverCache,
$useDB,
- $expiry,
Language $contLang = null
) {
$this->wanCache = $wanCache;
$this->cache = new MapCacheLRU( 5 ); // limit size for sanity
$this->mDisable = !$useDB;
- $this->mExpiry = $expiry;
$this->contLang = $contLang ?? MediaWikiServices::getInstance()->getContentLanguage();
}
global $wgUser;
if ( !$this->mParserOptions ) {
- if ( !$wgUser->isSafeToLoad() ) {
- // $wgUser isn't unstubbable yet, so don't try to get a
+ if ( !$wgUser || !$wgUser->isSafeToLoad() ) {
+ // $wgUser isn't available yet, so don't try to get a
// ParserOptions for it. And don't cache this ParserOptions
// either.
$po = ParserOptions::newFromAnon();
// Set the text for small software-defined messages in the main cache map
$revisionStore = MediaWikiServices::getInstance()->getRevisionStore();
$revQuery = $revisionStore->getQueryInfo( [ 'page', 'user' ] );
+
+ // T231196: MySQL/MariaDB (10.1.37) can sometimes irrationally decide that querying `actor` then
+ // `revision` then `page` is somehow better than starting with `page`. Tell it not to reorder the
+ // query (and also reorder it ourselves because as generated by RevisionStore it'll have
+ // `revision` first rather than `page`).
+ $revQuery['joins']['revision'] = $revQuery['joins']['page'];
+ unset( $revQuery['joins']['page'] );
+ // It isn't actually necesssary to reorder $revQuery['tables'] as Database does the right thing
+ // when join conditions are given for all joins, but Gergő is wary of relying on that so pull
+ // `page` to the start.
+ $revQuery['tables'] = array_merge(
+ [ 'page' ],
+ array_diff( $revQuery['tables'], [ 'page' ] )
+ );
+
$res = $dbr->select(
$revQuery['tables'],
$revQuery['fields'],
'page_latest = rev_id' // get the latest revision only
] ),
__METHOD__ . "($code)-small",
- [],
+ [ 'STRAIGHT_JOIN' ],
$revQuery['joins']
);
foreach ( $res as $row ) {
# messages larger than $wgMaxMsgCacheEntrySize, since those are only
# stored and fetched from memcache.
$cache['HASH'] = md5( serialize( $cache ) );
- $cache['EXPIRY'] = wfTimestamp( TS_MW, time() + $this->mExpiry );
+ $cache['EXPIRY'] = wfTimestamp( TS_MW, time() + self::WAN_TTL );
unset( $cache['EXCESSIVE'] ); // only needed for hash
return $cache;
$this->wanCache->set(
$this->bigMessageCacheKey( $cache['HASH'], $title ),
' ' . $newTextByTitle[$title],
- $this->mExpiry
+ self::WAN_TTL
);
}
// Mark this cache as definitely being "latest" (non-volatile) so
$fname = __METHOD__;
return $this->srvCache->getWithSetCallback(
$this->srvCache->makeKey( 'messages-big', $hash, $dbKey ),
- IExpiringStore::TTL_MINUTE,
+ BagOStuff::TTL_HOUR,
function () use ( $code, $dbKey, $hash, $fname ) {
return $this->wanCache->getWithSetCallback(
$this->bigMessageCacheKey( $hash, $dbKey ),
- $this->mExpiry,
+ self::WAN_TTL,
function ( $oldValue, &$ttl, &$setOpts ) use ( $dbKey, $code, $fname ) {
// Try loading the message from the database
$dbr = wfGetDB( DB_REPLICA );
$class = $wgParserConf['class'];
if ( $class == ParserDiffTest::class ) {
# Uncloneable
+ // @phan-suppress-next-line PhanTypeMismatchProperty
$this->mParser = new $class( $wgParserConf );
} else {
$this->mParser = clone $parser;
*/
class LCStoreCDB implements LCStore {
- /** @var Reader[] */
+ /** @var Reader[]|false[] */
private $readers;
/** @var Writer */
use CLDRPluralRuleParser\Evaluator;
use CLDRPluralRuleParser\Error as CLDRPluralRuleError;
-use MediaWiki\Config\ServiceOptions;
-use MediaWiki\Languages\LanguageNameUtils;
-use Psr\Log\LoggerInterface;
+use MediaWiki\Logger\LoggerFactory;
+use MediaWiki\MediaWikiServices;
/**
* Class for caching the contents of localisation files, Messages*.php
* and *.i18n.php.
*
- * An instance of this class is available using MediaWikiServices.
+ * An instance of this class is available using Language::getLocalisationCache().
*
* The values retrieved from here are merged, containing items from extension
* files, core messages files and the language fallback sequence (e.g. zh-cn ->
class LocalisationCache {
const VERSION = 4;
- /** @var ServiceOptions */
- private $options;
+ /** Configuration associative array */
+ private $conf;
/**
* True if recaching should only be done on an explicit call to recache().
*/
private $manualRecache = false;
+ /**
+ * True to treat all files as expired until they are regenerated by this object.
+ */
+ private $forceRecache = false;
+
/**
* The cache data. 3-d array, where the first key is the language code,
* the second key is the item key e.g. 'messages', and the third key is
private $store;
/**
- * @var LoggerInterface
+ * @var \Psr\Log\LoggerInterface
*/
private $logger;
- /** @var callable[] See comment for parameter in constructor */
- private $clearStoreCallbacks;
-
- /** @var LanguageNameUtils */
- private $langNameUtils;
-
/**
* A 2-d associative array, code/key, where presence indicates that the item
* is loaded. Value arbitrary.
private $mergeableKeys = null;
- /**
- * @todo Make this a const when HHVM support is dropped (T192166)
- *
- * @var array
- * @since 1.34
- */
- public static $constructorOptions = [
- // True to treat all files as expired until they are regenerated by this object.
- 'forceRecache',
- 'manualRecache',
- 'ExtensionMessagesFiles',
- 'MessagesDirs',
- ];
-
/**
* For constructor parameters, see the documentation in DefaultSettings.php
* for $wgLocalisationCacheConf.
*
- * Do not construct this directly. Use MediaWikiServices.
- *
- * @param ServiceOptions $options
- * @param LCStore $store What backend to use for storage
- * @param LoggerInterface $logger
- * @param callable[] $clearStoreCallbacks To be called whenever the cache is cleared. Can be
- * used to clear other caches that depend on this one, such as ResourceLoader's
- * MessageBlobStore.
- * @param LanguageNameUtils $langNameUtils
+ * @param array $conf
* @throws MWException
*/
- function __construct(
- ServiceOptions $options,
- LCStore $store,
- LoggerInterface $logger,
- array $clearStoreCallbacks,
- LanguageNameUtils $langNameUtils
- ) {
- $options->assertRequiredOptions( self::$constructorOptions );
-
- $this->options = $options;
- $this->store = $store;
- $this->logger = $logger;
- $this->clearStoreCallbacks = $clearStoreCallbacks;
- $this->langNameUtils = $langNameUtils;
-
- // Keep this separate from $this->options so it can be mutable
- $this->manualRecache = $options->get( 'manualRecache' );
+ function __construct( $conf ) {
+ global $wgCacheDirectory;
+
+ $this->conf = $conf;
+ $this->logger = LoggerFactory::getInstance( 'localisation' );
+
+ $directory = !empty( $conf['storeDirectory'] ) ? $conf['storeDirectory'] : $wgCacheDirectory;
+ $storeArg = [];
+ $storeArg['directory'] = $directory;
+
+ if ( !empty( $conf['storeClass'] ) ) {
+ $storeClass = $conf['storeClass'];
+ } else {
+ switch ( $conf['store'] ) {
+ case 'files':
+ case 'file':
+ $storeClass = LCStoreCDB::class;
+ break;
+ case 'db':
+ $storeClass = LCStoreDB::class;
+ $storeArg['server'] = $conf['storeServer'] ?? [];
+ break;
+ case 'array':
+ $storeClass = LCStoreStaticArray::class;
+ break;
+ case 'detect':
+ if ( $directory ) {
+ $storeClass = LCStoreCDB::class;
+ } else {
+ $storeClass = LCStoreDB::class;
+ $storeArg['server'] = $conf['storeServer'] ?? [];
+ }
+ break;
+ default:
+ throw new MWException(
+ 'Please set $wgLocalisationCacheConf[\'store\'] to something sensible.'
+ );
+ }
+ }
+ $this->logger->debug( static::class . ": using store $storeClass" );
+
+ $this->store = new $storeClass( $storeArg );
+ foreach ( [ 'manualRecache', 'forceRecache' ] as $var ) {
+ if ( isset( $conf[$var] ) ) {
+ $this->$var = $conf[$var];
+ }
+ }
}
/**
* @return bool
*/
public function isExpired( $code ) {
- if ( $this->options->get( 'forceRecache' ) && !isset( $this->recachedLangs[$code] ) ) {
+ if ( $this->forceRecache && !isset( $this->recachedLangs[$code] ) ) {
$this->logger->debug( __METHOD__ . "($code): forced reload" );
return true;
$this->initialisedLangs[$code] = true;
# If the code is of the wrong form for a Messages*.php file, do a shallow fallback
- if ( !$this->langNameUtils->isValidBuiltInCode( $code ) ) {
+ if ( !Language::isValidBuiltInCode( $code ) ) {
$this->initShallowFallback( $code, 'en' );
return;
# Recache the data if necessary
if ( !$this->manualRecache && $this->isExpired( $code ) ) {
- if ( $this->langNameUtils->isSupportedLanguage( $code ) ) {
+ if ( Language::isSupportedLanguage( $code ) ) {
$this->recache( $code );
} elseif ( $code === 'en' ) {
throw new MWException( 'MessagesEn.php is missing.' );
global $IP;
// This reads in the PHP i18n file with non-messages l10n data
- $fileName = $this->langNameUtils->getMessagesFileName( $code );
+ $fileName = Language::getMessagesFileName( $code );
if ( !file_exists( $fileName ) ) {
$data = [];
} else {
if ( in_array( $key, self::$mergeableMapKeys ) ) {
$value = $value + $fallbackValue;
} elseif ( in_array( $key, self::$mergeableListKeys ) ) {
+ // @phan-suppress-next-line PhanTypeMismatchArgumentInternal
$value = array_unique( array_merge( $fallbackValue, $value ) );
} elseif ( in_array( $key, self::$mergeableAliasListKeys ) ) {
$value = array_merge_recursive( $value, $fallbackValue );
public function getMessagesDirs() {
global $IP;
+ $config = MediaWikiServices::getInstance()->getMainConfig();
+ $messagesDirs = $config->get( 'MessagesDirs' );
return [
'core' => "$IP/languages/i18n",
'exif' => "$IP/languages/i18n/exif",
'api' => "$IP/includes/api/i18n",
'oojs-ui' => "$IP/resources/lib/ooui/i18n",
- ] + $this->options->get( 'MessagesDirs' );
+ ] + $messagesDirs;
}
/**
* @throws MWException
*/
public function recache( $code ) {
+ global $wgExtensionMessagesFiles;
+
if ( !$code ) {
throw new MWException( "Invalid language code requested" );
}
- $this->recachedLangs[$code] = true;
+ $this->recachedLangs[ $code ] = true;
# Initial values
$initialData = array_fill_keys( self::$allKeys, null );
# Load the primary localisation from the source file
$data = $this->readSourceFilesAndRegisterDeps( $code, $deps );
- if ( $data === false ) {
- $this->logger->debug( __METHOD__ . ": no localisation file for $code, using fallback to en" );
- $coreData['fallback'] = 'en';
- } else {
- $this->logger->debug( __METHOD__ . ": got localisation for $code from source" );
+ $this->logger->debug( __METHOD__ . ": got localisation for $code from source" );
- # Merge primary localisation
- foreach ( $data as $key => $value ) {
- $this->mergeItem( $key, $coreData[$key], $value );
- }
+ # Merge primary localisation
+ foreach ( $data as $key => $value ) {
+ $this->mergeItem( $key, $coreData[ $key ], $value );
}
# Fill in the fallback if it's not there already
# Load non-JSON localisation data for extensions
$extensionData = array_fill_keys( $codeSequence, $initialData );
- foreach ( $this->options->get( 'ExtensionMessagesFiles' ) as $extension => $fileName ) {
+ foreach ( $wgExtensionMessagesFiles as $extension => $fileName ) {
if ( isset( $messageDirs[$extension] ) ) {
# This extension has JSON message data; skip the PHP shim
continue;
# Load the secondary localisation from the source file to
# avoid infinite cycles on cyclic fallbacks
$fbData = $this->readSourceFilesAndRegisterDeps( $csCode, $deps );
- if ( $fbData !== false ) {
- # Only merge the keys that make sense to merge
- foreach ( self::$allKeys as $key ) {
- if ( !isset( $fbData[$key] ) ) {
- continue;
- }
-
- if ( is_null( $coreData[$key] ) || $this->isMergeableKey( $key ) ) {
- $this->mergeItem( $key, $csData[$key], $fbData[$key] );
- }
+ # Only merge the keys that make sense to merge
+ foreach ( self::$allKeys as $key ) {
+ if ( !isset( $fbData[ $key ] ) ) {
+ continue;
+ }
+
+ if ( is_null( $coreData[ $key ] ) || $this->isMergeableKey( $key ) ) {
+ $this->mergeItem( $key, $csData[ $key ], $fbData[ $key ] );
}
}
}
# HACK: If using a null (i.e. disabled) storage backend, we
# can't write to the MessageBlobStore either
if ( !$this->store instanceof LCStoreNull ) {
- foreach ( $this->clearStoreCallbacks as $callback ) {
- $callback();
- }
+ $blobStore = MediaWikiServices::getInstance()->getResourceLoader()->getMessageBlobStore();
+ $blobStore->clear();
}
}
$this->store = new LCStoreNull;
$this->manualRecache = false;
}
+
}
/** Check for rollback permissions, disallow special pages, and only
* show a link on the top-most revision
*/
- if ( $title->quickUserCan( 'rollback', $this->getUser() ) ) {
+ if ( MediaWikiServices::getInstance()->getPermissionManager()
+ ->quickUserCan( 'rollback', $this->getUser(), $title )
+ ) {
$rev = new Revision( [
'title' => $title,
'id' => $rc->mAttribs['rc_this_oldid'],
* but 'Bot' is unchecked, hidebots=1 will be sent.
*
* @since 1.29
+ * @method ChangesListBooleanFilter[] getFilters()
*/
class ChangesListBooleanFilterGroup extends ChangesListFilterGroup {
/**
* Registers a filter in this group
*
* @param ChangesListBooleanFilter $filter
+ * @suppress PhanParamSignaturePHPDocMismatchHasParamType,PhanParamSignatureMismatch
*/
public function registerFilter( ChangesListBooleanFilter $filter ) {
$this->filters[$filter->getName()] = $filter;
* Represents a filter group (used on ChangesListSpecialPage and descendants)
*
* @since 1.29
+ * @method registerFilter($filter)
*/
abstract class ChangesListFilterGroup {
/**
* Registers a filter in this group
*
* @param ChangesListStringOptionsFilter $filter
+ * @suppress PhanParamSignaturePHPDocMismatchHasParamType,PhanParamSignatureMismatch
*/
public function registerFilter( ChangesListStringOptionsFilter $filter ) {
$this->filters[$filter->getName()] = $filter;
$block[0], $block[0]->unpatrolled, $block[0]->watched );
}
- $queryParams['curid'] = $curId;
+ $queryParams = [ 'curid' => $curId ];
# Sub-entries
$lines = [];
protected function recentChangesBlockLine( $rcObj ) {
$data = [];
- $query['curid'] = $rcObj->mAttribs['rc_cur_id'];
+ $query = [ 'curid' => $rcObj->mAttribs['rc_cur_id'] ];
$type = $rcObj->mAttribs['rc_type'];
$logType = $rcObj->mAttribs['rc_log_type'];
*/
const SEND_FEED = false;
+ /** @var array */
public $mAttribs = [];
public $mExtra = [];
/**
- * @var Title
+ * @var Title|false
*/
public $mTitle = false;
/**
- * @var User
+ * @var User|false
*/
private $mPerformer = false;
}
# If our database is strict about IP addresses, use NULL instead of an empty string
- $strictIPs = in_array( $dbw->getType(), [ 'oracle', 'postgres' ] ); // legacy
+ $strictIPs = $dbw->getType() === 'postgres'; // legacy
if ( $strictIPs && $this->mAttribs['rc_ip'] == '' ) {
unset( $this->mAttribs['rc_ip'] );
}
}
$logEntry->setParameters( $params );
$logEntry->setRelations( [ 'Tag' => $tag ] );
- $logEntry->setTags( $logEntryTags );
+ $logEntry->addTags( $logEntryTags );
$logId = $logEntry->insert( $dbw );
$logEntry->publish( $logId );
/**
* Generic list for change tagging.
+ *
+ * @property ChangeTagsLogItem $current
+ * @method ChangeTagsLogItem next()
+ * @method ChangeTagsLogItem reset()
+ * @method ChangeTagsLogItem current()
+ * @phan-file-suppress PhanParamSignatureMismatch
*/
abstract class ChangeTagsList extends RevisionListBase {
function __construct( IContextSource $context, Title $title, array $ids ) {
}
if ( !( $handler instanceof ContentHandler ) ) {
- throw new MWException( "$classOrCallback from \$wgContentHandlers is not " .
- "compatible with ContentHandler" );
+ throw new MWException(
+ var_export( $classOrCallback, true ) . " from \$wgContentHandlers is not " .
+ "compatible with ContentHandler"
+ );
}
}
* @since 1.28
*/
public function getFieldsForSearchIndex( SearchEngine $engine ) {
+ $fields = [];
$fields['category'] = $engine->makeSearchFieldMapping(
'category',
SearchIndexField::INDEX_TYPE_TEXT
class FileContentHandler extends WikitextContentHandler {
public function getFieldsForSearchIndex( SearchEngine $engine ) {
+ $fields = [];
$fields['file_media_type'] =
$engine->makeSearchFieldMapping( 'file_media_type', SearchIndexField::INDEX_TYPE_KEYWORD );
$fields['file_media_type']->setFlag( SearchIndexField::FLAG_CASEFOLD );
* @return string|bool The raw text, or false if the conversion failed.
*/
public function getWikitextForTransclusion() {
+ /** @var WikitextContent $wikitext */
$wikitext = $this->convert( CONTENT_MODEL_WIKITEXT, 'lossy' );
+ '@phan-var WikitextContent $wikitext';
if ( $wikitext ) {
return $wikitext->getText();
*/
public function diff( Content $that, Language $lang = null ) {
$this->checkModelID( $that->getModel() );
-
+ /** @var self $that */
+ '@phan-var self $that';
// @todo could implement this in DifferenceEngine and just delegate here?
if ( !$lang ) {
public function serializeContent( Content $content, $format = null ) {
$this->checkFormat( $format );
+ // @phan-suppress-next-line PhanUndeclaredMethod
return $content->getText();
}
--- /dev/null
+<?php
+/**
+ * Content object implementation for representing unknown content.
+ *
+ * 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
+ *
+ * @since 1.34
+ *
+ * @file
+ * @ingroup Content
+ *
+ * @author Daniel Kinzler
+ */
+
+/**
+ * Content object implementation representing unknown content.
+ *
+ * This can be used to handle content for which no ContentHandler exists on the system,
+ * perhaps because the extension that provided it has been removed.
+ *
+ * UnknownContent instances are immutable.
+ *
+ * @ingroup Content
+ */
+class UnknownContent extends AbstractContent {
+
+ /** @var string */
+ private $data;
+
+ /**
+ * @param string $data
+ * @param string $model_id The model ID to handle
+ */
+ public function __construct( $data, $model_id ) {
+ parent::__construct( $model_id );
+
+ $this->data = $data;
+ }
+
+ /**
+ * @return Content $this
+ */
+ public function copy() {
+ // UnknownContent is immutable, so no need to copy.
+ return $this;
+ }
+
+ /**
+ * Returns an empty string.
+ *
+ * @param int $maxlength
+ *
+ * @return string
+ */
+ public function getTextForSummary( $maxlength = 250 ) {
+ return '';
+ }
+
+ /**
+ * Returns the data size in bytes.
+ *
+ * @return int
+ */
+ public function getSize() {
+ return strlen( $this->data );
+ }
+
+ /**
+ * Returns false.
+ *
+ * @param bool|null $hasLinks If it is known whether this content contains links,
+ * provide this information here, to avoid redundant parsing to find out.
+ *
+ * @return bool
+ */
+ public function isCountable( $hasLinks = null ) {
+ return false;
+ }
+
+ /**
+ * @return string data of unknown format and meaning
+ */
+ public function getNativeData() {
+ return $this->getData();
+ }
+
+ /**
+ * @return string data of unknown format and meaning
+ */
+ public function getData() {
+ return $this->data;
+ }
+
+ /**
+ * Returns an empty string.
+ *
+ * @return string The raw text.
+ */
+ public function getTextForSearchIndex() {
+ return '';
+ }
+
+ /**
+ * Returns false.
+ */
+ public function getWikitextForTransclusion() {
+ return false;
+ }
+
+ /**
+ * Fills the ParserOutput with an error message.
+ */
+ protected function fillParserOutput( Title $title, $revId,
+ ParserOptions $options, $generateHtml, ParserOutput &$output
+ ) {
+ $msg = wfMessage( 'unsupported-content-model', [ $this->getModel() ] );
+ $html = Html::rawElement( 'div', [ 'class' => 'error' ], $msg->inContentLanguage()->parse() );
+ $output->setText( $html );
+ }
+
+ /**
+ * Returns false.
+ */
+ public function convert( $toModel, $lossy = '' ) {
+ return false;
+ }
+
+ protected function equalsInternal( Content $that ) {
+ if ( !$that instanceof UnknownContent ) {
+ return false;
+ }
+
+ return $this->getData() == $that->getData();
+ }
+
+}
--- /dev/null
+<?php
+/**
+ * Base content handler class for flat text contents.
+ *
+ * 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
+ *
+ * @since 1.34
+ *
+ * @file
+ * @ingroup Content
+ */
+
+/**
+ * Content handler implementation for unknown content.
+ *
+ * This can be used to handle content for which no ContentHandler exists on the system,
+ * perhaps because the extension that provided it has been removed.
+ *
+ * @ingroup Content
+ */
+class UnknownContentHandler extends ContentHandler {
+
+ /**
+ * Constructs an UnknownContentHandler. Since UnknownContentHandler can be registered
+ * for multiple model IDs on a system, multiple instances of UnknownContentHandler may
+ * coexist.
+ *
+ * To preserve the serialization format of the original content model, it must be supplied
+ * to the constructor via the $formats parameter. If not given, the default format is
+ * reported as 'application/octet-stream'.
+ *
+ * @param string $modelId
+ * @param string[]|null $formats
+ */
+ public function __construct( $modelId, $formats = null ) {
+ parent::__construct(
+ $modelId,
+ $formats ?? [
+ 'application/octet-stream',
+ 'application/unknown',
+ 'application/x-binary',
+ 'text/unknown',
+ 'unknown/unknown',
+ ]
+ );
+ }
+
+ /**
+ * Returns the content's data as-is.
+ *
+ * @param Content $content
+ * @param string|null $format The serialization format to check
+ *
+ * @return mixed
+ */
+ public function serializeContent( Content $content, $format = null ) {
+ /** @var UnknownContent $content */
+ '@phan-var UnknownContent $content';
+ return $content->getData();
+ }
+
+ /**
+ * Constructs an UnknownContent instance wrapping the given data.
+ *
+ * @since 1.21
+ *
+ * @param string $blob serialized content in an unknown format
+ * @param string|null $format ignored
+ *
+ * @return Content The UnknownContent object wrapping $data
+ */
+ public function unserializeContent( $blob, $format = null ) {
+ return new UnknownContent( $blob, $this->getModelID() );
+ }
+
+ /**
+ * Creates an empty UnknownContent object.
+ *
+ * @since 1.21
+ *
+ * @return Content A new UnknownContent object with empty text.
+ */
+ public function makeEmptyContent() {
+ return $this->unserializeContent( '' );
+ }
+
+ /**
+ * @return false
+ */
+ public function supportsDirectEditing() {
+ return false;
+ }
+
+ /**
+ * @param IContextSource $context
+ *
+ * @return SlotDiffRenderer
+ */
+ protected function getSlotDiffRendererInternal( IContextSource $context ) {
+ return new UnsupportedSlotDiffRenderer( $context );
+ }
+}
"document uses $myModelId but " .
"section uses $sectionModelId." );
}
+ /** @var self $with $oldtext */
+ '@phan-var self $with';
$oldtext = $this->getText();
$text = $with->getText();
* @param string|string[]|MessageSpecifier $key Message key, or array of keys,
* or a MessageSpecifier.
* @param mixed $args,...
+ * @suppress PhanCommentParamWithoutRealParam HHVM bug T228695#5450847
* @return Message
*/
public function msg( $key /* $args */ ) {
* @param string|string[]|MessageSpecifier $key Message key, or array of keys,
* or a MessageSpecifier.
* @param mixed $args,... Arguments to wfMessage
+ * @suppress PhanCommentParamWithoutRealParam HHVM bug T228695#5450847
* @return Message
*/
public function msg( $key ) {
* @param string|string[]|MessageSpecifier $key Message key, or array of keys,
* or a MessageSpecifier.
* @param mixed $args,...
+ * @suppress PhanCommentParamWithoutRealParam HHVM bug T228695#5450847
* @return Message
*/
public function msg( $key ) {
* @param array $lbConf Config for LBFactory::__construct()
* @param ServiceOptions $options
* @param ConfiguredReadOnlyMode $readOnlyMode
- * @param BagOStuff $srvCace
+ * @param BagOStuff $srvCache
* @param BagOStuff $mainStash
* @param WANObjectCache $wanCache
* @return array
array $lbConf,
ServiceOptions $options,
ConfiguredReadOnlyMode $readOnlyMode,
- BagOStuff $srvCace,
+ BagOStuff $srvCache,
BagOStuff $mainStash,
WANObjectCache $wanCache
) {
$options->get( 'DBprefix' )
);
- $lbConf = self::injectObjectCaches( $lbConf, $srvCace, $mainStash, $wanCache );
+ $lbConf = self::injectObjectCaches( $lbConf, $srvCache, $mainStash, $wanCache );
return $lbConf;
}
* @return array
*/
private static function getDbTypesWithSchemas() {
- return [ 'postgres', 'mssql' ];
+ return [ 'postgres' ];
}
/**
// Work around the reserved word usage in MediaWiki schema
'keywordTableMap' => [ 'user' => 'mwuser', 'text' => 'pagecontent' ]
];
- } elseif ( $server['type'] === 'oracle' ) {
- $server += [
- // Work around the reserved word usage in MediaWiki schema
- 'keywordTableMap' => [ 'user' => 'mwuser', 'text' => 'pagecontent' ]
- ];
- } elseif ( $server['type'] === 'mssql' ) {
- $server += [
- 'port' => $options->get( 'DBport' ),
- 'useWindowsAuth' => $options->get( 'DBWindowsAuthentication' )
- ];
}
if ( in_array( $server['type'], self::getDbTypesWithSchemas(), true ) ) {
private static function injectObjectCaches(
array $lbConf, BagOStuff $sCache, BagOStuff $mStash, WANObjectCache $wCache
) {
+ // Fallback if APC style caching is not an option
+ if ( $sCache instanceof EmptyBagOStuff ) {
+ $sCache = new HashBagOStuff( [ 'maxKeys' => 100 ] );
+ }
+
// Use APC/memcached style caching, but avoids loops with CACHE_DB (T141804)
if ( $sCache->getQoS( $sCache::ATTR_EMULATION ) > $sCache::QOS_EMULATION_SQL ) {
$lbConf['srvCache'] = $sCache;
+++ /dev/null
-<?php
-
-use Wikimedia\Rdbms\Field;
-
-class ORAField implements Field {
- private $name, $tablename, $default, $max_length, $nullable,
- $is_pk, $is_unique, $is_multiple, $is_key, $type;
-
- function __construct( $info ) {
- $this->name = $info['column_name'];
- $this->tablename = $info['table_name'];
- $this->default = $info['data_default'];
- $this->max_length = $info['data_length'];
- $this->nullable = $info['not_null'];
- $this->is_pk = isset( $info['prim'] ) && $info['prim'] == 1 ? 1 : 0;
- $this->is_unique = isset( $info['uniq'] ) && $info['uniq'] == 1 ? 1 : 0;
- $this->is_multiple = isset( $info['nonuniq'] ) && $info['nonuniq'] == 1 ? 1 : 0;
- $this->is_key = ( $this->is_pk || $this->is_unique || $this->is_multiple );
- $this->type = $info['data_type'];
- }
-
- function name() {
- return $this->name;
- }
-
- function tableName() {
- return $this->tablename;
- }
-
- function defaultValue() {
- return $this->default;
- }
-
- function maxLength() {
- return $this->max_length;
- }
-
- function isNullable() {
- return $this->nullable;
- }
-
- function isKey() {
- return $this->is_key;
- }
-
- function isMultipleKey() {
- return $this->is_multiple;
- }
-
- function type() {
- return $this->type;
- }
-}
+++ /dev/null
-<?php
-
-use Wikimedia\Rdbms\IDatabase;
-
-/**
- * The oci8 extension is fairly weak and doesn't support oci_num_rows, among
- * other things. We use a wrapper class to handle that and other
- * Oracle-specific bits, like converting column names back to lowercase.
- * @ingroup Database
- */
-class ORAResult {
- private $rows;
- private $cursor;
- private $nrows;
-
- private $columns = [];
-
- private function array_unique_md( $array_in ) {
- $array_out = [];
- $array_hashes = [];
-
- foreach ( $array_in as $item ) {
- $hash = md5( serialize( $item ) );
- if ( !isset( $array_hashes[$hash] ) ) {
- $array_hashes[$hash] = $hash;
- $array_out[] = $item;
- }
- }
-
- return $array_out;
- }
-
- /**
- * @param IDatabase &$db
- * @param resource $stmt A valid OCI statement identifier
- * @param bool $unique
- */
- function __construct( &$db, $stmt, $unique = false ) {
- $this->db =& $db;
-
- $this->nrows = oci_fetch_all( $stmt, $this->rows, 0, -1, OCI_FETCHSTATEMENT_BY_ROW | OCI_NUM );
- if ( $this->nrows === false ) {
- $e = oci_error( $stmt );
- $db->reportQueryError( $e['message'], $e['code'], '', __METHOD__ );
- $this->free();
-
- return;
- }
-
- if ( $unique ) {
- $this->rows = $this->array_unique_md( $this->rows );
- $this->nrows = count( $this->rows );
- }
-
- if ( $this->nrows > 0 ) {
- foreach ( $this->rows[0] as $k => $v ) {
- $this->columns[$k] = strtolower( oci_field_name( $stmt, $k + 1 ) );
- }
- }
-
- $this->cursor = 0;
- oci_free_statement( $stmt );
- }
-
- public function free() {
- unset( $this->db );
- }
-
- public function seek( $row ) {
- $this->cursor = min( $row, $this->nrows );
- }
-
- public function numRows() {
- return $this->nrows;
- }
-
- public function numFields() {
- return count( $this->columns );
- }
-
- public function fetchObject() {
- if ( $this->cursor >= $this->nrows ) {
- return false;
- }
- $row = $this->rows[$this->cursor++];
- $ret = new stdClass();
- foreach ( $row as $k => $v ) {
- $lc = $this->columns[$k];
- $ret->$lc = $v;
- }
-
- return $ret;
- }
-
- public function fetchRow() {
- if ( $this->cursor >= $this->nrows ) {
- return false;
- }
-
- $row = $this->rows[$this->cursor++];
- $ret = [];
- foreach ( $row as $k => $v ) {
- $lc = $this->columns[$k];
- $ret[$lc] = $v;
- $ret[$k] = $v;
- }
-
- return $ret;
- }
-}
if ( isset( $queue[$class] ) ) {
/** @var MergeableUpdate $existingUpdate */
$existingUpdate = $queue[$class];
+ '@phan-var MergeableUpdate $existingUpdate';
$existingUpdate->merge( $update );
// Move the update to the end to handle things like mergeable purge
// updates that might depend on the prior updates in the queue running
* @param Diff $diff A Diff object.
*
* @return array[] List of associative arrays, each describing a difference.
+ * @suppress PhanParamSignatureMismatch
*/
public function format( $diff ) {
$oldline = 1;
class DiffEngine {
// Input variables
+ /** @var string[] */
private $from;
+ /** @var string[] */
private $to;
private $m;
private $n;
*/
$max = min( $this->m, $this->n );
for ( $forwardBound = 0; $forwardBound < $max
+ // @phan-suppress-next-line PhanTypeInvalidDimOffset
&& $this->from[$forwardBound] === $this->to[$forwardBound];
++$forwardBound
) {
public $type;
/**
- * @var string[]
+ * @var string[]|false
*/
public $orig;
/**
- * @var string[]
+ * @var string[]|false
*/
public $closing;
*/
use MediaWiki\MediaWikiServices;
-use MediaWiki\Permissions\PermissionManager;
use MediaWiki\Revision\RevisionRecord;
use MediaWiki\Revision\SlotRecord;
use MediaWiki\Storage\NameTableAccessException;
$permissionManager = MediaWikiServices::getInstance()->getPermissionManager();
- if ( $samePage && $this->mNewPage && $permissionManager->userCan(
- 'edit', $user, $this->mNewPage, PermissionManager::RIGOR_QUICK
+ if ( $samePage && $this->mNewPage && $permissionManager->quickUserCan(
+ 'edit', $user, $this->mNewPage
) ) {
if ( $this->mNewRev->isCurrent() && $permissionManager->userCan(
'rollback', $user, $this->mNewPage
}
}
- if ( !$this->mOldRev->isDeleted( RevisionRecord::DELETED_TEXT ) &&
- !$this->mNewRev->isDeleted( RevisionRecord::DELETED_TEXT )
+ if ( $this->userCanEdit( $this->mOldRev ) &&
+ $this->userCanEdit( $this->mNewRev )
) {
$undoLink = Html::element( 'a', [
'href' => $this->mNewPage->getLocalURL( [
protected function getMarkPatrolledLinkInfo() {
$user = $this->getUser();
$config = $this->getConfig();
+ $permissionManager = MediaWikiServices::getInstance()->getPermissionManager();
// Prepare a change patrol link, if applicable
if (
// Is patrolling enabled and the user allowed to?
$config->get( 'UseRCPatrol' ) &&
- $this->mNewPage && $this->mNewPage->quickUserCan( 'patrol', $user ) &&
+ $this->mNewPage &&
+ $permissionManager->quickUserCan( 'patrol', $user, $this->mNewPage ) &&
// Only do this if the revision isn't more than 6 hours older
// than the Max RC age (6h because the RC might not be cleaned out regularly)
RecentChange::isInRCLifespan( $this->mNewRev->getTimestamp(), 21600 )
// Build the link
if ( $rcid ) {
$this->getOutput()->preventClickjacking();
- if ( MediaWikiServices::getInstance()->getPermissionManager()
- ->userHasRight( $user, 'writeapi' ) ) {
+ if ( $permissionManager->userHasRight( $user, 'writeapi' ) ) {
$this->getOutput()->addModules( 'mediawiki.page.patrol.ajax' );
}
) {
$out->addParserOutput( $parserOutput, [
'enableSectionEditLinks' => $this->mNewRev->isCurrent()
- && $this->mNewRev->getTitle()->quickUserCan( 'edit', $this->getUser() ),
+ && MediaWikiServices::getInstance()->getPermissionManager()->quickUserCan(
+ 'edit',
+ $this->getUser(),
+ $this->mNewRev->getTitle()
+ )
] );
}
}
return wfMessage( $msg )->numParams( $numEdits, $numUsers )->parse();
}
+ /**
+ * @param Revision $rev
+ * @return bool whether the user can see and edit the revision.
+ */
+ private function userCanEdit( Revision $rev ) {
+ $user = $this->getUser();
+
+ if ( !$rev->getContentHandler()->supportsDirectEditing() ) {
+ return false;
+ }
+
+ if ( !$rev->userCan( RevisionRecord::DELETED_TEXT, $user ) ) {
+ return false;
+ }
+
+ return true;
+ }
+
/**
* Get a header for a specified revision.
*
$header = Linker::linkKnown( $title, $header, [],
[ 'oldid' => $rev->getId() ] );
- if ( $rev->userCan( RevisionRecord::DELETED_TEXT, $user ) ) {
+ if ( $this->userCanEdit( $rev ) ) {
$editQuery = [ 'action' => 'edit' ];
if ( !$rev->isCurrent() ) {
$editQuery['oldid'] = $rev->getId();
}
- $key = $title->quickUserCan( 'edit', $user ) ? 'editold' : 'viewsourceold';
+ $key = MediaWikiServices::getInstance()->getPermissionManager()
+ ->quickUserCan( 'edit', $user, $title ) ? 'editold' : 'viewsourceold';
$msg = $this->msg( $key )->escaped();
$editLink = $this->msg( 'parentheses' )->rawParams(
Linker::linkKnown( $title, $msg, [], $editQuery ) )->escaped();
* must have the same content model that was used to obtain this diff renderer.
* @param Content|null $oldContent
* @param Content|null $newContent
- * @return string
+ * @return string HTML, one or more <tr> tags.
*/
abstract public function getDiff( Content $oldContent = null, Content $newContent = null );
/** @var TextSlotDiffRenderer $slotDiffRenderer */
$slotDiffRenderer = ContentHandler::getForModelID( CONTENT_MODEL_TEXT )
->getSlotDiffRenderer( RequestContext::getMain() );
+ '@phan-var TextSlotDiffRenderer $slotDiffRenderer';
return $slotDiffRenderer->getTextDiff( $oldText, $newText );
}
* Diff the text representations of two content objects (or just two pieces of text in general).
* @param string $oldText
* @param string $newText
- * @return string
+ * @return string HTML, one or more <tr> tags.
*/
public function getTextDiff( $oldText, $newText ) {
Assert::parameterType( 'string', $oldText, '$oldText' );
--- /dev/null
+<?php
+/**
+ * Renders a slot diff by doing a text diff on the native representation.
+ *
+ * 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
+ * @ingroup DifferenceEngine
+ */
+
+/**
+ * Produces a warning message about not being able to render a slot diff.
+ *
+ * @since 1.34
+ *
+ * @ingroup DifferenceEngine
+ */
+class UnsupportedSlotDiffRenderer extends SlotDiffRenderer {
+
+ /**
+ * @var MessageLocalizer
+ */
+ private $localizer;
+
+ /**
+ * UnsupportedSlotDiffRenderer constructor.
+ *
+ * @param MessageLocalizer $localizer
+ */
+ public function __construct( MessageLocalizer $localizer ) {
+ $this->localizer = $localizer;
+ }
+
+ /** @inheritDoc */
+ public function getDiff( Content $oldContent = null, Content $newContent = null ) {
+ $this->normalizeContents( $oldContent, $newContent );
+
+ $oldModel = $oldContent->getModel();
+ $newModel = $newContent->getModel();
+
+ if ( $oldModel !== $newModel ) {
+ $msg = $this->localizer->msg( 'unsupported-content-diff2', $oldModel, $newModel );
+ } else {
+ $msg = $this->localizer->msg( 'unsupported-content-diff', $oldModel );
+ }
+
+ return Html::rawElement(
+ 'tr',
+ [],
+ Html::rawElement(
+ 'td',
+ [ 'colspan' => 4, 'class' => 'error' ],
+ $msg->parse()
+ )
+ );
+ }
+
+}
$res = false;
if ( $this->useMessageCache() ) {
try {
- $res = wfMessage( $key, $params )->text();
+ $res = wfMessage( $key, ...$params )->text();
} catch ( Exception $e ) {
}
}
// FIXME: Keep logic in sync with MWException::msg.
try {
- $res = wfMessage( $key, $params )->text();
+ $res = wfMessage( $key, ...$params )->text();
} catch ( Exception $e ) {
$res = wfMsgReplaceArgs( $fallback, $params );
// If an exception happens inside message rendering,
/**
* @param DumpOutput &$sink
- * @param array $param
+ * @param string $param
* @throws MWException
*/
function __construct( &$sink, $param ) {
"NS_CATEGORY" => NS_CATEGORY,
"NS_CATEGORY_TALK" => NS_CATEGORY_TALK ];
- if ( $param { 0 } == '!' ) {
+ if ( $param[0] == '!' ) {
$this->invert = true;
$param = substr( $param, 1 );
}
*/
class DumpPipeOutput extends DumpFileOutput {
protected $command, $filename;
+ /** @var resource|bool */
protected $procOpenResource = false;
/**
use MediaWiki\MediaWikiServices as MediaWikiServicesAlias;
use MediaWiki\Storage\RevisionRecord;
use Wikimedia\Rdbms\IResultWrapper;
-use Wikimedia\Rdbms\IDatabase;
/**
* @ingroup SpecialPage Dump
/** @var XmlDumpWriter */
private $writer;
- /** @var IDatabase */
+ /** @var Database */
protected $db;
/** @var array|int */
}
/**
- * @param IDatabase $db
+ * @param Database $db
* @param int|array $history One of WikiExporter::FULL, WikiExporter::CURRENT,
* WikiExporter::RANGE or WikiExporter::STABLE, or an associative array:
* - offset: non-inclusive offset at which to start the query
*/
function writeUpload( $file, $dumpContents = false ) {
if ( $file->isOld() ) {
+ /** @var OldLocalFile $file */
+ '@phan-var OldLocalFile $file';
$archiveName = " " .
Xml::element( 'archivename', null, $file->getArchiveName() ) . "\n";
} else {
$class = $config['class'];
if ( $class === FileBackendMultiWrite::class ) {
+ // @todo How can we test this? What's the intended use-case?
foreach ( $config['backends'] as $index => $beConfig ) {
if ( isset( $beConfig['template'] ) ) {
// Config is just a modified version of a registered backend's.
'mimeCallback' => [ $this, 'guessMimeInternal' ],
'obResetFunc' => 'wfResetOutputBuffers',
'streamMimeFunc' => [ StreamFile::class, 'contentTypeFromPath' ],
- 'tmpFileFactory' => MediaWikiServices::getInstance()->getTempFSFileFactory(),
+ 'tmpFileFactory' => $services->getTempFSFileFactory(),
'statusWrapper' => [ Status::class, 'wrap' ],
'wanCache' => $services->getMainWANObjectCache(),
'srvCache' => ObjectCache::getLocalServerInstance( 'hash' ),
use MediaWiki\MediaWikiServices;
use Wikimedia\Rdbms\IDatabase;
use Wikimedia\Rdbms\DBError;
+use Wikimedia\Timestamp\ConvertibleTimestamp;
/**
* Version of FileJournal that logs to a DB table
protected $domain;
/**
- * Construct a new instance from configuration.
+ * Construct a new instance from configuration. Do not call directly, use FileJournal::factory.
*
* @param array $config Includes:
* domain: database domain ID of the wiki
*/
- protected function __construct( array $config ) {
+ public function __construct( array $config ) {
parent::__construct( $config );
$this->domain = $config['domain'] ?? $config['wiki']; // b/c
return $status;
}
- $now = wfTimestamp( TS_UNIX );
+ $now = ConvertibleTimestamp::time();
$data = [];
foreach ( $entries as $entry ) {
try {
$dbw->insert( 'filejournal', $data, __METHOD__ );
+ // XXX Should we do this deterministically so it's testable? Maybe look at the last two
+ // digits of a hash of a bunch of the data?
if ( mt_rand( 0, 99 ) == 0 ) {
- $this->purgeOldLogs(); // occasionally delete old logs
+ // occasionally delete old logs
+ $this->purgeOldLogs(); // @codeCoverageIgnore
}
} catch ( DBError $e ) {
$status->fatal( 'filejournal-fail-dbquery', $this->backend );
}
$dbw = $this->getMasterDB();
- $dbCutoff = $dbw->timestamp( time() - 86400 * $this->ttlDays );
+ $dbCutoff = $dbw->timestamp( ConvertibleTimestamp::time() - 86400 * $this->ttlDays );
$dbw->delete( 'filejournal',
[ 'fj_timestamp < ' . $dbw->addQuotes( $dbCutoff ) ],
*/
use MediaWiki\MediaWikiServices;
use MediaWiki\Logger\LoggerFactory;
+use Wikimedia\Rdbms\LBFactory;
/**
* Class to handle file lock manager registration
* @since 1.19
*/
class LockManagerGroup {
- /** @var LockManagerGroup[] (domain => LockManagerGroup) */
- protected static $instances = [];
+ /** @var string domain (usually wiki ID) */
+ protected $domain;
- protected $domain; // string; domain (usually wiki ID)
+ /** @var LBFactory */
+ protected $lbFactory;
/** @var array Array of (name => ('class' => ..., 'config' => ..., 'instance' => ...)) */
protected $managers = [];
/**
+ * Do not call this directly. Use LockManagerGroupFactory.
+ *
* @param string $domain Domain (usually wiki ID)
+ * @param array[] $lockManagerConfigs In format of $wgLockManagers
+ * @param LBFactory $lbFactory
*/
- protected function __construct( $domain ) {
+ public function __construct( $domain, array $lockManagerConfigs, LBFactory $lbFactory ) {
$this->domain = $domain;
- }
-
- /**
- * @param bool|string $domain Domain (usually wiki ID). Default: false.
- * @return LockManagerGroup
- */
- public static function singleton( $domain = false ) {
- if ( $domain === false ) {
- $domain = WikiMap::getCurrentWikiDbDomain()->getId();
- }
-
- if ( !isset( self::$instances[$domain] ) ) {
- self::$instances[$domain] = new self( $domain );
- self::$instances[$domain]->initFromGlobals();
- }
-
- return self::$instances[$domain];
- }
-
- /**
- * Destroy the singleton instances
- */
- public static function destroySingletons() {
- self::$instances = [];
- }
-
- /**
- * Register lock managers from the global variables
- */
- protected function initFromGlobals() {
- global $wgLockManagers;
-
- $this->register( $wgLockManagers );
- }
+ $this->lbFactory = $lbFactory;
- /**
- * Register an array of file lock manager configurations
- *
- * @param array $configs
- * @throws Exception
- */
- protected function register( array $configs ) {
- foreach ( $configs as $config ) {
+ foreach ( $lockManagerConfigs as $config ) {
$config['domain'] = $this->domain;
if ( !isset( $config['name'] ) ) {
throw new Exception( "Cannot register a lock manager with no name." );
}
}
+ /**
+ * @deprecated since 1.34, use LockManagerGroupFactory
+ *
+ * @param bool|string $domain Domain (usually wiki ID). Default: false.
+ * @return LockManagerGroup
+ */
+ public static function singleton( $domain = false ) {
+ return MediaWikiServices::getInstance()->getLockManagerGroupFactory()
+ ->getLockManagerGroup( $domain );
+ }
+
+ /**
+ * Destroy the singleton instances
+ *
+ * @deprecated since 1.34, use resetServiceForTesting() on LockManagerGroupFactory
+ */
+ public static function destroySingletons() {
+ MediaWikiServices::getInstance()->resetServiceForTesting( 'LockManagerGroupFactory' );
+ }
+
/**
* Get the lock manager object with a given name
*
// Lazy-load the actual lock manager instance
if ( !isset( $this->managers[$name]['instance'] ) ) {
$class = $this->managers[$name]['class'];
+ '@phan-var string $class';
$config = $this->managers[$name]['config'];
- if ( $class === DBLockManager::class ) {
- $lbFactory = MediaWikiServices::getInstance()->getDBLoadBalancerFactory();
- $lb = $lbFactory->getMainLB( $config['domain'] );
- $config['dbServers']['localDBMaster'] = $lb->getLazyConnectionRef(
- DB_MASTER,
- [],
- $config['domain'],
- $lb::CONN_TRX_AUTOCOMMIT
- );
- $config['srvCache'] = ObjectCache::getLocalServerInstance( 'hash' );
- }
$config['logger'] = LoggerFactory::getInstance( 'LockManager' );
- // @phan-suppress-next-line PhanTypeInstantiateAbstract
$this->managers[$name]['instance'] = new $class( $config );
}
* Get the default lock manager configured for the site.
* Returns NullLockManager if no lock manager could be found.
*
+ * XXX This looks unused, should we just get rid of it?
+ *
* @return LockManager
*/
public function getDefault() {
* or at least some other effective configured lock manager.
* Throws an exception if no lock manager could be found.
*
+ * XXX This looks unused, should we just get rid of it?
+ *
* @return LockManager
* @throws Exception
*/
--- /dev/null
+<?php
+
+namespace MediaWiki\FileBackend\LockManager;
+
+use LockManagerGroup;
+use Wikimedia\Rdbms\LBFactory;
+
+/**
+ * Service to construct LockManagerGroups.
+ */
+class LockManagerGroupFactory {
+ /** @var string */
+ private $defaultDomain;
+
+ /** @var array */
+ private $lockManagerConfigs;
+
+ /** @var LBFactory */
+ private $lbFactory;
+
+ /** @var LockManagerGroup[] (domain => LockManagerGroup) */
+ private $instances = [];
+
+ /**
+ * Do not call directly, use MediaWikiServices.
+ *
+ * @param string $defaultDomain
+ * @param array $lockManagerConfigs In format of $wgLockManagers
+ * @param LBFactory $lbFactory
+ */
+ public function __construct( $defaultDomain, array $lockManagerConfigs, LBFactory $lbFactory ) {
+ $this->defaultDomain = $defaultDomain;
+ $this->lockManagerConfigs = $lockManagerConfigs;
+ $this->lbFactory = $lbFactory;
+ }
+
+ /**
+ * @param string|null|false $domain Domain (usually wiki ID). false for the default (normally
+ * the current wiki's domain).
+ * @return LockManagerGroup
+ */
+ public function getLockManagerGroup( $domain = false ) : LockManagerGroup {
+ if ( $domain === false || $domain === null ) {
+ $domain = $this->defaultDomain;
+ }
+
+ if ( !isset( $this->instances[$domain] ) ) {
+ $this->instances[$domain] =
+ new LockManagerGroup( $domain, $this->lockManagerConfigs, $this->lbFactory );
+ }
+
+ return $this->instances[$domain];
+ }
+}
}
// Resolve source to a storage path if virtual
- $srcPath = $this->resolveToStoragePath( $srcPath );
+ $srcPath = $this->resolveToStoragePathIfVirtual( $srcPath );
- // Get the appropriate file operation
- if ( FileBackend::isStoragePath( $srcPath ) ) {
- $opName = 'copy';
- } else {
- $opName = 'store';
- }
+ // Copy the source file to the destination
$operations[] = [
- 'op' => $opName,
- 'src' => $srcPath,
+ 'op' => FileBackend::isStoragePath( $srcPath ) ? 'copy' : 'store',
+ 'src' => $srcPath, // storage path (copy) or local file path (store)
'dst' => $dstPath,
- 'overwrite' => $flags & self::OVERWRITE,
- 'overwriteSame' => $flags & self::OVERWRITE_SAME,
+ 'overwrite' => ( $flags & self::OVERWRITE ) ? true : false,
+ 'overwriteSame' => ( $flags & self::OVERWRITE_SAME ) ? true : false,
];
}
$path = $this->getZonePath( $zone ) . "/$rel";
} else {
// Resolve source to a storage path if virtual
- $path = $this->resolveToStoragePath( $path );
+ $path = $this->resolveToStoragePathIfVirtual( $path );
}
$operations[] = [ 'op' => 'delete', 'src' => $path ];
}
public function quickCleanDir( $dir ) {
$status = $this->newGood();
$status->merge( $this->backend->clean(
- [ 'dir' => $this->resolveToStoragePath( $dir ) ] ) );
+ [ 'dir' => $this->resolveToStoragePathIfVirtual( $dir ) ] ) );
return $status;
}
if ( $src instanceof FSFile ) {
$op = 'store';
} else {
- $src = $this->resolveToStoragePath( $src );
+ $src = $this->resolveToStoragePathIfVirtual( $src );
$op = FileBackend::isStoragePath( $src ) ? 'copy' : 'store';
}
- $dst = $this->resolveToStoragePath( $dst );
+ $dst = $this->resolveToStoragePathIfVirtual( $dst );
if ( !isset( $triple[2] ) ) {
$headers = [];
foreach ( $paths as $path ) {
$operations[] = [
'op' => 'delete',
- 'src' => $this->resolveToStoragePath( $path ),
+ 'src' => $this->resolveToStoragePathIfVirtual( $path ),
'ignoreMissingSource' => true
];
}
$sources = [];
foreach ( $srcPaths as $srcPath ) {
// Resolve source to a storage path if virtual
- $source = $this->resolveToStoragePath( $srcPath );
+ $source = $this->resolveToStoragePathIfVirtual( $srcPath );
$sources[] = $source; // chunk to merge
}
$options = $ntuple[3] ?? [];
// Resolve source to a storage path if virtual
- $srcPath = $this->resolveToStoragePath( $srcPath );
+ $srcPath = $this->resolveToStoragePathIfVirtual( $srcPath );
if ( !$this->validateFilename( $dstRel ) ) {
throw new MWException( 'Validation error in $dstRel' );
}
// Copy (or move) the source file to the destination
if ( FileBackend::isStoragePath( $srcPath ) ) {
- if ( $flags & self::DELETE_SOURCE ) {
- $operations[] = [
- 'op' => 'move',
- 'src' => $srcPath,
- 'dst' => $dstPath,
- 'overwrite' => true, // replace current
- 'headers' => $headers
- ];
- } else {
- $operations[] = [
- 'op' => 'copy',
- 'src' => $srcPath,
- 'dst' => $dstPath,
- 'overwrite' => true, // replace current
- 'headers' => $headers
- ];
- }
- } else { // FS source path
+ $operations[] = [
+ 'op' => ( $flags & self::DELETE_SOURCE ) ? 'move' : 'copy',
+ 'src' => $srcPath,
+ 'dst' => $dstPath,
+ 'overwrite' => true, // replace current
+ 'headers' => $headers
+ ];
+ } else {
$operations[] = [
'op' => 'store',
- 'src' => $src, // prefer FSFile objects
+ 'src' => $src, // FSFile (preferred) or local file path
'dst' => $dstPath,
'overwrite' => true, // replace current
'headers' => $headers
* @return Status
*/
protected function initDirectory( $dir ) {
- $path = $this->resolveToStoragePath( $dir );
+ $path = $this->resolveToStoragePathIfVirtual( $dir );
list( , $container, ) = FileBackend::splitStoragePath( $path );
$params = [ 'dir' => $path ];
$status = $this->newGood();
$status->merge( $this->backend->clean(
- [ 'dir' => $this->resolveToStoragePath( $dir ) ] ) );
+ [ 'dir' => $this->resolveToStoragePathIfVirtual( $dir ) ] ) );
return $status;
}
* @return array Map of files and existence flags, or false
*/
public function fileExistsBatch( array $files ) {
- $paths = array_map( [ $this, 'resolveToStoragePath' ], $files );
+ $paths = array_map( [ $this, 'resolveToStoragePathIfVirtual' ], $files );
$this->backend->preloadFileStat( [ 'srcs' => $paths ] );
$result = [];
foreach ( $files as $key => $file ) {
- $path = $this->resolveToStoragePath( $file );
+ $path = $this->resolveToStoragePathIfVirtual( $file );
$result[$key] = $this->backend->fileExists( [ 'src' => $path ] );
}
* @return string
* @throws MWException
*/
- protected function resolveToStoragePath( $path ) {
+ protected function resolveToStoragePathIfVirtual( $path ) {
if ( self::isVirtualUrl( $path ) ) {
return $this->resolveVirtualUrl( $path );
}
* @return TempFSFile|null Returns null on failure
*/
public function getLocalCopy( $virtualUrl ) {
- $path = $this->resolveToStoragePath( $virtualUrl );
+ $path = $this->resolveToStoragePathIfVirtual( $virtualUrl );
return $this->backend->getLocalCopy( [ 'src' => $path ] );
}
* @return FSFile|null Returns null on failure.
*/
public function getLocalReference( $virtualUrl ) {
- $path = $this->resolveToStoragePath( $virtualUrl );
+ $path = $this->resolveToStoragePathIfVirtual( $virtualUrl );
return $this->backend->getLocalReference( [ 'src' => $path ] );
}
* @return string|bool False on failure
*/
public function getFileTimestamp( $virtualUrl ) {
- $path = $this->resolveToStoragePath( $virtualUrl );
+ $path = $this->resolveToStoragePathIfVirtual( $virtualUrl );
return $this->backend->getFileTimestamp( [ 'src' => $path ] );
}
* @return int|bool False on failure
*/
public function getFileSize( $virtualUrl ) {
- $path = $this->resolveToStoragePath( $virtualUrl );
+ $path = $this->resolveToStoragePathIfVirtual( $virtualUrl );
return $this->backend->getFileSize( [ 'src' => $path ] );
}
* @return string|bool
*/
public function getFileSha1( $virtualUrl ) {
- $path = $this->resolveToStoragePath( $virtualUrl );
+ $path = $this->resolveToStoragePathIfVirtual( $virtualUrl );
return $this->backend->getFileSha1Base36( [ 'src' => $path ] );
}
* @since 1.27
*/
public function streamFileWithStatus( $virtualUrl, $headers = [], $optHeaders = [] ) {
- $path = $this->resolveToStoragePath( $virtualUrl );
+ $path = $this->resolveToStoragePathIfVirtual( $virtualUrl );
$params = [ 'src' => $path, 'headers' => $headers, 'options' => $optHeaders ];
// T172851: HHVM does not flush the output properly, causing OOM
/**
* @param string $virtualUrl
- * @return false
+ * @return array
*/
function getFileProps( $virtualUrl ) {
- return false;
+ return [];
}
/**
* @return string
*/
public static function getHashFromKey( $key ) {
- return strtok( $key, '.' );
+ $sha1 = strtok( $key, '.' );
+ if ( is_string( $sha1 ) && strlen( $sha1 ) === 32 && $sha1[0] === '0' ) {
+ $sha1 = substr( $sha1, 1 );
+ }
+ return $sha1;
}
/**
$setOpts += Database::getCacheSetOptions( $dbr );
- if ( $title instanceof Title ) {
- $row = $dbr->selectRow(
- [ 'page', 'redirect' ],
- [ 'rd_namespace', 'rd_title' ],
- [
- 'page_namespace' => $title->getNamespace(),
- 'page_title' => $title->getDBkey(),
- 'rd_from = page_id'
- ],
- $method
- );
- } else {
- $row = false;
- }
+ $row = $dbr->selectRow(
+ [ 'page', 'redirect' ],
+ [ 'rd_namespace', 'rd_title' ],
+ [
+ 'page_namespace' => $title->getNamespace(),
+ 'page_title' => $title->getDBkey(),
+ 'rd_from = page_id'
+ ],
+ $method
+ );
return ( $row && $row->rd_namespace == NS_FILE )
? Title::makeTitle( $row->rd_namespace, $row->rd_title )->getDBkey()
* user is allowed to view them. Otherwise, such files will not
* be found.
* latest: If true, load from the latest available data into File objects
+ * @phan-param array{time?:mixed,ignoreRedirect?:bool,private?:bool,latest?:bool} $options
+ * @suppress PhanTypeInvalidDimOffset
* @return File|bool False if title is not found
*/
function findFile( $title, $options = [] ) {
* @return string
*/
public function getName() {
- if ( !isset( $this->name ) ) {
+ if ( $this->name === null ) {
$this->assertRepoDefined();
$this->name = $this->repo->getNameFromTitle( $this->title );
}
$thumb = false;
} elseif ( $thumb->isError() ) { // transform error
/** @var MediaTransformError $thumb */
+ '@phan-var MediaTransformError $thumb';
$this->lastError = $thumb->toText();
// Ignore errors if requested
if ( $wgIgnoreImageErrors && !( $flags & self::RENDER_NOW ) ) {
* @return string
*/
function getHashPath() {
- if ( !isset( $this->hashPath ) ) {
+ if ( $this->hashPath === null ) {
$this->assertRepoDefined();
$this->hashPath = $this->repo->getHashPath( $this->getName() );
}
? count( $data['query']['redirects'] ) - 1
: -1;
if ( $lastRedirect >= 0 ) {
+ // @phan-suppress-next-line PhanTypeArraySuspiciousNullable
$newtitle = Title::newFromText( $data['query']['redirects'][$lastRedirect]['to'] );
$img = new self( $newtitle, $repo, $info, true );
$img->redirectedFrom( $title->getDBkey() );
$this->loadFromDB( self::READ_NORMAL );
$fields = $this->getCacheFields( '' );
+ $cacheVal = [];
$cacheVal['fileExists'] = $this->fileExists;
if ( $this->fileExists ) {
foreach ( $fields as $field ) {
/**
* Delete cached transformed files for the current version only.
* @param array $options
+ * @phan-param array{forThumbRefresh?:bool} $options
*/
public function purgeThumbnails( $options = [] ) {
$files = $this->getThumbnails();
array_shift( $urls ); // don't purge directory
// Give media handler a chance to filter the file purge list
+ // @phan-suppress-next-line PhanTypeInvalidDimOffset
if ( !empty( $options['forThumbRefresh'] ) ) {
$handler = $this->getHandler();
if ( $handler ) {
# Add change tags, if any
if ( $tags ) {
- $logEntry->setTags( $tags );
+ $logEntry->addTags( $tags );
}
# Uploads can be patrolled
: FSFile::getSha1Base36FromPath( $srcPath );
/** @var FileBackendDBRepoWrapper $wrapperBackend */
$wrapperBackend = $repo->getBackend();
+ '@phan-var FileBackendDBRepoWrapper $wrapperBackend';
$dst = $wrapperBackend->getPathForSHA1( $sha1 );
$status = $repo->quickImport( $src, $dst );
if ( $flags & File::DELETE_SOURCE ) {
wfDebugLog( 'imagemove', "Finished moving {$this->name}" );
- // Purge the source and target files...
+ // Purge the source and target files outside the transaction...
$oldTitleFile = $localRepo->newFile( $this->title );
$newTitleFile = $localRepo->newFile( $target );
- // To avoid slow purges in the transaction, move them outside...
DeferredUpdates::addUpdate(
new AutoCommitUpdate(
$this->getRepo()->getMasterDB(),
function () use ( $oldTitleFile, $newTitleFile, $archiveNames ) {
$oldTitleFile->purgeEverything();
foreach ( $archiveNames as $archiveName ) {
+ /** @var OldLocalFile $oldTitleFile */
+ '@phan-var OldLocalFile $oldTitleFile';
$oldTitleFile->purgeOldThumbnails( $archiveName );
}
$newTitleFile->purgeEverything();
// Now switch the object
$this->title = $target;
// Force regeneration of the name and hashpath
- unset( $this->name );
- unset( $this->hashPath );
+ $this->name = null;
+ $this->hashPath = null;
}
return $status;
public function execute() {
$repo = $this->file->repo;
$status = $repo->newGood();
+ /** @var LocalFile $destFile */
$destFile = MediaWikiServices::getInstance()->getRepoGroup()->getLocalRepo()
->newFile( $this->target );
+ '@phan-var LocalFile $destFile';
$this->file->lock();
$destFile->lock(); // quickly fail if destination is not available
/** @var bool|string */
protected $mime;
- /** @var array Dimension data */
+ /** @var array[]|bool[] Dimension data */
protected $dims;
/** @var bool|string Handler-specific metadata which will be saved in the img_metadata field */
/**
* @param int $page
- * @return bool
+ * @return array|bool
*/
private function cachePageDimensions( $page = 1 ) {
$page = (int)$page;
protected $mHideBadImages;
/**
- * @var Parser Registered parser object for output callbacks
+ * @var Parser|false Registered parser object for output callbacks
*/
public $mParser;
/**
- * @var Title Contextual title, used when images are being screened against
+ * @var Title|null Contextual title, used when images are being screened against
* the bad image list
*/
- protected $contextTitle = false;
+ protected $contextTitle = null;
/** @var array */
protected $mAttribs = [];
- /** @var bool */
- private static $modeMapping = false;
+ /** @var array */
+ private static $modeMapping;
/**
* Get a new image gallery. This is the method other callers
}
private static function loadModes() {
- if ( self::$modeMapping === false ) {
+ if ( self::$modeMapping === null ) {
self::$modeMapping = [
'traditional' => TraditionalImageGallery::class,
'nolines' => NolinesImageGallery::class,
/**
* Set the contextual title
*
- * @param Title $title Contextual title
+ * @param Title|null $title Contextual title
*/
public function setContextTitle( $title ) {
$this->contextTitle = $title;
/**
* Get the contextual title, if applicable
*
- * @return Title|bool Title or false
+ * @return Title|null
*/
public function getContextTitle() {
- return is_object( $this->contextTitle ) && $this->contextTitle instanceof Title
- ? $this->contextTitle
- : false;
+ return $this->contextTitle;
}
/**
* Improves compression ratio by concatenating like objects before gzipping
*/
class ConcatenatedGzipHistoryBlob implements HistoryBlob {
- public $mVersion = 0, $mCompressed = false, $mItems = [], $mDefaultHash = '';
+ public $mVersion = 0;
+ public $mCompressed = false;
+ /**
+ * @var array|string
+ * @fixme Why are some methods treating it as an array, and others as a string, unconditionally?
+ */
+ public $mItems = [];
+ public $mDefaultHash = '';
public $mSize = 0;
public $mMaxSize = 10000000;
public $mMaxCount = 100;
$seqName = 'main';
}
}
- $seq =& $sequences[$seqName];
- $tail = $seq['tail'];
+
+ $tail = $sequences[$seqName]['tail'];
$diff = $this->diff( $tail, $text );
- $seq['diffs'][] = $diff;
- $seq['map'][] = $i;
- $seq['tail'] = $text;
+ $sequences[$seqName]['diffs'][] = $diff;
+ $sequences[$seqName]['map'][] = $i;
+ $sequences[$seqName]['tail'] = $text;
}
- unset( $seq ); // unlink dangerous alias
// Knit the sequences together
$tail = '';
// addItem() doesn't work if mItems is partially filled from mDiffs
$this->mFrozen = true;
$info = unserialize( gzinflate( $this->mCompressed ) );
- unset( $this->mCompressed );
+ $this->mCompressed = null;
if ( !$info ) {
// Empty object
protected $mUseMultipart = false;
protected $mHiddenFields = [];
+ /**
+ * @var array[]
+ * @phan-var array<array{name:string,value:string,label-message?:string,label?:string,label-raw?:string,id?:string,attribs?:array,flags?:string|string[],framed?:bool}>
+ */
protected $mButtons = [];
protected $mWrapperLegend = false;
*
* @param string $displayFormat
* @param mixed $arguments,... Additional arguments to pass to the constructor.
+ * @suppress PhanCommentParamWithoutRealParam HHVM bug T228695#5450847
* @return HTMLForm
*/
public static function factory( $displayFormat/*, $arguments...*/ ) {
* - attribs: (array, optional) Additional HTML attributes.
* - flags: (string|string[], optional) OOUI flags.
* - framed: (boolean=true, optional) OOUI framed attribute.
+ * @codingStandardsIgnoreStart
+ * @phan-param array{name:string,value:string,label-message?:string,label?:string,label-raw?:string,id?:string,attribs?:array,flags?:string|string[],framed?:bool} $data
+ * @codingStandardsIgnoreEnd
* @return HTMLForm $this for chaining calls (since 1.20)
*/
public function addButton( $data ) {
* (defined in htmlform.Element.js) picks up the extra config when constructed using OO.ui.infuse().
*
* Currently only supports passing 'hide-if' data.
+ * @phan-file-suppress PhanUndeclaredMethod
*/
trait HTMLFormElement {
* be a subclass of this.
*/
abstract class HTMLFormField {
+ /** @var array|array[] */
public $mParams;
protected $mValidationCallback;
* The old name of autocomplete-data[-messages] was autocomplete[-messages] which is still
* recognized but deprecated since MediaWiki 1.29 since it conflicts with how autocomplete is
* used in HTMLTextField.
+ *
+ * @phan-file-suppress PhanTypeMismatchProperty This is doing weird things with mClass
*/
class HTMLAutoCompleteSelectField extends HTMLTextField {
protected $autocompleteData = [];
$ret = $select->getHTML() . "<br />\n";
+ // @phan-suppress-next-line PhanTypeMismatchDimEmpty
$this->mClass[] = 'mw-htmlform-hide-if';
}
}
}
+ // @phan-suppress-next-line PhanTypeMismatchDimEmpty
$this->mClass[] = 'mw-htmlform-autocomplete';
$ret .= parent::getInputHTML( $valInSelect ? '' : $value );
$this->mClass = $oldClass;
* mParams['columns'] is an array with column labels as keys and column tags as values.
*
* @param array $value Array of the options that should be checked
+ * @suppress PhanParamSignatureMismatch
*
* @return string
*/
* @since 1.28
* @param string[] $value
* @return string|OOUI\CheckboxMultiselectInputWidget
+ * @suppress PhanParamSignatureMismatch
*/
public function getInputOOUI( $value ) {
$this->mParent->getOutput()->addModules( 'oojs-ui-widgets' );
protected $handler = null;
protected $sink = null;
+ /** @var array */
protected $guzzleOptions = [ 'http_errors' => false ];
/**
* - password Password for HTTP Basic Authentication
* - originalRequest Information about the original request (as a WebRequest object or
* an associative array with 'ip' and 'userAgent').
+ * @codingStandardsIgnoreStart
+ * @phan-param array{timeout?:int,connectTimeout?:int,postData?:array,proxy?:string,noProxy?:bool,sslVerifyHost?:bool,sslVerifyCert?:bool,caInfo?:string,maxRedirects?:int,followRedirects?:bool,userAgent?:string,logger?:\Psr\Logger\LoggerInterface,username?:string,password?:string,originalRequest?:WebRequest|array{ip:string,userAgent:string}} $options
+ * @codingStandardsIgnoreEnd
* @param string $caller The method making this request, for profiling
* @throws RuntimeException
* @return MWHttpRequest
* @see MWHttpRequest::__construct
+ * @suppress PhanUndeclaredTypeParameter
*/
public function create( $url, array $options = [], $caller = __METHOD__ ) {
if ( !Http::$httpEngine ) {
protected $sslVerifyCert = true;
protected $caInfo = null;
protected $method = "GET";
+ /** @var array */
protected $reqHeaders = [];
protected $url;
protected $parsedUrl;
protected $headerList = [];
protected $respVersion = "0.9";
protected $respStatus = "200 Ok";
+ /** @var string[][] */
protected $respHeaders = [];
/** @var StatusValue */
/**
* @param string $url Url to use. If protocol-relative, will be expanded to an http:// URL
* @param array $options (optional) extra params to pass (see HttpRequestFactory::create())
+ * @codingStandardsIgnoreStart
+ * @phan-param array{timeout?:int,connectTimeout?:int,postData?:array,proxy?:string,noProxy?:bool,sslVerifyHost?:bool,sslVerifyCert?:bool,caInfo?:string,maxRedirects?:int,followRedirects?:bool,userAgent?:string,logger?:LoggerInterface,username?:string,password?:string,originalRequest?:WebRequest|array{ip:string,userAgent:string},method?:string} $options
+ * @codingStandardsIgnoreEnd
* @param string $caller The method making this request, for profiling
* @param Profiler|null $profiler An instance of the profiler for profiling, or null
* @throws Exception
$this->url = wfExpandUrl( $url, PROTO_HTTP );
$this->parsedUrl = wfParseUrl( $this->url );
+ // @phan-suppress-next-line PhanTypeInvalidDimOffset
$this->logger = $options['logger'] ?? new NullLogger();
if ( !$this->parsedUrl || !Http::isValidURI( $this->url ) ) {
// ensure that MWHttpRequest::method is always
// uppercased. T38137
if ( $o == 'method' ) {
+ // @phan-suppress-next-line PhanTypeInvalidDimOffset
$options[$o] = strtoupper( $options[$o] );
}
$this->$o = $options[$o];
/**
* Take care of whatever is necessary to perform the URI request.
*
- * @return StatusValue
+ * @return Status
* @note currently returns Status for B/C
*/
public function execute() {
$user
);
} else {
+ '@phan-var LocalFile $file';
$flags = 0;
$status = $file->upload(
$source,
return $this->logItemCallback( $revision );
}
+ /**
+ * @suppress PhanTypeInvalidDimOffset Phan not reading the reference inside the hook
+ */
private function handlePage() {
// Handle page data.
$this->debug( "Enter page handler." );
// PerformInstallation bails on a fatal, so make sure the last item
// completed before giving 'next.' Likewise, only provide back on failure
$lastStepStatus = end( $result );
- if ( $lastStepStatus->isOk() ) {
+ if ( $lastStepStatus->isOK() ) {
return Status::newGood();
} else {
return $lastStepStatus;
* This will return a cached connection if one is available.
*
* @return Status
+ * @suppress PhanUndeclaredMethod
*/
public function getConnection() {
if ( $this->db ) {
public function setupSchemaVars() {
$status = $this->getConnection();
if ( $status->isOK() ) {
+ // @phan-suppress-next-line PhanUndeclaredMethod
$status->value->setSchemaVars( $this->getSchemaVars() );
} else {
$msg = __METHOD__ . ': unexpected error while establishing'
foreach ( $updates as $funcList ) {
list( $func, $args, $origParams ) = $funcList;
+ // @phan-suppress-next-line PhanUndeclaredInvokeInCallable
$func( ...$args );
flush();
$this->updatesSkipped[] = $origParams;
$cl = $this->maintenance->runChild(
RebuildLocalisationCache::class, 'rebuildLocalisationCache.php'
);
+ '@phan-var RebuildLocalisationCache $cl';
$this->output( "Rebuilding localisation cache...\n" );
$cl->setForce();
$cl->execute();
$task = $this->maintenance->runChild(
MigrateImageCommentTemp::class, 'migrateImageCommentTemp.php'
);
+ // @phan-suppress-next-line PhanUndeclaredMethod
$task->setForce();
$ok = $task->execute();
$this->output( $ok ? "done.\n" : "errors were encountered.\n" );
if ( $this->db->fieldExists( 'archive', 'ar_text', __METHOD__ ) ) {
$this->output( "Migrating archive ar_text to modern storage.\n" );
$task = $this->maintenance->runChild( MigrateArchiveText::class, 'migrateArchiveText.php' );
+ // @phan-suppress-next-line PhanUndeclaredMethod
$task->setForce();
if ( $task->execute() ) {
$this->applyPatch( 'patch-drop-ar_text.sql', false,
// This will be overridden in the web installer with the user-specified language
RequestContext::getMain()->setLanguage( 'en' );
+ // Disable the i18n cache
+ // TODO: manage LocalisationCache singleton in MediaWikiServices
+ Language::getLocalisationCache()->disableBackend();
+
// Disable all global services, since we don't have any configuration yet!
MediaWikiServices::disableStorageBackend();
$mwServices = MediaWikiServices::getInstance();
-
- // Disable i18n cache
- $mwServices->getLocalisationCache()->disableBackend();
-
- // Clear language cache so the old i18n cache doesn't sneak back in
- Language::clearCaches();
-
// Disable object cache (otherwise CACHE_ANYTHING will try CACHE_DB and
// SqlBagOStuff will then throw since we just disabled wfGetDB)
$wgObjectCaches = $mwServices->getMainConfig()->get( 'ObjectCaches' );
if ( !$status->isOK() ) {
return $status;
}
+ // @phan-suppress-next-line PhanUndeclaredMethod
$status->value->insert(
'site_stats',
[
*
* @param string $directory Directory to search in, relative to $IP, must be either "extensions"
* or "skins"
- * @return array [ $extName => [ 'screenshots' => [ '...' ] ]
+ * @return array[][] [ $extName => [ 'screenshots' => [ '...' ] ]
*/
public function findExtensions( $directory = 'extensions' ) {
switch ( $directory ) {
// If we've hit some sort of fatal, we need to bail.
// Callback already had a chance to do output above.
- if ( !$status->isOk() ) {
+ if ( !$status->isOK() ) {
break;
}
}
- if ( $status->isOk() ) {
+ if ( $status->isOK() ) {
$this->showMessage(
'config-install-db-success'
);
* @var Database $conn
*/
$conn = $status->value;
+ '@phan-var Database $conn';
// Check version
return static::meetsMinimumRequirement( $conn->getServerVersion() );
*
* @ingroup Deployment
* @since 1.17
+ * @property DatabaseMysqlBase $db
*/
class MysqlUpdater extends DatabaseUpdater {
protected function getCoreUpdateList() {
if ( !$status->isOK() ) {
return $status;
}
+ // @phan-suppress-next-line PhanUndeclaredMethod
$exists = $status->value->roleExists( $this->getVar( 'wgDBuser' ) );
}
}
/** @var DatabasePostgres $conn */
$conn = $status->value;
+ '@phan-var DatabasePostgres $conn';
// Create the schema if necessary
$schema = $this->getVar( 'wgDBmwschema' );
if ( !$status->isOK() ) {
return $status;
}
+ /** @var DatabasePostgres $conn */
$conn = $status->value;
+ '@phan-var DatabasePostgres $conn';
$safeuser = $conn->addIdentifierQuotes( $this->getVar( 'wgDBuser' ) );
$safepass = $conn->addQuotes( $this->getVar( 'wgDBpassword' ) );
/** @var DatabasePostgres $conn */
$conn = $status->value;
+ '@phan-var DatabasePostgres $conn';
if ( $conn->tableExists( 'archive' ) ) {
$status->warning( 'config-install-tables-exist' );
$this->setVar( 'wgDBpassword', '' );
$this->setupSchemaVars();
- # Create the global cache DB
- try {
- $conn = Database::factory(
- 'sqlite', [ 'dbname' => 'wikicache', 'dbDirectory' => $dir ] );
- # @todo: don't duplicate objectcache definition, though it's very simple
- $sql =
-<<<EOT
- CREATE TABLE IF NOT EXISTS objectcache (
- keyname BLOB NOT NULL default '' PRIMARY KEY,
- value BLOB,
- exptime TEXT
- )
-EOT;
- $conn->query( $sql );
- $conn->query( "CREATE INDEX IF NOT EXISTS exptime ON objectcache (exptime)" );
- $conn->query( "PRAGMA journal_mode=WAL" ); // this is permanent
- $conn->close();
- } catch ( DBConnectionError $e ) {
- return Status::newFatal( 'config-sqlite-connection-error', $e->getMessage() );
- }
-
# Create the l10n cache DB
try {
$conn = Database::factory(
# Special case for Creative Commons partner chooser box.
if ( $this->request->getVal( 'SubmitCC' ) ) {
+ /** @var WebInstallerOptions $page */
$page = $this->getPageByName( 'Options' );
+ '@phan-var WebInstallerOptions $page';
$this->output->useShortHeader();
$this->output->allowFrames();
$page->submitCC();
}
if ( $this->request->getVal( 'ShowCC' ) ) {
+ /** @var WebInstallerOptions $page */
$page = $this->getPageByName( 'Options' );
+ '@phan-var WebInstallerOptions $page';
$this->output->useShortHeader();
$this->output->allowFrames();
$this->output->addHTML( $page->getCCDoneBox() );
foreach ( $moduleNames as $moduleName ) {
/** @var ResourceLoaderFileModule $module */
$module = $resourceLoader->getModule( $moduleName );
+ '@phan-var ResourceLoaderFileModule $module';
if ( !$module ) {
// T98043: Don't fatal, but it won't look as pretty.
continue;
"config-install-step-failed": "mislykkedes",
"config-install-extensions": "Inkluderer udvidelser",
"config-install-database": "Opsætter database",
+ "config-install-user": "Opretter databasebruger",
"config-install-user-alreadyexists": "Brugeren \"$1\" findes allerede",
"config-install-user-create-failed": "Oprettelse af brugeren \"$1\" mislykkedes: $2",
"config-install-tables": "Opretter tabeller",
"config-install-keys": "Genererer hemmelige nøgler",
"config-install-mainpage-exists": "Forsiden findes allerede, springer over",
"config-install-mainpage-failed": "Kunne ikke indsætte forside: $1",
+ "config-install-db-success": "Databasen blev sat op",
"config-help": "hjælp",
"config-help-tooltip": "klik for at udvide",
"config-nofile": "Filen \"$1\" kunne ikke blive fundet. Er den blevet slettet?",
"config-restart": "Ya, nyalakan ulang",
"config-welcome": "=== Pengecekan lingkungan ===\nPengecekan dasar kini akan dilakukan untuk melihat apakah lingkungan ini memadai untuk instalasi MediaWiki.\nIngatlah untuk menyertakan informasi ini jika Anda mencari bantuan tentang cara menyelesaikan instalasi.",
"config-welcome-section-copyright": "=== Hak cipta dan persyaratan ===\n\n$1\n\nProgram ini adalah perangkat lunak bebas; Anda dapat mendistribusikan dan/atau memodifikasinya di bawah persyaratan GNU General Public License seperti yang diterbitkan oleh Free Software Foundation; baik versi 2 lisensi, atau (sesuai pilihan Anda) versi yang lebih baru.\n\nProgram ini didistribusikan dengan harapan bahwa itu akan berguna, tetapi <strong>tanpa jaminan apa pun</strong>; bahkan tanpa jaminan tersirat untuk <strong>dapat diperjualbelikan</strong> atau <strong>sesuai untuk tujuan tertentu</strong>.\nLihat GNU General Public License untuk lebih jelasnya.\n\nAnda seharusnya telah menerima [$2 salinan dari GNU General Public License] bersama dengan program ini; jika tidak, kirimkan surat untuk Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA, atau [https://www.gnu.org/copyleft/gpl.html baca versi daring].",
- "config-sidebar": "* [https://www.mediawiki.org/wiki/MediaWiki/id Situs MediaWiki]\n* [https://www.mediawiki.org/wiki/Special:MyLanguage/Help:Contents/id Pedoman Pengguna]\n* [https://www.mediawiki.org/wiki/Special:MyLanguage/Manual:Contents/id Pedoman Administrator]\n* [https://www.mediawiki.org/wiki/Special:MyLanguage/Manual:FAQ/id FAQ]\n----\n* <doclink href=Readme>Read me</doclink>\n* <doclink href=ReleaseNotes>Release notes</doclink>\n* <doclink href=Copying>Copying</doclink>\n* <doclink href=UpgradeDoc>Upgrading</doclink>",
+ "config-sidebar": "* [https://www.mediawiki.org Halaman depan MediaWiki]\n* [https://www.mediawiki.org/wiki/Special:MyLanguage/Help:Contents Panduan Pengguna]\n* [https://www.mediawiki.org/wiki/Special:MyLanguage/Manual:Contents Panduan Pengurus]\n* [https://www.mediawiki.org/wiki/Special:MyLanguage/Manual:FAQ Pertanyaan yang sering ditanyakan]",
+ "config-sidebar-readme": "Pelajari selengkapnya",
+ "config-sidebar-relnotes": "Catatan rilis",
+ "config-sidebar-license": "Menyalin",
+ "config-sidebar-upgrade": "Memperbarui",
"config-env-good": "Kondisi telah diperiksa.\nAnda dapat menginstal MediaWiki.",
"config-env-bad": "Kondisi telah diperiksa.\nAnda tidak dapat menginstal MediaWiki.",
"config-env-php": "PHP $1 diinstal.",
"config-env-hhvm": "HHVM $1 telah dipasang.",
- "config-unicode-using-intl": "Menggunakan [https://pecl.php.net/intl ekstensi PECL intl] untuk normalisasi Unicode.",
+ "config-unicode-using-intl": "Menggunakan [https://php.net/manual/en/book.intl.php ekstensi internasional PHP] untuk normalisasi Unicode.",
"config-unicode-pure-php-warning": "<strong>Peringatan:</strong> [https://pecl.php.net/intl intl Ekstensi PECL] tidak tersedia untuk menangani normalisasi Unicode, dikembalikan untuk melambatkan implementasi PHP asli.\nApabila Anda menjalankan situs dengan lalu-lintas tinggi, Anda harus membaca [https://www.mediawiki.org/wiki/Special:MyLanguage/Unicode_normalization_considerations normalisasi Unicode].",
"config-unicode-update-warning": "<strong>Peringatan:</strong> Versi terinstal dari pembungkus normalisasi Unicode menggunakan versi lama pustaka [http://site.icu-project.org/ proyek ICU].\nAnda harus [https://www.mediawiki.org/wiki/Special:MyLanguage/Unicode_normalization_considerations meningkatkan versinya] jika ingin menggunakan Unicode.",
"config-no-db": "Pengandar basis data yang sesuai tidak ditemukan! Anda perlu menginstal pengandar basis data untuk PHP.\n{{PLURAL:$2|Jenis|Jenis}} basis data yang didukung: $1.\n\nJika Anda mengompilasi PHP sendiri, ubahlah konfigurasinya dengan mengaktifkan klien basis data, misalnya menggunakan <code>./configure --with-mysqli</code>.\nJika Anda menginstal PHP dari paket Debian atau Ubuntu, maka Anda juga perlu menginstal seperti paket <code>php-mysql</code>.",
"config-db-host": "Inang basis data:",
"config-db-host-help": "Jika server basis data Anda berada di server yang berbeda, masukkan nama inang atau alamat IP di sini.\n\nJika Anda menggunakan inang web bersama, penyedia inang Anda harus memberikan nama inang yang benar di dokumentasi mereka.\n\nJika Anda menginstal pada server Windows dan menggunakan MySQL, \"localhost\" mungkin tidak dapat digunakan sebagai nama server. Jika demikian, coba \"127.0.0.1\" untuk alamat IP lokal.\n\nJika Anda menggunakan PostgreSQL, biarkan field ini kosong untuk menghubungkan lewat soket Unix.",
"config-db-wiki-settings": "Identifikasi wiki ini",
- "config-db-name": "Nama basis data:",
+ "config-db-name": "Nama basis data (tanpa tanda hubung):",
"config-db-name-help": "Pilih nama yang mengidentifikasikan wiki Anda.\nNama tersebut tidak boleh mengandung spasi.\n\nJika Anda menggunakan inang web bersama, penyedia inang Anda dapat memberikan Anda nama basis data khusus untuk digunakan atau mengizinkan Anda membuat basis data melalui panel kontrol.",
"config-db-install-account": "Akun pengguna untuk instalasi",
"config-db-username": "Nama pengguna basis data:",
"config-db-account-lock": "Gunakan nama pengguna dan kata sandi yang sama selama operasi normal",
"config-db-wiki-account": "Akun pengguna untuk operasi normal",
"config-db-wiki-help": "Masukkan nama pengguna dan sandi yang akan digunakan untuk terhubung ke basis data wiki selama operasi normal.\nJika akun tidak ada, akun instalasi memiliki hak yang memadai, akun pengguna ini akan dibuat dengan hak akses minimum yang diperlukan untuk mengoperasikan wiki.",
- "config-db-prefix": "Prefiks tabel basis data:",
+ "config-db-prefix": "Prefiks tabel basis data (tanpa tanda hubung):",
"config-db-prefix-help": "Jika Anda perlu berbagi satu basis data di antara beberapa wiki, atau antara MediaWiki dan aplikasi web lain, Anda dapat memilih untuk menambahkan prefiks terhadap semua nama tabel demi menghindari konflik.\nJangan gunakan spasi.\n\nPrefiks ini biasanya dibiarkan kosong.",
"config-mysql-old": "MySQL $1 atau versi terbaru diperlukan, Anda menggunakan $2.",
"config-db-port": "Porta basis data:",
- "config-db-schema": "Skema untuk MediaWiki",
+ "config-db-schema": "Skema untuk MediaWiki (tanpa tanda hubung):",
"config-db-schema-help": "Skema ini biasanya berjalan baik.\nUbah hanya jika Anda tahu Anda perlu mengubahnya.",
"config-pg-test-error": "Tidak dapat terhubung ke basis data <strong>$1</strong>: $2",
"config-sqlite-dir": "Direktori data SQLite:",
"config-sqlite-dir-help": "SQLite menyimpan semua data dalam satu berkas.\n\nDirektori yang Anda berikan harus dapat ditulisi oleh server web selama instalasi.\n\nDirektori itu '''tidak''' boleh dapat diakses melalui web, inilah sebabnya kami tidak menempatkannya bersama dengan berkas PHP lain.\n\nPenginstal akan membuat berkas <code>.htaccess</code> bersamaan dengan itu, tetapi jika gagal, orang dapat memperoleh akses ke basis data mentah Anda.\nItu termasuk data mentah pengguna (alamat surel, hash sandi) serta revisi yang dihapus dan data lainnya yang dibatasi pada wiki.\n\nPertimbangkan untuk menempatkan basis data di tempat lain, misalnya di <code>/var/lib/mediawiki/yourwiki</code>.",
- "config-type-mysql": "MySQL (atau yang kompatibel)",
+ "config-type-mysql": "MariaDB, MySQL, atau yang kompatibel",
"config-type-postgres": "PostgreSQL",
"config-type-sqlite": "SQLite",
"config-support-info": "MediaWiki mendukung sistem basis data berikut:\n\n$1\n\nJika Anda tidak melihat sistem basis data yang Anda gunakan tercantum di bawah ini, ikuti petunjuk terkait di atas untuk mengaktifkan dukungan.",
"config-dbsupport-mysql": "* [{{int:version-db-mysql-url}} MySQL] adalah target utama MediaWiki dan memiliki dukungan terbaik. MediaWiki juga berjalan dengan [{{int:version-db-mariadb-url}} MariaDB] dan [{{int:version-db-percona-url}} Server Percona], yang kompatibel dengan MySQL. ([https://www.php.net/manual/en/mysql.installation.php Cara mengompilasi PHP dengan dukungan MySQL])",
"config-dbsupport-postgres": "* [{{int:version-db-postgres-url}} PostgreSQL] adalah sistem basis data sumber terbuka populer sebagai alternatif MySQL.([https://www.php.net/manual/en/pgsql.installation.php Bagaimana mengompilasikan PHP dengan dukungan PostgreSQL])",
- "config-dbsupport-sqlite": "* [{{int:version-db-sqlite-url}} SQLite] adalah sistem basis data yang ringan yang sangat baik dukungannya. ([http://www.php.net/manual/en/pdo.installation.php cara mengompilasi PHP dengan dukungan SQLite], menggunakan PDO)",
+ "config-dbsupport-sqlite": "* [{{int:version-db-sqlite-url}} SQLite] adalah sistem basis data yang ringan yang sangat baik dukungannya. ([http://www.php.net/manual/en/pdo.installation.php Bagaimana mengompilasi PHP dengan dukungan SQLite], menggunakan PDO)",
"config-header-mysql": "Pengaturan MariaDB/MySQL",
"config-header-postgres": "Pengaturan PostgreSQL",
"config-header-sqlite": "Pengaturan SQLite",
"config-missing-db-host": "Anda harus memasukkan nilai untuk \"{{int:config-db-host}}\"",
"config-invalid-db-name": "Nama basis data \"$1\" tidak sah.\nGunakan hanya huruf ASCII (a-z, A-Z), angka (0-9), garis bawah (_), dan tanda hubung (-).",
"config-invalid-db-prefix": "Prefiks basis data \"$1\" tidak sah.\nGunakan hanya huruf ASCII (a-z, A-Z), angka (0-9), garis bawah (_), dan tanda hubung (-).",
- "config-connection-error": "$1.\n\nPeriksa nama inang, pengguna, dan sandi di bawah ini dan coba lagi.",
+ "config-connection-error": "$1.\n\nPeriksa nama inang, pengguna, dan kata sandi dan coba lagi. Jika menggunakan \"localhost\" sebagai inang basis data, coba gunakan \"127.0.0.1\" (atau sebaliknya).",
"config-invalid-schema": "Skema MediaWiki \"$1\" tidak sah.\nGunakan hanya huruf ASCII (a-z, A-Z), angka (0-9), dan garis bawah (_).",
"config-postgres-old": "PostgreSQL $1 atau versi terbaru diperlukan, Anda menggunakan $2.",
"config-sqlite-name-help": "Pilih nama yang mengidentifikasi wiki Anda.\nJangan gunakan spasi atau tanda hubung.\nNama ini akan digunakan untuk nama berkas data SQLite.",
"config-sqlite-cant-create-db": "Tidak dapat membuat berkas basis data <code>$1</code>.",
"config-sqlite-fts3-downgrade": "PHP tidak memiliki dukungan FTS3, tabel dituruntarafkan.",
"config-can-upgrade": "Ada tabel MediaWiki di basis dataini.\nUntuk memperbaruinya ke MediaWiki $1, klik '''Lanjut'''.",
+ "config-upgrade-error": "Terjadi sebuah galat ketika memperbarui tabel MediaWiki dalam basis data Anda.\n\nUntuk informasi lebih lanjut, lihat catatan di atas, untuk mencoba kembali klik <strong>Lanjutkan</strong>.",
"config-upgrade-done": "Pemutakhiran selesai.\n\nAnda sekarang dapat [$1 mulai menggunakan wiki Anda].\n\nJika Anda ingin membuat ulang berkas <code>LocalSettings.php</code>, klik tombol di bawah ini.\nTindakan ini '''tidak dianjurkan''' kecuali jika Anda mengalami masalah dengan wiki Anda.",
"config-upgrade-done-no-regenerate": "Pemutakhiran selesai.\n\nAnda sekarang dapat [$1 mulai menggunakan wiki Anda].",
"config-regenerate": "Regenerasi LocalSettings.php →",
"config-db-web-create": "Buat akun jika belum ada",
"config-db-web-no-create-privs": "Akun Anda berikan untuk instalasi tidak memiliki hak yang cukup untuk membuat akun.\nAkun yang Anda berikan harus sudah ada.",
"config-mysql-engine": "Mesin penyimpanan:",
- "config-mysql-innodb": "InnoDB",
+ "config-mysql-innodb": "InnoDB (disarankan)",
"config-mysql-engine-help": "'''InnoDB''' hampir selalu merupakan pilihan terbaik karena memiliki dukungan konkurensi yang baik.\n\n'''MyISAM''' mungkin lebih cepat dalam instalasi pengguna-tunggal atau hanya-baca.\nBasis data MyISAM cenderung lebih sering rusak daripada basis data InnoDB.",
"config-site-name": "Nama wiki:",
"config-site-name-help": "Ini akan muncul di bilah judul peramban dan di berbagai tempat lainnya.",
"config-install-subscribe-fail": "Tidak dapat berlangganan mediawiki-announce: $1",
"config-install-subscribe-notpossible": "cURL tidak diinstal dan <code>allow_url_fopen</code> tidak tersedia.",
"config-install-mainpage": "Membuat halaman utama dengan konten bawaan",
+ "config-install-mainpage-exists": "Halaman utama sudah ada, meloncati",
"config-install-extension-tables": "Pembuatan tabel untuk ekstensi yang diaktifkan",
"config-install-mainpage-failed": "Tidak dapat membuat halaman utama: $1",
"config-install-done": "<strong>Selamat!</strong>\nAnda telah berhasil menginstal MediaWiki.\n\nPemasang telah membuat sebuah berkas <code>LocalSettings.php</code>.\nBerkas itu berisi semua setelan Anda.\n\nAnda perlu mengunduh berkas itu dan meletakkannya di direktori instalasi wiki (direktori yang sama dengan index.php). Pengunduhan akan dimulai secara otomatis.\n\nJika pengunduhan tidak terjadi, atau jika Anda membatalkannya, Anda dapat mengulangi pengunduhan dengan mengeklik tautan berikut:\n\n$3\n\n<strong>Catatan</strong>: Jika Anda tidak melakukannya sekarang, berkas konfigurasi yang dihasilkan ini tidak akan tersedia lagi setelah Anda keluar dari proses instalasi tanpa mengunduhnya.\n\nSetelah melakukannya, Anda dapat <strong>[$2 memasuki wiki Anda]</strong>.",
+ "config-install-success": "MediaWiki telah dipasang dengan sukses. Anda dapat mengunjungi <$1$2> untuk melihat wiki ini. Jika Anda memiliki pertanyaan, lihat daftar pertanyaan yang sering ditanyakan: <https://www.mediawiki.org/wiki/Special:MyLanguage/Manual:FAQ> atau gunakan salah satu forum yang ada di halaman tersebut.",
+ "config-install-db-success": "Basis data telah sukses diatur",
"config-download-localsettings": "Unduh <code>LocalSettings.php</code>",
"config-help": "bantuan",
"config-help-tooltip": "klik untuk memperluas",
"config-skins-screenshots": "$1 (tangkapan layar: $2)",
"config-extensions-requires": "$1 (memerlukan $2)",
"config-screenshot": "tangkapan layar",
+ "config-extension-not-found": "Tidak dapat menemukan berkas registrasi untuk ekstensi \"$1\"",
"mainpagetext": "<strong>MediaWiki telah terpasang dengan sukses.</strong>",
"mainpagedocfooter": "Konsultasikan [https://www.mediawiki.org/wiki/Help:Contents Panduan Pengguna] untuk cara penggunaan perangkat lunak wiki ini.\n\n== Memulai ==\n* [https://www.mediawiki.org/wiki/Special:MyLanguage/Manual:Configuration_settings Daftar pengaturan konfigurasi]\n* [https://www.mediawiki.org/wiki/Special:MyLanguage/Manual:FAQ Pertanyaan yang sering diajukan mengenai MediaWiki]\n* [https://lists.wikimedia.org/mailman/listinfo/mediawiki-announce Milis rilis MediaWiki]\n* [https://www.mediawiki.org/wiki/Special:MyLanguage/Localisation#Translation_resources Pelokalan MediaWiki untuk bahasa Anda]\n* [https://www.mediawiki.org/wiki/Special:MyLanguage/Manual:Combating_spam Belajar bagaimana menghadapi spam di wiki lokal]"
}
"C.R.",
"Chelin",
"Macofe",
- "Fitoschido"
+ "Fitoschido",
+ "Ruthven"
]
},
"config-desc": "'O prugramma d'istallazione 'e MediaWiki",
"config-db-web-account": "Cunto d' 'o database pe' ne fà acciesso web",
"config-db-web-help": "Scigliete 'o nomme utente e passwrod ca 'o web server ausarrà pe' se cullegà 'o server database, pe' tramente ca se fa' operazione normale d' 'o wiki.",
"config-db-web-account-same": "Aúsa 'o stisso cunto comme quanno s'è fatta 'a installazione",
- "config-db-web-create": "Crìa 'o cunto si nun esiste ancora",
+ "config-db-web-create": "Crìa 'o cunto si nun esiste perzi",
"config-db-web-no-create-privs": "'O cunto ausato pe' ne fà l'installazione nun tene diritte necessarie pe' ne putè crià n'atu cunto.\n'O cunto zegnàto ccà adda esistere già.",
"config-mysql-engine": "Mutore d'astipo:",
"config-mysql-innodb": "InnoDB (fosse 'o cunzigliato)",
"config-welcome": "=== Verificări ale mediului ===\nVerificări de bază vor fi efectuate pentru a vedea dacă este potrivit pentru instalarea MediaWiki.\nNu uitați să includeți aceste informații dacă doriți asistență pentru completarea instalării.",
"config-welcome-section-copyright": "=== Drepturi de autor și termeni ===\n\n$1\n\nAcest program este un software liber; îl puteți redistribui și / sau modifica în conformitate cu termenii Licenței Publice Generale GNU, publicată de Fundația pentru Software Liber; fie versiunea 2 a Licenței, fie (la alegere) orice versiune ulterioară.\nAcest program este distribuit în speranța că va fi util, dar <strong>fără nicio garanție</strong>; fără nici măcar garanția implicită de <strong>vandabilitate</strong> sau <strong>fitness pentru un anumit scop</strong>.\nPentru mai multe detalii, consultați Licența publică generală GNU.\nAr fi trebuit să fi primit [$2 o copie a GNU General Public License] împreună cu acest program; dacă nu, scrieți la Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, SUA, sau [https://www.gnu.org/copyleft/gpl.html citiți-o online] .",
"config-sidebar": "* [https://www.mediawiki.org Acasă MediaWiki]\n* [https://www.mediawiki.org/wiki/Special:MyLanguage/Help:Contents User's Guide]\n* [https://www.mediawiki.org/wiki/Special:MyLanguage/Manual:Contents Administrator's Guide]\n* [https://www.mediawiki.org/wiki/Special:MyLanguage/Manual:FAQ FAQ]\n----\n* <doclink href=Readme>Read me</doclink>\n* <doclink href=ReleaseNotes>Release notes</doclink>\n* <doclink href=Copying>Copying</doclink>\n* <doclink href=UpgradeDoc>Upgrading</doclink>",
+ "config-sidebar-readme": "Read me",
+ "config-sidebar-relnotes": "Note de lansare",
+ "config-sidebar-license": "Copiere",
+ "config-sidebar-upgrade": "Actualizare",
"config-env-good": "Verificarea mediului a fost efectuată cu succes.\nPuteți instala MediaWiki.",
"config-env-bad": "Verificarea mediului a fost efectuată.\nNu puteți instala MediaWiki.",
"config-env-php": "PHP $1 este instalat.",
"config-env-hhvm": "HHVM $1 este instalat.",
- "config-unicode-using-intl": "Utilizarea extensiei [https://pecl.php.net/intl intl PECL] pentru normalizarea Unicode.",
- "config-unicode-pure-php-warning": "<strong>Atenție:</strong> Extensia [https://pecl.php.net/intl intl PECL] nu este disponibilă pentru a face față normalizării Unicode, revenind la o implementare lentă pur PHP.\nDacă rulați un site cu trafic ridicat, ar trebui să citiți puțin în [https://www.mediawiki.org/wiki/Special:MyLanguage/Unicode_normalization_considerations Normalizarea Unicode].",
+ "config-unicode-using-intl": "Se folosește extensia [https://php.net/manual/en/book.intl.php PHP intl] pentru normalizarea Unicode.",
+ "config-unicode-pure-php-warning": "<strong>Atenție:</strong> Extensia [https://php.net/manual/en/book.intl.php PHP intl] nu este disponibilă pentru a procesa normalizarea Unicode, se folosește o implementare lentă pur PHP.\nDacă rulați un site cu trafic ridicat, ar trebui să citiți despre [https://www.mediawiki.org/wiki/Special:MyLanguage/Unicode_normalization_considerations Normalizarea Unicode].",
"config-unicode-update-warning": "<strong>Avertisment:</strong> Versiunea instalată a pachetului de normalizare Unicode utilizează o versiune mai veche a bibliotecii [http://site.icu-project.org/ proiectul ICU].\nAr trebui să faceți upgrade [https://www.mediawiki.org/wiki/Special:MyLanguage/Unicode_normalization_considerations] dacă sunteți preocupat de utilizarea Unicode.",
"config-no-db": "Nu am găsit un driver de bază de date potrivit! Trebuie să instalați un driver de bază de date pentru PHP.\nUrmătoarea bază de date {{PLURAL:$2|tip este|tipuri sunt}} este acceptată: $1.\nDacă ați compilat singuri PHP, reconfigurați-l cu un client de bază de date activat, de exemplu, utilizând <code>./ configure --with-mysqli</code>.\nDacă ați instalat PHP dintr-un pachet Debian sau Ubuntu, atunci trebuie să instalați, de exemplu, pachetul <code>php-mysql</code>",
- "config-outdated-sqlite": "<strong>Atenție:</strong> ai SQLite $1, care este mai mic decât minimul necesar pentru versiunea $2. SQLite va fi nedisponibil.",
+ "config-outdated-sqlite": "<strong>Atenție:</strong> aveții SQLite $2, care este mai mic decât versiunea minimă $1. SQLite nu va fi disponibil.",
"config-no-fts3": "<strong>Atenție:</strong> SQLite este compus fără [//sqlite.org/fts3.html modulu FTS3], caută caracteristici care nu vor fi disponibile la finalul acesta.",
"config-pcre-old": "<strong>Fatal:</> PCRE $1 sau mai târziu este necesar este necesar. \nPHP tău este binar este legat de PCRE $2. \n[https://www.mediawiki.org/wiki/Manual:Errors_and_symptoms/PCRE Mai multe informații].",
"config-pcre-no-utf8": "<strong>Fatal:</strong> Modul PCRE al PHP pare să fie compilat fără suport PCRE_UTF8.\nMediaWiki necesită ca suportul UTF-8 să funcționeze corect.",
"config-admin-name": "Numele dumneavoastră de utilizator:",
"config-admin-password": "Parolă:",
"config-admin-password-confirm": "Parola, din nou:",
+ "config-admin-name-blank": "Introduceți numele de utilizator al administratorului.",
"config-admin-password-blank": "Introduceți o parolă pentru contul de administrator.",
"config-admin-password-mismatch": "Cele două parole introduse nu corespund.",
"config-admin-email": "Adresa de e-mail:",
"config-license-pd": "Domeniu public",
"config-license-cc-choose": "Alegeți o licență Creative Commons personalizată",
"config-email-settings": "Setări pentru e-mail",
+ "config-enable-email": "Permiteți trimiterea de e-mail",
+ "config-email-user": "Permiteți e-mailurile între utilizatori",
"config-email-usertalk": "Activați notificările pentru pagina de discuții a utilizatorului",
"config-upload-settings": "Încărcare de imagini și fișiere",
"config-upload-deleted": "Director pentru fișierele șterse:",
"config-memcached-servers": "Memcached-serveri:",
"config-memcached-help": "Lista IP adresa za uporabu u Memcached.\nTreba da se navede jednu u svaki red, kao i port što će se koristiti. Na primer:\n 127.0.0.1:11211\n 192.168.1.25:1234",
"config-memcache-needservers": "Odabrali ste Memcached kao vaš tip međuspremnika (keša), ali niste naveli nijedan server.",
- "mainpagetext": "<strong>MediaWiki je uspješno instaliran.</strong>",
+ "config-install-step-done": "gotovo",
+ "config-install-step-failed": "nije uspjelo",
+ "config-install-extensions": "Uključujem dodatke",
+ "config-install-database": "Postavljam bazu podataka",
+ "config-install-schema": "Pravim šemu",
+ "config-install-pg-schema-not-exist": "PostgreSQL-šema ne postoji.",
+ "config-install-pg-schema-failed": "Pravljenje natabela nije uspelo.\nUvjerite se da korisnik „$1” može da zapisuje u šemi „$2”.",
+ "config-install-pg-commit": "Usproveđivanje promjena",
+ "config-install-user": "Pravim korisnika baze podataka",
+ "config-install-user-alreadyexists": "Korisnik \"$1\" već postoji",
+ "config-install-user-create-failed": "Pravljenje korisnika \"$1\" nije uspjelo: $2",
+ "config-install-user-grant-failed": "Dodjeljivanje dozvola korisniku \"$1\" nije uspjelo: $2",
+ "config-install-user-missing": "Navedeni korisnik \"$1\" ne postoji.",
+ "config-install-user-missing-create": "Navedeni korisnik \"$1\" ne postoji.\nAko želite da ga otvorite, štiklirajte mogućnost „napravi račun”.",
+ "config-install-tables": "Pravim tabele",
+ "config-install-tables-exist": "<strong>Upozorenje:</strong> Izgleda da MediaWiki tabele već postoje.\nPreskočim pravljenje.",
+ "config-install-tables-failed": "<strong>Greška:</strong> Pravljenje tabele nije uspjelo zbog sljedeće greške: $1",
+ "config-install-interwiki": "Popunjavam predodređene međuprojektne tabele",
+ "config-install-interwiki-list": "Nisam mogao pronaći datoteku <code>interwiki.list</code>.",
+ "config-install-interwiki-exists": "<strong>Upozorenje:</strong> Tabela međuwikija već ima unose.\nPreskočim podrazumevano-zadanu listu.",
+ "config-install-stats": "Pokrećem statistiku",
+ "config-install-keys": "Generisanje tajnih ključeva",
+ "config-install-updates": "Spriječi vršenje nepotrebnih podnova",
+ "config-install-updates-failed": "<strong>Greška:</strong> Umetanje podnovnih klučeva u tabele nije uspjelo, zbog sljedeće greške: $1",
+ "config-install-sysop": "Otvaranje korisničkog računa administratora",
+ "config-install-subscribe-fail": "Nije moguće Vas pretplatiti se na izvješćenje mediawiki-announce: $1",
+ "config-install-subscribe-notpossible": "cURL nije instaliran, a <code>allow_url_fopen</code> nije dostupno.",
+ "config-install-mainpage": "Pravim početnu stranicu sa standardnim sadržajem",
+ "config-install-mainpage-exists": "Početna strana već postoji. Prelazim na sljedeće.",
+ "config-install-extension-tables": "Izrada tabela za omogućene dodatke",
+ "config-install-mainpage-failed": "Nisam mogao umetnuti početnu stranu: $1",
+ "config-download-localsettings": "Preuzmi <code>LocalSettings.php</code>",
+ "config-help": "pomoć",
+ "config-help-tooltip": "kliknite da rasklopite",
+ "config-nofile": "Datoteka \"$1\" nije pronađena. Da nije obrisana?",
+ "config-skins-screenshots": "$1 (ekr. snimci: $2)",
+ "config-extensions-requires": "$1 (zahtjeva $2)",
+ "config-screenshot": "ekranski snimak",
+ "config-extension-not-found": "Nisam mogao naći datoteku registracije za dodatak „$1”",
+ "config-extension-dependency": "Naišao na grešku sa zavisnošću pri instaliranju dodatka „$1”: $2",
+ "mainpagetext": "<strong>MediaWiki je instaliran.</strong>",
"mainpagedocfooter": "Za informacije o korištenju wiki softvera konzultirajte [https://meta.wikimedia.org/wiki/Help:Contents Vodič za korisnike].\n\n== Uvod u rad ==\n* [https://www.mediawiki.org/wiki/Special:MyLanguage/Manual:Configuration_settings Lista konfiguracije postavki]\n* [https://www.mediawiki.org/wiki/Special:MyLanguage/Manual:FAQ MediaWiki FAQ]\n* [https://lists.wikimedia.org/mailman/listinfo/mediawiki-announce Lista primatelja izdanja MediaWikija]\n* [https://www.mediawiki.org/wiki/Special:MyLanguage/Localisation#Translation_resources Lokalizirajte MediaWiki za svoj jezik]\n* [https://www.mediawiki.org/wiki/Special:MyLanguage/Manual:Combating_spam Saznajte kako se boriti protiv spama na svojem wikiju]"
}
// When constructing this class for submitting to the queue,
// normalise the $title arg of old job classes as part of $params.
$params['namespace'] = $title->getNamespace();
- $params['title'] = $title->getDBKey();
+ $params['title'] = $title->getDBkey();
}
$this->command = $command;
if ( $dbw->getType() === 'mysql' ) {
// Per https://bugs.mysql.com/bug.php?id=6980, we can't use subqueries on the
// same table being changed in an UPDATE query in MySQL (gives Error: 1093).
- // Oracle and Postgre have no such limitation. However, MySQL offers an
+ // Postgres has no such limitation. However, MySQL offers an
// alternative here by supporting ORDER BY + LIMIT for UPDATE queries.
$dbw->query( "UPDATE {$dbw->tableName( 'job' )} " .
"SET " .
}
/**
- * @return JobQueue[]
+ * @return array[]
+ * @phan-return array<string,array{queue:JobQueue,types:array<string,class-string>}>
*/
protected function getCoalescedQueues() {
global $wgJobTypeConf;
] );
$this->debugCallback( $msg );
+ // Clear out title cache data from prior snapshots
+ // (e.g. from before JobRunner was invoked in this process)
+ MediaWikiServices::getInstance()->getLinkCache()->clear();
+
// Run the job...
$rssStart = $this->getMaxRssKb();
$jobStartTime = microtime( true );
try {
$fnameTrxOwner = get_class( $job ) . '::run'; // give run() outer scope
- if ( !$job->hasExecutionFlag( $job::JOB_NO_EXPLICIT_TRX_ROUND ) ) {
- $lbFactory->beginMasterChanges( $fnameTrxOwner );
+ // Flush any pending changes left over from an implicit transaction round
+ if ( $job->hasExecutionFlag( $job::JOB_NO_EXPLICIT_TRX_ROUND ) ) {
+ $lbFactory->commitMasterChanges( $fnameTrxOwner ); // new implicit round
+ } else {
+ $lbFactory->beginMasterChanges( $fnameTrxOwner ); // new explicit round
}
+ // Clear any stale REPEATABLE-READ snapshots from replica DB connections
+ $lbFactory->flushReplicaSnapshots( $fnameTrxOwner );
$status = $job->run();
$error = $job->getLastError();
+ // Commit all pending changes from this job
$this->commitMasterChanges( $lbFactory, $job, $fnameTrxOwner );
// Run any deferred update tasks; doUpdates() manages transactions itself
DeferredUpdates::doUpdates();
}
// Always attempt to call teardown() even if Job throws exception.
try {
- $job->teardown( $status );
+ $job->tearDown( $status );
} catch ( Exception $e ) {
MWExceptionHandler::logException( $e );
}
- // Commit all outstanding connections that are in a transaction
- // to get a fresh repeatable read snapshot on every connection.
- // Note that jobs are still responsible for handling replica DB lag.
- $lbFactory->flushReplicaSnapshots( __METHOD__ );
- // Clear out title cache data from prior snapshots
- MediaWikiServices::getInstance()->getLinkCache()->clear();
$timeMs = intval( ( microtime( true ) - $jobStartTime ) * 1000 );
$rssEnd = $this->getMaxRssKb();
// T203135 We don't wait for the request to complete, as this is mostly fire & forget.
// Looking at the HTTP status of requests that take less than 1s is a sanity check.
- $request = MWHttpRequest::factory( $thumbUrl,
+ $request = MediaWikiServices::getInstance()->getHttpRequestFactory()->create(
+ $thumbUrl,
[ 'method' => 'HEAD', 'followRedirects' => true, 'timeout' => 1 ],
__METHOD__
);
--- /dev/null
+<?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
+ * @ingroup Language
+ */
+
+/**
+ * Parser for rules of language conversion, parse rules in -{ }- tag.
+ * @ingroup Language
+ * @author fdcn <fdcn64@gmail.com>, PhiLiP <philip.npc@gmail.com>
+ */
+class ConverterRule {
+ public $mText; // original text in -{text}-
+ public $mConverter; // LanguageConverter object
+ public $mRuleDisplay = '';
+ public $mRuleTitle = false;
+ public $mRules = ''; // string : the text of the rules
+ public $mRulesAction = 'none';
+ public $mFlags = [];
+ public $mVariantFlags = [];
+ public $mConvTable = [];
+ public $mBidtable = []; // array of the translation in each variant
+ public $mUnidtable = []; // array of the translation in each variant
+
+ /**
+ * @param string $text The text between -{ and }-
+ * @param LanguageConverter $converter
+ */
+ public function __construct( $text, $converter ) {
+ $this->mText = $text;
+ $this->mConverter = $converter;
+ }
+
+ /**
+ * Check if variants array in convert array.
+ *
+ * @param array|string $variants Variant language code
+ * @return string 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->mFlags;
+ $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'] ) ) {
+ $flags = [ 'R' => true ];// remove other flags
+ } elseif ( isset( $flags['N'] ) ) {
+ $flags = [ 'N' => true ];// remove other flags
+ } elseif ( isset( $flags['-'] ) ) {
+ $flags = [ '-' => true ];// remove other flags
+ } 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->mVariants );
+ if ( $variantFlags ) {
+ $variantFlags = array_flip( $variantFlags );
+ $flags = [];
+ }
+ }
+ $this->mVariantFlags = $variantFlags;
+ $this->mRules = $text;
+ $this->mFlags = $flags;
+ }
+
+ /**
+ * Generate conversion table.
+ * @private
+ */
+ function parseRules() {
+ $rules = $this->mRules;
+ $bidtable = [];
+ $unidtable = [];
+ $variants = $this->mConverter->mVariants;
+ $varsep_pattern = $this->mConverter->getVarSeparatorPattern();
+
+ // Split according to $varsep_pattern, but ignore semicolons from HTML entities
+ $rules = preg_replace( '/(&[#a-zA-Z0-9]+);/', "$1\x01", $rules );
+ $choice = preg_split( $varsep_pattern, $rules );
+ $choice = str_replace( "\x01", ';', $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->mVariantNames[$vv] ) ) {
+ $bidtable = [];
+ $unidtable = [];
+ break;
+ }
+ }
+ $this->mBidtable = $bidtable;
+ $this->mUnidtable = $unidtable;
+ }
+
+ /**
+ * @private
+ *
+ * @return string
+ */
+ function getRulesDesc() {
+ $codesep = $this->mConverter->mDescCodeSep;
+ $varsep = $this->mConverter->mDescVarSep;
+ $text = '';
+ foreach ( $this->mBidtable as $k => $v ) {
+ $text .= $this->mConverter->mVariantNames[$k] . "$codesep$v$varsep";
+ }
+ foreach ( $this->mUnidtable as $k => $a ) {
+ foreach ( $a as $from => $to ) {
+ $text .= $from . '⇒' . $this->mConverter->mVariantNames[$k] .
+ "$codesep$to$varsep";
+ }
+ }
+ return $text;
+ }
+
+ /**
+ * Parse rules conversion.
+ * @private
+ *
+ * @param string $variant
+ *
+ * @return string
+ */
+ function getRuleConvertedStr( $variant ) {
+ $bidtable = $this->mBidtable;
+ $unidtable = $this->mUnidtable;
+
+ if ( count( $bidtable ) + count( $unidtable ) == 0 ) {
+ return $this->mRules;
+ } else {
+ // 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->mManualLevel[$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 original
+ * page title if $variant === $this->mConverter->mMainLanguageCode
+ * 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|bool The converted title or false if just page name
+ */
+ function getRuleConvertedTitle( $variant ) {
+ if ( $variant === $this->mConverter->mMainLanguageCode ) {
+ // 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;
+ } else {
+ 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->mManualLevel;
+
+ $vmarked = [];
+ foreach ( $this->mConverter->mVariants 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 current variant no 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::removeHTMLtags
+ $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 text in -{A/H/-|text}- is non-empty but without rules
+ if ( $rules !== '' ) {
+ foreach ( $this->mConverter->mVariants 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->mVariantNames[$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
+ */
+ public function getTitle() {
+ return $this->mRuleTitle;
+ }
+
+ /**
+ * Return how 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;
+ }
+}
/**
* Methods for dealing with language codes.
+ * @todo Move some of the code-related static methods out of Language into this class
*
* @since 1.29
* @ingroup Language
+++ /dev/null
-<?php
-/**
- * Internationalisation code.
- * See https://www.mediawiki.org/wiki/Special:MyLanguage/Localisation for more information.
- *
- * 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
- * @ingroup Language
- */
-
-/**
- * @defgroup Language Language
- */
-
-namespace MediaWiki\Languages;
-
-use HashBagOStuff;
-use Hooks;
-use MediaWiki\Config\ServiceOptions;
-use MediaWikiTitleCodec;
-use MWException;
-use Wikimedia\Assert\Assert;
-
-/**
- * @ingroup Language
- *
- * A service that provides utilities to do with language names and codes.
- *
- * @since 1.34
- */
-class LanguageNameUtils {
- /**
- * Return autonyms in getLanguageName(s).
- */
- const AUTONYMS = null;
-
- /**
- * Return all known languages in getLanguageName(s).
- */
- const ALL = 'all';
-
- /**
- * Return in getLanguageName(s) only the languages that are defined by MediaWiki.
- */
- const DEFINED = 'mw';
-
- /**
- * Return in getLanguageName(s) only the languages for which we have at least some localisation.
- */
- const SUPPORTED = 'mwfile';
-
- /** @var ServiceOptions */
- private $options;
-
- /**
- * Cache for language names
- * @var HashBagOStuff|null
- */
- private $languageNameCache;
-
- /**
- * Cache for validity of language codes
- * @var array
- */
- private $validCodeCache = [];
-
- public static $constructorOptions = [
- 'ExtraLanguageNames',
- 'UsePigLatinVariant',
- ];
-
- /**
- * @param ServiceOptions $options
- */
- public function __construct( ServiceOptions $options ) {
- $options->assertRequiredOptions( self::$constructorOptions );
- $this->options = $options;
- }
-
- /**
- * Checks whether any localisation is available for that language tag in MediaWiki
- * (MessagesXx.php or xx.json exists).
- *
- * @param string $code Language tag (in lower case)
- * @return bool Whether language is supported
- */
- public function isSupportedLanguage( $code ) {
- if ( !$this->isValidBuiltInCode( $code ) ) {
- return false;
- }
-
- if ( $code === 'qqq' ) {
- // Special code for internal use, not supported even though there is a qqq.json
- return false;
- }
-
- return is_readable( $this->getMessagesFileName( $code ) ) ||
- is_readable( $this->getJsonMessagesFileName( $code ) );
- }
-
- /**
- * Returns true if a language code string is of a valid form, whether or not it exists. This
- * includes codes which are used solely for customisation via the MediaWiki namespace.
- *
- * @param string $code
- *
- * @return bool
- */
- public function isValidCode( $code ) {
- Assert::parameterType( 'string', $code, '$code' );
- if ( !isset( $this->validCodeCache[$code] ) ) {
- // People think language codes are HTML-safe, so enforce it. Ideally we should only
- // allow a-zA-Z0-9- but .+ and other chars are often used for {{int:}} hacks. See bugs
- // T39564, T39587, T38938.
- $this->validCodeCache[$code] =
- // Protect against path traversal
- strcspn( $code, ":/\\\000&<>'\"" ) === strlen( $code ) &&
- !preg_match( MediaWikiTitleCodec::getTitleInvalidRegex(), $code );
- }
- return $this->validCodeCache[$code];
- }
-
- /**
- * Returns true if a language code is of a valid form for the purposes of internal customisation
- * of MediaWiki, via Messages*.php or *.json.
- *
- * @param string $code
- * @return bool
- */
- public function isValidBuiltInCode( $code ) {
- Assert::parameterType( 'string', $code, '$code' );
-
- return (bool)preg_match( '/^[a-z0-9-]{2,}$/', $code );
- }
-
- /**
- * Returns true if a language code is an IETF tag known to MediaWiki.
- *
- * @param string $tag
- *
- * @return bool
- */
- public function isKnownLanguageTag( $tag ) {
- // Quick escape for invalid input to avoid exceptions down the line when code tries to
- // process tags which are not valid at all.
- if ( !$this->isValidBuiltInCode( $tag ) ) {
- return false;
- }
-
- if ( isset( Data\Names::$names[$tag] ) || $this->getLanguageName( $tag, $tag ) !== '' ) {
- return true;
- }
-
- return false;
- }
-
- /**
- * Get an array of language names, indexed by code.
- * @param null|string $inLanguage Code of language in which to return the names
- * Use self::AUTONYMS for autonyms (native names)
- * @param string $include One of:
- * self::ALL all available languages
- * self::DEFINED only if the language is defined in MediaWiki or wgExtraLanguageNames
- * (default)
- * self::SUPPORTED only if the language is in self::DEFINED *and* has a message file
- * @return array Language code => language name (sorted by key)
- */
- public function getLanguageNames( $inLanguage = self::AUTONYMS, $include = self::DEFINED ) {
- $cacheKey = $inLanguage === self::AUTONYMS ? 'null' : $inLanguage;
- $cacheKey .= ":$include";
- if ( !$this->languageNameCache ) {
- $this->languageNameCache = new HashBagOStuff( [ 'maxKeys' => 20 ] );
- }
-
- $ret = $this->languageNameCache->get( $cacheKey );
- if ( !$ret ) {
- $ret = $this->getLanguageNamesUncached( $inLanguage, $include );
- $this->languageNameCache->set( $cacheKey, $ret );
- }
- return $ret;
- }
-
- /**
- * Uncached helper for getLanguageNames
- * @param null|string $inLanguage As getLanguageNames
- * @param string $include As getLanguageNames
- * @return array Language code => language name (sorted by key)
- */
- private function getLanguageNamesUncached( $inLanguage, $include ) {
- // If passed an invalid language code to use, fallback to en
- if ( $inLanguage !== self::AUTONYMS && !$this->isValidCode( $inLanguage ) ) {
- $inLanguage = 'en';
- }
-
- $names = [];
-
- if ( $inLanguage !== self::AUTONYMS ) {
- # TODO: also include for self::AUTONYMS, when this code is more efficient
- Hooks::run( 'LanguageGetTranslatedLanguageNames', [ &$names, $inLanguage ] );
- }
-
- $mwNames = $this->options->get( 'ExtraLanguageNames' ) + Data\Names::$names;
- if ( $this->options->get( 'UsePigLatinVariant' ) ) {
- // Pig Latin (for variant development)
- $mwNames['en-x-piglatin'] = 'Igpay Atinlay';
- }
-
- foreach ( $mwNames as $mwCode => $mwName ) {
- # - Prefer own MediaWiki native name when not using the hook
- # - For other names just add if not added through the hook
- if ( $mwCode === $inLanguage || !isset( $names[$mwCode] ) ) {
- $names[$mwCode] = $mwName;
- }
- }
-
- if ( $include === self::ALL ) {
- ksort( $names );
- return $names;
- }
-
- $returnMw = [];
- $coreCodes = array_keys( $mwNames );
- foreach ( $coreCodes as $coreCode ) {
- $returnMw[$coreCode] = $names[$coreCode];
- }
-
- if ( $include === self::SUPPORTED ) {
- $namesMwFile = [];
- # We do this using a foreach over the codes instead of a directory loop so that messages
- # files in extensions will work correctly.
- foreach ( $returnMw as $code => $value ) {
- if ( is_readable( $this->getMessagesFileName( $code ) ) ||
- is_readable( $this->getJsonMessagesFileName( $code ) )
- ) {
- $namesMwFile[$code] = $names[$code];
- }
- }
-
- ksort( $namesMwFile );
- return $namesMwFile;
- }
-
- ksort( $returnMw );
- # self::DEFINED option; default if it's not one of the other two options
- # (self::ALL/self::SUPPORTED)
- return $returnMw;
- }
-
- /**
- * @param string $code The code of the language for which to get the name
- * @param null|string $inLanguage Code of language in which to return the name (self::AUTONYMS
- * for autonyms)
- * @param string $include See getLanguageNames(), except this defaults to self::ALL instead of
- * self::DEFINED
- * @return string Language name or empty
- * @since 1.20
- */
- public function getLanguageName( $code, $inLanguage = self::AUTONYMS, $include = self::ALL ) {
- $code = strtolower( $code );
- $array = $this->getLanguageNames( $inLanguage, $include );
- return $array[$code] ?? '';
- }
-
- /**
- * Get the name of a file for a certain language code
- * @param string $prefix Prepend this to the filename
- * @param string $code Language code
- * @param string $suffix Append this to the filename
- * @throws MWException
- * @return string $prefix . $mangledCode . $suffix
- */
- public function getFileName( $prefix, $code, $suffix = '.php' ) {
- if ( !$this->isValidBuiltInCode( $code ) ) {
- throw new MWException( "Invalid language code \"$code\"" );
- }
-
- return $prefix . str_replace( '-', '_', ucfirst( $code ) ) . $suffix;
- }
-
- /**
- * @param string $code
- * @return string
- */
- public function getMessagesFileName( $code ) {
- global $IP;
- $file = $this->getFileName( "$IP/languages/messages/Messages", $code, '.php' );
- Hooks::run( 'Language::getMessagesFileName', [ $code, &$file ] );
- return $file;
- }
-
- /**
- * @param string $code
- * @return string
- * @throws MWException
- */
- public function getJsonMessagesFileName( $code ) {
- global $IP;
-
- if ( !$this->isValidBuiltInCode( $code ) ) {
- throw new MWException( "Invalid language code \"$code\"" );
- }
-
- return "$IP/languages/i18n/$code.json";
- }
-}
* @see https://www.mediawiki.org/wiki/Localisation
*
* @since 1.17
+ * @phan-file-suppress PhanCommentParamOnEmptyParamList Cannot make variadic due to HHVM bug,
+ * T191668#5263929
*/
class Message implements MessageSpecifier, Serializable {
/** Use message text as-is */
*
* @param string|string[]|MessageSpecifier $key
* @param mixed $param,... Parameters as strings.
+ * @suppress PhanCommentParamWithoutRealParam HHVM bug T228695#5450847
*
* @return Message
*/
* @param string|string[]|MessageSpecifier $key Message key, or array of keys,
* or a MessageSpecifier.
* @param mixed $params,... Normal message parameters
+ * @suppress PhanCommentParamWithoutRealParam HHVM bug T228695#5450847
* @return Message
*/
public function msg( $key /*...*/ );
}
/**
- * @return string
+ * @return void
*/
public function next() {
if ( $this->endPos === false ) {
}
}
$this->refreshCurrent();
-
- return $this->current;
}
/**
* @param string $serialization
*
* @return array
+ * @suppress PhanParamSignatureMismatchInternal The stub appears to be wrong
*/
public function unserialize( $serialization ) {
$serializationData = unserialize( $serialization );
/** @var int[] Map of (location => UNIX timestamp) */
protected $ejectExpiryByLocation;
- /** @var array[] Non-empty list of (float, node name, location name) */
+ /** @var array[] Non-empty position-ordered list of (position, location name) */
protected $baseRing;
- /** @var array[] Non-empty list of (float, node name, location name) */
+ /** @var array[] Non-empty position-ordered list of (position, location name) */
protected $liveRing;
/** @var float Number of positions on the ring */
$this->algo = $algo;
$this->weightByLocation = $weightByLocation;
$this->ejectExpiryByLocation = $ejections;
- $this->baseRing = $this->buildLocationRing( $this->weightByLocation, $this->algo );
+ $this->baseRing = $this->buildLocationRing( $this->weightByLocation );
}
/**
}
/**
- * Get the location of an item on the ring, as well as the next locations
+ * Get the location of an item on the ring followed by the next ring locations
*
* @param string $item
* @param int $limit Maximum number of locations to return
* @param int $from One of the RING_* class constants
* @return string[] List of locations
+ * @throws InvalidArgumentException
* @throws UnexpectedValueException
*/
public function getLocations( $item, $limit, $from = self::RING_ALL ) {
throw new InvalidArgumentException( "Invalid ring source specified." );
}
- // Locate this item's position on the hash ring
- $position = $this->getItemPosition( $item );
- $itemNodeIndex = $this->findNodeIndexForPosition( $position, $ring );
+ // Short-circuit for the common single-location case. Note that if there was only one
+ // location and it was ejected from the live ring, getLiveRing() would have error out.
+ if ( count( $this->weightByLocation ) == 1 ) {
+ return ( $limit > 0 ) ? [ $ring[0][self::KEY_LOCATION] ] : [];
+ }
+
+ // Locate the node index for this item's position on the hash ring
+ $itemIndex = $this->findNodeIndexForPosition( $this->getItemPosition( $item ), $ring );
$locations = [];
- $currentIndex = $itemNodeIndex;
+ $currentIndex = null;
while ( count( $locations ) < $limit ) {
+ if ( $currentIndex === null ) {
+ $currentIndex = $itemIndex;
+ } else {
+ $currentIndex = $this->getNextClockwiseNodeIndex( $currentIndex, $ring );
+ if ( $currentIndex === $itemIndex ) {
+ break; // all nodes visited
+ }
+ }
$nodeLocation = $ring[$currentIndex][self::KEY_LOCATION];
if ( !in_array( $nodeLocation, $locations, true ) ) {
// Ignore other nodes for the same locations already added
$locations[] = $nodeLocation;
}
- $currentIndex = $this->getNextClockwiseNodeIndex( $currentIndex, $ring );
- if ( $currentIndex === $itemNodeIndex ) {
- break; // all nodes visited
- }
}
return $locations;
if ( $count === 0 ) {
return null;
}
+
+ $index = null;
$lowPos = 0;
$highPos = $count;
while ( true ) {
- $midPos = intval( ( $lowPos + $highPos ) / 2 );
+ $midPos = (int)( ( $lowPos + $highPos ) / 2 );
if ( $midPos === $count ) {
- return 0;
+ $index = 0;
+ break;
}
- $midVal = $ring[$midPos][self::KEY_POS];
- $midMinusOneVal = $midPos === 0 ? 0 : $ring[$midPos - 1][self::KEY_POS];
+ $midVal = $ring[$midPos][self::KEY_POS];
+ $midMinusOneVal = ( $midPos === 0 ) ? 0 : $ring[$midPos - 1][self::KEY_POS];
if ( $position <= $midVal && $position > $midMinusOneVal ) {
- return $midPos;
+ $index = $midPos;
+ break;
}
if ( $midVal < $position ) {
}
if ( $lowPos > $highPos ) {
- return 0;
+ $index = 0;
+ break;
}
}
+
+ return $index;
}
/**
/**
* @param int[] $weightByLocation
- * @param string $algo Hashing algorithm
* @return array[]
*/
- private function buildLocationRing( array $weightByLocation, $algo ) {
+ private function buildLocationRing( array $weightByLocation ) {
$locationCount = count( $weightByLocation );
$totalWeight = array_sum( $weightByLocation );
throw new UnexpectedValueException( __METHOD__ . ": {$this->algo} is < 32 bits." );
}
- return (float)sprintf( '%u', unpack( 'V', $octets )[1] );
+ $pos = unpack( 'V', $octets )[1];
+ if ( $pos < 0 ) {
+ // Most-significant-bit is set, causing unpack() to return a negative integer due
+ // to the fact that it returns a signed int. Cast it to an unsigned integer string.
+ $pos = sprintf( '%u', $pos );
+ }
+
+ return (float)$pos;
}
/**
// int64
// pack() does not support 64-bit ints either so pack into two 32-bits
$p1 = pack( 'l', $value & 0xFFFFFFFF );
+ // @phan-suppress-next-line PhanTypeInvalidLeftOperandOfIntegerOp
$p2 = pack( 'l', ( $value >> 32 ) & 0xFFFFFFFF );
return self::$bigendian
? pack( 'Ca4a4', 0xD3, $p1, $p2 )
* the base iterator (post-callback) and will return true if that value should be
* included in iteration of the MappedIterator (otherwise it will be filtered out).
*
- * @param Iterator|Array $iter
+ * @param Iterator|array $iter
* @param callable $vCallback Value transformation callback
* @param array $options Options map (includes "accept") (since 1.22)
+ * @phan-param array{accept?:callable} $options
* @throws UnexpectedValueException
*/
public function __construct( $iter, $vCallback, array $options = [] ) {
}
parent::__construct( $baseIterator );
$this->vCallback = $vCallback;
+ // @phan-suppress-next-line PhanTypeInvalidDimOffset
$this->aCallback = $options['accept'] ?? null;
}
--- /dev/null
+<?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;
+}
--- /dev/null
+<?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 );
+}
--- /dev/null
+<?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}>";
+ }
+}
--- /dev/null
+<?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';
+}
--- /dev/null
+<?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();
+}
--- /dev/null
+<?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>';
+ }
+}
--- /dev/null
+<?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';
+}
--- /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}>";
+ }
+}
if ( self::isEnabled() ) {
throw new Exception( 'Profiling is already enabled.' );
}
+
+ $args = [ $flags ];
+ if ( $options ) {
+ $args[] = $options;
+ }
+
self::$enabled = true;
self::callAny(
[
'tideways_enable',
'tideways_xhprof_enable'
],
- [ $flags, $options ]
+ $args
);
}
/**
* Per-function inclusive data.
- * @var array $inclusive
+ * @var array[] $inclusive
*/
protected $inclusive;
/**
* Per-function inclusive and exclusive data.
- * @var array $complete
+ * @var array[] $complete
*/
protected $complete;
* - max: Maximum value
* - variance: Variance (spread) of the values
*
- * @return array
+ * @return array[]
* @see getRawData()
* @see getCompleteMetrics()
*/
* metrics have an additional 'exclusive' measurement which is the total
* minus the totals of all child function calls.
*
- * @return array
+ * @return array[]
* @see getRawData()
* @see getInclusiveMetrics()
*/
} elseif ( !$hadError ) {
return false; // file does not exist
} else {
- return null; // failure
+ return self::UNKNOWN; // failure
}
}
$exists = is_dir( $dir );
$hadError = $this->untrapWarnings();
- return $hadError ? null : $exists;
+ return $hadError ? self::UNKNOWN : $exists;
}
/**
} elseif ( !is_readable( $dir ) ) {
$this->logger->warning( __METHOD__ . "() given directory is unreadable: '$dir'\n" );
- return null; // bad permissions?
+ return self::UNKNOWN; // bad permissions?
}
return new FSFileBackendDirList( $dir, $params );
} elseif ( !is_readable( $dir ) ) {
$this->logger->warning( __METHOD__ . "() given directory is unreadable: '$dir'\n" );
- return null; // bad permissions?
+ return self::UNKNOWN; // bad permissions?
}
return new FSFileBackendFileList( $dir, $params );
const ATTR_METADATA = 2; // files can be stored with metadata key/values
const ATTR_UNICODE_PATHS = 4; // files can have Unicode paths (not just ASCII)
+ /** @var null Idiom for "could not determine due to I/O errors" */
+ const UNKNOWN = null;
+
/**
* Create a new backend instance from configuration.
* This should only be called from within FileBackendGroup.
}
/**
- * Get the unique backend name.
+ * Get the unique backend name
+ *
* We may have multiple different backends of the same type.
* For example, we can have two Swift backends using different proxies.
*
/**
* Alias to getDomainId()
+ *
* @return string
* @since 1.20
* @deprecated Since 1.34 Use getDomainId()
* - b) predicted operation errors occurred and 'force' was not set
*
* @param array $ops List of operations to execute in order
+ * @codingStandardsIgnoreStart
+ * @phan-param array{ignoreMissingSource?:bool,overwrite?:bool,overwriteSame?:bool,headers?:bool} $ops
* @param array $opts Batch operation options
+ * @phan-param array{force?:bool,nonLocking?:bool,nonJournaled?:bool,parallelize?:bool,bypassReadOnly?:bool,preserveCache?:bool} $opts
+ * @codingStandardsIgnoreEnd
* @return StatusValue
*/
final public function doOperations( array $ops, array $opts = [] ) {
* considered "OK" as long as no fatal errors occurred.
*
* @param array $ops Set of operations to execute
+ * @phan-param array{ignoreMissingSource?:bool,headers?:bool} $ops
* @param array $opts Batch operation options
+ * @phan-param array{bypassReadOnly?:bool} $opts
* @return StatusValue
* @since 1.20
*/
abstract public function getFileHttpUrl( array $params );
/**
- * Check if a directory exists at a given storage path.
- * Backends using key/value stores will check if the path is a
- * virtual directory, meaning there are files under the given directory.
+ * Check if a directory exists at a given storage path
+ *
+ * For backends using key/value stores, a directory is said to exist whenever
+ * there exist any files with paths using the given directory path as a prefix
+ * followed by a forward slash. For example, if there is a file called
+ * "mwstore://backend/container/dir/path.svg" then directories are said to exist
+ * at "mwstore://backend/container" and "mwstore://backend/container/dir". These
+ * can be thought of as "virtual" directories.
+ *
+ * Backends that directly use a filesystem layer might enumerate empty directories.
+ * The clean() method should always be used when files are deleted or moved if this
+ * is a concern. This is a trade-off to avoid write amplication/contention on file
+ * changes or read amplification when calling this method.
*
* Storage backends with eventual consistency might return stale data.
*
+ * @see FileBackend::clean()
+ *
* @param array $params Parameters include:
* - dir : storage directory
- * @return bool|null Returns null on failure
+ * @return bool|null Whether a directory exists or null on failure
* @since 1.20
*/
abstract public function directoryExists( array $params );
/**
- * Get an iterator to list *all* directories under a storage directory.
+ * Get an iterator to list *all* directories under a storage directory
+ *
* If the directory is of the form "mwstore://backend/container",
* then all directories in the container will be listed.
* If the directory is of form "mwstore://backend/container/dir",
*
* Failures during iteration can result in FileBackendError exceptions (since 1.22).
*
+ * @see FileBackend::directoryExists()
+ *
* @param array $params Parameters include:
* - dir : storage directory
* - topOnly : only return direct child dirs of the directory
- * @return Traversable|array|null Returns null on failure
+ * @return Traversable|array|null Directory list enumerator null on failure
* @since 1.20
*/
abstract public function getDirectoryList( array $params );
*
* Failures during iteration can result in FileBackendError exceptions (since 1.22).
*
+ * @see FileBackend::directoryExists()
+ *
* @param array $params Parameters include:
* - dir : storage directory
- * @return Traversable|array|null Returns null on failure
+ * @return Traversable|array|null Directory list enumerator or null on failure
* @since 1.20
*/
final public function getTopDirectoryList( array $params ) {
}
/**
- * Get an iterator to list *all* stored files under a storage directory.
- * If the directory is of the form "mwstore://backend/container",
- * then all files in the container will be listed.
- * If the directory is of form "mwstore://backend/container/dir",
- * then all files under that directory will be listed.
- * Results will be storage paths relative to the given directory.
+ * Get an iterator to list *all* stored files under a storage directory
+ *
+ * If the directory is of the form "mwstore://backend/container", then all
+ * files in the container will be listed. If the directory is of form
+ * "mwstore://backend/container/dir", then all files under that directory will
+ * be listed. Results will be storage paths relative to the given directory.
*
* Storage backends with eventual consistency might return stale data.
*
* - dir : storage directory
* - topOnly : only return direct child files of the directory (since 1.20)
* - adviseStat : set to true if stat requests will be made on the files (since 1.22)
- * @return Traversable|array|null Returns null on failure
+ * @return Traversable|array|null File list enumerator or null on failure
*/
abstract public function getFileList( array $params );
* @param array $params Parameters include:
* - dir : storage directory
* - adviseStat : set to true if stat requests will be made on the files (since 1.22)
- * @return Traversable|array|null Returns null on failure
+ * @return Traversable|array|null File list enumerator or null on failure
* @since 1.20
*/
final public function getTopFileList( array $params ) {
* @param array $params Parameters include:
* - srcs : list of source storage paths
* - latest : use the latest available data
- * @return bool All requests proceeded without I/O errors (since 1.24)
+ * @return bool Whether all requests proceeded without I/O errors (since 1.24)
* @since 1.23
*/
abstract public function preloadFileStat( array $params );
*
* @param string $type One of (attachment, inline)
* @param string $filename Suggested file name (should not contain slashes)
- * @throws FileBackendError
+ * @throws InvalidArgumentException
* @return string
* @since 1.20
*/
* @ingroup FileBackend
*/
+use Wikimedia\Timestamp\ConvertibleTimestamp;
+
/**
* @brief Proxy backend that mirrors writes to several internal backends.
*
/** @var bool */
protected $asyncWrites = false;
- /* Possible internal backend consistency checks */
+ /** @var int Compare file sizes among backends */
const CHECK_SIZE = 1;
+ /** @var int Compare file mtimes among backends */
const CHECK_TIME = 2;
+ /** @var int Compare file hashes among backends */
const CHECK_SHA1 = 4;
/**
$mbe = $this->backends[$this->masterIndex]; // convenience
- // Try to lock those files for the scope of this function...
- $scopeLock = null;
+ // Acquire any locks as needed
if ( empty( $opts['nonLocking'] ) ) {
- // Try to lock those files for the scope of this function...
/** @noinspection PhpUnusedLocalVariableInspection */
$scopeLock = $this->getScopedLocksForOps( $ops, $status );
if ( !$status->isOK() ) {
// Clear any cache entries (after locks acquired)
$this->clearCache();
$opts['preserveCache'] = true; // only locked files are cached
- // Get the list of paths to read/write...
+ // Get the list of paths to read/write
$relevantPaths = $this->fileStoragePathsForOps( $ops );
- // Check if the paths are valid and accessible on all backends...
+ // Check if the paths are valid and accessible on all backends
$status->merge( $this->accessibilityCheck( $relevantPaths ) );
if ( !$status->isOK() ) {
return $status; // abort
}
- // Do a consistency check to see if the backends are consistent...
+ // Do a consistency check to see if the backends are consistent
$syncStatus = $this->consistencyCheck( $relevantPaths );
if ( !$syncStatus->isOK() ) {
- wfDebugLog( 'FileOperation', static::class .
- " failed sync check: " . FormatJson::encode( $relevantPaths ) );
- // Try to resync the clone backends to the master on the spot...
- if ( $this->autoResync === false
- || !$this->resyncFiles( $relevantPaths, $this->autoResync )->isOK()
+ $this->logger->error(
+ __METHOD__ . ": failed sync check: " . FormatJson::encode( $relevantPaths )
+ );
+ // Try to resync the clone backends to the master on the spot
+ if (
+ $this->autoResync === false ||
+ !$this->resyncFiles( $relevantPaths, $this->autoResync )->isOK()
) {
$status->merge( $syncStatus );
return $status; // abort
}
}
- // Actually attempt the operation batch on the master backend...
+ // Actually attempt the operation batch on the master backend
$realOps = $this->substOpBatchPaths( $ops, $mbe );
$masterStatus = $mbe->doOperations( $realOps, $opts );
$status->merge( $masterStatus );
// Bind $scopeLock to the callback to preserve locks
DeferredUpdates::addCallableUpdate(
function () use ( $backend, $realOps, $opts, $scopeLock, $relevantPaths ) {
- wfDebugLog( 'FileOperationReplication',
+ $this->logger->error(
"'{$backend->getName()}' async replication; paths: " .
- FormatJson::encode( $relevantPaths ) );
+ FormatJson::encode( $relevantPaths )
+ );
$backend->doOperations( $realOps, $opts );
}
);
} else {
- wfDebugLog( 'FileOperationReplication',
+ $this->logger->error(
"'{$backend->getName()}' sync replication; paths: " .
- FormatJson::encode( $relevantPaths ) );
+ FormatJson::encode( $relevantPaths )
+ );
$status->merge( $backend->doOperations( $realOps, $opts ) );
}
}
/**
* Check that a set of files are consistent across all internal backends
*
+ * This method should only be called if the files are locked or the backend
+ * is in read-only mode
+ *
* @param array $paths List of storage paths
* @return StatusValue
*/
return $status; // skip checks
}
- // Preload all of the stat info in as few round trips as possible...
+ // Preload all of the stat info in as few round trips as possible
foreach ( $this->backends as $backend ) {
$realPaths = $this->substPaths( $paths, $backend );
$backend->preloadFileStat( [ 'srcs' => $realPaths, 'latest' => true ] );
}
- $mBackend = $this->backends[$this->masterIndex];
foreach ( $paths as $path ) {
$params = [ 'src' => $path, 'latest' => true ];
- $mParams = $this->substOpPaths( $params, $mBackend );
- // Stat the file on the 'master' backend
- $mStat = $mBackend->getFileStat( $mParams );
+ // Get the state of the file on the master backend
+ $masterBackend = $this->backends[$this->masterIndex];
+ $masterParams = $this->substOpPaths( $params, $masterBackend );
+ $masterStat = $masterBackend->getFileStat( $masterParams );
+ if ( $masterStat === self::UNKNOWN ) {
+ $status->fatal( 'backend-fail-stat', $path );
+ continue;
+ }
if ( $this->syncChecks & self::CHECK_SHA1 ) {
- $mSha1 = $mBackend->getFileSha1Base36( $mParams );
+ $masterSha1 = $masterBackend->getFileSha1Base36( $masterParams );
+ if ( ( $masterSha1 !== false ) !== (bool)$masterStat ) {
+ $status->fatal( 'backend-fail-hash', $path );
+ continue;
+ }
} else {
- $mSha1 = false;
+ $masterSha1 = null; // unused
}
+
// Check if all clone backends agree with the master...
- foreach ( $this->backends as $index => $cBackend ) {
+ foreach ( $this->backends as $index => $cloneBackend ) {
if ( $index === $this->masterIndex ) {
continue; // master
}
- $cParams = $this->substOpPaths( $params, $cBackend );
- $cStat = $cBackend->getFileStat( $cParams );
- if ( $mStat ) { // file is in master
- if ( !$cStat ) { // file should exist
+
+ // Get the state of the file on the clone backend
+ $cloneParams = $this->substOpPaths( $params, $cloneBackend );
+ $cloneStat = $cloneBackend->getFileStat( $cloneParams );
+
+ if ( $masterStat ) {
+ // File exists in the master backend
+ if ( !$cloneStat ) {
+ // File is missing from the clone backend
$status->fatal( 'backend-fail-synced', $path );
- continue;
- }
- if ( ( $this->syncChecks & self::CHECK_SIZE )
- && $cStat['size'] != $mStat['size']
- ) { // wrong size
+ } elseif (
+ ( $this->syncChecks & self::CHECK_SIZE ) &&
+ $cloneStat['size'] !== $masterStat['size']
+ ) {
+ // File in the clone backend is different
$status->fatal( 'backend-fail-synced', $path );
- continue;
- }
- if ( $this->syncChecks & self::CHECK_TIME ) {
- $mTs = wfTimestamp( TS_UNIX, $mStat['mtime'] );
- $cTs = wfTimestamp( TS_UNIX, $cStat['mtime'] );
- if ( abs( $mTs - $cTs ) > 30 ) { // outdated file somewhere
- $status->fatal( 'backend-fail-synced', $path );
- continue;
- }
- }
- if (
+ } elseif (
+ ( $this->syncChecks & self::CHECK_TIME ) &&
+ abs(
+ ConvertibleTimestamp::convert( TS_UNIX, $masterStat['mtime'] ) -
+ ConvertibleTimestamp::convert( TS_UNIX, $cloneStat['mtime'] )
+ ) > 30
+ ) {
+ // File in the clone backend is significantly newer or older
+ $status->fatal( 'backend-fail-synced', $path );
+ } elseif (
( $this->syncChecks & self::CHECK_SHA1 ) &&
- $cBackend->getFileSha1Base36( $cParams ) !== $mSha1
- ) { // wrong SHA1
+ $cloneBackend->getFileSha1Base36( $cloneParams ) !== $masterSha1
+ ) {
+ // File in the clone backend is different
+ $status->fatal( 'backend-fail-synced', $path );
+ }
+ } else {
+ // File does not exist in the master backend
+ if ( $cloneStat ) {
+ // Stray file exists in the clone backend
$status->fatal( 'backend-fail-synced', $path );
- continue;
}
- } elseif ( $cStat ) { // file is not in master; file should not exist
- $status->fatal( 'backend-fail-synced', $path );
}
}
}
* Check that a set of files are consistent across all internal backends
* and re-synchronize those files against the "multi master" if needed.
*
+ * This method should only be called if the files are locked
+ *
* @param array $paths List of storage paths
* @param string|bool $resyncMode False, True, or "conservative"; see __construct()
* @return StatusValue
public function resyncFiles( array $paths, $resyncMode = true ) {
$status = $this->newStatus();
- $mBackend = $this->backends[$this->masterIndex];
+ $fname = __METHOD__;
foreach ( $paths as $path ) {
- $mPath = $this->substPaths( $path, $mBackend );
- $mSha1 = $mBackend->getFileSha1Base36( [ 'src' => $mPath, 'latest' => true ] );
- $mStat = $mBackend->getFileStat( [ 'src' => $mPath, 'latest' => true ] );
- if ( $mStat === null || ( $mSha1 !== false && !$mStat ) ) { // sanity
- $status->fatal( 'backend-fail-internal', $this->name );
- wfDebugLog( 'FileOperation', __METHOD__
- . ': File is not available on the master backend' );
- continue; // file is not available on the master backend...
+ $params = [ 'src' => $path, 'latest' => true ];
+ // Get the state of the file on the master backend
+ $masterBackend = $this->backends[$this->masterIndex];
+ $masterParams = $this->substOpPaths( $params, $masterBackend );
+ $masterPath = $masterParams['src'];
+ $masterStat = $masterBackend->getFileStat( $masterParams );
+ if ( $masterStat === self::UNKNOWN ) {
+ $status->fatal( 'backend-fail-stat', $path );
+ $this->logger->error( "$fname: file '$masterPath' is not available" );
+ continue;
+ }
+ $masterSha1 = $masterBackend->getFileSha1Base36( $masterParams );
+ if ( ( $masterSha1 !== false ) !== (bool)$masterStat ) {
+ $status->fatal( 'backend-fail-hash', $path );
+ $this->logger->error( "$fname: file '$masterPath' hash does not match stat" );
+ continue;
}
+
// Check of all clone backends agree with the master...
- foreach ( $this->backends as $index => $cBackend ) {
+ foreach ( $this->backends as $index => $cloneBackend ) {
if ( $index === $this->masterIndex ) {
continue; // master
}
- $cPath = $this->substPaths( $path, $cBackend );
- $cSha1 = $cBackend->getFileSha1Base36( [ 'src' => $cPath, 'latest' => true ] );
- $cStat = $cBackend->getFileStat( [ 'src' => $cPath, 'latest' => true ] );
- if ( $cStat === null || ( $cSha1 !== false && !$cStat ) ) { // sanity
- $status->fatal( 'backend-fail-internal', $cBackend->getName() );
- wfDebugLog( 'FileOperation', __METHOD__ .
- ': File is not available on the clone backend' );
- continue; // file is not available on the clone backend...
+
+ // Get the state of the file on the clone backend
+ $cloneParams = $this->substOpPaths( $params, $cloneBackend );
+ $clonePath = $cloneParams['src'];
+ $cloneStat = $cloneBackend->getFileStat( $cloneParams );
+ if ( $cloneStat === self::UNKNOWN ) {
+ $status->fatal( 'backend-fail-stat', $path );
+ $this->logger->error( "$fname: file '$clonePath' is not available" );
+ continue;
}
- if ( $mSha1 === $cSha1 ) {
- // already synced; nothing to do
- } elseif ( $mSha1 !== false ) { // file is in master
- if ( $resyncMode === 'conservative'
- && $cStat && $cStat['mtime'] > $mStat['mtime']
+ $cloneSha1 = $cloneBackend->getFileSha1Base36( $cloneParams );
+ if ( ( $cloneSha1 !== false ) !== (bool)$cloneStat ) {
+ $status->fatal( 'backend-fail-hash', $path );
+ $this->logger->error( "$fname: file '$clonePath' hash does not match stat" );
+ continue;
+ }
+
+ if ( $masterSha1 === $cloneSha1 ) {
+ // File is either the same in both backends or absent from both backends
+ $this->logger->debug( "$fname: file '$clonePath' matches '$masterPath'" );
+ } elseif ( $masterSha1 !== false ) {
+ // File is either missing from or different in the clone backend
+ if (
+ $resyncMode === 'conservative' &&
+ $cloneStat &&
+ $cloneStat['mtime'] > $masterStat['mtime']
) {
+ // Do not replace files with older ones; reduces the risk of data loss
$status->fatal( 'backend-fail-synced', $path );
- continue; // don't rollback data
+ } else {
+ // Copy the master backend file to the clone backend in overwrite mode
+ $fsFile = $masterBackend->getLocalReference( $masterParams );
+ $status->merge( $cloneBackend->quickStore( [
+ 'src' => $fsFile,
+ 'dst' => $clonePath
+ ] ) );
}
- $fsFile = $mBackend->getLocalReference(
- [ 'src' => $mPath, 'latest' => true ] );
- $status->merge( $cBackend->quickStore(
- [ 'src' => $fsFile->getPath(), 'dst' => $cPath ]
- ) );
- } elseif ( $mStat === false ) { // file is not in master
+ } elseif ( $masterStat === false ) {
+ // Stray file exists in the clone backend
if ( $resyncMode === 'conservative' ) {
+ // Do not delete stray files; reduces the risk of data loss
$status->fatal( 'backend-fail-synced', $path );
- continue; // don't delete data
+ } else {
+ // Delete the stay file from the clone backend
+ $status->merge( $cloneBackend->quickDelete( [ 'src' => $clonePath ] ) );
}
- $status->merge( $cBackend->quickDelete( [ 'src' => $cPath ] ) );
}
}
}
if ( !$status->isOK() ) {
- wfDebugLog( 'FileOperation', static::class .
- " failed to resync: " . FormatJson::encode( $paths ) );
+ $this->logger->error( "$fname: failed to resync: " . FormatJson::encode( $paths ) );
}
return $status;
protected function doQuickOperationsInternal( array $ops ) {
$status = $this->newStatus();
- // Do the operations on the master backend; setting StatusValue fields...
+ // Do the operations on the master backend; setting StatusValue fields
$realOps = $this->substOpBatchPaths( $ops, $this->backends[$this->masterIndex] );
$masterStatus = $this->backends[$this->masterIndex]->doQuickOperations( $realOps );
$status->merge( $masterStatus );
* @file
* @ingroup FileBackend
*/
+
use Wikimedia\AtEase\AtEase;
use Wikimedia\Timestamp\ConvertibleTimestamp;
* @return StatusValue
*/
final public function createInternal( array $params ) {
+ /** @noinspection PhpUnusedLocalVariableInspection */
$ps = $this->scopedProfileSection( __METHOD__ . "-{$this->name}" );
if ( strlen( $params['content'] ) > $this->maxFileSizeInternal() ) {
$status = $this->newStatus( 'backend-fail-maxsize',
* @return StatusValue
*/
final public function storeInternal( array $params ) {
+ /** @noinspection PhpUnusedLocalVariableInspection */
$ps = $this->scopedProfileSection( __METHOD__ . "-{$this->name}" );
if ( filesize( $params['src'] ) > $this->maxFileSizeInternal() ) {
$status = $this->newStatus( 'backend-fail-maxsize',
* @return StatusValue
*/
final public function copyInternal( array $params ) {
+ /** @noinspection PhpUnusedLocalVariableInspection */
$ps = $this->scopedProfileSection( __METHOD__ . "-{$this->name}" );
$status = $this->doCopyInternal( $params );
$this->clearCache( [ $params['dst'] ] );
* @return StatusValue
*/
final public function deleteInternal( array $params ) {
+ /** @noinspection PhpUnusedLocalVariableInspection */
$ps = $this->scopedProfileSection( __METHOD__ . "-{$this->name}" );
$status = $this->doDeleteInternal( $params );
$this->clearCache( [ $params['src'] ] );
* @return StatusValue
*/
final public function moveInternal( array $params ) {
+ /** @noinspection PhpUnusedLocalVariableInspection */
$ps = $this->scopedProfileSection( __METHOD__ . "-{$this->name}" );
$status = $this->doMoveInternal( $params );
$this->clearCache( [ $params['src'], $params['dst'] ] );
* @return StatusValue
*/
final public function describeInternal( array $params ) {
+ /** @noinspection PhpUnusedLocalVariableInspection */
$ps = $this->scopedProfileSection( __METHOD__ . "-{$this->name}" );
if ( count( $params['headers'] ) ) {
$status = $this->doDescribeInternal( $params );
}
final public function concatenate( array $params ) {
+ /** @noinspection PhpUnusedLocalVariableInspection */
$ps = $this->scopedProfileSection( __METHOD__ . "-{$this->name}" );
$status = $this->newStatus();
// Try to lock the source files for the scope of this function
+ /** @noinspection PhpUnusedLocalVariableInspection */
$scopeLockS = $this->getScopedFileLocks( $params['srcs'], LockManager::LOCK_UW, $status );
if ( $status->isOK() ) {
// Actually do the file concatenation...
}
final protected function doPrepare( array $params ) {
+ /** @noinspection PhpUnusedLocalVariableInspection */
$ps = $this->scopedProfileSection( __METHOD__ . "-{$this->name}" );
$status = $this->newStatus();
}
final protected function doSecure( array $params ) {
+ /** @noinspection PhpUnusedLocalVariableInspection */
$ps = $this->scopedProfileSection( __METHOD__ . "-{$this->name}" );
$status = $this->newStatus();
}
final protected function doPublish( array $params ) {
+ /** @noinspection PhpUnusedLocalVariableInspection */
$ps = $this->scopedProfileSection( __METHOD__ . "-{$this->name}" );
$status = $this->newStatus();
}
final protected function doClean( array $params ) {
+ /** @noinspection PhpUnusedLocalVariableInspection */
$ps = $this->scopedProfileSection( __METHOD__ . "-{$this->name}" );
$status = $this->newStatus();
// Attempt to lock this directory...
$filesLockEx = [ $params['dir'] ];
+ /** @noinspection PhpUnusedLocalVariableInspection */
$scopedLockE = $this->getScopedFileLocks( $filesLockEx, LockManager::LOCK_EX, $status );
if ( !$status->isOK() ) {
return $status; // abort
}
final public function fileExists( array $params ) {
+ /** @noinspection PhpUnusedLocalVariableInspection */
$ps = $this->scopedProfileSection( __METHOD__ . "-{$this->name}" );
$stat = $this->getFileStat( $params );
- return ( $stat === null ) ? null : (bool)$stat; // null => failure
+ return ( $stat === self::UNKNOWN ) ? self::UNKNOWN : (bool)$stat;
}
final public function getFileTimestamp( array $params ) {
+ /** @noinspection PhpUnusedLocalVariableInspection */
$ps = $this->scopedProfileSection( __METHOD__ . "-{$this->name}" );
$stat = $this->getFileStat( $params );
}
final public function getFileSize( array $params ) {
+ /** @noinspection PhpUnusedLocalVariableInspection */
$ps = $this->scopedProfileSection( __METHOD__ . "-{$this->name}" );
$stat = $this->getFileStat( $params );
if ( $path === null ) {
return false; // invalid storage path
}
+ /** @noinspection PhpUnusedLocalVariableInspection */
$ps = $this->scopedProfileSection( __METHOD__ . "-{$this->name}" );
$latest = !empty( $params['latest'] ); // use latest data?
// cache entries from mass object listings that do not include the SHA-1. In that
// case, loading the persistent stat cache will likely yield the SHA-1.
if (
- $stat === null ||
+ $stat === self::UNKNOWN ||
( $requireSHA1 && is_array( $stat ) && !isset( $stat['sha1'] ) )
) {
$this->primeFileCache( [ $path ] ); // check persistent cache
abstract protected function doGetFileStat( array $params );
public function getFileContentsMulti( array $params ) {
+ /** @noinspection PhpUnusedLocalVariableInspection */
$ps = $this->scopedProfileSection( __METHOD__ . "-{$this->name}" );
$params = $this->setConcurrencyFlags( $params );
if ( $path === null ) {
return false; // invalid storage path
}
+ /** @noinspection PhpUnusedLocalVariableInspection */
$ps = $this->scopedProfileSection( __METHOD__ . "-{$this->name}" );
$latest = !empty( $params['latest'] ); // use latest data?
if ( $this->cheapCache->hasField( $path, 'xattr', self::CACHE_TTL ) ) {
if ( $path === null ) {
return false; // invalid storage path
}
+ /** @noinspection PhpUnusedLocalVariableInspection */
$ps = $this->scopedProfileSection( __METHOD__ . "-{$this->name}" );
$latest = !empty( $params['latest'] ); // use latest data?
if ( $this->cheapCache->hasField( $path, 'sha1', self::CACHE_TTL ) ) {
}
final public function getFileProps( array $params ) {
+ /** @noinspection PhpUnusedLocalVariableInspection */
$ps = $this->scopedProfileSection( __METHOD__ . "-{$this->name}" );
$fsFile = $this->getLocalReference( $params );
$props = $fsFile ? $fsFile->getProps() : FSFile::placeholderProps();
}
final public function getLocalReferenceMulti( array $params ) {
+ /** @noinspection PhpUnusedLocalVariableInspection */
$ps = $this->scopedProfileSection( __METHOD__ . "-{$this->name}" );
$params = $this->setConcurrencyFlags( $params );
}
final public function getLocalCopyMulti( array $params ) {
+ /** @noinspection PhpUnusedLocalVariableInspection */
$ps = $this->scopedProfileSection( __METHOD__ . "-{$this->name}" );
$params = $this->setConcurrencyFlags( $params );
}
final public function streamFile( array $params ) {
+ /** @noinspection PhpUnusedLocalVariableInspection */
$ps = $this->scopedProfileSection( __METHOD__ . "-{$this->name}" );
$status = $this->newStatus();
$res = true;
break; // found one!
} elseif ( $exists === null ) { // error?
- $res = null; // if we don't find anything, it is indeterminate
+ $res = self::UNKNOWN; // if we don't find anything, it is indeterminate
}
}
final public function getDirectoryList( array $params ) {
list( $fullCont, $dir, $shard ) = $this->resolveStoragePath( $params['dir'] );
if ( $dir === null ) { // invalid storage path
- return null;
+ return self::UNKNOWN;
}
if ( $shard !== null ) {
// File listing is confined to a single container/shard
final public function getFileList( array $params ) {
list( $fullCont, $dir, $shard ) = $this->resolveStoragePath( $params['dir'] );
if ( $dir === null ) { // invalid storage path
- return null;
+ return self::UNKNOWN;
}
if ( $shard !== null ) {
// File listing is confined to a single container/shard
}
final protected function doOperationsInternal( array $ops, array $opts ) {
+ /** @noinspection PhpUnusedLocalVariableInspection */
$ps = $this->scopedProfileSection( __METHOD__ . "-{$this->name}" );
$status = $this->newStatus();
// Build up a list of files to lock...
$paths = $this->getPathsToLockForOpsInternal( $performOps );
// Try to lock those files for the scope of this function...
-
+ /** @noinspection PhpUnusedLocalVariableInspection */
$scopeLock = $this->getScopedFileLocks( $paths, 'mixed', $status );
if ( !$status->isOK() ) {
return $status; // abort
}
final protected function doQuickOperationsInternal( array $ops ) {
+ /** @noinspection PhpUnusedLocalVariableInspection */
$ps = $this->scopedProfileSection( __METHOD__ . "-{$this->name}" );
$status = $this->newStatus();
* @throws FileBackendError
*/
final public function executeOpHandlesInternal( array $fileOpHandles ) {
+ /** @noinspection PhpUnusedLocalVariableInspection */
$ps = $this->scopedProfileSection( __METHOD__ . "-{$this->name}" );
foreach ( $fileOpHandles as $fileOpHandle ) {
*/
protected function doExecuteOpHandlesInternal( array $fileOpHandles ) {
if ( count( $fileOpHandles ) ) {
- throw new LogicException( "Backend does not support asynchronous operations." );
+ throw new FileBackendError( "Backend does not support asynchronous operations." );
}
return [];
}
final public function preloadFileStat( array $params ) {
+ /** @noinspection PhpUnusedLocalVariableInspection */
$ps = $this->scopedProfileSection( __METHOD__ . "-{$this->name}" );
$success = true; // no network errors
* @param array $items
*/
final protected function primeContainerCache( array $items ) {
+ /** @noinspection PhpUnusedLocalVariableInspection */
$ps = $this->scopedProfileSection( __METHOD__ . "-{$this->name}" );
$paths = []; // list of storage paths
* @param array $items List of storage paths
*/
final protected function primeFileCache( array $items ) {
+ /** @noinspection PhpUnusedLocalVariableInspection */
$ps = $this->scopedProfileSection( __METHOD__ . "-{$this->name}" );
$paths = []; // list of storage paths
protected function doGetFileStat( array $params ) {
$src = $this->resolveHashKey( $params['src'] );
if ( $src === null ) {
- return null;
+ return false; // invalid path
}
if ( isset( $this->files[$src] ) ) {
$stat = $this->getContainerStat( $fullCont );
if ( is_array( $stat ) ) {
return $status; // already there
- } elseif ( $stat === null ) {
+ } elseif ( $stat === self::UNKNOWN ) {
$status->fatal( 'backend-fail-internal', $this->name );
$this->logger->error( __METHOD__ . ': cannot get container stat' );
return ( count( $status->value ) ) > 0;
}
- return null; // error
+ return self::UNKNOWN; // error
}
/**
throw new FileBackendError( "Iterator page I/O error." );
}
$objects = $status->value;
+ // @phan-suppress-next-line PhanTypeSuspiciousNonTraversableForeach
foreach ( $objects as $object ) { // files and directories
if ( substr( $object, -1 ) === '/' ) {
$dirs[] = $object; // directories end in '/'
$objects = $status->value;
+ // @phan-suppress-next-line PhanTypeSuspiciousNonTraversableForeach
foreach ( $objects as $object ) { // files
$objectDir = $getParentDir( $object ); // directory of object
$stat = $this->getFileStat( $params );
}
+ // @phan-suppress-next-line PhanTypeArraySuspiciousNullable
return $stat['xattr'];
} else {
return false;
if ( !$this->containerStatCache->hasField( $container, 'stat' ) ) {
$auth = $this->getAuthentication();
if ( !$auth ) {
- return null;
+ return self::UNKNOWN;
}
list( $rcode, $rdesc, $rhdrs, $rbody, $rerr ) = $this->http->run( [
$this->onError( null, __METHOD__,
[ 'cont' => $container ], $rerr, $rcode, $rdesc );
- return null;
+ return self::UNKNOWN;
}
}
$stats[$path] = false;
continue; // invalid storage path
} elseif ( !$auth ) {
- $stats[$path] = null;
+ $stats[$path] = self::UNKNOWN;
continue;
}
$stats[$path] = false;
continue; // ok, nothing to do
} elseif ( !is_array( $cstat ) ) {
- $stats[$path] = null;
+ $stats[$path] = self::UNKNOWN;
continue;
}
} elseif ( $rcode === 404 ) {
$stat = false;
} else {
- $stat = null;
+ $stat = self::UNKNOWN;
$this->onError( null, __METHOD__, $params, $rerr, $rcode, $rdesc );
}
$stats[$path] = $stat;
* @ingroup FileJournal
*/
+use Wikimedia\ObjectFactory;
use Wikimedia\Timestamp\ConvertibleTimestamp;
/**
abstract class FileJournal {
/** @var string */
protected $backend;
- /** @var int */
+ /** @var int|false */
protected $ttlDays;
/**
- * Construct a new instance from configuration.
+ * Construct a new instance from configuration. Do not call this directly, use factory().
*
* @param array $config Includes:
* 'ttlDays' : days to keep log entries around (false means "forever")
*/
- protected function __construct( array $config ) {
+ public function __construct( array $config ) {
$this->ttlDays = $config['ttlDays'] ?? false;
}
* @return FileJournal
*/
final public static function factory( array $config, $backend ) {
- $class = $config['class'];
- $jrn = new $class( $config );
- if ( !$jrn instanceof self ) {
- throw new InvalidArgumentException( "$class is not an instance of " . __CLASS__ );
- }
+ $jrn = ObjectFactory::getObjectFromSpec(
+ $config,
+ [ 'specIsArg' => true, 'assertClass' => __CLASS__ ]
+ );
$jrn->backend = $backend;
return $jrn;
* A starting change ID and/or limit can be specified.
*
* @param int|null $start Starting change ID or null
- * @param int $limit Maximum number of items to return
+ * @param int $limit Maximum number of items to return (0 = unlimited)
* @param string|null &$next Updated to the ID of the next entry.
* @return array List of associative arrays, each having:
* id : unique, monotonic, ID for this change
* This is true for the request headers and the response headers. Integer-indexed
* method/URL entries will also be changed to use the corresponding string keys.
*
- * @param array $reqs Map of HTTP request arrays
+ * @param array[] $reqs Map of HTTP request arrays
* @param array $opts
* - connTimeout : connection timeout per request (seconds)
* - reqTimeout : post-connection timeout per request (seconds)
*
* @see MultiHttpClient::runMulti()
*
- * @param array $reqs Map of HTTP request arrays
+ * @param array[] $reqs Map of HTTP request arrays
* @param array $opts
* - connTimeout : connection timeout per request (seconds)
* - reqTimeout : post-connection timeout per request (seconds)
* - usePipelining : whether to use HTTP pipelining if possible
* - maxConnsPerHost : maximum number of concurrent connections (per host)
+ * @codingStandardsIgnoreStart
+ * @phan-param array{connTimeout?:int,reqTimeout?:int,usePipelining?:bool,maxConnsPerHost?:int} $opts
+ * @codingStandardsIgnoreEnd
* @return array $reqs With response array populated for each
* @throws Exception
+ * @suppress PhanTypeInvalidDimOffset
*/
private function runMultiCurl( array $reqs, array $opts = [] ) {
$chm = $this->getCurlMulti();
* - reqTimeout : default request timeout
* @return resource
* @throws Exception
+ * @suppress PhanTypeMismatchArgumentInternal
*/
protected function getCurlHandle( array &$req, array $opts = [] ) {
$ch = curl_init();
$name = strtolower( $name );
$value = trim( $value );
if ( isset( $req['response']['headers'][$name] ) ) {
+ // @phan-suppress-next-line PhanTypeInvalidDimOffset
$req['response']['headers'][$name] .= ', ' . $value;
} else {
$req['response']['headers'][$name] = $value;
'error' => '',
];
- if ( !$sv->isOk() ) {
+ if ( !$sv->isOK() ) {
$svErrors = $sv->getErrors();
if ( isset( $svErrors[0] ) ) {
$req['response']['error'] = $svErrors[0]['message'];
if ( isset( $svErrors[0]['params'][0] ) ) {
if ( is_numeric( $svErrors[0]['params'][0] ) ) {
if ( isset( $svErrors[0]['params'][1] ) ) {
+ // @phan-suppress-next-line PhanTypeInvalidDimOffset
$req['response']['reason'] = $svErrors[0]['params'][1];
}
} else {
/**
* Normalize request information
*
- * @param array $reqs the requests to normalize
+ * @param array[] $reqs the requests to normalize
*/
private function normalizeRequests( array &$reqs ) {
foreach ( $reqs as &$req ) {
final protected function doLockByType( array $pathsByType ) {
$status = StatusValue::newGood();
- $pathsToLock = []; // (bucket => type => paths)
+ $pathsByTypeByBucket = []; // (bucket => type => paths)
// Get locks that need to be acquired (buckets => locks)...
foreach ( $pathsByType as $type => $paths ) {
foreach ( $paths as $path ) {
++$this->locksHeld[$path][$type];
} else {
$bucket = $this->getBucketFromPath( $path );
- $pathsToLock[$bucket][$type][] = $path;
+ $pathsByTypeByBucket[$bucket][$type][] = $path;
}
}
}
+ // Acquire locks in each bucket in bucket order to reduce contention. Any blocking
+ // mutexes during the acquisition step will not involve circular waiting on buckets.
+ ksort( $pathsByTypeByBucket );
+
$lockedPaths = []; // files locked in this attempt (type => paths)
// Attempt to acquire these locks...
- foreach ( $pathsToLock as $bucket => $pathsToLockByType ) {
+ foreach ( $pathsByTypeByBucket as $bucket => $bucketPathsByType ) {
// Try to acquire the locks for this bucket
- $status->merge( $this->doLockingRequestBucket( $bucket, $pathsToLockByType ) );
+ $status->merge( $this->doLockingRequestBucket( $bucket, $bucketPathsByType ) );
if ( !$status->isOK() ) {
$status->merge( $this->doUnlockByType( $lockedPaths ) );
return $status;
}
// Record these locks as active
- foreach ( $pathsToLockByType as $type => $paths ) {
+ foreach ( $bucketPathsByType as $type => $paths ) {
foreach ( $paths as $path ) {
$this->locksHeld[$path][$type] = 1; // locked
// Keep track of what locks were made in this attempt
protected function doUnlockByType( array $pathsByType ) {
$status = StatusValue::newGood();
- $pathsToUnlock = []; // (bucket => type => paths)
+ $pathsByTypeByBucket = []; // (bucket => type => paths)
foreach ( $pathsByType as $type => $paths ) {
foreach ( $paths as $path ) {
if ( !isset( $this->locksHeld[$path][$type] ) ) {
if ( $this->locksHeld[$path][$type] <= 0 ) {
unset( $this->locksHeld[$path][$type] );
$bucket = $this->getBucketFromPath( $path );
- $pathsToUnlock[$bucket][$type][] = $path;
+ $pathsByTypeByBucket[$bucket][$type][] = $path;
}
if ( $this->locksHeld[$path] === [] ) {
unset( $this->locksHeld[$path] ); // no SH or EX locks left for key
// Remove these specific locks if possible, or at least release
// all locks once this process is currently not holding any locks.
- foreach ( $pathsToUnlock as $bucket => $pathsToUnlockByType ) {
- $status->merge( $this->doUnlockingRequestBucket( $bucket, $pathsToUnlockByType ) );
+ foreach ( $pathsByTypeByBucket as $bucket => $bucketPathsByType ) {
+ $status->merge( $this->doUnlockingRequestBucket( $bucket, $bucketPathsByType ) );
}
if ( $this->locksHeld === [] ) {
$status->merge( $this->releaseAllLocks() );
$this->error( 'invalid signature: ' . bin2hex( $this->header['header_signature'] ),
self::ERROR_INVALID_SIGNATURE );
}
+ // @phan-suppress-next-line PhanTypeInvalidRightOperandOfIntegerOp
$this->sectorLength = 1 << $this->header['sector_shift'];
$this->readDifat();
$this->readDirectory();
);
}
+ /**
+ * @param int $offset
+ * @param int[] $struct
+ * @return array
+ */
private function unpackOffset( $offset, $struct ) {
$block = $this->readOffset( $offset, array_sum( $struct ) );
return $this->unpack( $block, 0, $struct );
}
- private function unpackSector( $sectorNumber, $struct ) {
- $offset = $this->sectorOffset( $sectorNumber );
- return $this->unpackOffset( $offset, array_sum( $struct ) );
- }
-
+ /**
+ * @param string $block
+ * @param int $offset
+ * @param int[] $struct
+ * @return array
+ */
private function unpack( $block, $offset, $struct ) {
$data = [];
foreach ( $struct as $key => $length ) {
}
private function readSector( $sectorId ) {
+ // @phan-suppress-next-line PhanTypeInvalidRightOperandOfIntegerOp
return $this->readOffset( $this->sectorOffset( $sectorId ), 1 << $this->header['sector_shift'] );
}
}
/**
- * @param string $fname the filename
+ * @param string $xml
+ * @param bool $isFile
*/
private function validateFromInput( $xml, $isFile ) {
$reader = new XMLReader();
* * Only contains entity definitions (e.g. No <!ATLIST )
* * Entity definitions are not "system" entities
* * Entity definitions are not "parameter" (i.e. %) entities
- * * Entity definitions do not reference other entites except &
+ * * Entity definitions do not reference other entities except &
* and quotes. Entity aliases (where the entity contains only
* another entity are allowed)
* * Entity references aren't overly long (>255 bytes).
* - asyncHandler: Callable to use for scheduling tasks after the web request ends.
* In CLI mode, it should run the task immediately.
* @param array $params
+ * @phan-param array{logger?:Psr\Log\LoggerInterface,asyncHandler?:callable} $params
*/
public function __construct( array $params = [] ) {
$this->setLogger( $params['logger'] ?? new NullLogger() );
/**
* @param array $params Additional parameters include:
* - maxKeys : only allow this many keys (using oldest-first eviction)
+ * @codingStandardsIgnoreStart
+ * @phan-param array{logger?:Psr\Log\LoggerInterface,asyncHandler?:callable,keyspace?:string,reportDupes?:bool,syncTimeout?:int,segmentationSize?:int,segmentedValueMaxSize?:int,maxKeys?:int} $params
+ * @codingStandardsIgnoreEnd
+ * @suppress PhanTypeInvalidDimOffset
*/
function __construct( $params = [] ) {
$params['segmentationSize'] = $params['segmentationSize'] ?? INF;
* This should be configured to a reasonable size give the site traffic and the
* amount of I/O between application and cache servers that the network can handle.
* @param array $params
+ * @codingStandardsIgnoreStart
+ * @phan-param array{logger?:Psr\Log\LoggerInterface,asyncHandler?:callable,keyspace?:string,reportDupes?:bool,syncTimeout?:int,segmentationSize?:int,segmentedValueMaxSize?:int} $params
+ * @codingStandardsIgnoreEnd
*/
public function __construct( array $params = [] ) {
parent::__construct( $params );
unset( $currentValue ); // free RAM in case the value is large
$this->clearLastError();
- if ( $value === false ) {
+ if ( $value === false || $exptime < 0 ) {
$success = true; // do nothing
} elseif ( $valueMatchesOldValue && $attemptsLeft !== $attempts ) {
$success = true; // recently set by another thread to the same value
// custom prefixes used by thing like WANObjectCache, limit to 205.
$charsLeft = 205 - strlen( $keyspace ) - count( $args );
- $args = array_map(
- function ( $arg ) use ( &$charsLeft ) {
- $arg = strtr( $arg, ' ', '_' );
+ foreach ( $args as &$arg ) {
+ $arg = strtr( $arg, ' ', '_' );
- // Make sure %, #, and non-ASCII chars are escaped
- $arg = preg_replace_callback(
- '/[^\x21-\x22\x24\x26-\x39\x3b-\x7e]+/',
- function ( $m ) {
- return rawurlencode( $m[0] );
- },
- $arg
- );
+ // Make sure %, #, and non-ASCII chars are escaped
+ $arg = preg_replace_callback(
+ '/[^\x21-\x22\x24\x26-\x39\x3b-\x7e]+/',
+ function ( $m ) {
+ return rawurlencode( $m[0] );
+ },
+ $arg
+ );
- // 33 = 32 characters for the MD5 + 1 for the '#' prefix.
- if ( $charsLeft > 33 && strlen( $arg ) > $charsLeft ) {
- $arg = '#' . md5( $arg );
- }
+ // 33 = 32 characters for the MD5 + 1 for the '#' prefix.
+ if ( $charsLeft > 33 && strlen( $arg ) > $charsLeft ) {
+ $arg = '#' . md5( $arg );
+ }
- $charsLeft -= strlen( $arg );
- return $arg;
- },
- $args
- );
+ $charsLeft -= strlen( $arg );
+ }
if ( $charsLeft < 0 ) {
return $keyspace . ':BagOStuff-long-key:##' . md5( implode( ':', $args ) );
* invalidation uses logical TTLs, invalidation uses etag/timestamp
* validation against the DB, or merge() is used to handle races.
* @param array $params
+ * @phan-param array{caches:array<int,array|BagOStuff>,replication:string} $params
* @throws InvalidArgumentException
*/
public function __construct( $params ) {
*
* @ingroup Cache
* @ingroup Redis
+ * @phan-file-suppress PhanTypeComparisonFromArray It's unclear whether exec() can return false
*/
class RedisBagOStuff extends MediumSpecificBagOStuff {
/** @var RedisConnectionPool */
*/
class ReplicatedBagOStuff extends BagOStuff {
/** @var BagOStuff */
- protected $writeStore;
+ private $writeStore;
/** @var BagOStuff */
- protected $readStore;
+ private $readStore;
+
+ /** @var int Seconds to read from the master source for a key after writing to it */
+ private $consistencyWindow;
+ /** @var float[] Map of (key => UNIX timestamp) */
+ private $lastKeyWrites = [];
+
+ /** @var int Max expected delay (in seconds) for writes to reach replicas */
+ const MAX_WRITE_DELAY = 5;
/**
* Constructor. Parameters are:
- * - writeFactory : ObjectFactory::getObjectFromSpec array yeilding BagOStuff.
- * This object will be used for writes (e.g. the master DB).
- * - readFactory : ObjectFactory::getObjectFromSpec array yeilding BagOStuff.
- * This object will be used for reads (e.g. a replica DB).
+ * - writeFactory: ObjectFactory::getObjectFromSpec array yeilding BagOStuff.
+ * This object will be used for writes (e.g. the master DB).
+ * - readFactory: ObjectFactory::getObjectFromSpec array yeilding BagOStuff.
+ * This object will be used for reads (e.g. a replica DB).
+ * - sessionConsistencyWindow: Seconds to read from the master source for a key
+ * after writing to it. [Default: ReplicatedBagOStuff::MAX_WRITE_DELAY]
*
* @param array $params
* @throws InvalidArgumentException
if ( !isset( $params['writeFactory'] ) ) {
throw new InvalidArgumentException(
__METHOD__ . ': the "writeFactory" parameter is required' );
- }
- if ( !isset( $params['readFactory'] ) ) {
+ } elseif ( !isset( $params['readFactory'] ) ) {
throw new InvalidArgumentException(
__METHOD__ . ': the "readFactory" parameter is required' );
}
- $opts = [ 'reportDupes' => false ]; // redundant
+ $this->consistencyWindow = $params['sessionConsistencyWindow'] ?? self::MAX_WRITE_DELAY;
$this->writeStore = ( $params['writeFactory'] instanceof BagOStuff )
? $params['writeFactory']
- : ObjectFactory::getObjectFromSpec( $opts + $params['writeFactory'] );
+ : ObjectFactory::getObjectFromSpec( $params['writeFactory'] );
$this->readStore = ( $params['readFactory'] instanceof BagOStuff )
? $params['readFactory']
- : ObjectFactory::getObjectFromSpec( $opts + $params['readFactory'] );
+ : ObjectFactory::getObjectFromSpec( $params['readFactory'] );
$this->attrMap = $this->mergeFlagMaps( [ $this->readStore, $this->writeStore ] );
}
}
public function get( $key, $flags = 0 ) {
- return $this->fieldHasFlags( $flags, self::READ_LATEST )
+ return (
+ $this->hadRecentSessionWrite( [ $key ] ) ||
+ $this->fieldHasFlags( $flags, self::READ_LATEST )
+ )
? $this->writeStore->get( $key, $flags )
: $this->readStore->get( $key, $flags );
}
public function set( $key, $value, $exptime = 0, $flags = 0 ) {
+ $this->remarkRecentSessionWrite( [ $key ] );
+
return $this->writeStore->set( $key, $value, $exptime, $flags );
}
public function delete( $key, $flags = 0 ) {
+ $this->remarkRecentSessionWrite( [ $key ] );
+
return $this->writeStore->delete( $key, $flags );
}
public function add( $key, $value, $exptime = 0, $flags = 0 ) {
+ $this->remarkRecentSessionWrite( [ $key ] );
+
return $this->writeStore->add( $key, $value, $exptime, $flags );
}
public function merge( $key, callable $callback, $exptime = 0, $attempts = 10, $flags = 0 ) {
+ $this->remarkRecentSessionWrite( [ $key ] );
+
return $this->writeStore->merge( $key, $callback, $exptime, $attempts, $flags );
}
public function changeTTL( $key, $exptime = 0, $flags = 0 ) {
+ $this->remarkRecentSessionWrite( [ $key ] );
+
return $this->writeStore->changeTTL( $key, $exptime, $flags );
}
}
public function getMulti( array $keys, $flags = 0 ) {
- return $this->fieldHasFlags( $flags, self::READ_LATEST )
+ return (
+ $this->hadRecentSessionWrite( $keys ) ||
+ $this->fieldHasFlags( $flags, self::READ_LATEST )
+ )
? $this->writeStore->getMulti( $keys, $flags )
: $this->readStore->getMulti( $keys, $flags );
}
public function setMulti( array $data, $exptime = 0, $flags = 0 ) {
+ $this->remarkRecentSessionWrite( array_keys( $data ) );
+
return $this->writeStore->setMulti( $data, $exptime, $flags );
}
public function deleteMulti( array $keys, $flags = 0 ) {
+ $this->remarkRecentSessionWrite( $keys );
+
return $this->writeStore->deleteMulti( $keys, $flags );
}
public function changeTTLMulti( array $keys, $exptime, $flags = 0 ) {
+ $this->remarkRecentSessionWrite( $keys );
+
return $this->writeStore->changeTTLMulti( $keys, $exptime, $flags );
}
public function incr( $key, $value = 1, $flags = 0 ) {
+ $this->remarkRecentSessionWrite( [ $key ] );
+
return $this->writeStore->incr( $key, $value, $flags );
}
public function decr( $key, $value = 1, $flags = 0 ) {
+ $this->remarkRecentSessionWrite( [ $key ] );
+
return $this->writeStore->decr( $key, $value, $flags );
}
public function incrWithInit( $key, $exptime, $value = 1, $init = null, $flags = 0 ) {
+ $this->remarkRecentSessionWrite( [ $key ] );
+
return $this->writeStore->incrWithInit( $key, $exptime, $value, $init, $flags );
}
public function getLastError() {
- return ( $this->writeStore->getLastError() != self::ERR_NONE )
+ return ( $this->writeStore->getLastError() !== self::ERR_NONE )
? $this->writeStore->getLastError()
: $this->readStore->getLastError();
}
$this->writeStore->setMockTime( $time );
$this->readStore->setMockTime( $time );
}
+
+ /**
+ * @param string[] $keys
+ * @return bool
+ */
+ private function hadRecentSessionWrite( array $keys ) {
+ $now = $this->getCurrentTime();
+ foreach ( $keys as $key ) {
+ $ts = $this->lastKeyWrites[$key] ?? 0;
+ if ( $ts && ( $now - $ts ) <= $this->consistencyWindow ) {
+ return true;
+ }
+ }
+
+ return false;
+ }
+
+ /**
+ * @param string[] $keys
+ */
+ private function remarkRecentSessionWrite( array $keys ) {
+ $now = $this->getCurrentTime();
+ foreach ( $keys as $key ) {
+ unset( $this->lastKeyWrites[$key] ); // move to the end
+ $this->lastKeyWrites[$key] = $now;
+ }
+ // Prune out the map if the first key is obsolete
+ if ( ( $now - reset( $this->lastKeyWrites ) ) > $this->consistencyWindow ) {
+ $this->lastKeyWrites = array_filter(
+ $this->lastKeyWrites,
+ function ( $timestamp ) use ( $now ) {
+ return ( ( $now - $timestamp ) <= $this->consistencyWindow );
+ }
+ );
+ }
+ }
}
* - version: Integer version number signifiying the format of the value.
* Default: null
* - walltime: How long the value took to generate in seconds. Default: 0.0
+ * @codingStandardsIgnoreStart
+ * @phan-param array{lag?:int,since?:int,pending?:bool,lockTSE?:int,staleTTL?:int,creating?:bool,version?:?string,walltime?:int|float} $opts
+ * @codingStandardsIgnoreEnd
* @note Options added in 1.28: staleTTL
* @note Options added in 1.33: creating
* @note Options added in 1.34: version, walltime
* @return bool Success
+ * @suppress PhanTypeInvalidDimOffset
*/
final public function set( $key, $value, $ttl = self::TTL_INDEFINITE, array $opts = [] ) {
$now = $this->getCurrentTime();
* most sense for values that are moderately to highly expensive to regenerate and easy
* to query for dependency timestamps. The use of "pcTTL" reduces timestamp queries.
* Default: null.
+ * @codingStandardsIgnoreStart
+ * @phan-param array{checkKeys?:string[],graceTTL?:int,lockTSE?:int,busyValue?:mixed,pcTTL?:int,pcGroup?:string,version?:int,minAsOf?:int,hotTTR?:int,lowTTL?:int,ageNew?:int,staleTTL?:int,touchedCallback?:callable} $opts
+ * @codingStandardsIgnoreEnd
* @return mixed Value found or written to the key
* @note Options added in 1.28: version, busyValue, hotTTR, ageNew, pcGroup, minAsOf
* @note Options added in 1.31: staleTTL, graceTTL
* @note Options added in 1.33: touchedCallback
* @note Callable type hints are not used to avoid class-autoloading
+ * @suppress PhanTypeInvalidDimOffset
*/
final public function getWithSetCallback( $key, $ttl, $callback, array $opts = [] ) {
$version = $opts['version'] ?? null;
* - Cached or regenerated value version number or null if not versioned
* - Timestamp of the current cached value at the key or null if there is no value
* @note Callable type hints are not used to avoid class-autoloading
+ * @suppress PhanTypeArraySuspicious
*/
private function fetchOrRegenerate( $key, $ttl, $callback, array $opts ) {
$checkKeys = $opts['checkKeys'] ?? [];
$this->setInterimValue( $key, $value, $lockTSE, $version, $walltime );
} else {
$finalSetOpts = [
+ // @phan-suppress-next-line PhanTypeInvalidDimOffset
'since' => $setOpts['since'] ?? $preCallbackTime,
'version' => $version,
'staleTTL' => $staleTTL,
* - curTTL: remaining time-to-live (negative if tombstoned) or null if there is no value
* - version: value version number or null if the if there is no value
* - tombAsOf: UNIX timestamp of the tombstone or null if there is no tombstone
+ * @phan-return array{0:mixed,1:array{asOf:?mixed,curTTL:?int|float,version:?mixed,tombAsOf:?mixed}}
*/
private function unwrap( $wrapped, $now ) {
$value = false;
/** @var float Query rount trip time estimate */
private $lastRoundTripEstimate = 0.0;
- /** @var string Whether the database is a file on disk */
- const ATTR_DB_IS_FILE = 'db-is-file';
/** @var string Lock granularity is on the level of the entire database */
const ATTR_DB_LEVEL_LOCKING = 'db-level-locking';
/** @var string The SCHEMA keyword refers to a grouping of tables in a database */
$this->cliMode = $params['cliMode'];
$this->agent = $params['agent'];
$this->flags = $params['flags'];
+ if ( $this->flags & self::DBO_DEFAULT ) {
+ if ( $this->cliMode ) {
+ $this->flags &= ~self::DBO_TRX;
+ } else {
+ $this->flags |= self::DBO_TRX;
+ }
+ }
$this->nonNativeInsertSelectBatchSize = $params['nonNativeInsertSelectBatchSize'] ?? 10000;
$this->srvCache = $params['srvCache'] ?? new HashBagOStuff();
*/
final public static function attributesFromType( $dbType, $driver = null ) {
static $defaults = [
- self::ATTR_DB_IS_FILE => false,
self::ATTR_DB_LEVEL_LOCKING => false,
self::ATTR_SCHEMAS_AS_TABLE_GROUPS => false
];
$this->trxAtomicCounter = 0;
$this->trxIdleCallbacks = []; // T67263; transaction already lost
$this->trxPreCommitCallbacks = []; // T67263; transaction already lost
+ // Clear additional subclass fields
+ $this->doHandleSessionLossPreconnect();
// @note: leave trxRecurringCallbacks in place
if ( $this->trxDoneWrites ) {
$this->trxProfiler->transactionWritingOut(
}
}
+ /**
+ * Reset any additional subclass trx* and session* fields
+ */
+ protected function doHandleSessionLossPreconnect() {
+ // no-op
+ }
+
/**
* Clean things up after session (and thus transaction) loss after reconnect
*/
$this->selectOptionsIncludeLocking( $options ) &&
$this->selectFieldsOrOptionsAggregate( $vars, $options )
) {
- // Some DB types (postgres/oracle) disallow FOR UPDATE with aggregate
+ // Some DB types (e.g. postgres) disallow FOR UPDATE with aggregate
// functions. Discourage use of such queries to encourage compatibility.
call_user_func(
$this->deprecationLogger,
if ( in_array( $entry[2], $sectionIds, true ) ) {
$callback = $entry[0];
$this->trxEndCallbacks[$key][0] = function () use ( $callback ) {
- // @phan-suppress-next-line PhanInfiniteRecursion No recursion at all here, phan is confused
+ // @phan-suppress-next-line PhanInfiniteRecursion, PhanUndeclaredInvokeInCallable
return $callback( self::TRIGGER_ROLLBACK, $this );
};
// This "on resolution" callback no longer belongs to a section.
try {
++$count;
list( $phpCallback ) = $callback;
+ // @phan-suppress-next-line PhanUndeclaredInvokeInCallable
$phpCallback( $this );
} catch ( Exception $ex ) {
( $this->errorLogger )( $ex );
foreach ( $callbacks as $entry ) {
if ( $sectionIds === null || in_array( $entry[2], $sectionIds, true ) ) {
try {
+ // @phan-suppress-next-line PhanUndeclaredInvokeInCallable
$entry[0]( $trigger, $this );
} catch ( Exception $ex ) {
( $this->errorLogger )( $ex );
}
public function serverIsReadOnly() {
- $flags = self::QUERY_IGNORE_DBO_TRX;
- $res = $this->query( "SHOW GLOBAL VARIABLES LIKE 'read_only'", __METHOD__, $flags );
+ // Avoid SHOW to avoid internal temporary tables
+ $flags = self::QUERY_IGNORE_DBO_TRX | self::QUERY_SILENCE_ERRORS;
+ $res = $this->query( "SELECT @@GLOBAL.read_only AS Value", __METHOD__, $flags );
$row = $this->fetchObject( $res );
- return $row ? ( strtolower( $row->Value ) === 'on' ) : false;
+ return $row ? (bool)$row->Value : false;
}
/**
* @ingroup Database
* @since 1.22
* @see Database
+ * @phan-file-suppress PhanParamSignatureMismatch resource vs mysqli_result
*/
class DatabaseMysqli extends DatabaseMysqlBase {
/**
$this->password = $password;
$connectVars = [
- // A database must be specified in order to connect to Postgres. If $dbName is not
- // specified, then use the standard "postgres" database that should exist by default.
+ // pg_connect() user $user as the default database. Since a database is required,
+ // then pick a "don't care" database that is more likely to exist than that one.
'dbname' => strlen( $dbName ) ? $dbName : 'postgres',
'user' => $user,
'password' => $password
return $row ? ( strtolower( $row->default_transaction_read_only ) === 'on' ) : false;
}
- protected static function getAttributes() {
+ public static function getAttributes() {
return [ self::ATTR_SCHEMAS_AS_TABLE_GROUPS => true ];
}
protected $lockMgr;
/** @var array List of shared database already attached to this connection */
- private $alreadyAttached = [];
-
- /** @var bool Whether full text is enabled */
- private static $fulltextEnabled = null;
+ private $sessionAttachedDbs = [];
/** @var string[] See https://www.sqlite.org/lang_transaction.html */
private static $VALID_TRX_MODES = [ '', 'DEFERRED', 'IMMEDIATE', 'EXCLUSIVE' ];
* - dbDirectory : directory containing the DB and the lock file directory
* - dbFilePath : use this to force the path of the DB file
* - trxMode : one of (deferred, immediate, exclusive)
- * @param array $params
+ * @param array $p
*/
- public function __construct( array $params ) {
- if ( isset( $params['dbFilePath'] ) ) {
- $this->dbPath = $params['dbFilePath'];
- if ( !strlen( $params['dbname'] ) ) {
- $params['dbname'] = self::generateDatabaseName( $this->dbPath );
+ public function __construct( array $p ) {
+ if ( isset( $p['dbFilePath'] ) ) {
+ $this->dbPath = $p['dbFilePath'];
+ if ( !strlen( $p['dbname'] ) ) {
+ $p['dbname'] = self::generateDatabaseName( $this->dbPath );
}
- } elseif ( isset( $params['dbDirectory'] ) ) {
- $this->dbDir = $params['dbDirectory'];
+ } elseif ( isset( $p['dbDirectory'] ) ) {
+ $this->dbDir = $p['dbDirectory'];
}
- parent::__construct( $params );
+ parent::__construct( $p );
- $this->trxMode = strtoupper( $params['trxMode'] ?? '' );
+ $this->trxMode = strtoupper( $p['trxMode'] ?? '' );
$lockDirectory = $this->getLockFileDirectory();
if ( $lockDirectory !== null ) {
}
protected static function getAttributes() {
- return [
- self::ATTR_DB_IS_FILE => true,
- self::ATTR_DB_LEVEL_LOCKING => true
- ];
+ return [ self::ATTR_DB_LEVEL_LOCKING => true ];
}
/**
if ( in_array( $sync, [ 'EXTRA', 'FULL', 'NORMAL', 'OFF' ], true ) ) {
$this->query( "PRAGMA synchronous = $sync", __METHOD__, $flags );
}
+ $this->attachDatabasesFromTableAliases();
} catch ( Exception $e ) {
throw $this->newExceptionAfterConnectError( $e->getMessage() );
}
}
/**
- * Attaches external database to our connection, see https://sqlite.org/lang_attach.html
- * for details.
+ * Attaches external database to the connection handle
+ *
+ * @see https://sqlite.org/lang_attach.html
*
* @param string $name Database name to be used in queries like
* SELECT foo FROM dbname.table
public function setTableAliases( array $aliases ) {
parent::setTableAliases( $aliases );
+ if ( $this->isOpen() ) {
+ $this->attachDatabasesFromTableAliases();
+ }
+ }
+
+ /**
+ * Issue ATTATCH statements for all unattached foreign DBs in table aliases
+ */
+ private function attachDatabasesFromTableAliases() {
foreach ( $this->tableAliases as $params ) {
- if ( isset( $this->alreadyAttached[$params['dbname']] ) ) {
- continue;
+ if (
+ $params['dbname'] !== $this->getDBname() &&
+ !isset( $this->sessionAttachedDbs[$params['dbname']] )
+ ) {
+ $this->attachDatabase( $params['dbname'] );
+ $this->sessionAttachedDbs[$params['dbname']] = true;
}
- $this->attachDatabase( $params['dbname'] );
- $this->alreadyAttached[$params['dbname']] = true;
}
}
return true;
}
+ protected function doHandleSessionLossPreconnect() {
+ $this->sessionAttachedDbs = [];
+ }
+
/**
* @return PDO
*/
use InvalidArgumentException;
use Wikimedia\ScopedCallback;
-use RuntimeException;
+use Exception;
use stdClass;
/**
const DBO_DEFAULT = 16;
/** @var int Use DB persistent connections if possible */
const DBO_PERSISTENT = 32;
- /** @var int DBA session mode; mostly for Oracle */
+ /** @var int DBA session mode; was used by Oracle */
const DBO_SYSDBA = 64;
- /** @var int Schema file mode; mostly for Oracle */
+ /** @var int Schema file mode; was used by Oracle */
const DBO_DDLMODE = 128;
/** @var int Enable SSL/TLS in connection protocol */
const DBO_SSL = 256;
const UNION_DISTINCT = false;
/**
- * A string describing the current software version, and possibly
- * other details in a user-friendly way. Will be listed on Special:Version, etc.
+ * Get a human-readable string describing the current software version
+ *
* Use getServerVersion() to get machine-friendly information.
*
* @return string Version information from the database server
public function explicitTrxActive();
/**
- * Assert that all explicit transactions or atomic sections have been closed.
+ * Assert that all explicit transactions or atomic sections have been closed
+ *
* @throws DBTransactionError
* @since 1.32
*/
public function assertNoOpenTransactions();
/**
- * Get/set the table prefix.
- * @param string|null $prefix The table prefix to set, or omitted to leave it unchanged.
+ * Get/set the table prefix
+ *
+ * @param string|null $prefix The table prefix to set, or omitted to leave it unchanged
* @return string The previous table prefix
- * @throws DBUnexpectedError
*/
public function tablePrefix( $prefix = null );
/**
- * Get/set the db schema.
- * @param string|null $schema The database schema to set, or omitted to leave it unchanged.
+ * Get/set the db schema
+ *
+ * @param string|null $schema The database schema to set, or omitted to leave it unchanged
* @return string The previous db schema
*/
public function dbSchema( $schema = null );
/**
- * Get properties passed down from the server info array of the load
- * balancer.
- *
- * @param string|null $name The entry of the info array to get, or null to get the
- * whole array
+ * Get properties passed down from the server info array of the load balancer
*
+ * @param string|null $name The entry of the info array to get, or null to get the whole array
* @return array|mixed|null
*/
public function getLBInfo( $name = null );
public function implicitOrderby();
/**
- * Return the last query that sent on account of IDatabase::query()
+ * Get the last query that sent on account of IDatabase::query()
+ *
* @return string SQL text or empty string if there was no such query
*/
public function lastQuery();
/**
- * Returns the last time the connection may have been used for write queries.
- * Should return a timestamp if unsure.
+ * Get the last time the connection may have been used for a write query
*
* @return int|float UNIX timestamp or false
* @since 1.24
/**
* Get the time spend running write queries for this transaction
*
- * High times could be due to scanning, updates, locking, and such
+ * High values could be due to scanning, updates, locking, and such.
*
* @param string $type IDatabase::ESTIMATE_* constant [default: ESTIMATE_ALL]
* @return float|bool Returns false if not transaction is active
public function pendingWriteRowsAffected();
/**
- * Is a connection to the database open?
- * @return bool
+ * @return bool Whether a connection to the database open
*/
public function isOpen();
public function getDomainID();
/**
- * Get the type of the DBMS, as it appears in $wgDBtype.
+ * Get the type of the DBMS (e.g. "mysql", "sqlite")
*
* @return string
*/
public function getType();
/**
- * Fetch the next row from the given result object, in object form.
+ * Fetch the next row from the given result object, in object form
+ *
* Fields can be retrieved with $row->fieldname, with fields acting like
- * member variables.
- * If no more rows are available, false is returned.
+ * member variables. If no more rows are available, false is returned.
*
* @param IResultWrapper|stdClass $res Object as returned from IDatabase::query(), etc.
* @return stdClass|bool
- * @throws DBUnexpectedError Thrown if the database returns an error
*/
public function fetchObject( $res );
/**
- * Fetch the next row from the given result object, in associative array
- * form. Fields are retrieved with $row['fieldname'].
+ * Fetch the next row from the given result object, in associative array form
+ *
+ * Fields are retrieved with $row['fieldname'].
* If no more rows are available, false is returned.
*
* @param IResultWrapper $res Result object as returned from IDatabase::query(), etc.
* @return array|bool
- * @throws DBUnexpectedError Thrown if the database returns an error
*/
public function fetchRow( $res );
/**
- * Get the number of rows in a query result. If the query did not return
- * any rows (for example, if it was a write query), this returns zero.
+ * Get the number of rows in a query result
+ *
+ * Returns zero if the query did not return any rows or was a write query.
*
* @param mixed $res A SQL result
* @return int
public function affectedRows();
/**
- * Returns a wikitext link to the DB's website, e.g.,
- * return "[https://www.mysql.com/ MySQL]";
- * Should at least contain plain text, if for some reason
- * your database has no website.
+ * Returns a wikitext style link to the DB's website (e.g. "[https://www.mysql.com/ MySQL]")
+ *
+ * Should at least contain plain text, if for some reason your database has no website.
*
* @return string Wikitext of a link to the server software's web site
*/
public function getSoftwareLink();
/**
- * A string describing the current software version, like from
- * mysql_get_server_info().
+ * A string describing the current software version, like from mysql_get_server_info()
*
* @return string Version information from the database server.
*/
* aside from read-only automatic transactions (assuming no callbacks are registered).
* If a transaction is still open anyway, it will be rolled back.
*
+ * @return bool Success
* @throws DBError
- * @return bool Operation success. true if already closed.
*/
public function close();
/**
- * Run an SQL query and return the result. Normally throws a DBQueryError
- * on failure. If errors are ignored, returns false instead.
+ * Run an SQL query and return the result
*
* If a connection loss is detected, then an attempt to reconnect will be made.
* For queries that involve no larger transactions or locks, they will be re-issued
* of errors is best handled by try/catch rather than using one of these flags.
* @return bool|IResultWrapper True for a successful write query, IResultWrapper object
* for a successful read query, or false on failure if QUERY_SILENCE_ERRORS is set.
- * @throws DBError
+ * @throws DBQueryError If the query is issued, fails, and QUERY_SILENCE_ERRORS is not set.
+ * @throws DBExpectedError If the query is not, and cannot, be issued yet (non-DBQueryError)
+ * @throws DBError If the query is inherently not allowed (non-DBExpectedError)
*/
public function query( $sql, $fname = __METHOD__, $flags = 0 );
/**
- * Free a result object returned by query() or select(). It's usually not
- * necessary to call this, just use unset() or let the variable holding
- * the result object go out of scope.
+ * Free a result object returned by query() or select()
+ *
+ * It's usually not necessary to call this, just use unset() or let the variable
+ * holding the result object go out of scope.
*
* @param mixed $res A SQL result
*/
public function freeResult( $res );
/**
- * A SELECT wrapper which returns a single field from a single result row.
- *
- * Usually throws a DBQueryError on failure. If errors are explicitly
- * ignored, returns false on failure.
+ * A SELECT wrapper which returns a single field from a single result row
*
* If no result rows are returned from the query, false is returned.
*
* @param string $fname The function name of the caller.
* @param string|array $options The query options. See IDatabase::select() for details.
* @param string|array $join_conds The query join conditions. See IDatabase::select() for details.
- *
* @return mixed The value from the field
- * @throws DBError
+ * @throws DBError If an error occurs, see IDatabase::query()
*/
public function selectField(
$table, $var, $cond = '', $fname = __METHOD__, $options = [], $join_conds = []
);
/**
- * A SELECT wrapper which returns a list of single field values from result rows.
- *
- * Usually throws a DBQueryError on failure. If errors are explicitly
- * ignored, returns false on failure.
+ * A SELECT wrapper which returns a list of single field values from result rows
*
* If no result rows are returned from the query, false is returned.
*
* @param string|array $join_conds The query join conditions. See IDatabase::select() for details.
*
* @return array The values from the field in the order they were returned from the DB
- * @throws DBError
+ * @throws DBError If an error occurs, see IDatabase::query()
* @since 1.25
*/
public function selectFieldValues(
);
/**
- * Execute a SELECT query constructed using the various parameters provided.
- * See below for full details of the parameters.
+ * Execute a SELECT query constructed using the various parameters provided
*
* @param string|array $table Table name(s)
*
* [ 'page' => [ 'LEFT JOIN', 'page_latest=rev_id' ] ]
*
* @return IResultWrapper Resulting rows
- * @throws DBError
+ * @throws DBError If an error occurs, see IDatabase::query()
*/
public function select(
- $table, $vars, $conds = '', $fname = __METHOD__,
- $options = [], $join_conds = []
+ $table,
+ $vars,
+ $conds = '',
+ $fname = __METHOD__,
+ $options = [],
+ $join_conds = []
);
/**
- * The equivalent of IDatabase::select() except that the constructed SQL
- * is returned, instead of being immediately executed. This can be useful for
- * doing UNION queries, where the SQL text of each query is needed. In general,
- * however, callers outside of Database classes should just use select().
+ * Take the same arguments as IDatabase::select() and return the SQL it would use
+ *
+ * This can be useful for making UNION queries, where the SQL text of each query
+ * is needed. In general, however, callers outside of Database classes should just
+ * use select().
*
* @see IDatabase::select()
*
* @return string SQL query string
*/
public function selectSQLText(
- $table, $vars, $conds = '', $fname = __METHOD__,
- $options = [], $join_conds = []
+ $table,
+ $vars,
+ $conds = '',
+ $fname = __METHOD__,
+ $options = [],
+ $join_conds = []
);
/**
- * Single row SELECT wrapper. Equivalent to IDatabase::select(), except
- * that a single row object is returned. If the query returns no rows,
- * false is returned.
+ * Wrapper to IDatabase::select() that only fetches one row (via LIMIT)
+ *
+ * If the query returns no rows, false is returned.
+ *
+ * This method is convenient for fetching a row based on a unique key condition.
*
* @param string|array $table Table name
* @param string|array $vars Field names
* @param string $fname Caller function name
* @param string|array $options Query options
* @param array|string $join_conds Join conditions
- *
* @return stdClass|bool
- * @throws DBError
+ * @throws DBError If an error occurs, see IDatabase::query()
*/
- public function selectRow( $table, $vars, $conds, $fname = __METHOD__,
- $options = [], $join_conds = []
+ public function selectRow(
+ $table,
+ $vars,
+ $conds,
+ $fname = __METHOD__,
+ $options = [],
+ $join_conds = []
);
/**
* @param array $options Options for select
* @param array|string $join_conds Join conditions
* @return int Row count
- * @throws DBError
+ * @throws DBError If an error occurs, see IDatabase::query()
*/
public function estimateRowCount(
$table, $var = '*', $conds = '', $fname = __METHOD__, $options = [], $join_conds = []
* @param array $options Options for select
* @param array $join_conds Join conditions (since 1.27)
* @return int Row count
- * @throws DBError
+ * @throws DBError If an error occurs, see IDatabase::query()
*/
public function selectRowCount(
$tables, $var = '*', $conds = '', $fname = __METHOD__, $options = [], $join_conds = []
* @param array $options Options for select ("FOR UPDATE" is added automatically)
* @param array $join_conds Join conditions
* @return int Number of matching rows found (and locked)
+ * @throws DBError If an error occurs, see IDatabase::query()
* @since 1.32
*/
public function lockForUpdate(
* @param string $field Filed to check on that table
* @param string $fname Calling function name (optional)
* @return bool Whether $table has filed $field
- * @throws DBError
+ * @throws DBError If an error occurs, see IDatabase::query()
*/
public function fieldExists( $table, $field, $fname = __METHOD__ );
/**
* Determines whether an index exists
- * Usually throws a DBQueryError on failure
- * If errors are explicitly ignored, returns NULL on failure
*
* @param string $table
* @param string $index
* @param string $fname
* @return bool|null
- * @throws DBError
+ * @throws DBError If an error occurs, see IDatabase::query()
*/
public function indexExists( $table, $index, $fname = __METHOD__ );
* @param string $table
* @param string $fname
* @return bool
- * @throws DBError
+ * @throws DBError If an error occurs, see IDatabase::query()
*/
public function tableExists( $table, $fname = __METHOD__ );
/**
- * INSERT wrapper, inserts an array into a table.
+ * INSERT wrapper, inserts an array into a table
*
* $a may be either:
*
* This causes a multi-row INSERT on DBMSs that support it. The keys in
* each subarray must be identical to each other, and in the same order.
*
- * Usually throws a DBQueryError on failure. If errors are explicitly ignored,
- * returns success.
- *
* $options is an array of options, with boolean options encoded as values
* with numeric keys, in the same style as $options in
* IDatabase::select(). Supported options are:
* @param string $fname Calling function name (use __METHOD__) for logs/profiling
* @param array $options Array of options
* @return bool Return true if no exception was thrown (deprecated since 1.33)
- * @throws DBError
+ * @throws DBError If an error occurs, see IDatabase::query()
*/
public function insert( $table, $a, $fname = __METHOD__, $options = [] );
* that field to. The data will be quoted by IDatabase::addQuotes().
* Values with integer keys form unquoted SET statements, which can be used for
* things like "field = field + 1" or similar computed values.
- * @param array $conds An array of conditions (WHERE). See
+ * @param array|string $conds An array of conditions (WHERE). See
* IDatabase::select() for the details of the format of condition
* arrays. Use '*' to update all rows.
* @param string $fname The function name of the caller (from __METHOD__),
* @param array $options An array of UPDATE options, can be:
* - IGNORE: Ignore unique key conflicts
* @return bool Return true if no exception was thrown (deprecated since 1.33)
- * @throws DBError
+ * @throws DBError If an error occurs, see IDatabase::query()
*/
public function update( $table, $values, $conds, $fname = __METHOD__, $options = [] );
* - IDatabase::LIST_OR: ORed WHERE clause (without the WHERE)
* - IDatabase::LIST_SET: Comma separated with field names, like a SET clause
* - IDatabase::LIST_NAMES: Comma separated field names
- * @throws DBError
+ * @throws DBError If an error occurs, see IDatabase::query()
* @return string
*/
public function makeList( $a, $mode = self::LIST_COMMA );
* @param array $valuedata
* @param string $valuename
*
- * @return string
+ * @return array|string
* @deprecated Since 1.33
*/
public function aggregateValue( $valuedata, $valuename = 'value' );
/**
* Build a concatenation list to feed into a SQL query
- * @param array $stringList List of raw SQL expressions; caller is
- * responsible for any quoting
+ * @param string[] $stringList Raw SQL expression list; caller is responsible for escaping
* @return string
*/
public function buildConcat( $stringList );
);
/**
- * Build a SUBSTRING function.
+ * Build a SUBSTRING function
*
* Behavior for non-ASCII values is undefined.
*
* @since 1.31
*/
public function buildSelectSubquery(
- $table, $vars, $conds = '', $fname = __METHOD__,
- $options = [], $join_conds = []
+ $table,
+ $vars,
+ $conds = '',
+ $fname = __METHOD__,
+ $options = [],
+ $join_conds = []
);
/**
- * Construct a LIMIT query with optional offset. This is used for query
- * pages. The SQL should be adjusted so that only the first $limit rows
+ * Construct a LIMIT query with optional offset
+ *
+ * The SQL should be adjusted so that only the first $limit rows
* are returned. If $offset is provided as well, then the first $offset
* rows should be discarded, and the next $limit rows should be returned.
* If the result of the query is not ordered, then the rows to be returned
* @param string $sql SQL query we will append the limit too
* @param int $limit The SQL limit
* @param int|bool $offset The SQL offset (default false)
- * @throws DBUnexpectedError
* @return string
* @since 1.34
*/
*
* In systems like mysql/mariadb, different databases can easily be referenced on a single
* connection merely by name, even in a single query via JOIN. On the other hand, Postgres
- * treats databases as logically separate, with different database users, requiring special
- * mechanisms like postgres_fdw to "mount" foreign DBs. This is true even among DBs on the
- * same server. Changing the selected database via selectDomain() requires a new connection.
+ * treats databases as fully separate, only allowing mechanisms like postgres_fdw to
+ * effectively "mount" foreign DBs. This is true even among DBs on the same server.
*
* @return bool
* @since 1.29
public function getServer();
/**
- * Adds quotes and backslashes.
+ * Escape and quote a raw value string for use in a SQL query
*
* @param string|int|null|bool|Blob $s
* @return string|int
public function addQuotes( $s );
/**
- * Quotes an identifier, in order to make user controlled input safe
+ * Escape a SQL identifier (e.g. table, column, database) for use in a SQL query
*
* Depending on the database this will either be `backticks` or "double quotes"
*
public function addIdentifierQuotes( $s );
/**
- * LIKE statement wrapper, receives a variable-length argument list with
- * parts of pattern to match containing either string literals that will be
- * escaped or tokens returned by anyChar() or anyString(). Alternatively,
- * the function could be provided with an array of aforementioned
- * parameters.
+ * LIKE statement wrapper
+ *
+ * This takes a variable-length argument list with parts of pattern to match
+ * containing either string literals that will be escaped or tokens returned by
+ * anyChar() or anyString(). Alternatively, the function could be provided with
+ * an array of aforementioned parameters.
*
* Example: $dbr->buildLike( 'My_page_title/', $dbr->anyString() ) returns
* a LIKE clause that searches for subpages of 'My page title'.
public function anyString();
/**
- * Deprecated method, calls should be removed.
+ * Deprecated method, calls should be removed
*
- * This was formerly used for PostgreSQL and Oracle to handle
+ * This was formerly used for PostgreSQL to handle
* self::insertId() auto-incrementing fields. It is no longer necessary
* since DatabasePostgres::insertId() has been reimplemented using
- * `lastval()` and Oracle has been reimplemented using triggers.
+ * `lastval()`
*
* Implementations should return null if inserting `NULL` into an
* auto-incrementing field works, otherwise it should return an instance of
public function nextSequenceValue( $seqName );
/**
- * REPLACE query wrapper.
+ * REPLACE query wrapper
*
* REPLACE is a very handy MySQL extension, which functions like an INSERT
* except that when there is a duplicate key error, the old row is deleted
* @param array $rows Can be either a single row to insert, or multiple rows,
* in the same format as for IDatabase::insert()
* @param string $fname Calling function name (use __METHOD__) for logs/profiling
- * @throws DBError
+ * @throws DBError If an error occurs, see IDatabase::query()
*/
public function replace( $table, $uniqueIndexes, $rows, $fname = __METHOD__ );
* to collide. However if you do this, you run the risk of encountering
* errors which wouldn't have occurred in MySQL.
*
- * Usually throws a DBQueryError on failure. If errors are explicitly ignored,
- * returns success.
- *
- * @since 1.22
- *
* @param string $table Table name. This will be passed through Database::tableName().
* @param array $rows A single row or list of rows to insert
* @param array[]|string[]|string $uniqueIndexes All unique indexes. One of the following:
* Values with integer keys form unquoted SET statements, which can be used for
* things like "field = field + 1" or similar computed values.
* @param string $fname Calling function name (use __METHOD__) for logs/profiling
- * @throws DBError
* @return bool Return true if no exception was thrown (deprecated since 1.33)
+ * @throws DBError If an error occurs, see IDatabase::query()
+ * @since 1.22
*/
public function upsert(
$table, array $rows, $uniqueIndexes, array $set, $fname = __METHOD__
* @param string $joinTable The other table.
* @param string $delVar The variable to join on, in the first table.
* @param string $joinVar The variable to join on, in the second table.
- * @param array $conds Condition array of field names mapped to variables,
+ * @param array|string $conds Condition array of field names mapped to variables,
* ANDed together in the WHERE clause
* @param string $fname Calling function name (use __METHOD__) for logs/profiling
- * @throws DBError
- */
- public function deleteJoin( $delTable, $joinTable, $delVar, $joinVar, $conds,
+ * @throws DBError If an error occurs, see IDatabase::query()
+ */
+ public function deleteJoin(
+ $delTable,
+ $joinTable,
+ $delVar,
+ $joinVar,
+ $conds,
$fname = __METHOD__
);
/**
- * DELETE query wrapper.
+ * DELETE query wrapper
*
* @param string $table Table name
* @param string|array $conds Array of conditions. See $conds in IDatabase::select()
* for the format. Use $conds == "*" to delete all rows
* @param string $fname Name of the calling function
- * @throws DBUnexpectedError
* @return bool Return true if no exception was thrown (deprecated since 1.33)
- * @throws DBError
+ * @throws DBError If an error occurs, see IDatabase::query()
*/
public function delete( $table, $conds, $fname = __METHOD__ );
/**
- * INSERT SELECT wrapper. Takes data from a SELECT query and inserts it
- * into another table.
+ * INSERT SELECT wrapper
*
* @warning If the insert will use an auto-increment or sequence to
* determine the value of a column, this may break replication on
* @param string $destTable The table name to insert into
* @param string|array $srcTable May be either a table name, or an array of table names
* to include in a join.
- *
* @param array $varMap Must be an associative array of the form
* [ 'dest1' => 'source1', ... ]. Source items may be literals
* rather than field names, but strings should be quoted with
* IDatabase::addQuotes()
- *
* @param array $conds Condition array. See $conds in IDatabase::select() for
* the details of the format of condition arrays. May be "*" to copy the
* whole table.
- *
* @param string $fname The function name of the caller, from __METHOD__
- *
* @param array $insertOptions Options for the INSERT part of the query, see
* IDatabase::insert() for details. Also, one additional option is
* available: pass 'NO_AUTO_COLUMNS' to hint that the query does not use
* IDatabase::select() for details.
* @param array $selectJoinConds Join conditions for the SELECT part of the query, see
* IDatabase::select() for details.
- *
* @return bool Return true if no exception was thrown (deprecated since 1.33)
- * @throws DBError
+ * @throws DBError If an error occurs, see IDatabase::query()
*/
- public function insertSelect( $destTable, $srcTable, $varMap, $conds,
+ public function insertSelect(
+ $destTable,
+ $srcTable,
+ $varMap,
+ $conds,
$fname = __METHOD__,
- $insertOptions = [], $selectOptions = [], $selectJoinConds = []
+ $insertOptions = [],
+ $selectOptions = [],
+ $selectJoinConds = []
);
/**
- * Returns true if current database backend supports ORDER BY or LIMIT for separate subqueries
- * within the UNION construct.
+ * Determine if the RDBMS supports ORDER BY and LIMIT for separate subqueries within UNION
+ *
* @return bool
*/
public function unionSupportsOrderAndLimit();
/**
* Construct a UNION query
+ *
* This is used for providing overload point for other DB abstractions
* not compatible with the MySQL syntax.
* @param array $sqls SQL statements to combine
* conditions and unions them all together.
*
* @see IDatabase::select()
- * @since 1.30
* @param string|array $table Table name
* @param string|array $vars Field names
* @param array $permute_conds Conditions for the Cartesian product. Keys
* instead of ORDER BY.
* @param string|array $join_conds Join conditions
* @return string SQL query string.
+ * @since 1.30
*/
public function unionConditionPermutations(
- $table, $vars, array $permute_conds, $extra_conds = '', $fname = __METHOD__,
- $options = [], $join_conds = []
+ $table,
+ $vars,
+ array $permute_conds,
+ $extra_conds = '',
+ $fname = __METHOD__,
+ $options = [],
+ $join_conds = []
);
/**
- * Returns an SQL expression for a simple conditional. This doesn't need
- * to be overridden unless CASE isn't supported in your DBMS.
+ * Returns an SQL expression for a simple conditional
+ *
+ * This doesn't need to be overridden unless CASE isn't supported in the RDBMS.
*
* @param string|array $cond SQL expression which will result in a boolean value
* @param string $trueVal SQL expression to return if true
public function conditional( $cond, $trueVal, $falseVal );
/**
- * Returns a command for str_replace function in SQL query.
- * Uses REPLACE() in MySQL
+ * Returns a SQL expression for simple string replacement (e.g. REPLACE() in mysql)
*
* @param string $orig Column to modify
* @param string $old Column to seek
* @param string $new Column to replace with
- *
* @return string
*/
public function strreplace( $orig, $old, $new );
public function wasConnectionLoss();
/**
- * Determines if the last failure was due to the database being read-only.
+ * Determines if the last failure was due to the database being read-only
*
* @return bool
*/
* @return int|null Zero if the replica DB was past that position already,
* greater than zero if we waited for some period of time, less than
* zero if it timed out, and null on error
- * @throws DBError
+ * @throws DBError If an error occurs, see IDatabase::query()
*/
public function masterPosWait( DBMasterPos $pos, $timeout );
* Get the replication position of this replica DB
*
* @return DBMasterPos|bool False if this is not a replica DB
- * @throws DBError
+ * @throws DBError If an error occurs, see IDatabase::query()
*/
public function getReplicaPos();
* Get the position of this master
*
* @return DBMasterPos|bool False if this is not a master
- * @throws DBError
+ * @throws DBError If an error occurs, see IDatabase::query()
*/
public function getMasterPos();
public function serverIsReadOnly();
/**
- * Run a callback as soon as the current transaction commits or rolls back.
+ * Run a callback as soon as the current transaction commits or rolls back
+ *
* An error is thrown if no transaction is pending. Queries in the function will run in
* AUTOCOMMIT mode unless there are begin() calls. Callbacks must commit any transactions
* that they begin.
*
* @param callable $callback
* @param string $fname Caller name
+ * @throws DBError If an error occurs, see IDatabase::query()
+ * @throws Exception If the callback runs immediately and an error occurs in it
* @since 1.28
*/
public function onTransactionResolution( callable $callback, $fname = __METHOD__ );
/**
- * Run a callback as soon as there is no transaction pending.
+ * Run a callback as soon as there is no transaction pending
+ *
* If there is a transaction and it is rolled back, then the callback is cancelled.
*
* When transaction round mode (DBO_TRX) is set, the callback will run at the end
*
* @param callable $callback
* @param string $fname Caller name
+ * @throws DBError If an error occurs, see IDatabase::query()
+ * @throws Exception If the callback runs immediately and an error occurs in it
* @since 1.32
*/
public function onTransactionCommitOrIdle( callable $callback, $fname = __METHOD__ );
public function onTransactionIdle( callable $callback, $fname = __METHOD__ );
/**
- * Run a callback before the current transaction commits or now if there is none.
+ * Run a callback before the current transaction commits or now if there is none
+ *
* If there is a transaction and it is rolled back, then the callback is cancelled.
*
* When transaction round mode (DBO_TRX) is set, the callback will run at the end
*
* @param callable $callback
* @param string $fname Caller name
+ * @throws DBError If an error occurs, see IDatabase::query()
+ * @throws Exception If the callback runs immediately and an error occurs in it
* @since 1.22
*/
public function onTransactionPreCommitOrIdle( callable $callback, $fname = __METHOD__ );
/**
- * Run a callback when the atomic section is cancelled.
+ * Run a callback when the atomic section is cancelled
*
* The callback is run just after the current atomic section, any outer
* atomic section, or the whole transaction is rolled back.
* @param string $cancelable Pass self::ATOMIC_CANCELABLE to use a
* savepoint and enable self::cancelAtomic() for this section.
* @return AtomicSectionIdentifier section ID token
- * @throws DBError
+ * @throws DBError If an error occurs, see IDatabase::query()
*/
public function startAtomic( $fname = __METHOD__, $cancelable = self::ATOMIC_NOT_CANCELABLE );
* @since 1.23
* @see IDatabase::startAtomic
* @param string $fname
- * @throws DBError
+ * @throws DBError If an error occurs, see IDatabase::query()
*/
public function endAtomic( $fname = __METHOD__ );
* @param string $fname
* @param AtomicSectionIdentifier|null $sectionId Section ID from startAtomic();
* passing this enables cancellation of unclosed nested sections [optional]
- * @throws DBError
+ * @throws DBError If an error occurs, see IDatabase::query()
*/
public function cancelAtomic( $fname = __METHOD__, AtomicSectionIdentifier $sectionId = null );
* @param string $cancelable Pass self::ATOMIC_CANCELABLE to use a
* savepoint and enable self::cancelAtomic() for this section.
* @return mixed $res Result of the callback (since 1.28)
- * @throws DBError
- * @throws RuntimeException
+ * @throws DBError If an error occurs, see IDatabase::query()
+ * @throws Exception If an error occurs in the callback
* @since 1.27; prior to 1.31 this did a rollback() instead of
* cancelAtomic(), and assumed no callers up the stack would ever try to
* catch the exception.
);
/**
- * Begin a transaction. If a transaction is already in progress,
- * that transaction will be committed before the new transaction is started.
+ * Begin a transaction
*
* Only call this from code with outer transcation scope.
* See https://www.mediawiki.org/wiki/Database_transactions for details.
*
* @param string $fname Calling function name
* @param string $mode A situationally valid IDatabase::TRANSACTION_* constant [optional]
- * @throws DBError
+ * @throws DBError If an error occurs, see IDatabase::query()
*/
public function begin( $fname = __METHOD__, $mode = self::TRANSACTION_EXPLICIT );
/**
- * Commits a transaction previously started using begin().
+ * Commits a transaction previously started using begin()
+ *
* If no transaction is in progress, a warning is issued.
*
* Only call this from code with outer transcation scope.
* @param string $flush Flush flag, set to situationally valid IDatabase::FLUSHING_*
* constant to disable warnings about explicitly committing implicit transactions,
* or calling commit when no transaction is in progress.
- *
* This will trigger an exception if there is an ongoing explicit transaction.
- *
* Only set the flush flag if you are sure that these warnings are not applicable,
* and no explicit transactions are open.
- *
- * @throws DBError
+ * @throws DBError If an error occurs, see IDatabase::query()
*/
public function commit( $fname = __METHOD__, $flush = self::FLUSHING_ONE );
/**
- * Rollback a transaction previously started using begin().
- * If no transaction is in progress, a warning is issued.
+ * Rollback a transaction previously started using begin()
*
* Only call this from code with outer transcation scope.
* See https://www.mediawiki.org/wiki/Database_transactions for details.
* constant to disable warnings about calling rollback when no transaction is in
* progress. This will silently break any ongoing explicit transaction. Only set the
* flush flag if you are sure that it is safe to ignore these warnings in your context.
- * @throws DBError
+ * @throws DBError If an error occurs, see IDatabase::query()
* @since 1.23 Added $flush parameter
*/
public function rollback( $fname = __METHOD__, $flush = self::FLUSHING_ONE );
* @param string $flush Flush flag, set to situationally valid IDatabase::FLUSHING_*
* constant to disable warnings about explicitly committing implicit transactions,
* or calling commit when no transaction is in progress.
- *
* This will trigger an exception if there is an ongoing explicit transaction.
- *
* Only set the flush flag if you are sure that these warnings are not applicable,
* and no explicit transactions are open.
- *
- * @throws DBError
+ * @throws DBError If an error occurs, see IDatabase::query()
* @since 1.28
* @since 1.34 Added $flush parameter
*/
public function flushSnapshot( $fname = __METHOD__, $flush = self::FLUSHING_ONE );
/**
- * Convert a timestamp in one of the formats accepted by wfTimestamp()
- * to the format used for inserting into timestamp fields in this DBMS.
+ * Convert a timestamp in one of the formats accepted by ConvertibleTimestamp
+ * to the format used for inserting into timestamp fields in this DBMS
*
* The result is unquoted, and needs to be passed through addQuotes()
* before it can be included in raw SQL.
public function timestamp( $ts = 0 );
/**
- * Convert a timestamp in one of the formats accepted by wfTimestamp()
- * to the format used for inserting into timestamp fields in this DBMS. If
- * NULL is input, it is passed through, allowing NULL values to be inserted
+ * Convert a timestamp in one of the formats accepted by ConvertibleTimestamp
+ * to the format used for inserting into timestamp fields in this DBMS
+ *
+ * If NULL is input, it is passed through, allowing NULL values to be inserted
* into timestamp fields.
*
* The result is unquoted, and needs to be passed through addQuotes()
* Callers should avoid using this method while a transaction is active
*
* @return int|bool Database replication lag in seconds or false on error
- * @throws DBError
+ * @throws DBError If an error occurs, see IDatabase::query()
*/
public function getLag();
* indication of the staleness of subsequent reads.
*
* @return array ('lag': seconds or false on error, 'since': UNIX timestamp of BEGIN)
- * @throws DBError
+ * @throws DBError If an error occurs, see IDatabase::query()
* @since 1.27
*/
public function getSessionLagStatus();
/**
- * Return the maximum number of items allowed in a list, or 0 for unlimited.
+ * Return the maximum number of items allowed in a list, or 0 for unlimited
*
* @return int
*/
*
* @param string $b
* @return string|Blob
+ * @throws DBError
*/
public function encodeBlob( $b );
*
* @param string|Blob $b
* @return string
+ * @throws DBError
*/
public function decodeBlob( $b );
*
* @param array $options
* @return void
- * @throws DBError
+ * @throws DBError If an error occurs, see IDatabase::query()
*/
public function setSessionOptions( array $options );
/**
- * Set schema variables to be used when streaming commands from SQL files or stdin
- *
- * Variables appear as SQL comments and are substituted by their corresponding values
+ * Set variables to be used in sourceFile/sourceStream, in preference to the
+ * ones in $GLOBALS. If an array is set here, $GLOBALS will not be used at
+ * all. If it's set to false, $GLOBALS will be used.
*
- * @param array|null $vars Map of (variable => value) or null to use the defaults
+ * @param bool|array $vars Mapping variable name to value.
*/
public function setSchemaVars( $vars );
* @param string $lockName Name of lock to poll
* @param string $method Name of method calling us
* @return bool
- * @throws DBError
+ * @throws DBError If an error occurs, see IDatabase::query()
* @since 1.20
*/
public function lockIsFree( $lockName, $method );
* @param string $lockName Name of lock to aquire
* @param string $method Name of the calling method
* @param int $timeout Acquisition timeout in seconds (0 means non-blocking)
- * @return bool
- * @throws DBError
+ * @return bool Success
+ * @throws DBError If an error occurs, see IDatabase::query()
*/
public function lock( $lockName, $method, $timeout = 5 );
*
* @param string $lockName Name of lock to release
* @param string $method Name of the calling method
- *
- * @return int Returns 1 if the lock was released, 0 if the lock was not established
- * by this thread (in which case the lock is not released), and NULL if the named lock
- * did not exist
- *
- * @throws DBError
+ * @return bool Success
+ * @throws DBError If an error occurs, see IDatabase::query()
*/
public function unlock( $lockName, $method );
* @param string $fname Name of the calling method
* @param int $timeout Acquisition timeout in seconds
* @return ScopedCallback|null
- * @throws DBError
+ * @throws DBError If an error occurs, see IDatabase::query()
* @since 1.27
*/
public function getScopedLockAndFlush( $lockKey, $fname, $timeout );
* @see https://dev.mysql.com/doc/refman/5.6/en/replication-gtids-concepts.html
*/
class MySQLMasterPos implements DBMasterPos {
- /** @var int One of (BINARY_LOG, GTID_MYSQL, GTID_MARIA) */
+ /** @var string One of (BINARY_LOG, GTID_MYSQL, GTID_MARIA) */
private $style;
/** @var string|null Base name of all Binary Log files */
private $binLog;
/**
* @return stdClass
+ * @suppress PhanParamSignatureMismatchInternal
*/
function next();
}
+++ /dev/null
-<?php
-
-namespace Wikimedia\Rdbms;
-
-use stdClass;
-
-class MssqlResultWrapper extends ResultWrapper {
- /** @var int|null */
- private $seekTo = null;
-
- /**
- * @return stdClass|bool
- */
- public function fetchObject() {
- $res = $this->result;
-
- if ( $this->seekTo !== null ) {
- $result = sqlsrv_fetch_object( $res, stdClass::class, [],
- SQLSRV_SCROLL_ABSOLUTE, $this->seekTo );
- $this->seekTo = null;
- } else {
- $result = sqlsrv_fetch_object( $res );
- }
-
- // Return boolean false when there are no more rows instead of null
- if ( $result === null ) {
- return false;
- }
-
- return $result;
- }
-
- /**
- * @return array|bool
- */
- public function fetchRow() {
- $res = $this->result;
-
- if ( $this->seekTo !== null ) {
- $result = sqlsrv_fetch_array( $res, SQLSRV_FETCH_BOTH,
- SQLSRV_SCROLL_ABSOLUTE, $this->seekTo );
- $this->seekTo = null;
- } else {
- $result = sqlsrv_fetch_array( $res );
- }
-
- // Return boolean false when there are no more rows instead of null
- if ( $result === null ) {
- return false;
- }
-
- return $result;
- }
-
- /**
- * @param int $row
- * @return bool
- */
- public function seek( $row ) {
- $res = $this->result;
-
- // check bounds
- $numRows = $this->db->numRows( $res );
- $row = intval( $row );
-
- if ( $numRows === 0 ) {
- return false;
- } elseif ( $row < 0 || $row > $numRows - 1 ) {
- return false;
- }
-
- // Unlike MySQL, the seek actually happens on the next access
- $this->seekTo = $row;
- return true;
- }
-}
+++ /dev/null
-<?php
-
-namespace Wikimedia\Rdbms;
-
-class MssqlBlob extends Blob {
- /** @noinspection PhpMissingParentConstructorInspection */
-
- /**
- * @param Blob|string $data
- */
- public function __construct( $data ) {
- if ( $data instanceof MssqlBlob ) {
- $this->data = $data->data;
- } elseif ( $data instanceof Blob ) {
- $this->data = $data->fetch();
- } else {
- $this->data = $data;
- }
- }
-
- /**
- * Returns an unquoted hex representation of a binary string
- * for insertion into varbinary-type fields
- * @return string
- */
- public function fetch() {
- if ( $this->data === null ) {
- return 'null';
- }
-
- $ret = '0x';
- $dataLength = strlen( $this->data );
- for ( $i = 0; $i < $dataLength; $i++ ) {
- $ret .= bin2hex( pack( 'C', ord( $this->data[$i] ) ) );
- }
-
- return $ret;
- }
-}
+++ /dev/null
-<?php
-
-namespace Wikimedia\Rdbms;
-
-class MssqlField implements Field {
- private $name, $tableName, $default, $max_length, $nullable, $type;
-
- function __construct( $info ) {
- $this->name = $info['COLUMN_NAME'];
- $this->tableName = $info['TABLE_NAME'];
- $this->default = $info['COLUMN_DEFAULT'];
- $this->max_length = $info['CHARACTER_MAXIMUM_LENGTH'];
- $this->nullable = !( strtolower( $info['IS_NULLABLE'] ) == 'no' );
- $this->type = $info['DATA_TYPE'];
- }
-
- function name() {
- return $this->name;
- }
-
- function tableName() {
- return $this->tableName;
- }
-
- function defaultValue() {
- return $this->default;
- }
-
- function maxLength() {
- return $this->max_length;
- }
-
- function isNullable() {
- return $this->nullable;
- }
-
- function type() {
- return $this->type;
- }
-}
$this->defaultGroup = $conf['defaultGroup'] ?? null;
$this->secret = $conf['secret'] ?? '';
- static $nextId, $nextTicket;
- $this->id = $nextId = ( is_int( $nextId ) ? $nextId++ : mt_rand() );
- $this->ticket = $nextTicket = ( is_int( $nextTicket ) ? $nextTicket++ : mt_rand() );
+ $this->id = mt_rand();
+ $this->ticket = mt_rand();
}
public function destroy() {
+ /** @noinspection PhpUnusedLocalVariableInspection */
+ $scope = ScopedCallback::newScopedIgnoreUserAbort();
+
$this->forEachLBCallMethod( 'disable' );
}
&$cpIndex = null,
&$cpClientId = null
) {
+ /** @noinspection PhpUnusedLocalVariableInspection */
+ $scope = ScopedCallback::newScopedIgnoreUserAbort();
+
$chronProt = $this->getChronologyProtector();
if ( $mode === self::SHUTDOWN_CHRONPROT_SYNC ) {
$this->shutdownChronologyProtector( $chronProt, $workCallback, 'sync', $cpIndex );
final public function beginMasterChanges( $fname = __METHOD__ ) {
$this->assertTransactionRoundStage( self::ROUND_CURSORY );
+ /** @noinspection PhpUnusedLocalVariableInspection */
+ $scope = ScopedCallback::newScopedIgnoreUserAbort();
+
$this->trxRoundStage = self::ROUND_BEGINNING;
if ( $this->trxRoundId !== false ) {
throw new DBTransactionError(
final public function commitMasterChanges( $fname = __METHOD__, array $options = [] ) {
$this->assertTransactionRoundStage( self::ROUND_CURSORY );
+ /** @noinspection PhpUnusedLocalVariableInspection */
+ $scope = ScopedCallback::newScopedIgnoreUserAbort();
+
$this->trxRoundStage = self::ROUND_COMMITTING;
if ( $this->trxRoundId !== false && $this->trxRoundId !== $fname ) {
throw new DBTransactionError(
"$fname: transaction round '{$this->trxRoundId}' still running"
);
}
- /** @noinspection PhpUnusedLocalVariableInspection */
- $scope = ScopedCallback::newScopedIgnoreUserAbort(); // try to ignore client aborts
// Run pre-commit callbacks and suppress post-commit callbacks, aborting on failure
do {
$count = 0; // number of callbacks executed this iteration
}
final public function rollbackMasterChanges( $fname = __METHOD__ ) {
+ /** @noinspection PhpUnusedLocalVariableInspection */
+ $scope = ScopedCallback::newScopedIgnoreUserAbort();
+
$this->trxRoundStage = self::ROUND_ROLLING_BACK;
$this->trxRoundId = false;
// Actually perform the rollback on all master DB connections and revert DBO_TRX
}
public function closeAll() {
+ /** @noinspection PhpUnusedLocalVariableInspection */
+ $scope = ScopedCallback::newScopedIgnoreUserAbort();
+
$this->forEachLBCallMethod( 'closeAll' );
}
foreach ( $loads as $serverName => $load ) {
$serverInfo = $template;
if ( $master ) {
+ $serverInfo['master'] = true;
if ( $this->masterTemplateOverrides ) {
$serverInfo = $this->masterTemplateOverrides + $serverInfo;
}
$master = false;
} else {
+ $serverInfo['replica'] = true;
}
if ( isset( $this->templateOverridesByServer[$serverName] ) ) {
$serverInfo = $this->templateOverridesByServer[$serverName] + $serverInfo;
parent::__construct( $conf );
$this->servers = $conf['servers'] ?? [];
+ foreach ( $this->servers as $i => $server ) {
+ if ( $i == 0 ) {
+ $this->servers[$i]['master'] = true;
+ } else {
+ $this->servers[$i]['replica'] = true;
+ }
+ }
+
$this->externalClusters = $conf['externalClusters'] ?? [];
$this->loadMonitorClass = $conf['loadMonitorClass'] ?? 'LoadMonitor';
}
const CONN_SILENCE_ERRORS = 2;
/** @var int Caller is requesting the master DB server for possibly writes */
const CONN_INTENT_WRITABLE = 4;
+ /** @var int Bypass and update any server-side read-only mode state cache */
+ const CONN_REFRESH_READ_ONLY = 8;
/** @var string Manager of ILoadBalancer instances is running post-commit callbacks */
const STAGE_POSTCOMMIT_CALLBACKS = 'stage-postcommit-callbacks';
*/
public function redefineLocalDomain( $domain );
+ /**
+ * Indicate whether the tables on this domain are only temporary tables for testing
+ *
+ * In "temporary tables mode", the ILoadBalancer::CONN_TRX_AUTOCOMMIT flag is ignored
+ *
+ * @param bool $value
+ * @param string $domain
+ * @return bool Whether "temporary tables mode" was active
+ * @since 1.34
+ */
+ public function setTempTablesOnlyMode( $value, $domain );
+
/**
* Get the server index of the reader connection for a given group
*
/**
* @note This method may trigger a DB connection if not yet done
* @param string|bool $domain DB domain ID or false for the local domain
- * @param IDatabase|null $conn DB master connection; used to avoid loops [optional]
* @return string|bool Reason the master is read-only or false if it is not
*/
- public function getReadOnlyReason( $domain = false, IDatabase $conn = null );
+ public function getReadOnlyReason( $domain = false );
/**
* Disables/enables lag checks
/** @var DatabaseDomain Local DB domain ID and default for selectDB() calls */
private $localDomain;
- /** @var Database[][][] Map of (connection category => server index => IDatabase[]) */
+ /**
+ * @var IDatabase[][][]|Database[][][] Map of (connection category => server index => IDatabase[])
+ */
private $conns;
/** @var array[] Map of (server index => server config array) */
private $tableAliases = [];
/** @var string[] Map of (index alias => index) */
private $indexAliases = [];
- /** @var array[] Map of (name => callable) */
+ /** @var callable[] Map of (name => callable) */
private $trxRecurringCallbacks = [];
+ /** @var bool[] Map of (domain => whether to use "temp tables only" mode) */
+ private $tempTablesOnlyMode = [];
/** @var Database Connection handle that caused a problem */
private $errorConnection;
/** @var bool Whether any connection has been attempted yet */
private $connectionAttempted = false;
- /** var int An identifier for this class instance */
- private $id;
/** @var int|null Integer ID of the managing LBFactory instance or null if none */
private $ownerId;
/** @var string|bool Explicit DBO_TRX transaction round active or false if none */
if ( ++$listKey !== $i ) {
throw new UnexpectedValueException( 'List expected for "servers" parameter' );
}
+ if ( $i == 0 ) {
+ $server['master'] = true;
+ } else {
+ $server['replica'] = true;
+ }
$this->servers[$i] = $server;
foreach ( ( $server['groupLoads'] ?? [] ) as $group => $ratio ) {
$this->groupLoads[$group][$i] = $ratio;
$group = $params['defaultGroup'] ?? self::GROUP_GENERIC;
$this->defaultGroup = isset( $this->groupLoads[$group] ) ? $group : self::GROUP_GENERIC;
- static $nextId;
- $this->id = $nextId = ( is_int( $nextId ) ? $nextId++ : mt_rand() );
$this->ownerId = $params['ownerId'] ?? null;
}
/**
* @param int $flags Bitfield of class CONN_* constants
* @param int $i Specific server index or DB_MASTER/DB_REPLICA
+ * @param string $domain Database domain
* @return int Sanitized bitfield
*/
- private function sanitizeConnectionFlags( $flags, $i ) {
+ private function sanitizeConnectionFlags( $flags, $i, $domain ) {
// Whether an outside caller is explicitly requesting the master database server
if ( $i === self::DB_MASTER || $i === $this->getWriterIndex() ) {
$flags |= self::CONN_INTENT_WRITABLE;
$flags &= ~self::CONN_TRX_AUTOCOMMIT;
$type = $this->getServerType( $this->getWriterIndex() );
$this->connLogger->info( __METHOD__ . ": CONN_TRX_AUTOCOMMIT disallowed ($type)" );
+ } elseif ( isset( $this->tempTablesOnlyMode[$domain] ) ) {
+ // T202116: integration tests are active and queries should be all be using
+ // temporary clone tables (via prefix). Such tables are not visible accross
+ // different connections nor can there be REPEATABLE-READ snapshot staleness,
+ // so use the same connection for everything.
+ $flags &= ~self::CONN_TRX_AUTOCOMMIT;
}
}
public function getConnection( $i, $groups = [], $domain = false, $flags = 0 ) {
$domain = $this->resolveDomainID( $domain );
$groups = $this->resolveGroups( $groups, $i );
- $flags = $this->sanitizeConnectionFlags( $flags, $i );
+ $flags = $this->sanitizeConnectionFlags( $flags, $i, $domain );
// If given DB_MASTER/DB_REPLICA, resolve it to a specific server index. Resolving
// DB_REPLICA might trigger getServerConnection() calls due to the getReaderIndex()
// connectivity checks or LoadMonitor::scaleLoads() server state cache regeneration.
// Get an open connection to that server (might trigger a new connection)
$conn = $this->getServerConnection( $serverIndex, $domain, $flags );
// Set master DB handles as read-only if there is high replication lag
- if ( $serverIndex === $this->getWriterIndex() && $this->getLaggedReplicaMode( $domain ) ) {
+ if (
+ $serverIndex === $this->getWriterIndex() &&
+ $this->getLaggedReplicaMode( $domain ) &&
+ !is_string( $conn->getLBInfo( 'readOnlyReason' ) )
+ ) {
$reason = ( $this->getExistingReaderIndex( self::GROUP_GENERIC ) >= 0 )
? 'The database is read-only until replication lag decreases.'
: 'The database is read-only until replica database servers becomes reachable.';
// or the master database server is running in server-side read-only mode. Note that
// replica DB handles are always read-only via Database::assertIsWritableMaster().
// Read-only mode due to replication lag is *avoided* here to avoid recursion.
- if ( $conn->getLBInfo( 'serverIndex' ) === $this->getWriterIndex() ) {
+ if ( $i === $this->getWriterIndex() ) {
if ( $this->readOnlyReason !== false ) {
- $conn->setLBInfo( 'readOnlyReason', $this->readOnlyReason );
- } elseif ( $this->masterRunningReadOnly( $domain, $conn ) ) {
- $conn->setLBInfo(
- 'readOnlyReason',
- 'The master database server is running in read-only mode.'
- );
+ $readOnlyReason = $this->readOnlyReason;
+ } elseif ( $this->isMasterConnectionReadOnly( $conn, $flags ) ) {
+ $readOnlyReason = 'The master database server is running in read-only mode.';
+ } else {
+ $readOnlyReason = false;
}
+ $conn->setLBInfo( 'readOnlyReason', $readOnlyReason );
}
return $conn;
*
* @note If disable() was called on this LoadBalancer, this method will throw a DBAccessError.
*
- * @param int $i Specific server index
+ * @param int $i Server index
* @param int $flags Class CONN_* constant bitfield
* @return Database
* @throws InvalidArgumentException When the server index is invalid
* @throws UnexpectedValueException When the DB domain of the connection is corrupted
*/
private function getLocalConnection( $i, $flags = 0 ) {
- $autoCommit = ( ( $flags & self::CONN_TRX_AUTOCOMMIT ) == self::CONN_TRX_AUTOCOMMIT );
// Connection handles required to be in auto-commit mode use a separate connection
// pool since the main pool is effected by implicit and explicit transaction rounds
- $connKey = $autoCommit ? self::KEY_LOCAL_NOROUND : self::KEY_LOCAL;
+ $autoCommit = ( ( $flags & self::CONN_TRX_AUTOCOMMIT ) == self::CONN_TRX_AUTOCOMMIT );
+ $connKey = $autoCommit ? self::KEY_LOCAL_NOROUND : self::KEY_LOCAL;
if ( isset( $this->conns[$connKey][$i][0] ) ) {
$conn = $this->conns[$connKey][$i][0];
} else {
- $conn = $this->reallyOpenConnection(
- $i,
- $this->localDomain,
- [ 'autoCommitOnly' => $autoCommit ]
- );
+ // Open a new connection
+ $server = $this->getServerInfoStrict( $i );
+ $server['serverIndex'] = $i;
+ $server['autoCommitOnly'] = $autoCommit;
+ $conn = $this->reallyOpenConnection( $server, $this->localDomain );
+ $host = $this->getServerName( $i );
if ( $conn->isOpen() ) {
- $this->connLogger->debug( __METHOD__ . ": opened new connection for $i" );
+ $this->connLogger->debug(
+ __METHOD__ . ": connected to database $i at '$host'." );
$this->conns[$connKey][$i][0] = $conn;
} else {
- $this->connLogger->warning( __METHOD__ . ": connection error for $i" );
+ $this->connLogger->warning(
+ __METHOD__ . ": failed to connect to database $i at '$host'." );
$this->errorConnection = $conn;
$conn = false;
}
}
- // Sanity check to make sure that the right domain is selected
+ // Final sanity check to make sure the right domain is selected
if (
$conn instanceof IDatabase &&
!$this->localDomain->isCompatible( $conn->getDomainID() )
) {
throw new UnexpectedValueException(
"Got connection to '{$conn->getDomainID()}', " .
- "but expected local domain ('{$this->localDomain}')"
- );
+ "but expected local domain ('{$this->localDomain}')" );
}
return $conn;
*
* @note If disable() was called on this LoadBalancer, this method will throw a DBAccessError.
*
- * @param int $i Specific server index
+ * @param int $i Server index
* @param string $domain Domain ID to open
* @param int $flags Class CONN_* constant bitfield
* @return Database|bool Returns false on connection error
*/
private function getForeignConnection( $i, $domain, $flags = 0 ) {
$domainInstance = DatabaseDomain::newFromId( $domain );
- $autoCommit = ( ( $flags & self::CONN_TRX_AUTOCOMMIT ) == self::CONN_TRX_AUTOCOMMIT );
// Connection handles required to be in auto-commit mode use a separate connection
// pool since the main pool is effected by implicit and explicit transaction rounds
+ $autoCommit = ( ( $flags & self::CONN_TRX_AUTOCOMMIT ) == self::CONN_TRX_AUTOCOMMIT );
+
if ( $autoCommit ) {
$connFreeKey = self::KEY_FOREIGN_FREE_NOROUND;
$connInUseKey = self::KEY_FOREIGN_INUSE_NOROUND;
}
if ( !$conn ) {
- $conn = $this->reallyOpenConnection(
- $i,
- $domainInstance,
- [
- 'autoCommitOnly' => $autoCommit,
- 'foreign' => true,
- 'foreignPoolRefCount' => 0
- ]
- );
- if ( $conn->isOpen() ) {
- // Note that if $domain is an empty string, getDomainID() might not match it
- $this->conns[$connInUseKey][$i][$conn->getDomainID()] = $conn;
- $this->connLogger->debug( __METHOD__ . ": opened new connection for $i/$domain" );
- } else {
+ // Open a new connection
+ $server = $this->getServerInfoStrict( $i );
+ $server['serverIndex'] = $i;
+ $server['foreignPoolRefCount'] = 0;
+ $server['foreign'] = true;
+ $server['autoCommitOnly'] = $autoCommit;
+ $conn = $this->reallyOpenConnection( $server, $domainInstance );
+ if ( !$conn->isOpen() ) {
$this->connLogger->warning( __METHOD__ . ": connection error for $i/$domain" );
$this->errorConnection = $conn;
$conn = false;
+ } else {
+ // Note that if $domain is an empty string, getDomainID() might not match it
+ $this->conns[$connInUseKey][$i][$conn->getDomainID()] = $conn;
+ $this->connLogger->debug( __METHOD__ . ": opened new connection for $i/$domain" );
}
}
if ( $conn instanceof IDatabase ) {
- // Sanity check to make sure that the right domain is selected
+ // Final sanity check to make sure the right domain is selected
if ( !$domainInstance->isCompatible( $conn->getDomainID() ) ) {
throw new UnexpectedValueException(
"Got connection to '{$conn->getDomainID()}', but expected '$domain'" );
*
* Returns a Database object whether or not the connection was successful.
*
- * @param int $i Specific server index
+ * @param array $server
* @param DatabaseDomain $domain Domain the connection is for, possibly unspecified
- * @param array $lbInfo Additional information for setLBInfo()
* @return Database
* @throws DBAccessError
* @throws InvalidArgumentException
*/
- protected function reallyOpenConnection( $i, DatabaseDomain $domain, array $lbInfo ) {
+ protected function reallyOpenConnection( array $server, DatabaseDomain $domain ) {
if ( $this->disabled ) {
throw new DBAccessError();
}
- $server = $this->getServerInfoStrict( $i );
- $server = array_merge( $server, [
- // Use the database specified in $domain (null means "none or entrypoint DB");
- // fallback to the $server default if the RDBMs is an embedded library using a file
- // on disk since there would be nothing to access to without a DB/file name.
- 'dbname' => $this->getServerAttributes( $i )[Database::ATTR_DB_IS_FILE]
- ? ( $domain->getDatabase() ?? $server['dbname'] ?? null )
- : $domain->getDatabase(),
- // Override the $server default schema with that of $domain if specified
- 'schema' => $domain->getSchema() ?? $server['schema'] ?? null,
- // Use the table prefix specified in $domain
- 'tablePrefix' => $domain->getTablePrefix(),
- // Participate in transaction rounds if $server does not specify otherwise
- 'flags' => $server['flags'] ?? IDatabase::DBO_DEFAULT,
- // Inject the PHP execution mode and the agent string
- 'cliMode' => $this->cliMode,
- 'agent' => $this->agent,
- // Inject object and callback dependencies
- 'srvCache' => $this->srvCache,
- 'connLogger' => $this->connLogger,
- 'queryLogger' => $this->queryLogger,
- 'errorLogger' => $this->errorLogger,
- 'deprecationLogger' => $this->deprecationLogger,
- 'profiler' => $this->profiler,
- 'trxProfiler' => $this->trxProfiler
- ] );
-
- $lbInfo = array_merge( $lbInfo, [
- 'ownerId' => $this->id,
- 'serverIndex' => $i,
- 'master' => ( $i === $this->getWriterIndex() ),
- 'replica' => ( $i !== $this->getWriterIndex() ),
- // Name of the master server of the relevant DB cluster (e.g. "db1052")
- 'clusterMasterHost' => $this->getServerName( $this->getWriterIndex() )
- ] );
+ if ( $domain->getDatabase() === null ) {
+ // The database domain does not specify a DB name and some database systems require a
+ // valid DB specified on connection. The $server configuration array contains a default
+ // DB name to use for connections in such cases.
+ if ( $server['type'] === 'mysql' ) {
+ // For MySQL, DATABASE and SCHEMA are synonyms, connections need not specify a DB,
+ // and the DB name in $server might not exist due to legacy reasons (the default
+ // domain used to ignore the local LB domain, even when mismatched).
+ $server['dbname'] = null;
+ }
+ } else {
+ $server['dbname'] = $domain->getDatabase();
+ }
+
+ if ( $domain->getSchema() !== null ) {
+ $server['schema'] = $domain->getSchema();
+ }
+
+ // It is always possible to connect with any prefix, even the empty string
+ $server['tablePrefix'] = $domain->getTablePrefix();
+
+ // Let the handle know what the cluster master is (e.g. "db1052")
+ $masterName = $this->getServerName( $this->getWriterIndex() );
+ $server['clusterMasterHost'] = $masterName;
+
+ $server['srvCache'] = $this->srvCache;
+ // Set loggers and profilers
+ $server['connLogger'] = $this->connLogger;
+ $server['queryLogger'] = $this->queryLogger;
+ $server['errorLogger'] = $this->errorLogger;
+ $server['deprecationLogger'] = $this->deprecationLogger;
+ $server['profiler'] = $this->profiler;
+ $server['trxProfiler'] = $this->trxProfiler;
+ // Use the same agent and PHP mode for all DB handles
+ $server['cliMode'] = $this->cliMode;
+ $server['agent'] = $this->agent;
+ // Use DBO_DEFAULT flags by default for LoadBalancer managed databases. Assume that the
+ // application calls LoadBalancer::commitMasterChanges() before the PHP script completes.
+ $server['flags'] = $server['flags'] ?? IDatabase::DBO_DEFAULT;
+ // Create a live connection object
$conn = Database::factory( $server['type'], $server, Database::NEW_UNCONNECTED );
+ $conn->setLBInfo( $server );
+ $conn->setLazyMasterHandle(
+ $this->getLazyConnectionRef( self::DB_MASTER, [], $conn->getDomainID() )
+ );
+ $conn->setTableAliases( $this->tableAliases );
+ $conn->setIndexAliases( $this->indexAliases );
+
try {
$conn->initConnection();
++$this->connectionCounter;
// ignore; let the DB handle the logging
}
- $conn->setLBInfo( $lbInfo );
- if ( $conn->getFlag( $conn::DBO_DEFAULT ) ) {
- if ( $this->cliMode ) {
- $conn->clearFlag( $conn::DBO_TRX );
- } else {
- $conn->setFlag( $conn::DBO_TRX );
- }
- }
- if ( $i === $this->getWriterIndex() ) {
+ if ( $server['serverIndex'] === $this->getWriterIndex() ) {
if ( $this->trxRoundId !== false ) {
$this->applyTransactionRoundFlags( $conn );
}
$conn->setTransactionListener( $name, $callback );
}
}
- $conn->setTableAliases( $this->tableAliases );
- $conn->setIndexAliases( $this->indexAliases );
-
- $conn->setLazyMasterHandle(
- $this->getLazyConnectionRef( self::DB_MASTER, [], $conn->getDomainID() )
- );
$this->lazyLoadReplicationPositions(); // session consistency
}
public function closeAll() {
+ if ( $this->ownerId === null ) {
+ /** @noinspection PhpUnusedLocalVariableInspection */
+ $scope = ScopedCallback::newScopedIgnoreUserAbort();
+ }
+
$fname = __METHOD__;
$this->forEachOpenConnection( function ( IDatabase $conn ) use ( $fname ) {
$host = $conn->getServer();
public function finalizeMasterChanges( $fname = __METHOD__, $owner = null ) {
$this->assertOwnership( $fname, $owner );
$this->assertTransactionRoundStage( [ self::ROUND_CURSORY, self::ROUND_FINALIZED ] );
+ if ( $this->ownerId === null ) {
+ /** @noinspection PhpUnusedLocalVariableInspection */
+ $scope = ScopedCallback::newScopedIgnoreUserAbort();
+ }
$this->trxRoundStage = self::ROUND_ERROR; // "failed" until proven otherwise
// Loop until callbacks stop adding callbacks on other connections
public function approveMasterChanges( array $options, $fname = __METHOD__, $owner = null ) {
$this->assertOwnership( $fname, $owner );
$this->assertTransactionRoundStage( self::ROUND_FINALIZED );
+ if ( $this->ownerId === null ) {
+ /** @noinspection PhpUnusedLocalVariableInspection */
+ $scope = ScopedCallback::newScopedIgnoreUserAbort();
+ }
$limit = $options['maxWriteDuration'] ?? 0;
);
}
$this->assertTransactionRoundStage( self::ROUND_CURSORY );
+ if ( $this->ownerId === null ) {
+ /** @noinspection PhpUnusedLocalVariableInspection */
+ $scope = ScopedCallback::newScopedIgnoreUserAbort();
+ }
// Clear any empty transactions (no writes/callbacks) from the implicit round
$this->flushMasterSnapshots( $fname );
public function commitMasterChanges( $fname = __METHOD__, $owner = null ) {
$this->assertOwnership( $fname, $owner );
$this->assertTransactionRoundStage( self::ROUND_APPROVED );
+ if ( $this->ownerId === null ) {
+ /** @noinspection PhpUnusedLocalVariableInspection */
+ $scope = ScopedCallback::newScopedIgnoreUserAbort();
+ }
$failures = [];
- /** @noinspection PhpUnusedLocalVariableInspection */
- $scope = ScopedCallback::newScopedIgnoreUserAbort(); // try to ignore client aborts
-
$restore = ( $this->trxRoundId !== false );
$this->trxRoundId = false;
$this->trxRoundStage = self::ROUND_ERROR; // "failed" until proven otherwise
"Transaction should be in the callback stage (not '{$this->trxRoundStage}')"
);
}
+ if ( $this->ownerId === null ) {
+ /** @noinspection PhpUnusedLocalVariableInspection */
+ $scope = ScopedCallback::newScopedIgnoreUserAbort();
+ }
$oldStage = $this->trxRoundStage;
$this->trxRoundStage = self::ROUND_ERROR; // "failed" until proven otherwise
"Transaction should be in the callback stage (not '{$this->trxRoundStage}')"
);
}
+ if ( $this->ownerId === null ) {
+ /** @noinspection PhpUnusedLocalVariableInspection */
+ $scope = ScopedCallback::newScopedIgnoreUserAbort();
+ }
$e = null;
public function rollbackMasterChanges( $fname = __METHOD__, $owner = null ) {
$this->assertOwnership( $fname, $owner );
+ if ( $this->ownerId === null ) {
+ /** @noinspection PhpUnusedLocalVariableInspection */
+ $scope = ScopedCallback::newScopedIgnoreUserAbort();
+ }
$restore = ( $this->trxRoundId !== false );
$this->trxRoundId = false;
return $this->laggedReplicaMode;
}
- public function getReadOnlyReason( $domain = false, IDatabase $conn = null ) {
+ public function getReadOnlyReason( $domain = false ) {
+ $domainInstance = DatabaseDomain::newFromId( $this->resolveDomainID( $domain ) );
+
if ( $this->readOnlyReason !== false ) {
return $this->readOnlyReason;
- } elseif ( $this->masterRunningReadOnly( $domain, $conn ) ) {
+ } elseif ( $this->isMasterRunningReadOnly( $domainInstance ) ) {
return 'The master database server is running in read-only mode.';
} elseif ( $this->getLaggedReplicaMode( $domain ) ) {
return ( $this->getExistingReaderIndex( self::GROUP_GENERIC ) >= 0 )
}
/**
- * @param string $domain Domain ID, or false for the current domain
- * @param IDatabase|null $conn DB master connectionl used to avoid loops [optional]
- * @return bool
+ * @param IDatabase $conn Master connection
+ * @param int $flags Bitfield of class CONN_* constants
+ * @return bool Whether the entire server or currently selected DB/schema is read-only
*/
- private function masterRunningReadOnly( $domain, IDatabase $conn = null ) {
- $cache = $this->wanCache;
- $masterServer = $this->getServerName( $this->getWriterIndex() );
+ private function isMasterConnectionReadOnly( IDatabase $conn, $flags = 0 ) {
+ // Note that table prefixes are not related to server-side read-only mode
+ $key = $this->srvCache->makeGlobalKey(
+ 'rdbms-server-readonly',
+ $conn->getServer(),
+ $conn->getDBname(),
+ $conn->dbSchema()
+ );
- return (bool)$cache->getWithSetCallback(
- $cache->makeGlobalKey( __CLASS__, 'server-read-only', $masterServer ),
+ if ( ( $flags & self::CONN_REFRESH_READ_ONLY ) == self::CONN_REFRESH_READ_ONLY ) {
+ try {
+ $readOnly = (int)$conn->serverIsReadOnly();
+ } catch ( DBError $e ) {
+ $readOnly = 0;
+ }
+ $this->srvCache->set( $key, $readOnly, BagOStuff::TTL_PROC_SHORT );
+ } else {
+ $readOnly = $this->srvCache->getWithSetCallback(
+ $key,
+ BagOStuff::TTL_PROC_SHORT,
+ function () use ( $conn ) {
+ try {
+ return (int)$conn->serverIsReadOnly();
+ } catch ( DBError $e ) {
+ return 0;
+ }
+ }
+ );
+ }
+
+ return (bool)$readOnly;
+ }
+
+ /**
+ * @param DatabaseDomain $domain
+ * @return bool Whether the entire master server or the local domain DB is read-only
+ */
+ private function isMasterRunningReadOnly( DatabaseDomain $domain ) {
+ // Context will often be HTTP GET/HEAD; heavily cache the results
+ return (bool)$this->wanCache->getWithSetCallback(
+ // Note that table prefixes are not related to server-side read-only mode
+ $this->wanCache->makeGlobalKey(
+ 'rdbms-server-readonly',
+ $this->getMasterServerName(),
+ $domain->getDatabase(),
+ $domain->getSchema()
+ ),
self::TTL_CACHE_READONLY,
- function () use ( $domain, $conn ) {
+ function () use ( $domain ) {
$old = $this->trxProfiler->setSilenced( true );
try {
$index = $this->getWriterIndex();
- $dbw = $conn ?: $this->getServerConnection( $index, $domain );
- $readOnly = (int)$dbw->serverIsReadOnly();
- if ( !$conn ) {
- $this->reuseConnection( $dbw );
- }
+ // Reset the cache for isMasterConnectionReadOnly()
+ $flags = self::CONN_REFRESH_READ_ONLY;
+ $conn = $this->getServerConnection( $index, $domain->getId(), $flags );
+ // Reuse the process cache set above
+ $readOnly = (int)$this->isMasterConnectionReadOnly( $conn );
+ $this->reuseConnection( $conn );
} catch ( DBError $e ) {
$readOnly = 0;
}
return $readOnly;
},
- [ 'pcTTL' => $cache::TTL_PROC_LONG, 'busyValue' => 0 ]
+ [ 'pcTTL' => WANObjectCache::TTL_PROC_LONG, 'lockTSE' => 10, 'busyValue' => 0 ]
);
}
public function waitForMasterPos( IDatabase $conn, $pos = false, $timeout = null ) {
$timeout = max( 1, $timeout ?: $this->waitTimeout );
- if ( $conn->getLBInfo( 'serverIndex' ) === $this->getWriterIndex() ) {
- return true; // not a replica DB server
+ if ( $this->getServerCount() <= 1 || !$conn->getLBInfo( 'replica' ) ) {
+ return true; // server is not a replica DB
}
if ( !$pos ) {
$this->setLocalDomain( DatabaseDomain::newFromId( $domain ) );
}
+ public function setTempTablesOnlyMode( $value, $domain ) {
+ $old = $this->tempTablesOnlyMode[$domain] ?? false;
+ if ( $value ) {
+ $this->tempTablesOnlyMode[$domain] = true;
+ } else {
+ unset( $this->tempTablesOnlyMode[$domain] );
+ }
+
+ return $old;
+ }
+
/**
* @param DatabaseDomain $domain
*/
return $this->servers[$i];
}
+ /**
+ * @return string
+ */
+ private function getMasterServerName() {
+ return $this->getServerName( $this->getWriterIndex() );
+ }
+
function __destruct() {
// Avoid connection leaks for sanity
$this->disable();
) );
}
- protected function reallyOpenConnection( $i, DatabaseDomain $domain, array $lbInfo = [] ) {
+ protected function reallyOpenConnection( array $server, DatabaseDomain $domain ) {
return $this->db;
}
$data = [ $data ];
}
if ( !$data ) {
- return;
+ return 0;
}
foreach ( $data as $item ) {
if ( !( $item instanceof StatsdDataInterface ) ) {
try {
$fp = $this->getSender()->open();
if ( !$fp ) {
- return;
+ return 0;
}
foreach ( $data as $message ) {
$written += $this->getSender()->write( $fp, $message );
return $params;
}
+ /**
+ * @inheritDoc
+ * @suppress PhanTypeInvalidDimOffset
+ */
public function formatParametersForApi() {
$ret = parent::formatParametersForApi();
if ( isset( $ret['flags'] ) ) {
*
* @since 1.26
* @param string $blob
- * @return array
+ * @return array|false
*/
public static function extractParams( $blob ) {
return unserialize( $blob );
/**
* @var array
+ * @deprecated since 1.34, no longer used.
*/
protected $mDefaultQuery;
];
}
- private function getDefaultQuery() {
- if ( !isset( $this->mDefaultQuery ) ) {
- $this->mDefaultQuery = $this->getRequest()->getQueryValues();
- unset( $this->mDefaultQuery['title'] );
- unset( $this->mDefaultQuery['dir'] );
- unset( $this->mDefaultQuery['offset'] );
- unset( $this->mDefaultQuery['limit'] );
- unset( $this->mDefaultQuery['order'] );
- unset( $this->mDefaultQuery['month'] );
- unset( $this->mDefaultQuery['year'] );
- }
-
- return $this->mDefaultQuery;
- }
-
/**
* @param array $queryTypes
* @return array Form descriptor
$params[] = $db->anyString();
}
array_pop( $params ); // Get rid of the last % we added.
- $this->mConds[] = 'log_title' . $db->buildLike( $params );
+ $this->mConds[] = 'log_title' . $db->buildLike( ...$params );
} elseif ( $pattern && !$wgMiserMode ) {
$this->mConds[] = 'log_title' . $db->buildLike( $title->getDBkey(), $db->anyString() );
$this->pattern = $pattern;
wfDebug( 'Overwriting existing ManualLogEntry tags' );
}
$this->tags = [];
- if ( $tags !== null ) {
- $this->addTags( $tags );
- }
+ $this->addTags( $tags );
}
/**
* Add change tags for the log entry
*
* @since 1.33
- * @param string|string[] $tags Tags to apply
+ * @param string|string[]|null $tags Tags to apply
*/
public function addTags( $tags ) {
+ if ( $tags === null ) {
+ return;
+ }
+
if ( is_string( $tags ) ) {
$tags = [ $tags ];
}
$entry->setTarget( $rc->getTitle() );
$entry->setParameters( self::buildParams( $rc, $auto ) );
$entry->setPerformer( $user );
- $entry->setTags( $tags );
+ $entry->addTags( $tags );
$logid = $entry->insert();
if ( !$auto ) {
$entry->publish( $logid, 'udp' );
* @param string $pageStatus
* @throws MWException
*/
- public function actuallyNotifyOnPageChange( $editor, $title, $timestamp, $summary, $minorEdit,
- $oldid, $watchers, $pageStatus = 'changed' ) {
+ public function actuallyNotifyOnPageChange(
+ $editor,
+ $title,
+ $timestamp,
+ $summary,
+ $minorEdit,
+ $oldid,
+ $watchers,
+ $pageStatus = 'changed'
+ ) {
# we use $wgPasswordSender as sender's address
global $wgUsersNotifiedOnAllChanges;
global $wgEnotifWatchlist, $wgBlockDisablesLogin;
global $wgEnotifMinorEdits, $wgEnotifUserTalk;
+ $messageCache = MediaWikiServices::getInstance()->getMessageCache();
+
# The following code is only run, if several conditions are met:
# 1. EmailNotification for pages (other than user_talk pages) must be enabled
# 2. minor edits (changes) are only regarded if the global flag indicates so
&& $this->canSendUserTalkEmail( $editor, $title, $minorEdit )
) {
$targetUser = User::newFromName( $title->getText() );
- $this->compose( $targetUser, self::USER_TALK );
+ $this->compose( $targetUser, self::USER_TALK, $messageCache );
$userTalkId = $targetUser->getId();
}
&& !( $wgBlockDisablesLogin && $watchingUser->getBlock() )
&& Hooks::run( 'SendWatchlistEmailNotification', [ $watchingUser, $title, $this ] )
) {
- $this->compose( $watchingUser, self::WATCHLIST );
+ $this->compose( $watchingUser, self::WATCHLIST, $messageCache );
}
}
}
continue;
}
$user = User::newFromName( $name );
- $this->compose( $user, self::ALL_CHANGES );
+ $this->compose( $user, self::ALL_CHANGES, $messageCache );
}
$this->sendMails();
/**
* Generate the generic "this page has been changed" e-mail text.
+ * @param MessageCache $messageCache
*/
- private function composeCommonMailtext() {
+ private function composeCommonMailtext( MessageCache $messageCache ) {
global $wgPasswordSender, $wgNoReplyAddress;
global $wgEnotifFromEditor, $wgEnotifRevealEditorAddress;
global $wgEnotifImpersonal, $wgEnotifUseRealName;
$body = wfMessage( 'enotif_body' )->inContentLanguage()->plain();
$body = strtr( $body, $keys );
- $body = MessageCache::singleton()->transform( $body, false, null, $this->title );
+ $body = $messageCache->transform( $body, false, null, $this->title );
$this->body = wordwrap( strtr( $body, $postTransformKeys ), 72 );
# Reveal the page editor's address as REPLY-TO address only if
* Call sendMails() to send any mails that were queued.
* @param User $user
* @param string $source
+ * @param MessageCache $messageCache
*/
- private function compose( $user, $source ) {
+ private function compose( $user, $source, MessageCache $messageCache ) {
global $wgEnotifImpersonal;
if ( !$this->composed_common ) {
- $this->composeCommonMailtext();
+ $this->composeCommonMailtext( $messageCache );
}
if ( $wgEnotifImpersonal ) {
/**
* @param File $image
- * @param array $metadata
+ * @param string $metadata
* @return bool|int
*/
public function isMetadataValid( $image, $metadata ) {
* Exif::getFilteredData() or BitmapMetadataHandler )
* @return array
* @since 1.23
+ * @suppress PhanTypeArraySuspiciousNullable
*/
public function makeFormattedData( $tags ) {
$resolutionunit = !isset( $tags['ResolutionUnit'] ) || $tags['ResolutionUnit'] == 2 ? 2 : 3;
case 'CustomRendered':
switch ( $val ) {
- case 0:
- case 1:
+ case 0: /* normal */
+ case 1: /* custom */
+ /* The following are unofficial Apple additions */
+ case 2: /* HDR (no original saved) */
+ case 3: /* HDR (original saved) */
+ case 4: /* Original (for HDR) */
+ /* Yes 5 is not present ;) */
+ case 6: /* Panorama */
+ case 7: /* Portrait HDR */
+ case 8: /* Portrait */
$val = $this->exifMsg( $tag, $val );
break;
default:
}
$buf = unpack( 'C', $data )[1];
$bpp = ( $buf & 7 ) + 1;
+ // @phan-suppress-next-line PhanTypeInvalidLeftOperandOfIntegerOp
$buf >>= 7;
$have_map = $buf & 1;
*
* @param string $rawData The app13 block from jpeg containing iptc/iim data
* @return array IPTC metadata array
+ * @suppress PhanTypeArraySuspicious
*/
static function parse( $rawData ) {
$parsed = iptcparse( $rawData );
* @param string $ext
* @param string $mime
* @param array|null $params
- * @return bool
+ * @return array
*/
public function getThumbType( $ext, $mime, $params = null ) {
global $wgTiffThumbnailType;
* Decodes a lossless chunk header
* @param string $header First few bytes of the header, expected to be at least 13 bytes long
* @return bool|array See WebPHandler::decodeHeader
+ * @suppress PhanTypeInvalidLeftOperandOfIntegerOp
*/
public static function decodeLosslessChunkHeader( $header ) {
// Bytes 0-3 are 'VP8L'
if ( !isset( $params['servers'] ) ) {
$params['servers'] = $GLOBALS['wgMemCachedServers'];
}
- if ( !isset( $params['debug'] ) ) {
- $params['debug'] = $GLOBALS['wgMemCachedDebug'];
- }
if ( !isset( $params['persistent'] ) ) {
$params['persistent'] = $GLOBALS['wgMemCachedPersistent'];
}
* @param array $params
* @return WANObjectCache
* @throws UnexpectedValueException
+ * @suppress PhanTypeMismatchReturn
*/
public static function newWANCacheFromParams( array $params ) {
global $wgCommandLineMode, $wgSecretKey;
*/
public static function detectLocalServerCache() {
if ( function_exists( 'apcu_fetch' ) ) {
- return 'apcu';
+ // Make sure the APCu methods actually store anything
+ if ( PHP_SAPI !== 'cli' || ini_get( 'apc.enable_cli' ) ) {
+ return 'apcu';
+ }
} elseif ( function_exists( 'apc_fetch' ) ) {
- return 'apc';
+ // Make sure the APC methods actually store anything
+ if ( PHP_SAPI !== 'cli' || ini_get( 'apc.enable_cli' ) ) {
+ return 'apc';
+ }
} elseif ( function_exists( 'wincache_ucache_get' ) ) {
return 'wincache';
}
+
return CACHE_NONE;
}
}
use Wikimedia\Rdbms\IMaintainableDatabase;
use Wikimedia\Rdbms\LoadBalancer;
use Wikimedia\ScopedCallback;
+use Wikimedia\Timestamp\ConvertibleTimestamp;
use Wikimedia\WaitConditionLoop;
/**
$this->numServerShards = count( $this->serverInfos );
} else {
// Default to using the main wiki's database servers
- $this->serverInfos = false;
+ $this->serverInfos = [];
$this->numServerShards = 1;
$this->attrMap[self::ATTR_SYNCWRITES] = self::QOS_SYNCWRITES_BE;
}
$type = $info['type'] ?? 'mysql';
$host = $info['host'] ?? '[unknown]';
$this->logger->debug( __CLASS__ . ": connecting to $host" );
- $db = Database::factory( $type, $info );
- $db->clearFlag( DBO_TRX ); // auto-commit mode
- $this->conns[$shardIndex] = $db;
+ $conn = Database::factory( $type, $info );
+ $conn->clearFlag( DBO_TRX ); // auto-commit mode
+ $this->conns[$shardIndex] = $conn;
}
- $db = $this->conns[$shardIndex];
+ $conn = $this->conns[$shardIndex];
} else {
// Use the main LB database
$lb = MediaWikiServices::getInstance()->getDBLoadBalancer();
$index = $this->replicaOnly ? DB_REPLICA : DB_MASTER;
- if ( $lb->getServerType( $lb->getWriterIndex() ) !== 'sqlite' ) {
- // Keep a separate connection to avoid contention and deadlocks
- $db = $lb->getConnectionRef( $index, [], false, $lb::CONN_TRX_AUTOCOMMIT );
- } else {
- // However, SQLite has the opposite behavior due to DB-level locking.
- // Stock sqlite MediaWiki installs use a separate sqlite cache DB instead.
- $db = $lb->getConnectionRef( $index );
+ // If the RDBMS has row-level locking, use the autocommit connection to avoid
+ // contention and deadlocks. Do not do this if it only has DB-level locking since
+ // that would just cause deadlocks.
+ $attribs = $lb->getServerAttributes( $lb->getWriterIndex() );
+ $flags = $attribs[Database::ATTR_DB_LEVEL_LOCKING] ? 0 : $lb::CONN_TRX_AUTOCOMMIT;
+ $conn = $lb->getMaintenanceConnectionRef( $index, [], false, $flags );
+ // Automatically create the objectcache table for sqlite as needed
+ if ( $conn->getType() === 'sqlite' ) {
+ $this->initSqliteDatabase( $conn );
}
}
- $this->logger->debug( sprintf( "Connection %s will be used for SqlBagOStuff", $db ) );
+ $this->logger->debug( sprintf( "Connection %s will be used for SqlBagOStuff", $conn ) );
- return $db;
+ return $conn;
}
/**
* @param string $exptime
* @return bool
*/
- private function isExpired( $db, $exptime ) {
+ private function isExpired( IDatabase $db, $exptime ) {
return (
$exptime != $this->getMaxDateTime( $db ) &&
- wfTimestamp( TS_UNIX, $exptime ) < $this->getCurrentTime()
+ ConvertibleTimestamp::convert( TS_UNIX, $exptime ) < $this->getCurrentTime()
);
}
$serversDoneCount = 0,
&$keysDeletedCount = 0
) {
- $cutoffUnix = wfTimestamp( TS_UNIX, $timestamp );
+ $cutoffUnix = ConvertibleTimestamp::convert( TS_UNIX, $timestamp );
$shardIndexes = range( 0, $this->numTableShards - 1 );
shuffle( $shardIndexes );
if ( $res->numRows() ) {
$row = $res->current();
if ( $lag === null ) {
- $lag = max( $cutoffUnix - wfTimestamp( TS_UNIX, $row->exptime ), 1 );
+ $rowExpUnix = ConvertibleTimestamp::convert( TS_UNIX, $row->exptime );
+ $lag = max( $cutoffUnix - $rowExpUnix, 1 );
}
$keys = [];
if ( is_callable( $progressCallback ) ) {
if ( $lag ) {
- $remainingLag = $cutoffUnix - wfTimestamp( TS_UNIX, $continue );
+ $continueUnix = ConvertibleTimestamp::convert( TS_UNIX, $continue );
+ $remainingLag = $cutoffUnix - $continueUnix;
$processedLag = max( $lag - $remainingLag, 0 );
$doneRatio = ( $numShardsDone + $processedLag / $lag ) / $this->numTableShards;
} else {
}
/**
- * Create shard tables. For use from eval.php.
+ * @param IMaintainableDatabase $db
+ * @throws DBError
+ */
+ private function initSqliteDatabase( IMaintainableDatabase $db ) {
+ if ( $db->tableExists( 'objectcache' ) ) {
+ return;
+ }
+ // Use one table for SQLite; sharding does not seem to have much benefit
+ $db->query( "PRAGMA journal_mode=WAL" ); // this is permanent
+ $db->startAtomic( __METHOD__ ); // atomic DDL
+ try {
+ $encTable = $db->tableName( 'objectcache' );
+ $encExptimeIndex = $db->addIdentifierQuotes( $db->tablePrefix() . 'exptime' );
+ $db->query(
+ "CREATE TABLE $encTable (\n" .
+ " keyname BLOB NOT NULL default '' PRIMARY KEY,\n" .
+ " value BLOB,\n" .
+ " exptime TEXT\n" .
+ ")",
+ __METHOD__
+ );
+ $db->query( "CREATE INDEX $encExptimeIndex ON $encTable (exptime)" );
+ $db->endAtomic( __METHOD__ );
+ } catch ( DBError $e ) {
+ $db->rollback( __METHOD__ );
+ throw $e;
+ }
+ }
+
+ /**
+ * Create the shard tables on all databases (e.g. via eval.php/shell.php)
*/
public function createTables() {
for ( $shardIndex = 0; $shardIndex < $this->numServerShards; $shardIndex++ ) {
$db = $this->getConnection( $shardIndex );
- if ( $db->getType() !== 'mysql' ) {
- throw new MWException( __METHOD__ . ' is not supported on this DB server' );
- }
-
- for ( $i = 0; $i < $this->numTableShards; $i++ ) {
- $db->query(
- 'CREATE TABLE ' . $db->tableName( $this->getTableNameByShard( $i ) ) .
- ' LIKE ' . $db->tableName( 'objectcache' ),
- __METHOD__ );
+ if ( in_array( $db->getType(), [ 'mysql', 'postgres' ], true ) ) {
+ for ( $i = 0; $i < $this->numTableShards; $i++ ) {
+ $encBaseTable = $db->tableName( 'objectcache' );
+ $encShardTable = $db->tableName( $this->getTableNameByShard( $i ) );
+ $db->query( "CREATE TABLE $encShardTable LIKE $encBaseTable" );
+ }
}
}
}
if ( $outputPage->isPrintable() ) {
$parserOptions->setIsPrintable( true );
$poOptions['enableSectionEditLinks'] = false;
- } elseif ( $this->viewIsRenderAction
- || !$this->isCurrent() || !$this->getTitle()->quickUserCan( 'edit', $user )
+ } elseif ( $this->viewIsRenderAction || !$this->isCurrent() ||
+ !MediaWikiServices::getInstance()->getPermissionManager()
+ ->quickUserCan( 'edit', $user, $this->getTitle() )
) {
$poOptions['enableSectionEditLinks'] = false;
}
$title = $this->getTitle();
$rc = false;
- if ( !$title->quickUserCan( 'patrol', $user )
+ if ( !MediaWikiServices::getInstance()->getPermissionManager()
+ ->quickUserCan( 'patrol', $user, $title )
|| !( $wgUseRCPatrol || $wgUseNPPatrol
|| ( $wgUseFilePatrol && $title->inNamespace( NS_FILE ) ) )
) {
# Show error message
$oldid = $this->getOldID();
+ $pm = MediaWikiServices::getInstance()->getPermissionManager();
if ( !$oldid && $title->getNamespace() === NS_MEDIAWIKI && $title->hasSourceText() ) {
// use fake Content object for system message
$parserOptions = ParserOptions::newCanonical( 'canonical' );
} else {
if ( $oldid ) {
$text = wfMessage( 'missing-revision', $oldid )->plain();
- } elseif ( $title->quickUserCan( 'create', $this->getContext()->getUser() )
- && $title->quickUserCan( 'edit', $this->getContext()->getUser() )
+ } elseif ( $pm->quickUserCan( 'create', $this->getContext()->getUser(), $title ) &&
+ $pm->quickUserCan( 'edit', $this->getContext()->getUser(), $title )
) {
$message = $this->getContext()->getUser()->isLoggedIn() ? 'noarticletext' : 'noarticletextanon';
$text = wfMessage( $message )->plain();
$outputPage->enableOOUI();
+ $fields = [];
+
$options = Xml::listDropDownOptions(
$ctx->msg( 'deletereason-dropdown' )->inContentLanguage()->text(),
[ 'other' => $ctx->msg( 'deletereasonotherlist' )->inContentLanguage()->text() ]
/**
* Special handling for category description pages, showing pages,
* subcategories and file that belong to the category
+ *
+ * @property WikiCategoryPage $mPage Set by overwritten newPage() in this class
*/
class CategoryPage extends Article {
# Subclasses can change this to override the viewer class.
protected $mCategoryViewerClass = CategoryViewer::class;
- /**
- * @var WikiCategoryPage
- */
- protected $mPage;
-
/**
* @param Title $title
* @return WikiCategoryPage
public function imageHistoryLine( $iscur, $file ) {
$user = $this->getUser();
$lang = $this->getLanguage();
+ $pm = MediaWikiServices::getInstance()->getPermissionManager();
$timestamp = wfTimestamp( TS_MW, $file->getTimestamp() );
+ // @phan-suppress-next-line PhanUndeclaredMethod
$img = $iscur ? $file->getName() : $file->getArchiveName();
$userId = $file->getUser( 'id' );
$userText = $file->getUser( 'text' );
$row = $selected = '';
// Deletion link
- if ( $local && ( MediaWikiServices::getInstance()
- ->getPermissionManager()
- ->userHasAnyRight( $user, 'delete', 'deletedhistory' ) )
+ if ( $local && ( $pm->userHasAnyRight( $user, 'delete', 'deletedhistory' ) )
) {
$row .= '<td>';
# Link to remove from history
$row .= '<td>';
if ( $iscur ) {
$row .= $this->msg( 'filehist-current' )->escaped();
- } elseif ( $local && $this->title->quickUserCan( 'edit', $user )
- && $this->title->quickUserCan( 'upload', $user )
+ } elseif ( $local && $pm->quickUserCan( 'edit', $user, $this->title )
+ && $pm->quickUserCan( 'upload', $user, $this->title )
) {
if ( $file->isDeleted( File::DELETED_FILE ) ) {
$row .= $this->msg( 'filehist-revert' )->escaped();
}
public function getQueryInfo() {
- return false;
+ return [];
}
/**
* Class for viewing MediaWiki file description pages
*
* @ingroup Media
+ *
+ * @property WikiFilePage $mPage Set by overwritten newPage() in this class
+ * @method WikiFilePage getPage()
*/
class ImagePage extends Article {
/** @var File|false */
/** @var bool */
protected $mExtraDescription = false;
- /**
- * @var WikiFilePage
- */
- protected $mPage;
-
/**
* @param Title $title
* @return WikiFilePage
return;
}
- $canUpload = $this->getTitle()->quickUserCan( 'upload', $this->getContext()->getUser() );
+ $canUpload = MediaWikiServices::getInstance()->getPermissionManager()
+ ->quickUserCan( 'upload', $this->getContext()->getUser(), $this->getTitle() );
if ( $canUpload && UploadBase::userCanReUpload(
$this->getContext()->getUser(),
$this->mPage->getFile() )
/**
* Interface for type hinting (accepts WikiPage, Article, ImagePage, CategoryPage)
+ *
+ * @method array getActionOverrides()
+ * @method string getUserText($audience=1,User $user=null)
+ * @method string getTimestamp()
+ * @method Title getTitle()
*/
interface Page {
}
$logEntry->setPerformer( $user );
$logEntry->setTarget( $this->title );
$logEntry->setComment( $comment );
- $logEntry->setTags( $tags );
+ $logEntry->addTags( $tags );
$logEntry->setParameters( [
':assoc:count' => [
'revisions' => $textRestored,
*/
public $mLatest = false;
- /** @var PreparedEdit Map of cache fields (text, parser output, ect) for a proposed/new edit */
+ /**
+ * @var PreparedEdit|false Map of cache fields (text, parser output, ect) for a proposed/new edit
+ */
public $mPreparedEdit = false;
/**
if ( !is_null( $nullRevision ) ) {
$logEntry->setAssociatedRevId( $nullRevision->getId() );
}
- $logEntry->setTags( $tags );
+ $logEntry->addTags( $tags );
if ( $logRelationsField !== null && count( $logRelationsValues ) ) {
$logEntry->setRelations( [ $logRelationsField => $logRelationsValues ] );
}
$logEntry->setPerformer( $deleter );
$logEntry->setTarget( $logTitle );
$logEntry->setComment( $reason );
- $logEntry->setTags( $tags );
+ $logEntry->addTags( $tags );
$logid = $logEntry->insert();
$dbw->onTransactionPreCommitOrIdle(
* @ingroup Pager
*/
-use Wikimedia\Rdbms\IResultWrapper;
-use Wikimedia\Rdbms\IDatabase;
+use MediaWiki\Linker\LinkRenderer;
use MediaWiki\Linker\LinkTarget;
+use MediaWiki\MediaWikiServices;
use MediaWiki\Navigation\PrevNextNavigationRenderer;
+use Wikimedia\Rdbms\IDatabase;
+use Wikimedia\Rdbms\IResultWrapper;
/**
* IndexPager is an efficient pager which uses a (roughly unique) index in the
*/
public $mResult;
- public function __construct( IContextSource $context = null ) {
+ /** @var LinkRenderer */
+ private $linkRenderer;
+
+ public function __construct( IContextSource $context = null, LinkRenderer $linkRenderer = null ) {
if ( $context ) {
$this->setContext( $context );
}
? $dir[$this->mOrderType]
: $dir;
}
+ $this->linkRenderer = $linkRenderer;
}
/**
$attrs['class'] = "mw-{$type}link";
}
- return Linker::linkKnown(
+ return $this->getLinkRenderer()->makeKnownLink(
$this->getTitle(),
- $text,
+ new HtmlArmor( $text ),
$attrs,
$query + $this->getDefaultQuery()
);
return $prevNext->buildPrevNextNavigation( $title, $offset, $limit, $query, $atend );
}
+
+ protected function getLinkRenderer() {
+ if ( $this->linkRenderer === null ) {
+ $this->linkRenderer = MediaWikiServices::getInstance()->getLinkRenderer();
+ }
+ return $this->linkRenderer;
+ }
}
* @ingroup Pager
*/
+use MediaWiki\Linker\LinkRenderer;
+
/**
* Table-based display with a user-selectable sort order
* @ingroup Pager
/** @var stdClass */
protected $mCurrentRow;
- public function __construct( IContextSource $context = null ) {
+ public function __construct( IContextSource $context = null, LinkRenderer $linkRenderer = null ) {
if ( $context ) {
$this->setContext( $context );
}
$this->mDefaultDirection = IndexPager::DIR_DESCENDING;
} /* Else leave it at whatever the class default is */
- parent::__construct();
+ // Parent constructor needs mSort set, so we call it last
+ parent::__construct( null, $linkRenderer );
}
/**
if ( !$wgRestrictDisplayTitle ||
( $title instanceof Title
&& !$title->hasFragment()
- && $title->equals( $parser->mTitle ) )
+ && $title->equals( $parser->getTitle() ) )
) {
$old = $parser->mOutput->getProperty( 'displaytitle' );
if ( $old === false || $arg !== 'displaytitle_noreplace' ) {
* @return string
*/
public static function protectionlevel( $parser, $type = '', $title = '' ) {
- $titleObject = Title::newFromText( $title );
- if ( !( $titleObject instanceof Title ) ) {
- $titleObject = $parser->mTitle;
- }
+ $titleObject = Title::newFromText( $title ) ?? $parser->getTitle();
if ( $titleObject->areRestrictionsLoaded() || $parser->incrementExpensiveFunctionCount() ) {
$restrictions = $titleObject->getRestrictions( strtolower( $type ) );
# Title::getRestrictions returns an array, its possible it may have
* @return string
*/
public static function protectionexpiry( $parser, $type = '', $title = '' ) {
- $titleObject = Title::newFromText( $title );
- if ( !( $titleObject instanceof Title ) ) {
- $titleObject = $parser->mTitle;
- }
+ $titleObject = Title::newFromText( $title ) ?? $parser->getTitle();
if ( $titleObject->areRestrictionsLoaded() || $parser->incrementExpensiveFunctionCount() ) {
$expiry = $titleObject->getRestrictionExpiry( strtolower( $type ) );
// getRestrictionExpiry() returns false on invalid type; trying to
* @since 1.23
*/
public static function cascadingsources( $parser, $title = '' ) {
- $titleObject = Title::newFromText( $title );
- if ( !( $titleObject instanceof Title ) ) {
- $titleObject = $parser->mTitle;
- }
+ $titleObject = Title::newFromText( $title ) ?? $parser->getTitle();
if ( $titleObject->areCascadeProtectionSourcesLoaded()
|| $parser->incrementExpensiveFunctionCount()
) {
* Reduce memory usage to reduce the impact of circular references
*/
public function __destruct() {
+ // @phan-suppress-next-line PhanTypeSuspiciousNonTraversableForeach
foreach ( $this as $name => $value ) {
unset( $this->$name );
}
// commentEnd Past-the-end input pointer for the last comment encountered
// visualEnd Past-the-end input pointer for the end of the accumulator minus comments
+ /**
+ * @param string $out
+ */
public function __construct( $out = '' ) {
$this->out = $out;
}
/**
* @ingroup Parser
+ * @property string[] $out
*/
// phpcs:ignore Squiz.Classes.ValidClassName.NotCamelCaps
class PPDPart_Hash extends PPDPart {
+ /**
+ * @param string $out
+ */
public function __construct( $out = '' ) {
if ( $out !== '' ) {
$accum = [ $out ];
* @ingroup Parser
*/
class PPDStack {
- public $stack, $rootAccum;
+ /** @var PPDStackElement[] */
+ public $stack;
+ public $rootAccum;
/**
- * @var PPDStack|false
+ * @var PPDStackElement|false
*/
public $top;
public $out;
/**
* @ingroup Parser
+ * @property PPDPart_Hash[] $parts
*/
// phpcs:ignore Squiz.Classes.ValidClassName.NotCamelCaps
class PPDStackElement_Hash extends PPDStackElement {
*
* @param int|bool $openingCount
* @return array
+ * @suppress PhanParamSignatureMismatch
*/
public function breakSyntax( $openingCount = false ) {
if ( $this->open == "\n" ) {
} else {
$accum[++$lastIndex] = '|';
}
+
foreach ( $part->out as $node ) {
if ( is_string( $node ) && is_string( $accum[$lastIndex] ) ) {
$accum[$lastIndex] .= $node;
* @param string $sep
* @param int $flags
* @param string|PPNode $args,...
+ * @suppress PhanCommentParamWithoutRealParam HHVM bug T228695#5450847
* @return string
*/
public function implodeWithFlags( $sep, $flags /*, ... */ );
* Implode with no flags specified
* @param string $sep
* @param string|PPNode $args,...
+ * @suppress PhanCommentParamWithoutRealParam HHVM bug T228695#5450847
* @return string
*/
public function implode( $sep /*, ... */ );
* Makes an object that, when expand()ed, will be the same as one obtained
* with implode()
* @param string $sep
- * @param string|PPNode $args,...
+ * @param string|PPNode ...$args
+ * @suppress PhanCommentParamWithoutRealParam HHVM bug T228695#5450847
* @return PPNode
*/
- public function virtualImplode( $sep /*, ... */ );
+ public function virtualImplode( $sep /* ...$args */ );
/**
* Virtual implode with brackets
* @param string $start
* @param string $sep
* @param string $end
- * @param string|PPNode $args,...
+ * @param string|PPNode ...$args
+ * @suppress PhanCommentParamWithoutRealParam HHVM bug T228695#5450847
* @return PPNode
*/
- public function virtualBracketedImplode( $start, $sep, $end /*, ... */ );
+ public function virtualBracketedImplode( $start, $sep, $end /* ...$args */ );
/**
* Returns true if there are no arguments in this frame
* An expansion frame, used as a context to expand the result of preprocessToObj()
* @deprecated since 1.34, use PPFrame_Hash
* @ingroup Parser
+ * @phan-file-suppress PhanUndeclaredMethod
*/
// phpcs:ignore Squiz.Classes.ValidClassName.NotCamelCaps
class PPFrame_DOM implements PPFrame {
public function __construct( $preprocessor ) {
$this->preprocessor = $preprocessor;
$this->parser = $preprocessor->parser;
- $this->title = $this->parser->mTitle;
+ $this->title = $this->parser->getTitle();
$this->titleCache = [ $this->title ? $this->title->getPrefixedDBkey() : false ];
$this->loopCheckHash = [];
$this->depth = 0;
* @param string $sep
* @param string|PPNode_DOM|DOMNode ...$args
* @return array
+ * @suppress PhanParamSignatureMismatch
*/
public function virtualImplode( $sep, ...$args ) {
$out = [];
* @param string $end
* @param string|PPNode_DOM|DOMNode ...$args
* @return array
+ * @suppress PhanParamSignatureMismatch
*/
public function virtualBracketedImplode( $start, $sep, $end, ...$args ) {
$out = [ $start ];
public function __construct( $preprocessor ) {
$this->preprocessor = $preprocessor;
$this->parser = $preprocessor->parser;
- $this->title = $this->parser->mTitle;
+ $this->title = $this->parser->getTitle();
$this->titleCache = [ $this->title ? $this->title->getPrefixedDBkey() : false ];
$this->loopCheckHash = [];
$this->depth = 0;
/**
* @deprecated since 1.34, use PPNode_Hash_{Tree,Text,Array,Attr}
* @ingroup Parser
+ * @phan-file-suppress PhanUndeclaredMethod
*/
// phpcs:ignore Squiz.Classes.ValidClassName.NotCamelCaps
class PPNode_DOM implements PPNode {
*/
public function __destruct() {
if ( isset( $this->mLinkHolders ) ) {
+ // @phan-suppress-next-line PhanTypeObjectUnsetDeclaredProperty
unset( $this->mLinkHolders );
}
+ // @phan-suppress-next-line PhanTypeSuspiciousNonTraversableForeach
foreach ( $this as $name => $value ) {
unset( $this->$name );
}
*/
public function replaceExternalLinks( $text ) {
$bits = preg_split( $this->mExtLinkBracketedRegex, $text, -1, PREG_SPLIT_DELIM_CAPTURE );
+ // @phan-suppress-next-line PhanTypeComparisonFromArray See phan issue #3161
if ( $bits === false ) {
throw new MWException( "PCRE needs to be compiled with "
. "--enable-unicode-properties in order for MediaWiki to function" );
* @param bool $isMain
* @return mixed|string
* @private
+ * @suppress PhanTypeInvalidDimOffset
*/
public function formatHeadings( $text, $origText, $isMain = true ) {
# Inhibit editsection links if requested in the page
Hooks::run( 'ParserMakeImageParams', [ $title, $file, &$params, $this ] );
# Linker does the rest
+ // @phan-suppress-next-line PhanTypeInvalidDimOffset
$time = $options['time'] ?? false;
$ret = Linker::makeImageLink( $this, $title, $file, $params['frame'], $params['handler'],
$time, $descQuery, $this->mOptions->getThumbSize() );
*/
private static function normalizeSectionName( $text ) {
# T90902: ensure the same normalization is applied for IDs as to links
+ /** @var MediaWikiTitleCodec $titleParser */
$titleParser = MediaWikiServices::getInstance()->getTitleParser();
+ '@phan-var MediaWikiTitleCodec $titleParser';
try {
$parts = $titleParser->splitTitleString( "#$text" );
}
$i += $count;
} elseif ( $found == 'close' ) {
+ /** @var PPDStackElement_Hash $piece */
$piece = $stack->top;
+ '@phan-var PPDStackElement_Hash $piece';
# lets check if there are enough characters for closing brace
$maxCount = $piece->count;
if ( $piece->close === '}-' && $curChar === '}' ) {
// Construct pseudo-hash based on params and arguments
/** @var ParameterizedPassword $passObj */
$passObj = $this->factory->newFromType( $type );
+ '@phan-var ParameterizedPassword $passObj';
$params = '';
$args = '';
// Hash the last hash with the next type in the layer
$passObj = $this->factory->newFromCiphertext( $existingHash );
+ '@phan-var ParameterizedPassword $passObj';
$passObj->crypt( $lastHash );
// Move over the params and args
// Construct pseudo-hash based on params and arguments
/** @var ParameterizedPassword $passObj */
$passObj = $this->factory->newFromType( $type );
+ '@phan-var ParameterizedPassword $passObj';
$params = '';
$args = '';
// Hash the last hash with the next type in the layer
$passObj = $this->factory->newFromCiphertext( $existingHash );
+ '@phan-var ParameterizedPassword $passObj';
$passObj->crypt( $lastHash );
// Move over the params and args
global $wgPopularPasswordFile, $wgSitename;
$status = Status::newGood();
if ( $policyVal > 0 ) {
- wfDeprecated( __METHOD__, '1.33' );
-
$langEn = Language::factory( 'en' );
$passwordKey = $langEn->lc( trim( $password ) );
if ( !$status->isOK() ) {
return $status;
}
+ /** @var RedisConnRef $conn */
$conn = $status->value;
+ '@phan-var RedisConnRef $conn';
// phpcs:disable Generic.Files.LineLength
static $script =
if ( !$status->isOK() ) {
return $status;
}
+ /** @var RedisConnRef $conn */
$conn = $status->value;
+ '@phan-var RedisConnRef $conn';
$now = microtime( true );
try {
} elseif ( $field->validate( $globalDefault, $user->getOptions() ) === true ) {
$info['default'] = $globalDefault;
} else {
- throw new MWException( "Global default '$globalDefault' is invalid for field $name" );
+ $globalDefault = json_encode( $globalDefault );
+ throw new MWException(
+ "Default '$globalDefault' is invalid for preference $name of user $user"
+ );
}
}
if ( $this->options->get( 'EnableEmail' ) ) {
if ( $canViewPrivateInfo ) {
+ $helpMessages = [];
$helpMessages[] = $this->options->get( 'EmailConfirmToEdit' )
? 'prefs-help-email-required'
: 'prefs-help-email';
* Handle the form submission if everything validated properly
*
* @param array $formData
- * @param HTMLForm $form
+ * @param PreferencesFormOOUI $form
* @param array[] $formDescriptor
* @return bool|Status|string
*/
- protected function saveFormData( $formData, HTMLForm $form, array $formDescriptor ) {
- /** @var \User $user */
+ protected function saveFormData( $formData, PreferencesFormOOUI $form, array $formDescriptor ) {
$user = $form->getModifiedUser();
$hiddenPrefs = $this->options->get( 'HiddenPrefs' );
$result = true;
* Save the form data and reload the page
*
* @param array $formData
- * @param HTMLForm $form
+ * @param PreferencesFormOOUI $form
* @param array $formDescriptor
* @return Status
*/
- protected function submitForm( array $formData, HTMLForm $form, array $formDescriptor ) {
+ protected function submitForm(
+ array $formData,
+ PreferencesFormOOUI $form,
+ array $formDescriptor
+ ) {
$res = $this->saveFormData( $formData, $form, $formDescriptor );
if ( $res === true ) {
*/
protected function getTimeZoneList( Language $language ) {
$identifiers = DateTimeZone::listIdentifiers();
+ // @phan-suppress-next-line PhanTypeComparisonFromArray See phan issue #3162
if ( $identifiers === false ) {
return [];
}
abstract class Profiler {
/** @var string|bool Profiler ID for bucketing data */
protected $profileID = false;
- /** @var bool Whether MediaWiki is in a SkinTemplate output context */
- protected $templated = false;
/** @var array All of the params passed from $wgProfiler */
protected $params = [];
/** @var IContextSource Current request context */
protected $context = null;
/** @var TransactionProfiler */
protected $trxProfiler;
+ /** @var bool */
+ private $allowOutput = false;
+
/** @var Profiler */
private static $instance = null;
* @since 1.26
*/
public function logDataPageOutputOnly() {
+ if ( !$this->allowOutput ) {
+ return;
+ }
+
$outputs = [];
foreach ( $this->getOutputs() as $output ) {
if ( $output->logsToOutput() ) {
}
/**
- * Get the content type sent out to the client.
- * Used for profilers that output instead of store data.
- * @return string
+ * Get the Content-Type for deciding how to format appended profile output.
+ *
+ * Disabled by default. Enable via setAllowOutput().
+ *
+ * @see ProfilerOutputText
* @since 1.25
+ * @return string|null Returns null if disabled or no Content-Type found.
*/
public function getContentType() {
- foreach ( headers_list() as $header ) {
- if ( preg_match( '#^content-type: (\w+/\w+);?#i', $header, $m ) ) {
- return $m[1];
+ if ( $this->allowOutput ) {
+ foreach ( headers_list() as $header ) {
+ if ( preg_match( '#^content-type: (\w+/\w+);?#i', $header, $m ) ) {
+ return $m[1];
+ }
}
}
return null;
/**
* Mark this call as templated or not
*
+ * @deprecated since 1.34 Use setAllowOutput() instead.
* @param bool $t
*/
public function setTemplated( $t ) {
- $this->templated = $t;
+ wfDeprecated( __METHOD__, '1.34' );
+ $this->allowOutput = ( $t === true );
}
/**
* Was this call as templated or not
*
+ * @deprecated since 1.34 Use getAllowOutput() instead.
* @return bool
*/
public function getTemplated() {
- return $this->templated;
+ wfDeprecated( __METHOD__, '1.34' );
+ return $this->getAllowOutput();
+ }
+
+ /**
+ * Enable appending profiles to standard output.
+ *
+ * @since 1.34
+ */
+ public function setAllowOutput() {
+ $this->allowOutput = true;
+ }
+
+ /**
+ * Whether appending profiles is allowed.
+ *
+ * @since 1.34
+ * @return bool
+ */
+ public function getAllowOutput() {
+ return $this->allowOutput;
}
/**
<?php
class ProfilerExcimer extends Profiler {
+ /** @var ExcimerProfiler */
private $cpuProf;
+ /** @var ExcimerProfiler */
private $realProf;
private $period;
}
/**
- * Does log() just send the data to the request/script output?
+ * May the log() try to write to standard output?
* @return bool
* @since 1.33
*/
}
/**
- * Log MediaWiki-style profiling data
+ * Log MediaWiki-style profiling data.
+ *
+ * For classes that enable logsToOutput(), this must not
+ * be called unless Profiler::setAllowOutput is enabled.
*
* @param array $stats Result of Profiler::getFunctionStats()
*/
* @ingroup Profiler
*
* @since 1.25
+ * @property ProfilerXhprof $collector
*/
class ProfilerOutputDump extends ProfilerOutput {
*/
class ProfilerOutputText extends ProfilerOutput {
/** @var float Min real time display threshold */
- protected $thresholdMs;
+ private $thresholdMs;
+
+ /** @var bool Whether to use visible text or a comment (for HTML responses) */
+ private $visible;
function __construct( Profiler $collector, array $params ) {
parent::__construct( $collector, $params );
$this->thresholdMs = $params['thresholdMs'] ?? 1.0;
+ $this->visible = $params['visible'] ?? false;
}
public function logsToOutput() {
}
public function log( array $stats ) {
- if ( $this->collector->getTemplated() ) {
- $out = '';
+ $out = '';
- // Filter out really tiny entries
- $min = $this->thresholdMs;
- $stats = array_filter( $stats, function ( $a ) use ( $min ) {
- return $a['real'] > $min;
- } );
- // Sort descending by time elapsed
- usort( $stats, function ( $a, $b ) {
- return $b['real'] <=> $a['real'];
- } );
+ // Filter out really tiny entries
+ $min = $this->thresholdMs;
+ $stats = array_filter( $stats, function ( $a ) use ( $min ) {
+ return $a['real'] > $min;
+ } );
+ // Sort descending by time elapsed
+ usort( $stats, function ( $a, $b ) {
+ return $b['real'] <=> $a['real'];
+ } );
- array_walk( $stats,
- function ( $item ) use ( &$out ) {
- $out .= sprintf( "%6.2f%% %3.3f %6d - %s\n",
- $item['%real'], $item['real'], $item['calls'], $item['name'] );
- }
- );
+ array_walk( $stats,
+ function ( $item ) use ( &$out ) {
+ $out .= sprintf( "%6.2f%% %3.3f %6d - %s\n",
+ $item['%real'], $item['real'], $item['calls'], $item['name'] );
+ }
+ );
- $contentType = $this->collector->getContentType();
- if ( wfIsCLI() ) {
+ $contentType = $this->collector->getContentType();
+ if ( wfIsCLI() ) {
+ print "<!--\n{$out}\n-->\n";
+ } elseif ( $contentType === 'text/html' ) {
+ if ( $this->visible ) {
+ print "<pre>{$out}</pre>";
+ } else {
print "<!--\n{$out}\n-->\n";
- } elseif ( $contentType === 'text/html' ) {
- $visible = $this->params['visible'] ?? false;
- if ( $visible ) {
- print "<pre>{$out}</pre>";
- } else {
- print "<!--\n{$out}\n-->\n";
- }
- } elseif ( $contentType === 'text/javascript' || $contentType === 'text/css' ) {
- print "\n/*\n{$out}*/\n";
}
+ } elseif ( $contentType === 'text/javascript' || $contentType === 'text/css' ) {
+ print "\n/*\n{$out}*/\n";
}
}
}
// @codeCoverageIgnoreStart
// T109544 - If a feed formatter returns null, this will otherwise cause an
// error in at least RedisPubSubFeedEngine. Not sure best to handle this.
+ // @phan-suppress-next-line PhanTypeMismatchReturn
return;
// @codeCoverageIgnoreEnd
}
}
/**
- * Remove newlines, carriage returns and decode html entites
+ * Remove newlines, carriage returns and decode html entities
* @param string $text
* @return string
*/
$autoloadNamespaces
);
- if ( isset( $info['AutoloadClasses'] ) ) {
- $autoload = $this->processAutoLoader( $dir, $info['AutoloadClasses'] );
- $GLOBALS['wgAutoloadClasses'] += $autoload;
- $autoloadClasses += $autoload;
- }
- if ( isset( $info['AutoloadNamespaces'] ) ) {
- $autoloadNamespaces += $this->processAutoLoader( $dir, $info['AutoloadNamespaces'] );
- AutoLoader::$psr4Namespaces += $autoloadNamespaces;
- }
-
// get all requirements/dependencies for this extension
$requires = $processor->getRequirements( $info, $this->checkDev );
*/
private $context;
+ /** @var int|array */
protected $modules = self::INHERIT_VALUE;
protected $language = self::INHERIT_VALUE;
protected $direction = self::INHERIT_VALUE;
if ( $this->modules === self::INHERIT_VALUE ) {
return $this->context->getModules();
}
+
return $this->modules;
}
}
/**
+ * @internal For use by ResourceLoaderStartUpModule only.
+ */
+ const HASH_LENGTH = 5;
+
+ /**
+ * Create a hash for module versioning purposes.
+ *
+ * This hash is used in three ways:
+ *
+ * - To differentiate between the current version and a past version
+ * of a module by the same name.
+ *
+ * In the cache key of localStorage in the browser (mw.loader.store).
+ * This store keeps only one version of any given module. As long as the
+ * next version the client encounters has a different hash from the last
+ * version it saw, it will correctly discard it in favour of a network fetch.
+ *
+ * A browser may evict a site's storage container for any reason (e.g. when
+ * the user hasn't visited a site for some time, and/or when the device is
+ * low on storage space). Anecdotally it seems devices rarely keep unused
+ * storage beyond 2 weeks on mobile devices and 4 weeks on desktop.
+ * But, there is no hard limit or expiration on localStorage.
+ * ResourceLoader's Client also clears localStorage when the user changes
+ * their language preference or when they (temporarily) use Debug Mode.
+ *
+ * The only hard factors that reduce the range of possible versions are
+ * 1) the name and existence of a given module, and
+ * 2) the TTL for mw.loader.store, and
+ * 3) the `$wgResourceLoaderStorageVersion` configuration variable.
+ *
+ * - To identify a batch response of modules from load.php in an HTTP cache.
+ *
+ * When fetching modules in a batch from load.php, a combined hash
+ * is created by the JS code, and appended as query parameter.
+ *
+ * In cache proxies (e.g. Varnish, Nginx) and in the browser's HTTP cache,
+ * these urls are used to identify other previously cached responses.
+ * The range of possible versions a given version has to be unique amongst
+ * is determined by the maximum duration each response is stored for, which
+ * is controlled by `$wgResourceLoaderMaxage['versioned']`.
+ *
+ * - To detect race conditions between multiple web servers in a MediaWiki
+ * deployment of which some have the newer version and some still the older
+ * version.
+ *
+ * An HTTP request from a browser for the Startup manifest may be responded
+ * to by a server with the newer version. The browser may then use that to
+ * request a given module, which may then be responded to by a server with
+ * the older version. To avoid caching this for too long (which would pollute
+ * all other users without repairing itself), the combined hash that the JS
+ * client adds to the url is verified by the server (in ::sendResponseHeaders).
+ * If they don't match, we instruct cache proxies and clients to not cache
+ * this response as long as they normally would. This is also the reason
+ * that the algorithm used here in PHP must match the one used in JS.
+ *
+ * The fnv132 digest creates a 32-bit integer, which goes upto 4 Giga and
+ * needs up to 7 chars in base 36.
+ * Within 7 characters, base 36 can count up to 78,364,164,096 (78 Giga),
+ * (but with fnv132 we'd use very little of this range, mostly padding).
+ * Within 6 characters, base 36 can count up to 2,176,782,336 (2 Giga).
+ * Within 5 characters, base 36 can count up to 60,466,176 (60 Mega).
+ *
* @since 1.26
* @param string $value
* @return string Hash
*/
public static function makeHash( $value ) {
$hash = hash( 'fnv132', $value );
- return Wikimedia\base_convert( $hash, 16, 36, 7 );
+ // The base_convert will pad it (if too short),
+ // then substr() will trim it (if too long).
+ return substr(
+ Wikimedia\base_convert( $hash, 16, 36, self::HASH_LENGTH ),
+ 0,
+ self::HASH_LENGTH
+ );
}
/**
$idx = -1;
foreach ( $grpModules as $name => $module ) {
$shouldEmbed = $module->shouldEmbedModule( $context );
+ // @phan-suppress-next-line PhanTypeInvalidDimOffset
if ( !$moduleSets || $moduleSets[$idx][0] !== $shouldEmbed ) {
$moduleSets[++$idx] = [ $shouldEmbed, [] ];
}
protected $direction;
protected $hash;
protected $userObj;
+ /** @var ResourceLoaderImage|false */
protected $imageObj;
/**
// Various parameters
$this->user = $request->getRawVal( 'user' );
$this->debug = $request->getRawVal( 'debug' ) === 'true';
- $this->only = $request->getRawVal( 'only', null );
- $this->version = $request->getRawVal( 'version', null );
+ $this->only = $request->getRawVal( 'only' );
+ $this->version = $request->getRawVal( 'version' );
$this->raw = $request->getFuzzyBool( 'raw' );
// Image requests
* @param string|string[]|MessageSpecifier $key Message key, or array of keys,
* or a MessageSpecifier.
* @param mixed $args,...
+ * @suppress PhanCommentParamWithoutRealParam HHVM bug T228695#5450847
* @return Message
*/
public function msg( $key ) {
if ( $module ) {
$dataPath = $this->getThemeImagesPath( $theme, $module );
if ( !$dataPath ) {
- return false;
+ return [];
}
} else {
// Backwards-compatibility for things that probably shouldn't have used this class...
$dataPath->getRemoteBasePath()
);
} else {
+ // @phan-suppress-next-line PhanTypeSuspiciousStringExpression
$path = dirname( $dataPath ) . '/' . $path;
}
};
'wgContentNamespaces' => $nsInfo->getContentNamespaces(),
'wgSiteName' => $conf->get( 'Sitename' ),
'wgDBname' => $conf->get( 'DBname' ),
+ 'wgWikiID' => WikiMap::getWikiIdFromDbDomain( WikiMap::getCurrentWikiDbDomain() ),
'wgExtraSignatureNamespaces' => $conf->get( 'ExtraSignatureNamespaces' ),
'wgExtensionAssetsPath' => $conf->get( 'ExtensionAssetsPath' ),
// MediaWiki sets cookies to have this prefix by default
$states[$name] = 'error';
}
- if ( $versionHash !== '' && strlen( $versionHash ) !== 7 ) {
+ if ( $versionHash !== '' && strlen( $versionHash ) !== ResourceLoader::HASH_LENGTH ) {
$e = new RuntimeException( "Badly formatted module version hash" );
$resourceLoader->outputErrorAndLog( $e,
"Module '{module}' produced an invalid version hash: '{version}'.",
/**
* Item class for a filearchive table row
+ *
+ * @property ArchivedFile $file
+ * @property RevDelArchivedFileList $list
*/
class RevDelArchivedFileItem extends RevDelFileItem {
- /** @var RevDelArchivedFileList $list */
- /** @var ArchivedFile $file */
/** @var LocalFile */
protected $lockFile;
}
public function doPostCommitUpdates( array $visibilityChangeMap ) {
+ /** @var LocalFile $file */
$file = MediaWikiServices::getInstance()->getRepoGroup()->getLocalRepo()
->newFile( $this->title );
+ '@phan-var LocalFile $file';
$file->purgeCache();
$file->purgeDescription();
* needs to be able to make a query from a set of identifiers to pull
* relevant rows, to return RevDelItem subclasses wrapping them, and
* to wrap bulk update operations.
+ *
+ * @property RevDelItem $current
+ * @method RevDelItem next()
+ * @method RevDelItem reset()
+ * @method RevDelItem current()
+ * @phan-file-suppress PhanParamSignatureMismatch
*/
abstract class RevDelList extends RevisionListBase {
function __construct( IContextSource $context, Title $title, array $ids ) {
}
$logEntry->setRelations( $relations );
// Apply change tags to the log entry
- $logEntry->setTags( $params['tags'] );
+ $logEntry->addTags( $params['tags'] );
$logId = $logEntry->insert();
$logEntry->publish( $logId );
}
/**
* Item class for a live revision table row
+ *
+ * @property RevDelRevisionList $list
*/
class RevDelRevisionItem extends RevDelItem {
/** @var Revision */
/**
* Move the iteration pointer to the next list item, and return it.
* @return Revision
+ * @suppress PhanParamSignatureMismatchInternal
*/
public function next() {
$this->res->next();
--- /dev/null
+<?php
+
+/**
+ * SearchResult class based on the Revision information.
+ * This class is suited for search engines that do not store a specialized version of the searched
+ * content.
+ */
+class RevisionSearchResult extends SearchResult {
+ use RevisionSearchResultTrait;
+
+ /**
+ * @param Title|null $title
+ */
+ public function __construct( $title ) {
+ $this->mTitle = $title;
+ $this->initFromTitle( $title );
+ }
+}
--- /dev/null
+<?php
+
+use MediaWiki\MediaWikiServices;
+
+/**
+ * Transitional trait used to share the methods between SearchResult and RevisionSearchResult.
+ * All the content of this trait can be moved to RevisionSearchResult once SearchResult is finally
+ * refactored into an abstract class.
+ * NOTE: This trait MUST NOT be used by something else than SearchResult and RevisionSearchResult.
+ * It will be removed without deprecation period once SearchResult
+ */
+trait RevisionSearchResultTrait {
+ /**
+ * @var Revision
+ */
+ protected $mRevision = null;
+
+ /**
+ * @var File
+ */
+ protected $mImage = null;
+
+ /**
+ * @var Title
+ */
+ protected $mTitle;
+
+ /**
+ * @var string
+ */
+ protected $mText;
+
+ /**
+ * Initialize from a Title and if possible initializes a corresponding
+ * Revision and File.
+ *
+ * @param Title $title
+ */
+ protected function initFromTitle( $title ) {
+ $this->mTitle = $title;
+ $services = MediaWikiServices::getInstance();
+ if ( !is_null( $this->mTitle ) ) {
+ $id = false;
+ Hooks::run( 'SearchResultInitFromTitle', [ $title, &$id ] );
+ $this->mRevision = Revision::newFromTitle(
+ $this->mTitle, $id, Revision::READ_NORMAL );
+ if ( $this->mTitle->getNamespace() === NS_FILE ) {
+ $this->mImage = $services->getRepoGroup()->findFile( $this->mTitle );
+ }
+ }
+ }
+
+ /**
+ * Check if this is result points to an invalid title
+ *
+ * @return bool
+ */
+ public function isBrokenTitle() {
+ return is_null( $this->mTitle );
+ }
+
+ /**
+ * Check if target page is missing, happens when index is out of date
+ *
+ * @return bool
+ */
+ public function isMissingRevision() {
+ return !$this->mRevision && !$this->mImage;
+ }
+
+ /**
+ * @return Title
+ */
+ public function getTitle() {
+ return $this->mTitle;
+ }
+
+ /**
+ * Get the file for this page, if one exists
+ * @return File|null
+ */
+ public function getFile() {
+ return $this->mImage;
+ }
+
+ /**
+ * Lazy initialization of article text from DB
+ */
+ protected function initText() {
+ if ( !isset( $this->mText ) ) {
+ if ( $this->mRevision != null ) {
+ $content = $this->mRevision->getContent();
+ $this->mText = $content !== null ? $content->getTextForSearchIndex() : '';
+ } else { // TODO: can we fetch raw wikitext for commons images?
+ $this->mText = '';
+ }
+ }
+ }
+
+ /**
+ * @param string[] $terms Terms to highlight (this parameter is deprecated and ignored)
+ * @return string Highlighted text snippet, null (and not '') if not supported
+ */
+ public function getTextSnippet( $terms = [] ) {
+ return '';
+ }
+
+ /**
+ * @return string Highlighted title, '' if not supported
+ */
+ public function getTitleSnippet() {
+ return '';
+ }
+
+ /**
+ * @return string Highlighted redirect name (redirect to this page), '' if none or not supported
+ */
+ public function getRedirectSnippet() {
+ return '';
+ }
+
+ /**
+ * @return Title|null Title object for the redirect to this page, null if none or not supported
+ */
+ public function getRedirectTitle() {
+ return null;
+ }
+
+ /**
+ * @return string Highlighted relevant section name, null if none or not supported
+ */
+ public function getSectionSnippet() {
+ return '';
+ }
+
+ /**
+ * @return Title|null Title object (pagename+fragment) for the section,
+ * null if none or not supported
+ */
+ public function getSectionTitle() {
+ return null;
+ }
+
+ /**
+ * @return string Highlighted relevant category name or '' if none or not supported
+ */
+ public function getCategorySnippet() {
+ return '';
+ }
+
+ /**
+ * @return string Timestamp
+ */
+ public function getTimestamp() {
+ if ( $this->mRevision ) {
+ return $this->mRevision->getTimestamp();
+ } elseif ( $this->mImage ) {
+ return $this->mImage->getTimestamp();
+ }
+ return '';
+ }
+
+ /**
+ * @return int Number of words
+ */
+ public function getWordCount() {
+ $this->initText();
+ return str_word_count( $this->mText );
+ }
+
+ /**
+ * @return int Size in bytes
+ */
+ public function getByteSize() {
+ $this->initText();
+ return strlen( $this->mText );
+ }
+
+ /**
+ * @return string Interwiki prefix of the title (return iw even if title is broken)
+ */
+ public function getInterwikiPrefix() {
+ return '';
+ }
+
+ /**
+ * @return string Interwiki namespace of the title (since we likely can't resolve it locally)
+ */
+ public function getInterwikiNamespaceText() {
+ return '';
+ }
+
+ /**
+ * Did this match file contents (eg: PDF/DJVU)?
+ * @return bool
+ */
+ public function isFileMatch() {
+ return false;
+ }
+}
* @param string $profileType the type of profiles
* @param User|null $user the user requesting the list of profiles
* @return array|null the list of profiles or null if none available
+ * @phan-return null|array{name:string,desc-message:string,default?:bool}
*/
public function getProfiles( $profileType, User $user = null ) {
return null;
* @ingroup Search
*/
-use MediaWiki\MediaWikiServices;
-
/**
- * @todo FIXME: This class is horribly factored. It would probably be better to
- * have a useful base class to which you pass some standard information, then
- * let the fancy self-highlighters extend that.
+ * NOTE: this class is being refactored into an abstract base class.
+ * If you extend this class directly, please implement all the methods declared
+ * in RevisionSearchResultTrait or extend RevisionSearchResult.
+ *
+ * Once the hard-deprecation period is over (1.36?):
+ * - all methods declared in RevisionSearchResultTrait should be declared
+ * as abstract in this class
+ * - RevisionSearchResultTrait body should be moved to RevisionSearchResult and then removed without
+ * deprecation
+ * - caveat: all classes extending this one may potentially break if they did not properly implement
+ * all the methods.
* @ingroup Search
*/
class SearchResult {
+ use SearchResultTrait;
+ use RevisionSearchResultTrait;
- /**
- * @var Revision
- */
- protected $mRevision = null;
-
- /**
- * @var File
- */
- protected $mImage = null;
-
- /**
- * @var Title
- */
- protected $mTitle;
-
- /**
- * @var string
- */
- protected $mText;
-
- /**
- * A function returning a set of extension data.
- * @var Closure|null
- */
- protected $extensionData;
+ public function __construct() {
+ if ( self::class === static::class ) {
+ wfDeprecated( __METHOD__, '1.34' );
+ }
+ }
/**
* Return a new SearchResult and initializes it with a title.
* @return SearchResult
*/
public static function newFromTitle( $title, ISearchResultSet $parentSet = null ) {
- $result = new static();
- $result->initFromTitle( $title );
+ $result = new RevisionSearchResult( $title );
if ( $parentSet ) {
$parentSet->augmentResult( $result );
}
return $result;
}
-
- /**
- * Initialize from a Title and if possible initializes a corresponding
- * Revision and File.
- *
- * @param Title $title
- */
- protected function initFromTitle( $title ) {
- $this->mTitle = $title;
- $services = MediaWikiServices::getInstance();
- if ( !is_null( $this->mTitle ) ) {
- $id = false;
- Hooks::run( 'SearchResultInitFromTitle', [ $title, &$id ] );
- $this->mRevision = Revision::newFromTitle(
- $this->mTitle, $id, Revision::READ_NORMAL );
- if ( $this->mTitle->getNamespace() === NS_FILE ) {
- $this->mImage = $services->getRepoGroup()->findFile( $this->mTitle );
- }
- }
- }
-
- /**
- * Check if this is result points to an invalid title
- *
- * @return bool
- */
- public function isBrokenTitle() {
- return is_null( $this->mTitle );
- }
-
- /**
- * Check if target page is missing, happens when index is out of date
- *
- * @return bool
- */
- public function isMissingRevision() {
- return !$this->mRevision && !$this->mImage;
- }
-
- /**
- * @return Title
- */
- public function getTitle() {
- return $this->mTitle;
- }
-
- /**
- * Get the file for this page, if one exists
- * @return File|null
- */
- public function getFile() {
- return $this->mImage;
- }
-
- /**
- * Lazy initialization of article text from DB
- */
- protected function initText() {
- if ( !isset( $this->mText ) ) {
- if ( $this->mRevision != null ) {
- $content = $this->mRevision->getContent();
- $this->mText = $content !== null ? $content->getTextForSearchIndex() : '';
- } else { // TODO: can we fetch raw wikitext for commons images?
- $this->mText = '';
- }
- }
- }
-
- /**
- * @param string[] $terms Terms to highlight (this parameter is deprecated and ignored)
- * @return string Highlighted text snippet, null (and not '') if not supported
- */
- public function getTextSnippet( $terms = [] ) {
- return '';
- }
-
- /**
- * @return string Highlighted title, '' if not supported
- */
- public function getTitleSnippet() {
- return '';
- }
-
- /**
- * @return string Highlighted redirect name (redirect to this page), '' if none or not supported
- */
- public function getRedirectSnippet() {
- return '';
- }
-
- /**
- * @return Title|null Title object for the redirect to this page, null if none or not supported
- */
- public function getRedirectTitle() {
- return null;
- }
-
- /**
- * @return string Highlighted relevant section name, null if none or not supported
- */
- public function getSectionSnippet() {
- return '';
- }
-
- /**
- * @return Title|null Title object (pagename+fragment) for the section,
- * null if none or not supported
- */
- public function getSectionTitle() {
- return null;
- }
-
- /**
- * @return string Highlighted relevant category name or '' if none or not supported
- */
- public function getCategorySnippet() {
- return '';
- }
-
- /**
- * @return string Timestamp
- */
- public function getTimestamp() {
- if ( $this->mRevision ) {
- return $this->mRevision->getTimestamp();
- } elseif ( $this->mImage ) {
- return $this->mImage->getTimestamp();
- }
- return '';
- }
-
- /**
- * @return int Number of words
- */
- public function getWordCount() {
- $this->initText();
- return str_word_count( $this->mText );
- }
-
- /**
- * @return int Size in bytes
- */
- public function getByteSize() {
- $this->initText();
- return strlen( $this->mText );
- }
-
- /**
- * @return string Interwiki prefix of the title (return iw even if title is broken)
- */
- public function getInterwikiPrefix() {
- return '';
- }
-
- /**
- * @return string Interwiki namespace of the title (since we likely can't resolve it locally)
- */
- public function getInterwikiNamespaceText() {
- return '';
- }
-
- /**
- * Did this match file contents (eg: PDF/DJVU)?
- * @return bool
- */
- public function isFileMatch() {
- return false;
- }
-
- /**
- * Get the extension data as:
- * augmentor name => data
- * @return array[]
- */
- public function getExtensionData() {
- if ( $this->extensionData ) {
- return call_user_func( $this->extensionData );
- } else {
- return [];
- }
- }
-
- /**
- * Set extension data for this result.
- * The data is:
- * augmentor name => data
- * @param Closure|array $extensionData Takes no arguments, returns
- * either array of extension data or null.
- */
- public function setExtensionData( $extensionData ) {
- if ( $extensionData instanceof Closure ) {
- $this->extensionData = $extensionData;
- } elseif ( is_array( $extensionData ) ) {
- wfDeprecated( __METHOD__ . ' with array argument', '1.32' );
- $this->extensionData = function () use ( $extensionData ) {
- return $extensionData;
- };
- } else {
- $type = is_object( $extensionData )
- ? get_class( $extensionData )
- : gettype( $extensionData );
- throw new \InvalidArgumentException(
- __METHOD__ . " must be called with Closure|array, but received $type" );
- }
- }
}
* This trait can be used directly by extensions providing a SearchEngine.
*
* @ingroup Search
+ * @phan-file-suppress PhanUndeclaredMethod
*/
trait SearchResultSetTrait {
/**
--- /dev/null
+<?php
+
+/**
+ * Trait for SearchResult subclasses to share non-obvious behaviors or methods
+ * that rarely specialized
+ */
+trait SearchResultTrait {
+ /**
+ * A function returning a set of extension data.
+ * @var Closure|null
+ */
+ protected $extensionData;
+
+ /**
+ * Get the extension data as:
+ * augmentor name => data
+ * @return array[]
+ */
+ public function getExtensionData() {
+ if ( $this->extensionData ) {
+ return call_user_func( $this->extensionData );
+ } else {
+ return [];
+ }
+ }
+
+ /**
+ * Set extension data for this result.
+ * The data is:
+ * augmentor name => data
+ * @param Closure|array $extensionData Takes no arguments, returns
+ * either array of extension data or null.
+ */
+ public function setExtensionData( $extensionData ) {
+ if ( $extensionData instanceof Closure ) {
+ $this->extensionData = $extensionData;
+ } elseif ( is_array( $extensionData ) ) {
+ wfDeprecated( __METHOD__ . ' with array argument', '1.32' );
+ $this->extensionData = function () use ( $extensionData ) {
+ return $extensionData;
+ };
+ } else {
+ $type = is_object( $extensionData )
+ ? get_class( $extensionData )
+ : gettype( $extensionData );
+ throw new \InvalidArgumentException(
+ __METHOD__ . " must be called with Closure|array, but received $type" );
+ }
+ }
+}
* @ingroup Search
*/
-class SqlSearchResult extends SearchResult {
+class SqlSearchResult extends RevisionSearchResult {
/** @var string[] */
private $terms;
* @param string[] $terms list of parsed terms
*/
public function __construct( Title $title, array $terms ) {
- $this->initFromTitle( $title );
+ parent::__construct( $title );
$this->terms = $terms;
}
/** @var array Track original session fields for later modification check */
protected $sessionFieldCache = [];
- protected function __construct( SessionManagerInterface $manager ) {
+ protected function __construct( SessionManager $manager ) {
$this->setEnableFlags(
\RequestContext::getMain()->getConfig()->get( 'PHPSessionHandling' )
);
/**
* Install a session handler for the current web request
- * @param SessionManagerInterface $manager
+ * @param SessionManager $manager
*/
- public static function install( SessionManagerInterface $manager ) {
+ public static function install( SessionManager $manager ) {
if ( self::$instance ) {
$manager->setupPHPSessionHandler( self::$instance );
return;
$this->idIsSafe = $data['idIsSafe'];
$this->forceUse = $data['forceUse'] && $this->provider;
} else {
+ // @phan-suppress-next-line PhanUndeclaredMethod
$this->id = $this->provider->getManager()->generateSessionId();
$this->idIsSafe = true;
$this->forceUse = false;
/**
* Get the global SessionManager
- * @return SessionManagerInterface
- * (really a SessionManager, but this is to make IDEs less confused)
+ * @return self
*/
public static function singleton() {
if ( self::$instance === null ) {
"$provider returned empty session info with id flagged unsafe"
);
}
+ // @phan-suppress-next-line PhanTypeInvalidDimOffset
$compare = $infos ? SessionInfo::compare( $infos[0], $info ) : -1;
if ( $compare > 0 ) {
continue;
$provider->setConfig( $this->config );
$provider->setManager( $this );
if ( isset( $this->sessionProviders[(string)$provider] ) ) {
+ // @phan-suppress-next-line PhanTypeSuspiciousStringExpression
throw new \UnexpectedValueException( "Duplicate provider name \"$provider\"" );
}
$this->sessionProviders[(string)$provider] = $provider;
// clear get_last_error without actually raising an error
// from https://www.php.net/manual/en/function.error-get-last.php#113518
- // TODO replace with clear_last_error when requirements are bumped to PHP7
+ // TODO replace with error_clear_last after dropping HHVM
+ // @phan-suppress-next-line PhanTypeMismatchArgumentInternal
set_error_handler( function () {
}, 0 );
AtEase::suppressWarnings();
* @param array $options Associative array of options:
* 'php': The path to the php executable
* 'wrapper': Path to a PHP wrapper to handle the maintenance script
+ * @phan-param array{php?:string,wrapper?:string} $options
* @return Command
*/
public static function makeScriptCommand( $script, $parameters, $options = [] ): Command {
// Give site config file a chance to run the script in a wrapper.
// The caller may likely want to call wfBasename() on $script.
Hooks::run( 'wfShellWikiCmd', [ &$script, &$parameters, &$options ] );
+ // @phan-suppress-next-line PhanTypeInvalidDimOffset
$cmd = [ $options['php'] ?? $wgPhpCli ];
if ( isset( $options['wrapper'] ) ) {
$cmd[] = $options['wrapper'];
*
* @since 1.21
*
- * @var array[]
+ * @var array[]|false
*/
protected $localIds = [];
*
* @param string $name Message name
* @param mixed $params,... Message params
+ * @suppress PhanCommentParamWithoutRealParam HHVM bug T228695#5450847
* @return Message
*/
public function getMsg( $name /* ... */ ) {
* @param array $item Array of list item data containing some of a specific set of keys.
* The "id", "class" and "itemtitle" keys will be used as attributes for the list item,
* if "active" contains a value of true a "active" class will also be appended to class.
+ * @phan-param array{id?:string,class?:string,itemtitle?:string,active?:bool} $item
*
* @param array $options
+ * @phan-param array{tag?:string} $options
*
* If you want something other than a "<li>" you can pass a tag name such as
* "tag" => "span" in the $options array to change the tag used.
if ( isset( $item['itemtitle'] ) ) {
$attrs['title'] = $item['itemtitle'];
}
+ // @phan-suppress-next-line PhanTypeInvalidDimOffset
return Html::rawElement( $options['tag'] ?? 'li', $attrs, $html );
}
/**
* Fetch the skinname messages for available skins.
+ * @deprecated since 1.34, no longer used.
* @return string[]
*/
static function getSkinNameMessages() {
+ wfDeprecated( __METHOD__, '1.34' );
$messages = [];
foreach ( self::getSkinNames() as $skinKey => $skinName ) {
$messages[] = "skinname-$skinKey";
$type = 'ns-subject';
}
// T208315: add HTML class when the user can edit the page
- if ( $title->quickUserCan( 'edit', $user ) ) {
+ if ( MediaWikiServices::getInstance()->getPermissionManager()
+ ->quickUserCan( 'edit', $user, $title )
+ ) {
$type .= ' mw-editable';
}
}
$action = $this->getRequest()->getVal( 'action', 'view' );
$title = $this->getTitle();
$linkRenderer = MediaWikiServices::getInstance()->getLinkRenderer();
+ $permissionManager = MediaWikiServices::getInstance()->getPermissionManager();
if ( ( !$title->exists() || $action == 'history' ) &&
- $title->quickUserCan( 'deletedhistory', $this->getUser() )
+ $permissionManager->quickUserCan( 'deletedhistory', $this->getUser(), $title )
) {
$n = $title->isDeleted();
if ( $n ) {
- if ( $this->getTitle()->quickUserCan( 'undelete', $this->getUser() ) ) {
+ if ( $permissionManager->quickUserCan( 'undelete',
+ $this->getUser(), $this->getTitle() )
+ ) {
$msg = 'thisisdeleted';
} else {
$msg = 'viewdeleted';
* @return array
*/
public function buildSidebar() {
+ $services = MediaWikiServices::getInstance();
$callback = function ( $old = null, &$ttl = null ) {
$bar = [];
$this->addToSidebar( $bar, 'sidebar' );
Hooks::run( 'SkinBuildSidebar', [ $this, &$bar ] );
- if ( MessageCache::singleton()->isDisabled() ) {
+ $msgCache = MediaWikiServices::getInstance()->getMessageCache();
+ if ( $msgCache->isDisabled() ) {
$ttl = WANObjectCache::TTL_UNCACHEABLE; // bug T133069
}
return $bar;
};
- $msgCache = MessageCache::singleton();
- $wanCache = MediaWikiServices::getInstance()->getMainWANObjectCache();
+ $msgCache = $services->getMessageCache();
+ $wanCache = $services->getMainWANObjectCache();
$config = $this->getConfig();
$sidebar = $config->get( 'EnableSidebarCache' )
* Initialize various variables and generate the template
*/
function outputPage() {
- Profiler::instance()->setTemplated( true );
+ Profiler::instance()->setAllowOutput();
$out = $this->getOutput();
$this->initPage( $out );
/** @var CreditsAction $action */
$action = Action::factory(
'credits', $this->getWikiPage(), $this->getContext() );
+ '@phan-var CreditsAction $action';
$tpl->set( 'credits',
$action->getCredits( $wgMaxCredits, $wgShowCreditsIfMax ) );
} else {
$out = $this->getOutput();
$request = $this->getRequest();
$user = $this->getUser();
+ $permissionManager = MediaWikiServices::getInstance()->getPermissionManager();
$content_navigation = [
'namespaces' => [],
// parameters
$action = $request->getVal( 'action', 'view' );
- $userCanRead = $title->quickUserCan( 'read', $user );
+ $userCanRead = $permissionManager->quickUserCan( 'read', $user, $title );
// Avoid PHP 7.1 warning of passing $this by reference
$skinTemplate = $this;
}
// Checks if user can edit the current page if it exists or create it otherwise
- if ( $title->quickUserCan( 'edit', $user )
- && ( $title->exists() || $title->quickUserCan( 'create', $user ) )
+ if ( $permissionManager->quickUserCan( 'edit', $user, $title ) &&
+ ( $title->exists() ||
+ $permissionManager->quickUserCan( 'create', $user, $title ) )
) {
// Builds CSS class for talk page links
$isTalkClass = $isTalk ? ' istalk' : '';
'href' => $title->getLocalURL( 'action=history' ),
];
- if ( $title->quickUserCan( 'delete', $user ) ) {
+ if ( $permissionManager->quickUserCan( 'delete', $user, $title ) ) {
$content_navigation['actions']['delete'] = [
'class' => ( $onPage && $action == 'delete' ) ? 'selected' : false,
'text' => wfMessageFallback( "$skname-action-delete", 'delete' )
];
}
- if ( $title->quickUserCan( 'move', $user ) ) {
+ if ( $permissionManager->quickUserCan( 'move', $user, $title ) ) {
$moveTitle = SpecialPage::getTitleFor( 'Movepage', $title->getPrefixedDBkey() );
$content_navigation['actions']['move'] = [
'class' => $this->getTitle()->isSpecial( 'Movepage' ) ? 'selected' : false,
}
} else {
// article doesn't exist or is deleted
- if ( $title->quickUserCan( 'deletedhistory', $user ) ) {
+ if ( $permissionManager->quickUserCan( 'deletedhistory', $user, $title ) ) {
$n = $title->isDeleted();
if ( $n ) {
$undelTitle = SpecialPage::getTitleFor( 'Undelete', $title->getPrefixedDBkey() );
// If the user can't undelete but can view deleted
// history show them a "View .. deleted" tab instead.
- $msgKey = $title->quickUserCan( 'undelete', $user ) ? 'undelete' : 'viewdeleted';
+ $msgKey = $permissionManager->quickUserCan( 'undelete',
+ $user, $title ) ? 'undelete' : 'viewdeleted';
$content_navigation['actions']['undelete'] = [
'class' => $this->getTitle()->isSpecial( 'Undelete' ) ? 'selected' : false,
'text' => wfMessageFallback( "$skname-action-$msgKey", "{$msgKey}_short" )
}
}
- if ( $title->quickUserCan( 'protect', $user ) && $title->getRestrictionTypes() &&
- MediaWikiServices::getInstance()->getPermissionManager()
- ->getNamespaceRestrictionLevels( $title->getNamespace(), $user ) !== [ '' ]
+ if ( $permissionManager->quickUserCan( 'protect', $user, $title ) &&
+ $title->getRestrictionTypes() &&
+ $permissionManager->getNamespaceRestrictionLevels( $title->getNamespace(),
+ $user ) !== [ '' ]
) {
$mode = $title->isProtected() ? 'unprotect' : 'protect';
$content_navigation['actions'][$mode] = [
}
// Checks if the user is logged in
- if ( $this->loggedin && MediaWikiServices::getInstance()
- ->getPermissionManager()
- ->userHasAllRights( $user, 'viewmywatchlist', 'editmywatchlist' )
+ if ( $this->loggedin && $permissionManager->userHasAllRights( $user,
+ 'viewmywatchlist', 'editmywatchlist' )
) {
/**
* The following actions use messages which, if made particular to
if ( is_string( reset( $status ) ) ) {
$status = Status::newFatal( ...$status );
} elseif ( is_array( reset( $status ) ) ) {
- $status = Status::newGood();
+ $ret = Status::newGood();
foreach ( $status as $message ) {
- $status->fatal( ...$message );
+ $ret->fatal( ...$message );
}
+ $status = $ret;
} else {
throw new UnexpectedValueException( 'invalid HTMLForm::trySubmit() return value: '
. 'first element of array is ' . gettype( reset( $status ) ) );
* Generates a HTMLForm descriptor array from a set of authentication requests.
* @param AuthenticationRequest[] $requests
* @param string $action AuthManager action name (one of the AuthManager::ACTION_* constants)
- * @return array
+ * @return array[]
*/
protected function getAuthFormDescriptor( $requests, $action ) {
$fieldInfo = AuthenticationRequest::mergeFieldInfo( $requests );
/**
* Adds a sequential tabindex starting from 1 to all form elements. This way the user can
* use the tab key to traverse the form without having to step through all links and such.
- * @param array &$formDescriptor
+ * @param array[] &$formDescriptor
*/
protected function addTabIndex( &$formDescriptor ) {
$i = 1;
}
}
+ /**
+ * @see $wgRCLinkDays in DefaultSettings.php.
+ * @see $wgRCFilterByAge in DefaultSettings.php.
+ * @return int[]
+ */
+ protected function getLinkDays() {
+ $linkDays = $this->getConfig()->get( 'RCLinkDays' );
+ $filterByAge = $this->getConfig()->get( 'RCFilterByAge' );
+ $maxAge = $this->getConfig()->get( 'RCMaxAge' );
+ if ( $filterByAge ) {
+ // Trim it to only links which are within $wgRCMaxAge.
+ // Note that we allow one link higher than the max for things like
+ // "age 56 days" being accessible through the "60 days" link.
+ sort( $linkDays );
+
+ $maxAgeDays = $maxAge / ( 3600 * 24 );
+ foreach ( $linkDays as $i => $days ) {
+ if ( $days >= $maxAgeDays ) {
+ array_splice( $linkDays, $i + 1 );
+ break;
+ }
+ }
+ }
+
+ return $linkDays;
+ }
+
/**
* Include the modules and configuration for the RCFilters app.
* Conditional on the user having the feature enabled.
'maxDays' => (int)$this->getConfig()->get( 'RCMaxAge' ) / ( 24 * 3600 ), // Translate to days
'limitArray' => $this->getConfig()->get( 'RCLinkLimits' ),
'limitDefault' => $this->getDefaultLimit(),
- 'daysArray' => $this->getConfig()->get( 'RCLinkDays' ),
+ 'daysArray' => $this->getLinkDays(),
'daysDefault' => $this->getDefaultDays(),
]
);
*
* There is light processing to simplify core maintenance.
* @param array $definition
- * @phan-param array<int,array{class:string}> $definition
+ * @phan-param array<int,array{class:string,filters:array}> $definition
*/
protected function registerFiltersFromDefinitions( array $definition ) {
$autoFillPriority = -1;
/**
* Process the form on POST submission.
* @param array $data
- * @param HTMLForm $form
+ * @param HTMLForm|null $form
+ * @suppress PhanCommentParamWithoutRealParam Many implementations don't have $form
* @return bool|string|array|Status As documented for HTMLForm::trySubmit.
*/
- abstract public function onSubmit( array $data /* $form = null */ );
+ abstract public function onSubmit( array $data /* HTMLForm $form = null */ );
/**
* Do something exciting on successful processing of the form, most likely to show a
/**
* @param string|null $subPage
+ * @suppress PhanTypeObjectUnsetDeclaredProperty
*/
public function execute( $subPage ) {
if ( $this->mPosted ) {
$isLoggedIn = $this->getUser()->isLoggedIn();
$continuePart = $this->isContinued() ? 'continue-' : '';
$anotherPart = $isLoggedIn ? 'another-' : '';
+ // @phan-suppress-next-line PhanUndeclaredMethod
$expiration = $this->getRequest()->getSession()->getProvider()->getRememberUserDuration();
$expirationDays = ceil( $expiration / ( 3600 * 24 ) );
$secureLoginLink = '';
return $title;
}
+ // @phan-suppress-next-line PhanUndeclaredMethod
$context->setTitle( $page->getPageTitle( $par ) );
} elseif ( !$page->isIncludable() ) {
return false;
* @param object $result Result row
* @return string
*/
- private function makeWlhLink( $title, $result ) {
+ protected function makeWlhLink( $title, $result ) {
$wlh = SpecialPage::getTitleFor( 'Whatlinkshere', $title->getPrefixedText() );
$label = $this->msg( 'nlinks' )->numParams( $result->value )->text();
return $this->getLinkRenderer()->makeLink( $wlh, $label );
$opts->fetchValuesFromRequest( $this->getRequest() );
$opts->validateIntBounds( 'limit', 0, 5000 );
- $pager = new AllMessagesTablePager( $this->getContext(), $opts );
+ $pager = new AllMessagesTablePager( $this->getContext(), $opts, $this->getLinkRenderer() );
$formDescriptor = [
'prefix' => [
foreach ( $block->getRestrictions() as $restriction ) {
switch ( $restriction->getType() ) {
case PageRestriction::TYPE:
+ /** @var PageRestriction $restriction */
+ '@phan-var PageRestriction $restriction';
if ( $restriction->getTitle() ) {
$pageRestrictions[] = $restriction->getTitle()->getPrefixedText();
}
$logId = $logEntry->insert();
if ( !empty( $data['Tags'] ) ) {
- $logEntry->setTags( $data['Tags'] );
+ $logEntry->addTags( $data['Tags'] );
}
$logEntry->publish( $logId );
'restrictions' => $data['restrictions'],
'grants' => array_merge(
MWGrants::getHiddenGrants(),
+ // @phan-suppress-next-next-line PhanTypeMismatchArgumentInternal See phan issue #3163,
+ // it's probably failing to infer the type of $data['grants']
preg_replace( '/^grant-/', '', $data['grants'] )
)
] );
$target = $par ?? $request->getVal( 'target' );
- if ( $request->getVal( 'contribs' ) == 'newbie' || $par === 'newbies' ) {
- $target = 'newbies';
- $this->opts['contribs'] = 'newbie';
- } else {
- $this->opts['contribs'] = 'user';
- }
-
$this->opts['deletedOnly'] = $request->getBool( 'deletedOnly' );
if ( !strlen( $target ) ) {
$this->opts['hideMinor'] = $request->getBool( 'hideMinor' );
$id = 0;
- if ( $this->opts['contribs'] === 'newbie' ) {
- $userObj = User::newFromName( $target ); // hysterical raisins
- $out->addSubtitle( $this->msg( 'sp-contributions-newbies-sub' ) );
- $out->setHTMLTitle( $this->msg(
- 'pagetitle',
- $this->msg( 'sp-contributions-newbies-title' )->plain()
- )->inContentLanguage() );
- } elseif ( ExternalUserNames::isExternal( $target ) ) {
+ if ( ExternalUserNames::isExternal( $target ) ) {
$userObj = User::newFromName( $target, false );
if ( !$userObj ) {
$out->addHTML( $this->getForm() );
}
$pager = new ContribsPager( $this->getContext(), [
'target' => $target,
- 'contribs' => $this->opts['contribs'],
'namespace' => $this->opts['namespace'],
'tagfilter' => $this->opts['tagfilter'],
'start' => $this->opts['start'],
'hideMinor' => $this->opts['hideMinor'],
'nsInvert' => $this->opts['nsInvert'],
'associated' => $this->opts['associated'],
- ] );
+ ], $this->getLinkRenderer() );
if ( IP::isValidRange( $target ) && !$pager->isQueryableRange( $target ) ) {
// Valid range, but outside CIDR limit.
$out->preventClickjacking( $pager->getPreventClickjacking() );
# Show the appropriate "footer" message - WHOIS tools, etc.
- if ( $this->opts['contribs'] == 'newbie' ) {
- $message = 'sp-contributions-footer-newbies';
- } elseif ( IP::isValidRange( $target ) ) {
+ if ( IP::isValidRange( $target ) ) {
$message = 'sp-contributions-footer-anon-range';
} elseif ( IP::isIPAddress( $target ) ) {
$message = 'sp-contributions-footer-anon';
$linkRenderer = $sp->getLinkRenderer();
+ $tools = [];
# No talk pages for IP ranges.
if ( !$isRange ) {
$tools['user-talk'] = $linkRenderer->makeLink(
$this->opts['associated'] = false;
}
- if ( !isset( $this->opts['contribs'] ) ) {
- $this->opts['contribs'] = 'user';
- }
-
if ( !isset( $this->opts['start'] ) ) {
$this->opts['start'] = '';
}
$this->opts['end'] = '';
}
- if ( $this->opts['contribs'] == 'newbie' ) {
- $this->opts['target'] = '';
- }
-
if ( !isset( $this->opts['tagfilter'] ) ) {
$this->opts['tagfilter'] = '';
}
$filterSelection = Html::rawElement( 'div', [], '' );
}
- $labelNewbies = Xml::radioLabel(
- $this->msg( 'sp-contributions-newbies' )->text(),
- 'contribs',
- 'newbie',
- 'newbie',
- $this->opts['contribs'] == 'newbie',
- [ 'class' => 'mw-input' ]
- );
$labelUsername = Xml::radioLabel(
$this->msg( 'sp-contributions-username' )->text(),
'contribs',
'user',
'user',
- $this->opts['contribs'] == 'user',
+ true,
[ 'class' => 'mw-input' ]
);
$input = Html::input(
'mw-autocomplete-user', // used by mediawiki.userSuggest
],
] + (
- // Only autofocus if target hasn't been specified or in non-newbies mode
- ( $this->opts['contribs'] === 'newbie' || $this->opts['target'] )
- ? [] : [ 'autofocus' => true ]
- )
+ // Only autofocus if target hasn't been specified
+ $this->opts['target'] ? [] : [ 'autofocus' => true ]
+ )
);
$targetSelection = Html::rawElement(
'div',
[],
- $labelNewbies . '<br>' . $labelUsername . ' ' . $input . ' '
+ $labelUsername . ' ' . $input . ' '
);
$hidden = $this->opts['namespace'] === '' ? ' mw-input-hidden' : '';
$this->getForm();
- $pager = new DeletedContribsPager( $this->getContext(), $target, $opts->getValue( 'namespace' ) );
+ $pager = new DeletedContribsPager( $this->getContext(), $target, $opts->getValue( 'namespace' ),
+ $this->getLinkRenderer() );
if ( !$pager->getNumRows() ) {
$out->addWikiMsg( 'nocontribs' );
# If there were contributions, and it was a valid user or IP, show
# the appropriate "footer" message - WHOIS tools, etc.
- if ( $target != 'newbies' ) {
- $message = IP::isIPAddress( $target ) ?
- 'sp-contributions-footer-anon' :
- 'sp-contributions-footer';
-
- if ( !$this->msg( $message )->isDisabled() ) {
- $out->wrapWikiMsg(
- "<div class='mw-contributions-footer'>\n$1\n</div>",
- [ $message, $target ]
- );
- }
+ $message = IP::isIPAddress( $target ) ?
+ 'sp-contributions-footer-anon' :
+ 'sp-contributions-footer';
+
+ if ( !$this->msg( $message )->isDisabled() ) {
+ $out->wrapWikiMsg(
+ "<div class='mw-contributions-footer'>\n$1\n</div>",
+ [ $message, $target ]
+ );
}
}
$linkRenderer = $this->getLinkRenderer();
$link = $linkRenderer->makeLink( $title );
+ $tools = [];
$tools['talk'] = $linkRenderer->makeLink(
$title->getTalkPage(),
$this->msg( 'talkpagelinktext' )->text()
$dom = $parser->preprocessToDom( $input );
if ( method_exists( $dom, 'saveXML' ) ) {
+ // @phan-suppress-next-line PhanUndeclaredMethod
$xml = $dom->saveXML();
} else {
+ // @phan-suppress-next-line PhanUndeclaredMethod
$xml = $dom->__toString();
}
}
$userName,
$search,
$this->including(),
- $showAll
+ $showAll,
+ $this->getLinkRenderer()
);
$out = $this->getOutput();
];
foreach ( $changeGroups as $messageKey => $changeGroup ) {
+ // @phan-suppress-next-line PhanTypeComparisonFromArray
if ( $changeGroup === true ) {
// For grep: listgrouprights-addgroup-all, listgrouprights-removegroup-all,
// listgrouprights-addgroup-self-all, listgrouprights-removegroup-self-all
$dbr->addQuotes( '/' ),
'img_minor_mime',
$dbr->addQuotes( ';' ),
- 'COUNT(*)',
+ $dbr->buildStringCast( 'COUNT(*)' ),
$dbr->addQuotes( ';' ),
- 'SUM( img_size )'
+ $dbr->buildStringCast( 'SUM( img_size )' )
] );
return [
'tables' => [ 'image' ],
}
if ( count( $err ) == 1 && isset( $err[0][0] ) && $err[0][0] == 'articleexists'
- && $newTitle->quickUserCan( 'delete', $user )
+ && MediaWikiServices::getInstance()->getPermissionManager()
+ ->quickUserCan( 'delete', $user, $newTitle )
) {
$out->wrapWikiMsg(
"<div class='warningbox'>\n$1\n</div>\n",
# Is the title semi-protected?
if ( $this->oldTitle->isSemiProtected( 'move' ) ) {
$noticeMsg = 'semiprotectedpagemovewarning';
- $classes[] = 'mw-textarea-sprotected';
} else {
# Then it must be protected based on static groups (regular)
$noticeMsg = 'protectedpagemovewarning';
- $classes[] = 'mw-textarea-protected';
}
$out->addHTML( "<div class='mw-warning-with-logexcerpt'>\n" );
$out->addWikiMsg( $noticeMsg );
// mediawiki.special.movePage module
$immovableNamespaces = [];
+ $namespaceInfo = MediaWikiServices::getInstance()->getNamespaceInfo();
foreach ( array_keys( $this->getLanguage()->getNamespaces() ) as $nsId ) {
- if ( !MediaWikiServices::getInstance()->getNamespaceInfo()->isMovable( $nsId ) ) {
+ if ( !$namespaceInfo->isMovable( $nsId ) ) {
$immovableNamespaces[] = $nsId;
}
}
return;
}
+ $services = MediaWikiServices::getInstance();
+
# Show a warning if the target file exists on a shared repo
+ $repoGroup = $services->getRepoGroup();
if ( $nt->getNamespace() == NS_FILE
&& !( $this->moveOverShared && $user->isAllowed( 'reupload-shared' ) )
- && !RepoGroup::singleton()->getLocalRepo()->findFile( $nt )
- && MediaWikiServices::getInstance()->getRepoGroup()->findFile( $nt )
+ && !$repoGroup->getLocalRepo()->findFile( $nt )
+ && $repoGroup->findFile( $nt )
) {
$this->showForm( [ [ 'file-exists-sharedrepo' ] ] );
// Delete an associated image if there is
if ( $nt->getNamespace() == NS_FILE ) {
- $file = MediaWikiServices::getInstance()->getRepoGroup()->getLocalRepo()
- ->newFile( $nt );
+ $file = $repoGroup->getLocalRepo()->newFile( $nt );
$file->load( File::READ_LATEST );
if ( $file->exists() ) {
$file->delete( $reason, false, $user );
$this->moveTalk = false;
}
if ( $this->moveSubpages ) {
- $permissionManager = MediaWikiServices::getInstance()->getPermissionManager();
+ $permissionManager = $services->getPermissionManager();
$this->moveSubpages = $permissionManager->userCan( 'move-subpages', $user, $ot );
}
*/
// @todo FIXME: Use Title::moveSubpages() here
- $nsInfo = MediaWikiServices::getInstance()->getNamespaceInfo();
+ $nsInfo = $services->getNamespaceInfo();
$dbr = wfGetDB( DB_MASTER );
if ( $this->moveSubpages && (
$nsInfo->hasSubpages( $nt->getNamespace() ) || (
$mp = new MovePage( $oldSubpage, $newSubpage );
# This was copy-pasted from Renameuser, bleh.
- if ( $newSubpage->exists() && !$mp->isValidMove()->isOk() ) {
+ if ( $newSubpage->exists() && !$mp->isValidMove()->isOK() ) {
$link = $linkRenderer->makeKnownLink( $newSubpage );
$extraOutput[] = $this->msg( 'movepage-page-exists' )->rawParams( $link )->escaped();
} else {
public function __construct() {
parent::__construct( 'NewSection' );
$this->mAllowedRedirectParams = [ 'preloadtitle', 'nosummary', 'editintro',
- 'preload', 'preloadparams[]', 'summary' ];
+ 'preload', 'preloadparams', 'summary' ];
}
/**
protected function showNoRedirectPage() {
$this->setHeaders();
$this->outputHeader();
+ $this->addHelpLink( 'Help:New section' );
$this->showForm();
}
$opts->add( 'like', '' );
$opts->add( 'user', '' );
$opts->add( 'showbots', false );
- $opts->add( 'newbies', false );
$opts->add( 'hidepatrolled', false );
$opts->add( 'mediatype', $this->mediaTypes );
$opts->add( 'limit', 50 );
$this->buildForm( $context );
}
- $pager = new NewFilesPager( $context, $opts );
+ $pager = new NewFilesPager( $context, $opts, $this->getLinkRenderer() );
$out->addHTML( $pager->getBody() );
if ( !$this->including() ) {
],
'user' => [
- 'type' => 'text',
+ 'class' => 'HTMLUserTextField',
'label-message' => 'newimages-user',
'name' => 'user',
],
- 'newbies' => [
- 'type' => 'check',
- 'label-message' => 'newimages-newbies',
- 'name' => 'newbies',
- ],
-
'showbots' => [
'type' => 'check',
'label-message' => 'newimages-showbots',
$entry->setTarget( $title );
$entry->setParameters( $logParams );
$entry->setComment( $reason );
- $entry->setTags( $tags );
+ $entry->addTags( $tags );
$logid = $entry->insert();
$entry->publish( $logid );
$user = $this->getUser();
$significance = $this->getFilterGroup( 'significance' );
+ /** @var ChangesListBooleanFilter $hideMinor */
$hideMinor = $significance->getFilter( 'hideminor' );
+ '@phan-var ChangesListBooleanFilter $hideMinor';
$hideMinor->setDefault( $user->getBoolOption( 'hideminor' ) );
$automated = $this->getFilterGroup( 'automated' );
+ /** @var ChangesListBooleanFilter $hideBots */
$hideBots = $automated->getFilter( 'hidebots' );
+ '@phan-var ChangesListBooleanFilter $hideBots';
$hideBots->setDefault( true );
+ /** @var ChangesListStringOptionsFilterGroup|null $reviewStatus */
$reviewStatus = $this->getFilterGroup( 'reviewStatus' );
+ '@phan-var ChangesListStringOptionsFilterGroup|null $reviewStatus';
if ( $reviewStatus !== null ) {
// Conditional on feature being available and rights
if ( $user->getBoolOption( 'hidepatrolled' ) ) {
$reviewStatus->setDefault( 'unpatrolled' );
$legacyReviewStatus = $this->getFilterGroup( 'legacyReviewStatus' );
+ /** @var ChangesListBooleanFilter $legacyHidePatrolled */
$legacyHidePatrolled = $legacyReviewStatus->getFilter( 'hidepatrolled' );
+ '@phan-var ChangesListBooleanFilter $legacyHidePatrolled';
$legacyHidePatrolled->setDefault( true );
}
}
$changeType = $this->getFilterGroup( 'changeType' );
+ /** @var ChangesListBooleanFilter $hideCategorization */
$hideCategorization = $changeType->getFilter( 'hidecategorization' );
+ '@phan-var ChangesListBooleanFilter $hideCategorization';
if ( $hideCategorization !== null ) {
// Conditional on feature being available
$hideCategorization->setDefault( $user->getBoolOption( 'hidecategorization' ) );
sort( $linkLimits );
$linkLimits = array_unique( $linkLimits );
- $linkDays = $config->get( 'RCLinkDays' );
+ $linkDays = $this->getLinkDays();
$linkDays[] = $options['days'];
sort( $linkDays );
$linkDays = array_unique( $linkDays );
$messageName = 'searchmenu-exists';
$linkClass = 'mw-search-exists';
} elseif ( ContentHandler::getForTitle( $title )->supportsDirectEditing()
- && $title->quickUserCan( 'create', $this->getUser() )
+ && MediaWikiServices::getInstance()->getPermissionManager()->quickUserCan( 'create',
+ $this->getUser(), $title )
) {
$messageName = 'searchmenu-new';
}
$logEntry->setComment( $data['Reason'] );
$logEntry->setPerformer( $performer );
if ( isset( $data['Tags'] ) ) {
- $logEntry->setTags( $data['Tags'] );
+ $logEntry->addTags( $data['Tags'] );
}
$logEntry->setRelations( [ 'ipb_id' => $block->getId() ] );
$logId = $logEntry->insert();
$out->enableOOUI();
+ $fields = [];
$fields[] = new OOUI\ActionFieldLayout(
new OOUI\TextInputWidget( [
'name' => 'prefix',
$buttonFields = [];
if ( $isText ) {
+ '@phan-var TextContent $content';
// TODO: MCR: make this work for multiple slots
// source view for textual content
$sourceView = Xml::element( 'textarea', [
}
if ( $this->mAllowed && ( $haveRevisions || $haveFiles ) ) {
+ $fields = [];
$fields[] = new OOUI\Layout( [
'content' => new OOUI\HtmlSnippet( $this->msg( 'undeleteextrahelp' )->parseAsBlock() )
] );
*
* @param string|null $par String if any subpage provided, else null
* @throws UserBlockedError|PermissionsError
+ * @suppress PhanUndeclaredMethod
*/
public function execute( $par ) {
$user = $this->getUser();
] );
$logid = $logEntry->insert();
if ( count( $tags ) ) {
- $logEntry->setTags( $tags );
+ $logEntry->addTags( $tags );
}
$logEntry->publish( $logid );
}
$this->getOutput()->addWikiTextAsInterface( $status->getWikiText() );
return;
- } else {
- $user = $status->value;
}
+ /** @var User $user */
+ $user = $status->value;
+ '@phan-var User $user';
+
$groups = $user->getGroups();
$groupMemberships = $user->getGroupMemberships();
$this->showEditUserGroupsForm( $user, $groups, $groupMemberships );
/**
* @inheritDoc
+ * @suppress PhanUndeclaredMethod
*/
protected function registerFilters() {
parent::registerFilters();
$fetchlinks = ( !$hidelinks || !$hideredirs );
// Build query conds in concert for all three tables...
+ $conds = [];
$conds['pagelinks'] = [
'pl_namespace' => $target->getNamespace(),
'pl_title' => $target->getDBkey(),
// Read the rows into an array and remove duplicates
// templatelinks comes second so that the templatelinks row overwrites the
// pagelinks row, so we get (inclusion) rather than nothing
+ $rows = [];
if ( $fetchlinks ) {
foreach ( $plRes as $row ) {
$row->is_template = 0;
protected $mMaxFileSize = [];
+ /** @var array */
protected $mMaxUploadSize = [];
public function __construct( array $options = [], IContextSource $context = null,
private $mOriginalLogCallback = null;
private $mOriginalPageOutCallback = null;
private $mLogItemCount = 0;
+ private $mPageCount;
+ private $mIsUpload;
+ private $mInterwiki;
/**
* @param WikiImporter $importer
// Make sure the null revision will be tagged as well
$logEntry->setAssociatedRevId( $nullRevId );
if ( count( $this->logTags ) ) {
- $logEntry->setTags( $this->logTags );
+ $logEntry->addTags( $this->logTags );
}
$logid = $logEntry->insert();
$logEntry->publish( $logid );
*/
use MediaWiki\MediaWikiServices;
+use MediaWiki\Linker\LinkRenderer;
use Wikimedia\Rdbms\FakeResultWrapper;
/**
/**
* @param IContextSource|null $context
* @param FormOptions $opts
+ * @param LinkRenderer $linkRenderer
*/
- public function __construct( IContextSource $context = null, FormOptions $opts ) {
- parent::__construct( $context );
+ public function __construct( IContextSource $context = null, FormOptions $opts,
+ LinkRenderer $linkRenderer
+ ) {
+ parent::__construct( $context, $linkRenderer );
$this->mIndexField = 'am_title';
// FIXME: Why does this need to be set to DIR_DESCENDING to produce ascending ordering?
}
function formatValue( $field, $value ) {
- $linkRenderer = MediaWikiServices::getInstance()->getLinkRenderer();
+ $linkRenderer = $this->getLinkRenderer();
switch ( $field ) {
case 'am_title' :
$title = Title::makeTitle( NS_MEDIAWIKI, $value . $this->suffix );
$title = $linkRenderer->makeKnownLink( $title, $this->getLanguage()->lcfirst( $value ) );
} else {
$title = $linkRenderer->makeBrokenLink(
- $title,
- $this->getLanguage()->lcfirst( $value )
+ $title, $this->getLanguage()->lcfirst( $value )
);
}
if ( $this->mCurrentRow->am_talk_exists ) {
}
function getQueryInfo() {
- return '';
+ return [];
}
}
* @param array $conds
*/
public function __construct( $page, $conds ) {
+ parent::__construct( $page->getContext(), $page->getLinkRenderer() );
$this->conds = $conds;
$this->mDefaultDirection = IndexPager::DIR_DESCENDING;
- parent::__construct( $page->getContext() );
}
function getFieldNames() {
return $headers;
}
+ /**
+ * @param string $name
+ * @param string $value
+ * @return string
+ * @suppress PhanTypeArraySuspiciousNullable,PhanTypeArraySuspicious
+ */
function formatValue( $name, $value ) {
static $msg = null;
if ( $msg === null ) {
$formatted = '';
- $linkRenderer = MediaWikiServices::getInstance()->getLinkRenderer();
+ $linkRenderer = $this->getLinkRenderer();
switch ( $name ) {
case 'ipb_timestamp':
/* User preference timezone */true
) );
if ( $this->getUser()->isAllowed( 'block' ) ) {
+ $links = [];
if ( $row->ipb_auto ) {
$links[] = $linkRenderer->makeKnownLink(
SpecialPage::getTitleFor( 'Unblock' ),
*/
private function getRestrictionListHTML( stdClass $row ) {
$items = [];
- $linkRenderer = MediaWikiServices::getInstance()->getLinkRenderer();
+ $linkRenderer = $this->getLinkRenderer();
foreach ( $this->restrictions as $restriction ) {
if ( $restriction->getBlockId() !== (int)$row->ipb_id ) {
switch ( $restriction->getType() ) {
case PageRestriction::TYPE:
+ '@phan-var PageRestriction $restriction';
if ( $restriction->getTitle() ) {
$items[$restriction->getType()][] = Html::rawElement(
'li',
*/
class CategoryPager extends AlphabeticPager {
- /**
- * @var LinkRenderer
- */
- protected $linkRenderer;
-
/**
* @param IContextSource $context
* @param string $from
*/
public function __construct( IContextSource $context, $from, LinkRenderer $linkRenderer
) {
- parent::__construct( $context );
+ parent::__construct( $context, $linkRenderer );
$from = str_replace( ' ', '_', $from );
if ( $from !== '' ) {
$from = Title::capitalize( $from, NS_CATEGORY );
$this->setOffset( $from );
$this->setIncludeOffset( true );
}
-
- $this->linkRenderer = $linkRenderer;
}
function getQueryInfo() {
function formatRow( $result ) {
$title = new TitleValue( NS_CATEGORY, $result->cat_title );
$text = $title->getText();
- $link = $this->linkRenderer->makeLink( $title, $text );
+ $link = $this->getLinkRenderer()->makeLink( $title, $text );
$count = $this->msg( 'nmembers' )->numParams( $result->cat_pages )->escaped();
return Html::rawElement( 'li', null, $this->getLanguage()->specialList( $link, $count ) ) . "\n";
* @ingroup Pager
*/
use MediaWiki\MediaWikiServices;
+use MediaWiki\Linker\LinkRenderer;
use MediaWiki\Storage\RevisionRecord;
use Wikimedia\Rdbms\IResultWrapper;
use Wikimedia\Rdbms\FakeResultWrapper;
*/
private $target;
- /**
- * @var string Set to "newbie" to list contributions from the most recent 1% registered users.
- * $this->target is ignored then. Defaults to "users".
- */
- private $contribs;
-
/**
* @var string|int A single namespace number, or an empty string for all namespaces
*/
*/
private $templateParser;
- public function __construct( IContextSource $context, array $options ) {
- // Set ->target and ->contribs before calling parent::__construct() so
+ public function __construct( IContextSource $context, array $options,
+ LinkRenderer $linkRenderer = null
+ ) {
+ // Set ->target before calling parent::__construct() so
// parent can call $this->getIndexField() and get the right result. Set
// the rest too just to keep things simple.
$this->target = $options['target'] ?? '';
- $this->contribs = $options['contribs'] ?? 'users';
$this->namespace = $options['namespace'] ?? '';
$this->tagFilter = $options['tagfilter'] ?? false;
$this->nsInvert = $options['nsInvert'] ?? false;
$this->newOnly = !empty( $options['newOnly'] );
$this->hideMinor = !empty( $options['hideMinor'] );
- parent::__construct( $context );
+ parent::__construct( $context, $linkRenderer );
$msgs = [
'diff',
* @return string
*/
private function getTargetTable() {
- if ( $this->contribs == 'newbie' ) {
- return 'revision';
- }
-
$user = User::newFromName( $this->target, false );
$ipRangeConds = $user->isAnon() ? $this->getIpRangeConds( $this->mDb, $this->target ) : null;
if ( $ipRangeConds ) {
];
// WARNING: Keep this in sync with getTargetTable()!
-
- if ( $this->contribs == 'newbie' ) {
- $max = $this->mDb->selectField( 'user', 'max(user_id)', '', __METHOD__ );
- $queryInfo['conds'][] = $revQuery['fields']['rev_user'] . ' >' . (int)( $max - $max / 100 );
- # ignore local groups with the bot right
- # @todo FIXME: Global groups may have 'bot' rights
- $groupsWithBotPermission = MediaWikiServices::getInstance()
- ->getPermissionManager()
- ->getGroupsWithPermission( 'bot' );
- if ( count( $groupsWithBotPermission ) ) {
- $queryInfo['tables'][] = 'user_groups';
- $queryInfo['conds'][] = 'ug_group IS NULL';
- $queryInfo['join_conds']['user_groups'] = [
- 'LEFT JOIN', [
- 'ug_user = ' . $revQuery['fields']['rev_user'],
- 'ug_group' => $groupsWithBotPermission,
- 'ug_expiry IS NULL OR ug_expiry >= ' .
- $this->mDb->addQuotes( $this->mDb->timestamp() )
- ]
- ];
- }
- // (T140537) Disallow looking too far in the past for 'newbies' queries. If the user requested
- // a timestamp offset far in the past such that there are no edits by users with user_ids in
- // the range, we would end up scanning all revisions from that offset until start of time.
- $queryInfo['conds'][] = 'rev_timestamp > ' .
- $this->mDb->addQuotes( $this->mDb->timestamp( wfTimestamp() - 30 * 24 * 60 * 60 ) );
+ $user = User::newFromName( $this->target, false );
+ $ipRangeConds = $user->isAnon() ? $this->getIpRangeConds( $this->mDb, $this->target ) : null;
+ if ( $ipRangeConds ) {
+ $queryInfo['tables'][] = 'ip_changes';
+ $queryInfo['join_conds']['ip_changes'] = [
+ 'LEFT JOIN', [ 'ipc_rev_id = rev_id' ]
+ ];
+ $queryInfo['conds'][] = $ipRangeConds;
} else {
- $user = User::newFromName( $this->target, false );
- $ipRangeConds = $user->isAnon() ? $this->getIpRangeConds( $this->mDb, $this->target ) : null;
- if ( $ipRangeConds ) {
- $queryInfo['tables'][] = 'ip_changes';
- $queryInfo['join_conds']['ip_changes'] = [
- 'LEFT JOIN', [ 'ipc_rev_id = rev_id' ]
- ];
- $queryInfo['conds'][] = $ipRangeConds;
+ // tables and joins are already handled by Revision::getQueryInfo()
+ $conds = ActorMigration::newMigration()->getWhere( $this->mDb, 'rev_user', $user );
+ $queryInfo['conds'][] = $conds['conds'];
+ // Force the appropriate index to avoid bad query plans (T189026)
+ if ( isset( $conds['orconds']['actor'] ) ) {
+ // @todo: This will need changing when revision_actor_temp goes away
+ $queryInfo['options']['USE INDEX']['temp_rev_user'] = 'actor_timestamp';
} else {
- // tables and joins are already handled by Revision::getQueryInfo()
- $conds = ActorMigration::newMigration()->getWhere( $this->mDb, 'rev_user', $user );
- $queryInfo['conds'][] = $conds['conds'];
- // Force the appropriate index to avoid bad query plans (T189026)
- if ( isset( $conds['orconds']['actor'] ) ) {
- // @todo: This will need changing when revision_actor_temp goes away
- $queryInfo['options']['USE INDEX']['temp_rev_user'] = 'actor_timestamp';
- } else {
- $queryInfo['options']['USE INDEX']['revision'] =
- isset( $conds['orconds']['userid'] ) ? 'user_timestamp' : 'usertext_timestamp';
- }
+ $queryInfo['options']['USE INDEX']['revision'] =
+ isset( $conds['orconds']['userid'] ) ? 'user_timestamp' : 'usertext_timestamp';
}
}
return $this->tagFilter;
}
- /**
- * @return string
- */
- public function getContribs() {
- return $this->contribs;
- }
-
/**
* @return string
*/
}
if ( isset( $row->rev_id ) ) {
$this->mParentLens[$row->rev_id] = $row->rev_len;
- if ( $this->contribs === 'newbie' ) { // multiple users
- $batch->add( NS_USER, $row->user_name );
- $batch->add( NS_USER_TALK, $row->user_name );
- } elseif ( $isIpRange ) {
+ if ( $isIpRange ) {
// If this is an IP range, batch the IP's talk page
$batch->add( NS_USER_TALK, $row->rev_user_text );
}
$classes = [];
$attribs = [];
- $linkRenderer = MediaWikiServices::getInstance()->getLinkRenderer();
+ $linkRenderer = $this->getLinkRenderer();
+ $permissionManager = MediaWikiServices::getInstance()->getPermissionManager();
$page = null;
// Create a title for the revision if possible
$topmarktext .= '<span class="mw-uctop">' . $this->messages['uctop'] . '</span>';
$classes[] = 'mw-contributions-current';
# Add rollback link
- if ( !$row->page_is_new && $page->quickUserCan( 'rollback', $user )
- && $page->quickUserCan( 'edit', $user )
+ if ( !$row->page_is_new &&
+ $permissionManager->quickUserCan( 'rollback', $user, $page ) &&
+ $permissionManager->quickUserCan( 'edit', $user, $page )
) {
$this->preventClickjacking();
$topmarktext .= ' ' . Linker::generateRollback( $rev, $this->getContext(),
$comment = $lang->getDirMark() . Linker::revComment( $rev, false, true, false );
$d = ChangesList::revDateLink( $rev, $user, $lang, $page );
- # Show user names for /newbies as there may be different users.
- # Note that only unprivileged users have rows with hidden user names excluded.
# When querying for an IP range, we want to always show user and user talk links.
$userlink = '';
- if ( ( $this->contribs == 'newbie' && !$rev->isDeleted( RevisionRecord::DELETED_USER ) )
- || $this->isQueryableRange( $this->target ) ) {
+ if ( $this->isQueryableRange( $this->target ) ) {
$userlink = ' <span class="mw-changeslist-separator"></span> '
. $lang->getDirMark()
. Linker::userLink( $rev->getUser(), $rev->getUserText() );
/**
* @ingroup Pager
*/
+use MediaWiki\Linker\LinkRenderer;
use MediaWiki\MediaWikiServices;
use MediaWiki\Storage\RevisionRecord;
use Wikimedia\Rdbms\IDatabase;
*/
protected $mNavigationBar;
- public function __construct( IContextSource $context, $target, $namespace = false ) {
- parent::__construct( $context );
+ public function __construct( IContextSource $context, $target, $namespace = false,
+ LinkRenderer $linkRenderer
+ ) {
+ parent::__construct( $context, $linkRenderer );
$msgs = [ 'deletionlog', 'undeleteviewlink', 'diff' ];
foreach ( $msgs as $msg ) {
$this->messages[$msg] = $this->msg( $msg )->text();
function formatRevisionRow( $row ) {
$page = Title::makeTitle( $row->ar_namespace, $row->ar_title );
- $linkRenderer = MediaWikiServices::getInstance()->getLinkRenderer();
+ $linkRenderer = $this->getLinkRenderer();
$rev = new Revision( [
'title' => $page,
/**
* @ingroup Pager
*/
+use MediaWiki\Linker\LinkRenderer;
use MediaWiki\MediaWikiServices;
use Wikimedia\Rdbms\IResultWrapper;
use Wikimedia\Rdbms\FakeResultWrapper;
protected $mTableName = 'image';
public function __construct( IContextSource $context, $userName = null, $search = '',
- $including = false, $showAll = false
+ $including = false, $showAll = false, LinkRenderer $linkRenderer
) {
$this->setContext( $context );
+
$this->mIncluding = $including;
$this->mShowAll = $showAll;
$this->mDefaultDirection = IndexPager::DIR_DESCENDING;
}
- parent::__construct( $context );
+ parent::__construct( $context, $linkRenderer );
}
/**
*/
function formatValue( $field, $value ) {
$services = MediaWikiServices::getInstance();
- $linkRenderer = $services->getLinkRenderer();
+ $linkRenderer = $this->getLinkRenderer();
switch ( $field ) {
case 'thumb':
$opt = [ 'time' => wfTimestamp( TS_MW, $this->mCurrentRow->img_timestamp ) ];
// Add delete links if allowed
// From https://github.com/Wikia/app/pull/3859
- $permissionManager = MediaWikiServices::getInstance()->getPermissionManager();
+ $permissionManager = $services->getPermissionManager();
if ( $permissionManager->userCan( 'delete', $this->getUser(), $filePage ) ) {
$deleteMsg = $this->msg( 'listfiles-delete' )->text();
/**
* @ingroup Pager
*/
+use MediaWiki\Linker\LinkRenderer;
use MediaWiki\MediaWikiServices;
class NewFilesPager extends RangeChronologicalPager {
/**
* @param IContextSource $context
* @param FormOptions $opts
+ * @param LinkRenderer $linkRenderer
*/
- public function __construct( IContextSource $context, FormOptions $opts ) {
- parent::__construct( $context );
+ public function __construct( IContextSource $context, FormOptions $opts,
+ LinkRenderer $linkRenderer
+ ) {
+ parent::__construct( $context, $linkRenderer );
$this->opts = $opts;
$this->setLimit( $opts->getValue( 'limit' ) );
->getWhere( wfGetDB( DB_REPLICA ), 'img_user', User::newFromName( $user, false ) )['conds'];
}
- if ( $opts->getValue( 'newbies' ) ) {
- // newbie = most recent 1% of users
- $dbr = wfGetDB( DB_REPLICA );
- $max = $dbr->selectField( 'user', 'max(user_id)', '', __METHOD__ );
- $conds[] = $imgQuery['fields']['img_user'] . ' >' . (int)( $max - $max / 100 );
-
- // there's no point in looking for new user activity in a far past;
- // beyond a certain point, we'd just end up scanning the rest of the
- // table even though the users we're looking for didn't yet exist...
- // see T140537, (for ContribsPages, but similar to this)
- $conds[] = 'img_timestamp > ' .
- $dbr->addQuotes( $dbr->timestamp( wfTimestamp() - 30 * 24 * 60 * 60 ) );
- }
-
if ( !$opts->getValue( 'showbots' ) ) {
$groupsWithBotPermission = MediaWikiServices::getInstance()
->getPermissionManager()
$user = User::newFromId( $row->img_user );
$title = Title::makeTitle( NS_FILE, $name );
- $ul = MediaWikiServices::getInstance()->getLinkRenderer()->makeLink(
+ $ul = $this->getLinkRenderer()->makeLink(
$user->getUserPage(),
$user->getName()
);
public $mConds;
private $type, $level, $namespace, $sizetype, $size, $indefonly, $cascadeonly, $noredirect;
- /**
- * @var LinkRenderer
- */
- private $linkRenderer;
-
/**
* @param SpecialPage $form
* @param array $conds
$sizetype, $size, $indefonly, $cascadeonly, $noredirect,
LinkRenderer $linkRenderer
) {
+ parent::__construct( $form->getContext(), $linkRenderer );
$this->mConds = $conds;
$this->type = $type ?: 'edit';
$this->level = $level;
$this->indefonly = (bool)$indefonly;
$this->cascadeonly = (bool)$cascadeonly;
$this->noredirect = (bool)$noredirect;
- $this->linkRenderer = $linkRenderer;
- parent::__construct( $form->getContext() );
}
function preprocessResults( $result ) {
function formatValue( $field, $value ) {
/** @var object $row */
$row = $this->mCurrentRow;
+ $linkRenderer = $this->getLinkRenderer();
switch ( $field ) {
case 'log_timestamp':
)
);
} else {
- $formatted = $this->linkRenderer->makeLink( $title );
+ $formatted = $linkRenderer->makeLink( $title );
}
if ( !is_null( $row->page_len ) ) {
$formatted .= $this->getLanguage()->getDirMark() .
$value, /* User preference timezone */true ) );
$title = Title::makeTitleSafe( $row->page_namespace, $row->page_title );
if ( $this->getUser()->isAllowed( 'protect' ) && $title ) {
- $changeProtection = $this->linkRenderer->makeKnownLink(
+ $changeProtection = $linkRenderer->makeKnownLink(
$title,
$this->msg( 'protect_change' )->text(),
[],
* Check a block of CSS or CSS fragment for anything that looks like
* it is bringing in remote code.
* @param string $value a string of CSS
- * @param bool $propOnly only check css properties (start regex with :)
* @return bool true if the CSS contains an illegal string, false if otherwise
*/
private static function checkCssFragment( $value ) {
$ext = FileBackend::extensionFromPath( $this->mVirtualTempPath );
// Get a 0-byte temp file to perform the concatenation at
$tmpFile = MediaWikiServices::getInstance()->getTempFSFileFactory()
- ->getTempFSFile( 'chunkedupload_', $ext );
+ ->newTempFSFile( 'chunkedupload_', $ext );
$tmpPath = false; // fail in concatenate()
if ( $tmpFile ) {
// keep alive with $this
$throttle->clear( $user->getName(), $request->getIP() );
}
return self::loginHook( $user, $bp,
+ // @phan-suppress-next-line PhanUndeclaredMethod
Status::newGood( $provider->newSessionForRequest( $user, $bp, $request ) ) );
}
/**
* Check if a given user has permission to use this functionality.
* @param User $user
- * @param bool $displayPassword If set, also check whether the user is allowed to reset the
- * password of another user and see the temporary password.
* @since 1.29 Second argument for displayPassword removed.
* @return StatusValue
*/
'mActorId',
];
- /**
- * @var string[]
- * @var string[] Cached results of getAllRights()
- */
- protected static $mAllRights = false;
-
/** Cache variables */
// @{
/** @var int */
$summary = "(limit $max in {$period}s)";
$count = $cache->get( $key );
// Already pinged?
- if ( $count ) {
- if ( $count >= $max ) {
- wfDebugLog( 'ratelimit', "User '{$this->getName()}' " .
- "(IP {$this->getRequest()->getIP()}) tripped $key at $count $summary" );
- $triggered = true;
- } else {
- wfDebug( __METHOD__ . ": ok. $key at $count $summary\n" );
- }
+ if ( $count && $count >= $max ) {
+ wfDebugLog( 'ratelimit', "User '{$this->getName()}' " .
+ "(IP {$this->getRequest()->getIP()}) tripped $key at $count $summary" );
+ $triggered = true;
} else {
wfDebug( __METHOD__ . ": adding record for $key $summary\n" );
if ( $incrBy > 0 ) {
}
}
if ( $incrBy > 0 ) {
- $cache->incr( $key, $incrBy );
+ $cache->incrWithInit( $key, (int)$period, $incrBy, $incrBy );
}
}
*
* @param string $permissions,... Permissions to test
* @return bool True if user is allowed to perform *any* of the given actions
+ * @suppress PhanCommentParamOnEmptyParamList Cannot make variadic due to HHVM bug, T191668#5263929
*/
public function isAllowedAny() {
return MediaWikiServices::getInstance()
* ->getPermissionManager()->userHasAllRights(...) instead
* @param string $permissions,... Permissions to test
* @return bool True if the user is allowed to perform *all* of the given actions
+ * @suppress PhanCommentParamOnEmptyParamList Cannot make variadic due to HHVM bug, T191668#5263929
*/
public function isAllowedAll() {
return MediaWikiServices::getInstance()
/**
* Get a list of all available permissions.
*
- * @deprecated since 1.34, use MediaWikiServices::getInstance()->getPermissionManager()
- * ->getAllPermissions() instead
+ * @deprecated since 1.34, use PermissionManager::getAllPermissions() instead
*
* @return string[] Array of permission names
*/
* @return bool
*/
public function addNewUserLogEntryAutoCreate() {
+ wfDeprecated( __METHOD__, '1.27' );
$this->addNewUserLogEntry( 'autocreate' );
return true;
$joinConds
);
- return $res === false ? [] : $res;
+ return $res;
}
}
* @return string|string[] An error or list of errors in the
* provided $datum. When no errors exist the empty array is
* returned.
+ * @suppress PhanUndeclaredMethod
*/
public static function getErrors( AvroSchema $schema, $datum ) {
switch ( $schema->type ) {
$errors[] = $result;
}
if ( $errors ) {
+ // @phan-suppress-next-line PhanTypeMismatchReturn
return [ "Expected any one of these to be true", $errors ];
}
return "No schemas provided to union";
protected $startToken;
/**
- * @var array List of tokens that are members of the current expect sequence
+ * @var array[]|string[] List of tokens that are members of the current expect sequence
*/
protected $tokens;
/**
* Accepts the next token in an expect sequence
*
- * @param array $token
+ * @param array|string $token
*/
protected function tryEndExpect( $token ) {
switch ( $this->startToken[0] ) {
* Read the central directory at the given location
* @param int $offset
* @param int $size
+ * @suppress PhanTypeInvalidLeftOperandOfIntegerOp
*/
function readCentralDirectory( $offset, $size ) {
$block = $this->getBlock( $offset, $size );
* - array $config['namespace'] Configuration for the NamespaceInputWidget dropdown
* with list of namespaces
* - array $config['title'] Configuration for the TitleInputWidget text field
+ * @phan-param array{namespace?:array,title?:array} $config
*/
public function __construct( array $config = [] ) {
// Configuration initialization
* @param string $profile The currently selected profile
* @param string $term The user provided search terms
* @return string HTML
+ * @suppress PhanTypeArraySuspiciousNullable
*/
protected function profileTabsHtml( $profile, $term ) {
$bareterm = $this->startsWithImage( $term )
+++ /dev/null
-<?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
- * @ingroup Language
- */
-
-/**
- * Parser for rules of language conversion, parse rules in -{ }- tag.
- * @ingroup Language
- * @author fdcn <fdcn64@gmail.com>, PhiLiP <philip.npc@gmail.com>
- */
-class ConverterRule {
- public $mText; // original text in -{text}-
- public $mConverter; // LanguageConverter object
- public $mRuleDisplay = '';
- public $mRuleTitle = false;
- public $mRules = ''; // string : the text of the rules
- public $mRulesAction = 'none';
- public $mFlags = [];
- public $mVariantFlags = [];
- public $mConvTable = [];
- public $mBidtable = []; // array of the translation in each variant
- public $mUnidtable = []; // array of the translation in each variant
-
- /**
- * @param string $text The text between -{ and }-
- * @param LanguageConverter $converter
- */
- public function __construct( $text, $converter ) {
- $this->mText = $text;
- $this->mConverter = $converter;
- }
-
- /**
- * Check if variants array in convert array.
- *
- * @param array|string $variants Variant language code
- * @return string 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->mFlags;
- $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'] ) ) {
- $flags = [ 'R' => true ];// remove other flags
- } elseif ( isset( $flags['N'] ) ) {
- $flags = [ 'N' => true ];// remove other flags
- } elseif ( isset( $flags['-'] ) ) {
- $flags = [ '-' => true ];// remove other flags
- } 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->mVariants );
- if ( $variantFlags ) {
- $variantFlags = array_flip( $variantFlags );
- $flags = [];
- }
- }
- $this->mVariantFlags = $variantFlags;
- $this->mRules = $text;
- $this->mFlags = $flags;
- }
-
- /**
- * Generate conversion table.
- * @private
- */
- function parseRules() {
- $rules = $this->mRules;
- $bidtable = [];
- $unidtable = [];
- $variants = $this->mConverter->mVariants;
- $varsep_pattern = $this->mConverter->getVarSeparatorPattern();
-
- // Split according to $varsep_pattern, but ignore semicolons from HTML entities
- $rules = preg_replace( '/(&[#a-zA-Z0-9]+);/', "$1\x01", $rules );
- $choice = preg_split( $varsep_pattern, $rules );
- $choice = str_replace( "\x01", ';', $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->mVariantNames[$vv] ) ) {
- $bidtable = [];
- $unidtable = [];
- break;
- }
- }
- $this->mBidtable = $bidtable;
- $this->mUnidtable = $unidtable;
- }
-
- /**
- * @private
- *
- * @return string
- */
- function getRulesDesc() {
- $codesep = $this->mConverter->mDescCodeSep;
- $varsep = $this->mConverter->mDescVarSep;
- $text = '';
- foreach ( $this->mBidtable as $k => $v ) {
- $text .= $this->mConverter->mVariantNames[$k] . "$codesep$v$varsep";
- }
- foreach ( $this->mUnidtable as $k => $a ) {
- foreach ( $a as $from => $to ) {
- $text .= $from . '⇒' . $this->mConverter->mVariantNames[$k] .
- "$codesep$to$varsep";
- }
- }
- return $text;
- }
-
- /**
- * Parse rules conversion.
- * @private
- *
- * @param string $variant
- *
- * @return string
- */
- function getRuleConvertedStr( $variant ) {
- $bidtable = $this->mBidtable;
- $unidtable = $this->mUnidtable;
-
- if ( count( $bidtable ) + count( $unidtable ) == 0 ) {
- return $this->mRules;
- } else {
- // 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->mManualLevel[$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 original
- * page title if $variant === $this->mConverter->mMainLanguageCode
- * 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|bool The converted title or false if just page name
- */
- function getRuleConvertedTitle( $variant ) {
- if ( $variant === $this->mConverter->mMainLanguageCode ) {
- // 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;
- } else {
- 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->mManualLevel;
-
- $vmarked = [];
- foreach ( $this->mConverter->mVariants 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 current variant no 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::removeHTMLtags
- $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 text in -{A/H/-|text}- is non-empty but without rules
- if ( $rules !== '' ) {
- foreach ( $this->mConverter->mVariants 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->mVariantNames[$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
- */
- public function getTitle() {
- return $this->mRuleTitle;
- }
-
- /**
- * Return how 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;
- }
-}
*/
use CLDRPluralRuleParser\Evaluator;
-use MediaWiki\Languages\LanguageNameUtils;
use MediaWiki\MediaWikiServices;
+use Wikimedia\Assert\Assert;
/**
* Internationalisation code
/**
* Return autonyms in fetchLanguageName(s).
* @since 1.32
- * @deprecated since 1.34, LanguageNameUtils::AUTONYMS
*/
- const AS_AUTONYMS = LanguageNameUtils::AUTONYMS;
+ const AS_AUTONYMS = null;
/**
* Return all known languages in fetchLanguageName(s).
* @since 1.32
- * @deprecated since 1.34, use LanguageNameUtils::ALL
*/
- const ALL = LanguageNameUtils::ALL;
+ const ALL = 'all';
/**
* Return in fetchLanguageName(s) only the languages for which we have at
* least some localisation.
* @since 1.32
- * @deprecated since 1.34, use LanguageNameUtils::SUPPORTED
*/
- const SUPPORTED = LanguageNameUtils::SUPPORTED;
+ const SUPPORTED = 'mwfile';
/**
- * @var LanguageConverter
+ * @var LanguageConverter|FakeConverter
*/
public $mConverter;
public $mVariants, $mCode, $mLoaded = false;
public $mMagicExtensions = [];
- private $mHtmlCode = null, $mParentLanguage = false;
+ private $mHtmlCode = null;
+ /** @var Language|false */
+ private $mParentLanguage = false;
public $dateFormatStrings = [];
public $mExtendedSpecialPageAliases;
*/
public $transformData = [];
- /** @var LocalisationCache */
- private $localisationCache;
-
- /** @var LanguageNameUtils */
- private $langNameUtils;
+ /**
+ * @var LocalisationCache
+ */
+ public static $dataCache;
public static $mLangObjCache = [];
*/
const STRICT_FALLBACKS = 1;
- // TODO Make these const once we drop HHVM support (T192166)
public static $mWeekdayMsgs = [
'sunday', 'monday', 'tuesday', 'wednesday', 'thursday',
'friday', 'saturday'
*/
private static $grammarTransformations;
+ /**
+ * Cache for language names
+ * @var HashBagOStuff|null
+ */
+ private static $languageNameCache;
+
/**
* Unicode directional formatting characters, for embedBidi()
*/
* @return Language
*/
protected static function newFromCode( $code, $fallback = false ) {
- $langNameUtils = MediaWikiServices::getInstance()->getLanguageNameUtils();
- if ( !$langNameUtils->isValidCode( $code ) ) {
+ if ( !self::isValidCode( $code ) ) {
throw new MWException( "Invalid language code \"$code\"" );
}
- if ( !$langNameUtils->isValidBuiltInCode( $code ) ) {
+ if ( !self::isValidBuiltInCode( $code ) ) {
// It's not possible to customise this code with class files, so
// just return a Language object. This is to support uselang= hacks.
$lang = new Language;
// Keep trying the fallback list until we find an existing class
$fallbacks = self::getFallbacksFor( $code );
foreach ( $fallbacks as $fallbackCode ) {
- if ( !$langNameUtils->isValidBuiltInCode( $fallbackCode ) ) {
+ if ( !self::isValidBuiltInCode( $fallbackCode ) ) {
throw new MWException( "Invalid fallback '$fallbackCode' in fallback sequence for '$code'" );
}
* @since 1.32
*/
public static function clearCaches() {
- if ( !defined( 'MW_PHPUNIT_TEST' ) && !defined( 'MEDIAWIKI_INSTALL' ) ) {
- throw new MWException( __METHOD__ . ' must not be used outside tests/installer' );
- }
- if ( !defined( 'MEDIAWIKI_INSTALL' ) ) {
- MediaWikiServices::getInstance()->resetServiceForTesting( 'LocalisationCache' );
- MediaWikiServices::getInstance()->resetServiceForTesting( 'LanguageNameUtils' );
+ if ( !defined( 'MW_PHPUNIT_TEST' ) ) {
+ throw new MWException( __METHOD__ . ' must not be used outside tests' );
}
+ self::$dataCache = null;
+ // Reinitialize $dataCache, since it's expected to always be available
+ self::getLocalisationCache();
self::$mLangObjCache = [];
self::$fallbackLanguageCache = [];
self::$grammarTransformations = null;
+ self::$languageNameCache = null;
}
/**
* Checks whether any localisation is available for that language tag
* in MediaWiki (MessagesXx.php exists).
*
- * @deprecated since 1.34, use LanguageNameUtils
* @param string $code Language tag (in lower case)
* @return bool Whether language is supported
* @since 1.21
*/
public static function isSupportedLanguage( $code ) {
- return MediaWikiServices::getInstance()->getLanguageNameUtils()
- ->isSupportedLanguage( $code );
+ if ( !self::isValidBuiltInCode( $code ) ) {
+ return false;
+ }
+
+ if ( $code === 'qqq' ) {
+ return false;
+ }
+
+ return is_readable( self::getMessagesFileName( $code ) ) ||
+ is_readable( self::getJsonMessagesFileName( $code ) );
}
/**
* not it exists. This includes codes which are used solely for
* customisation via the MediaWiki namespace.
*
- * @deprecated since 1.34, use LanguageNameUtils
- *
* @param string $code
*
* @return bool
*/
public static function isValidCode( $code ) {
- return MediaWikiServices::getInstance()->getLanguageNameUtils()->isValidCode( $code );
+ static $cache = [];
+ Assert::parameterType( 'string', $code, '$code' );
+ if ( !isset( $cache[$code] ) ) {
+ // People think language codes are html safe, so enforce it.
+ // Ideally we should only allow a-zA-Z0-9-
+ // but, .+ and other chars are often used for {{int:}} hacks
+ // see bugs T39564, T39587, T38938
+ $cache[$code] =
+ // Protect against path traversal
+ strcspn( $code, ":/\\\000&<>'\"" ) === strlen( $code )
+ && !preg_match( MediaWikiTitleCodec::getTitleInvalidRegex(), $code );
+ }
+ return $cache[$code];
}
/**
* Returns true if a language code is of a valid form for the purposes of
* internal customisation of MediaWiki, via Messages*.php or *.json.
*
- * @deprecated since 1.34, use LanguageNameUtils
- *
* @param string $code
*
* @since 1.18
* @return bool
*/
public static function isValidBuiltInCode( $code ) {
- return MediaWikiServices::getInstance()->getLanguageNameUtils()
- ->isValidBuiltInCode( $code );
+ Assert::parameterType( 'string', $code, '$code' );
+
+ return (bool)preg_match( '/^[a-z0-9-]{2,}$/', $code );
}
/**
* Returns true if a language code is an IETF tag known to MediaWiki.
*
- * @deprecated since 1.34, use LanguageNameUtils
- *
* @param string $tag
*
* @since 1.21
* @return bool
*/
public static function isKnownLanguageTag( $tag ) {
- return MediaWikiServices::getInstance()->getLanguageNameUtils()
- ->isKnownLanguageTag( $tag );
+ // Quick escape for invalid input to avoid exceptions down the line
+ // when code tries to process tags which are not valid at all.
+ if ( !self::isValidBuiltInCode( $tag ) ) {
+ return false;
+ }
+
+ if ( isset( MediaWiki\Languages\Data\Names::$names[$tag] )
+ || self::fetchLanguageName( $tag, $tag ) !== ''
+ ) {
+ return true;
+ }
+
+ return false;
}
/**
* Get the LocalisationCache instance
*
- * @deprecated since 1.34, use MediaWikiServices
* @return LocalisationCache
*/
public static function getLocalisationCache() {
- return MediaWikiServices::getInstance()->getLocalisationCache();
+ if ( is_null( self::$dataCache ) ) {
+ global $wgLocalisationCacheConf;
+ $class = $wgLocalisationCacheConf['class'];
+ self::$dataCache = new $class( $wgLocalisationCacheConf );
+ }
+ return self::$dataCache;
}
function __construct() {
} else {
$this->mCode = str_replace( '_', '-', strtolower( substr( static::class, 8 ) ) );
}
- $services = MediaWikiServices::getInstance();
- $this->localisationCache = $services->getLocalisationCache();
- $this->langNameUtils = $services->getLanguageNameUtils();
+ self::getLocalisationCache();
}
/**
* Reduce memory usage
+ * @suppress PhanTypeSuspiciousNonTraversableForeach
*/
function __destruct() {
foreach ( $this as $name => $value ) {
* @return array
*/
public function getBookstoreList() {
- return $this->localisationCache->getItem( $this->mCode, 'bookstoreList' );
+ return self::$dataCache->getItem( $this->mCode, 'bookstoreList' );
}
/**
getCanonicalNamespaces();
$this->namespaceNames = $wgExtraNamespaces +
- $this->localisationCache->getItem( $this->mCode, 'namespaceNames' );
+ self::$dataCache->getItem( $this->mCode, 'namespaceNames' );
$this->namespaceNames += $validNamespaces;
$this->namespaceNames[NS_PROJECT] = $wgMetaNamespace;
}
# Sometimes a language will be localised but not actually exist on this wiki.
+ // @phan-suppress-next-line PhanTypeMismatchForeach
foreach ( $this->namespaceNames as $key => $text ) {
if ( !isset( $validNamespaces[$key] ) ) {
unset( $this->namespaceNames[$key] );
# The above mixing may leave namespaces out of canonical order.
# Re-order by namespace ID number...
+ // @phan-suppress-next-line PhanTypeMismatchArgumentInternal
ksort( $this->namespaceNames );
Hooks::run( 'LanguageGetNamespaces', [ &$this->namespaceNames ] );
global $wgExtraGenderNamespaces;
$ns = $wgExtraGenderNamespaces +
- (array)$this->localisationCache->getItem( $this->mCode, 'namespaceGenderAliases' );
+ (array)self::$dataCache->getItem( $this->mCode, 'namespaceGenderAliases' );
return $ns[$index][$gender] ?? $this->getNsText( $index );
}
return false;
} else {
// Check what is in i18n files
- $aliases = $this->localisationCache->getItem( $this->mCode, 'namespaceGenderAliases' );
+ $aliases = self::$dataCache->getItem( $this->mCode, 'namespaceGenderAliases' );
return count( $aliases ) > 0;
}
}
*/
public function getNamespaceAliases() {
if ( is_null( $this->namespaceAliases ) ) {
- $aliases = $this->localisationCache->getItem( $this->mCode, 'namespaceAliases' );
+ $aliases = self::$dataCache->getItem( $this->mCode, 'namespaceAliases' );
if ( !$aliases ) {
$aliases = [];
} else {
}
global $wgExtraGenderNamespaces;
- $genders = $wgExtraGenderNamespaces + (array)$this->localisationCache
- ->getItem( $this->mCode, 'namespaceGenderAliases' );
+ $genders = $wgExtraGenderNamespaces +
+ (array)self::$dataCache->getItem( $this->mCode, 'namespaceGenderAliases' );
foreach ( $genders as $index => $forms ) {
foreach ( $forms as $alias ) {
$aliases[$alias] = $index;
if ( $usemsg && wfMessage( $msg )->exists() ) {
return $this->getMessageFromDB( $msg );
}
- $name = $this->langNameUtils->getLanguageName( $code );
+ $name = self::fetchLanguageName( $code );
if ( $name ) {
return $name; # if it's defined as a language name, show that
} else {
* @return string[]|bool List of date format preference keys, or false if disabled.
*/
public function getDatePreferences() {
- return $this->localisationCache->getItem( $this->mCode, 'datePreferences' );
+ return self::$dataCache->getItem( $this->mCode, 'datePreferences' );
}
/**
* @return array
*/
function getDateFormats() {
- return $this->localisationCache->getItem( $this->mCode, 'dateFormats' );
+ return self::$dataCache->getItem( $this->mCode, 'dateFormats' );
}
/**
* @return array|string
*/
public function getDefaultDateFormat() {
- $df = $this->localisationCache->getItem( $this->mCode, 'defaultDateFormat' );
+ $df = self::$dataCache->getItem( $this->mCode, 'defaultDateFormat' );
if ( $df === 'dmy or mdy' ) {
global $wgAmericanDates;
return $wgAmericanDates ? 'mdy' : 'dmy';
* @return array
*/
public function getDatePreferenceMigrationMap() {
- return $this->localisationCache->getItem( $this->mCode, 'datePreferenceMigrationMap' );
+ return self::$dataCache->getItem( $this->mCode, 'datePreferenceMigrationMap' );
}
/**
/**
* Get an array of language names, indexed by code.
- *
- * @deprecated since 1.34, use LanguageNameUtils::getLanguageNames
* @param null|string $inLanguage Code of language in which to return the names
* Use self::AS_AUTONYMS for autonyms (native names)
* @param string $include One of:
* @since 1.20
*/
public static function fetchLanguageNames( $inLanguage = self::AS_AUTONYMS, $include = 'mw' ) {
- return MediaWikiServices::getInstance()->getLanguageNameUtils()
- ->getLanguageNames( $inLanguage, $include );
+ $cacheKey = $inLanguage === self::AS_AUTONYMS ? 'null' : $inLanguage;
+ $cacheKey .= ":$include";
+ if ( self::$languageNameCache === null ) {
+ self::$languageNameCache = new HashBagOStuff( [ 'maxKeys' => 20 ] );
+ }
+
+ $ret = self::$languageNameCache->get( $cacheKey );
+ if ( !$ret ) {
+ $ret = self::fetchLanguageNamesUncached( $inLanguage, $include );
+ self::$languageNameCache->set( $cacheKey, $ret );
+ }
+ return $ret;
+ }
+
+ /**
+ * Uncached helper for fetchLanguageNames
+ * @param null|string $inLanguage Code of language in which to return the names
+ * Use self::AS_AUTONYMS for autonyms (native names)
+ * @param string $include One of:
+ * self::ALL all available languages
+ * 'mw' only if the language is defined in MediaWiki or wgExtraLanguageNames (default)
+ * self::SUPPORTED only if the language is in 'mw' *and* has a message file
+ * @return array Language code => language name (sorted by key)
+ */
+ private static function fetchLanguageNamesUncached(
+ $inLanguage = self::AS_AUTONYMS,
+ $include = 'mw'
+ ) {
+ global $wgExtraLanguageNames, $wgUsePigLatinVariant;
+
+ // If passed an invalid language code to use, fallback to en
+ if ( $inLanguage !== self::AS_AUTONYMS && !self::isValidCode( $inLanguage ) ) {
+ $inLanguage = 'en';
+ }
+
+ $names = [];
+
+ if ( $inLanguage ) {
+ # TODO: also include when $inLanguage is null, when this code is more efficient
+ Hooks::run( 'LanguageGetTranslatedLanguageNames', [ &$names, $inLanguage ] );
+ }
+
+ $mwNames = $wgExtraLanguageNames + MediaWiki\Languages\Data\Names::$names;
+ if ( $wgUsePigLatinVariant ) {
+ // Pig Latin (for variant development)
+ $mwNames['en-x-piglatin'] = 'Igpay Atinlay';
+ }
+
+ foreach ( $mwNames as $mwCode => $mwName ) {
+ # - Prefer own MediaWiki native name when not using the hook
+ # - For other names just add if not added through the hook
+ if ( $mwCode === $inLanguage || !isset( $names[$mwCode] ) ) {
+ $names[$mwCode] = $mwName;
+ }
+ }
+
+ if ( $include === self::ALL ) {
+ ksort( $names );
+ return $names;
+ }
+
+ $returnMw = [];
+ $coreCodes = array_keys( $mwNames );
+ foreach ( $coreCodes as $coreCode ) {
+ $returnMw[$coreCode] = $names[$coreCode];
+ }
+
+ if ( $include === self::SUPPORTED ) {
+ $namesMwFile = [];
+ # We do this using a foreach over the codes instead of a directory
+ # loop so that messages files in extensions will work correctly.
+ foreach ( $returnMw as $code => $value ) {
+ if ( is_readable( self::getMessagesFileName( $code ) )
+ || is_readable( self::getJsonMessagesFileName( $code ) )
+ ) {
+ $namesMwFile[$code] = $names[$code];
+ }
+ }
+
+ ksort( $namesMwFile );
+ return $namesMwFile;
+ }
+
+ ksort( $returnMw );
+ # 'mw' option; default if it's not one of the other two options (all/mwfile)
+ return $returnMw;
}
/**
- * @deprecated since 1.34, use LanguageNameUtils::getLanguageName
* @param string $code The code of the language for which to get the name
* @param null|string $inLanguage Code of language in which to return the name
* (SELF::AS_AUTONYMS for autonyms)
$inLanguage = self::AS_AUTONYMS,
$include = self::ALL
) {
- return MediaWikiServices::getInstance()->getLanguageNameUtils()
- ->getLanguageName( $code, $inLanguage, $include );
+ $code = strtolower( $code );
+ $array = self::fetchLanguageNames( $inLanguage, $include );
+ return !array_key_exists( $code, $array ) ? '' : $array[$code];
}
/**
}
if ( !isset( $this->dateFormatStrings[$type][$pref] ) ) {
- $df =
- $this->localisationCache->getSubitem( $this->mCode, 'dateFormats', "$pref $type" );
+ $df = self::$dataCache->getSubitem( $this->mCode, 'dateFormats', "$pref $type" );
if ( $type === 'pretty' && $df === null ) {
$df = $this->getDateFormatString( 'date', $pref );
if ( !$wasDefault && $df === null ) {
$pref = $this->getDefaultDateFormat();
- $df = $this->getLocalisationCache()
- ->getSubitem( $this->mCode, 'dateFormats', "$pref $type" );
+ $df = self::$dataCache->getSubitem( $this->mCode, 'dateFormats', "$pref $type" );
}
$this->dateFormatStrings[$type][$pref] = $df;
* @return string|null
*/
public function getMessage( $key ) {
- return $this->localisationCache->getSubitem( $this->mCode, 'messages', $key );
+ return self::$dataCache->getSubitem( $this->mCode, 'messages', $key );
}
/**
* @return array
*/
function getAllMessages() {
- return $this->localisationCache->getItem( $this->mCode, 'messages' );
+ return self::$dataCache->getItem( $this->mCode, 'messages' );
}
/**
* @return string
*/
function fallback8bitEncoding() {
- return $this->localisationCache->getItem( $this->mCode, 'fallback8bitEncoding' );
+ return self::$dataCache->getItem( $this->mCode, 'fallback8bitEncoding' );
}
/**
* @return bool
*/
function isRTL() {
- return $this->localisationCache->getItem( $this->mCode, 'rtl' );
+ return self::$dataCache->getItem( $this->mCode, 'rtl' );
}
/**
* @return array
*/
function capitalizeAllNouns() {
- return $this->localisationCache->getItem( $this->mCode, 'capitalizeAllNouns' );
+ return self::$dataCache->getItem( $this->mCode, 'capitalizeAllNouns' );
}
/**
* @return bool
*/
function linkPrefixExtension() {
- return $this->localisationCache->getItem( $this->mCode, 'linkPrefixExtension' );
+ return self::$dataCache->getItem( $this->mCode, 'linkPrefixExtension' );
}
/**
* @return array
*/
function getMagicWords() {
- return $this->localisationCache->getItem( $this->mCode, 'magicWords' );
+ return self::$dataCache->getItem( $this->mCode, 'magicWords' );
}
/**
*/
function getMagic( $mw ) {
$rawEntry = $this->mMagicExtensions[$mw->mId] ??
- $this->localisationCache->getSubitem( $this->mCode, 'magicWords', $mw->mId );
+ self::$dataCache->getSubitem( $this->mCode, 'magicWords', $mw->mId );
if ( !is_array( $rawEntry ) ) {
wfWarn( "\"$rawEntry\" is not a valid magic word for \"$mw->mId\"" );
$fallbackChain = array_reverse( $fallbackChain );
foreach ( $fallbackChain as $code ) {
if ( isset( $newWords[$code] ) ) {
+ // @phan-suppress-next-line PhanTypeMismatchProperty
$this->mMagicExtensions = $newWords[$code] + $this->mMagicExtensions;
}
}
if ( is_null( $this->mExtendedSpecialPageAliases ) ) {
// Initialise array
$this->mExtendedSpecialPageAliases =
- $this->localisationCache->getItem( $this->mCode, 'specialPageAliases' );
+ self::$dataCache->getItem( $this->mCode, 'specialPageAliases' );
}
return $this->mExtendedSpecialPageAliases;
* @return string
*/
function digitGroupingPattern() {
- return $this->localisationCache->getItem( $this->mCode, 'digitGroupingPattern' );
+ return self::$dataCache->getItem( $this->mCode, 'digitGroupingPattern' );
}
/**
* @return array
*/
function digitTransformTable() {
- return $this->localisationCache->getItem( $this->mCode, 'digitTransformTable' );
+ return self::$dataCache->getItem( $this->mCode, 'digitTransformTable' );
}
/**
* @return array
*/
function separatorTransformTable() {
- return $this->localisationCache->getItem( $this->mCode, 'separatorTransformTable' );
+ return self::$dataCache->getItem( $this->mCode, 'separatorTransformTable' );
}
/**
* @return int|null
*/
function minimumGroupingDigits() {
- return $this->localisationCache->getItem( $this->mCode, 'minimumGroupingDigits' );
+ return self::$dataCache->getItem( $this->mCode, 'minimumGroupingDigits' );
}
/**
* @return string
*/
public function linkTrail() {
- return $this->localisationCache->getItem( $this->mCode, 'linkTrail' );
+ return self::$dataCache->getItem( $this->mCode, 'linkTrail' );
}
/**
* @return string
*/
public function linkPrefixCharset() {
- return $this->localisationCache->getItem( $this->mCode, 'linkPrefixCharset' );
+ return self::$dataCache->getItem( $this->mCode, 'linkPrefixCharset' );
}
/**
/**
* Get the name of a file for a certain language code
- *
- * @deprecated since 1.34, use LanguageNameUtils
* @param string $prefix Prepend this to the filename
* @param string $code Language code
* @param string $suffix Append this to the filename
* @return string $prefix . $mangledCode . $suffix
*/
public static function getFileName( $prefix, $code, $suffix = '.php' ) {
- return MediaWikiServices::getInstance()->getLanguageNameUtils()
- ->getFileName( $prefix, $code, $suffix );
+ if ( !self::isValidBuiltInCode( $code ) ) {
+ throw new MWException( "Invalid language code \"$code\"" );
+ }
+
+ return $prefix . str_replace( '-', '_', ucfirst( $code ) ) . $suffix;
}
/**
- * @deprecated since 1.34, use LanguageNameUtils
* @param string $code
* @return string
*/
public static function getMessagesFileName( $code ) {
- return MediaWikiServices::getInstance()->getLanguageNameUtils()
- ->getMessagesFileName( $code );
+ global $IP;
+ $file = self::getFileName( "$IP/languages/messages/Messages", $code, '.php' );
+ Hooks::run( 'Language::getMessagesFileName', [ $code, &$file ] );
+ return $file;
}
/**
- * @deprecated since 1.34, use LanguageNameUtils
* @param string $code
* @return string
* @throws MWException
* @since 1.23
*/
public static function getJsonMessagesFileName( $code ) {
- return MediaWikiServices::getInstance()->getLanguageNameUtils()
- ->getJsonMessagesFileName( $code );
+ global $IP;
+
+ if ( !self::isValidBuiltInCode( $code ) ) {
+ throw new MWException( "Invalid language code \"$code\"" );
+ }
+
+ return "$IP/languages/i18n/$code.json";
}
/**
* @return array Associative array with plural form, and plural rule as key-value pairs
*/
public function getCompiledPluralRules() {
- $pluralRules =
- $this->localisationCache->getItem( strtolower( $this->mCode ), 'compiledPluralRules' );
+ $pluralRules = self::$dataCache->getItem( strtolower( $this->mCode ), 'compiledPluralRules' );
$fallbacks = self::getFallbacksFor( $this->mCode );
if ( !$pluralRules ) {
foreach ( $fallbacks as $fallbackCode ) {
- $pluralRules = $this->localisationCache
- ->getItem( strtolower( $fallbackCode ), 'compiledPluralRules' );
+ $pluralRules = self::$dataCache->getItem( strtolower( $fallbackCode ), 'compiledPluralRules' );
if ( $pluralRules ) {
break;
}
* @return array Associative array with plural form number and plural rule as key-value pairs
*/
public function getPluralRules() {
- $pluralRules =
- $this->localisationCache->getItem( strtolower( $this->mCode ), 'pluralRules' );
+ $pluralRules = self::$dataCache->getItem( strtolower( $this->mCode ), 'pluralRules' );
$fallbacks = self::getFallbacksFor( $this->mCode );
if ( !$pluralRules ) {
foreach ( $fallbacks as $fallbackCode ) {
- $pluralRules = $this->localisationCache
- ->getItem( strtolower( $fallbackCode ), 'pluralRules' );
+ $pluralRules = self::$dataCache->getItem( strtolower( $fallbackCode ), 'pluralRules' );
if ( $pluralRules ) {
break;
}
* @return array Associative array with plural form number and plural rule type as key-value pairs
*/
public function getPluralRuleTypes() {
- $pluralRuleTypes =
- $this->localisationCache->getItem( strtolower( $this->mCode ), 'pluralRuleTypes' );
+ $pluralRuleTypes = self::$dataCache->getItem( strtolower( $this->mCode ), 'pluralRuleTypes' );
$fallbacks = self::getFallbacksFor( $this->mCode );
if ( !$pluralRuleTypes ) {
foreach ( $fallbacks as $fallbackCode ) {
- $pluralRuleTypes = $this->localisationCache
- ->getItem( strtolower( $fallbackCode ), 'pluralRuleTypes' );
+ $pluralRuleTypes = self::$dataCache->getItem( strtolower( $fallbackCode ), 'pluralRuleTypes' );
if ( $pluralRuleTypes ) {
break;
}
public $mTablesLoaded = false;
/**
- * @var ReplacementArray[]
- * @phan-var array<string,ReplacementArray>
+ * @var ReplacementArray[]|bool[]
*/
public $mTables;
}
$this->mTablesLoaded = true;
- $this->mTables = false;
+ $this->mTables = null;
$cache = ObjectCache::getInstance( $wgLanguageConverterCacheType );
$cacheKey = $cache->makeKey( 'conversiontables', $this->mMainLanguageCode );
if ( $fromCache ) {
*/
private function reloadTables() {
if ( $this->mTables ) {
+ // @phan-suppress-next-line PhanTypeObjectUnsetDeclaredProperty
unset( $this->mTables );
}
$revision = Revision::newFromTitle( $title );
if ( $revision ) {
if ( $revision->getContentModel() == CONTENT_MODEL_WIKITEXT ) {
+ // @phan-suppress-next-line PhanUndeclaredMethod
$txt = $revision->getContent( RevisionRecord::RAW )->getText();
}
* If you are adding support for such a language, add it also to
* the relevant section in shared.css.
*
- * Do not use this class directly. Use LanguageNameUtils::getLanguageNames(), which
+ * Do not use this class directly. Use Language::fetchLanguageNames(), which
* includes support for the CLDR extension.
*
* @ingroup Language
'bh' => 'भोजपुरी', # Bihari macro language. Falls back to Bhojpuri (bho)
'bho' => 'भोजपुरी', # Bhojpuri
'bi' => 'Bislama', # Bislama
- 'bjn' => 'Bahasa Banjar', # Banjarese
+ 'bjn' => 'Banjar', # Banjarese
'bm' => 'bamanankan', # Bambara
'bn' => 'বাংলা', # Bengali
'bo' => 'བོད་ཡིག', # Tibetan
'st' => 'Sesotho', # Southern Sotho
'sty' => 'cебертатар', # Siberian Tatar
'stq' => 'Seeltersk', # Saterland Frisian
- 'su' => 'Basa Sunda', # Sundanese
+ 'su' => 'Sunda', # Sundanese
'sv' => 'svenska', # Swedish
'sw' => 'Kiswahili', # Swahili
'szl' => 'ślůnski', # Silesian
"uctop": "sakarang",
"month": "Dar bulan (deng sabalong)",
"year": "Dar taong (deng sabalong):",
- "sp-contributions-newbies": "Kas lia yang dar pangguna baru sa",
"sp-contributions-blocklog": "catatan blokir",
"sp-contributions-uploads": "Kas maso ka internet",
"sp-contributions-logs": "log",
"watchthispage": "Kalön ôn nyoë",
"unwatch": "Bateuë kalön",
"watchlist-details": "Na {{PLURAL:$1|$1 laman}} lam dapeuta keunalön-neuh (rôh laman marit).",
- "wlshowlast": "Peuleumah $1 jeum $2 uroe seuneulheueh",
"watchlist-hide": "Peusom",
"watchlist-options": "Peuniléh dapeuta kalön",
"watching": "Kalön...",
"uctop": "jinoë",
"month": "Mula phôn buleuen (ngön sigohlomjih)",
"year": "Mula phôn thôn (ngön sigohlomjih)",
- "sp-contributions-newbies": "Peuleumah beuneuri atra ureuëng ban dapeuta mantöng",
- "sp-contributions-newbies-sub": "Keu ureuëng nguy barô",
"sp-contributions-blocklog": "Log peutheun",
"sp-contributions-uploads": "peunasoe",
"sp-contributions-logs": "log",
"uctop": "джырэ",
"month": "Мазэм ыкӀоцӀ (ыкӀи нахь жьэу):",
"year": "Илъэсым ыкӀоцӀ (ыкӀи нахь жьэу):",
- "sp-contributions-newbies": "Аккаунт кШэ закъомэ я лэжьыгъэр къэгъэлъагъу",
- "sp-contributions-newbies-sub": "Аккаунт кIэмэ апай",
"sp-contributions-logs": "Логхэр",
"sp-contributions-talk": "тегущыI",
"sp-contributions-username": "IP-адрес е нэбгырацIэ:",
"watch": "راقب",
"unwatch": "أوقف المراقبة",
"watchlist-details": "{{PLURAL:$1||صفحة واحدة|صفحتان|$1 صفحات|$1 صفحة}} في قائمة مراقبتك، بدون عد صفحات النقاش.",
- "wlshowlast": "عرض آخر $1 ساعات $2 أيام",
"watchlist-options": "خيارات قائمة المراقبة",
"actioncomplete": "انتهاء العملية",
"actionfailed": "الفعل فشل",
"contribsub2": "ل{{GENDER:$3|$1}} ($2)",
"month": "من شهر (و أقدم):",
"year": "من عام (و أقدم):",
- "sp-contributions-newbies": "اعرض مساهمات الحسابات الجديدة فقط",
"sp-contributions-blocklog": "سجل المنع",
"sp-contributions-uploads": "مرفوعات",
"sp-contributions-logs": "سجلات",
"querypage-disabled": "Hierdie spesiale bladsy is afgeskakel om werkverrigting te verbeter (bediener is oorlaai).",
"apihelp-no-such-module": "Module \"$1\" nie gevind nie.",
"apisandbox": "API-sandput",
- "apisandbox-api-disabled": "API is afgeskakel op hierdie webwerf.",
"apisandbox-intro": "Gebruik hierdie bladsy om te eksperimenteer met die '''MediaWiki-API'''.\nSien die [https://www.mediawiki.org/wiki/API:Main_page API-dokumentasie] vir verdere details oor die gebruik van die API. Voorbeeld: [https://www.mediawiki.org/wiki/API#A_simple_example hoe die inhoud van 'n Tuisblad te laai]. Kies 'n handeling om meer voorbeelde te sien.",
"apisandbox-submit": "Maak versoek",
"apisandbox-reset": "Vee uit",
"wlheader-enotif": "E-pos kennisgewings is aangeskakel.",
"wlheader-showupdated": "Bladsye wat verander is sedert u hulle laas besoek het word in '''vetdruk''' uitgewys.",
"wlnote": "Hier volg die laaste {{PLURAL:$1|verandering|<strong>$1</strong> veranderings}} binne die laaste {{PLURAL:$2|uur|<strong>$2</strong> ure}}, soos op $3 om $4.",
- "wlshowlast": "Wys afgelope $1 ure, $2 dae",
"watchlist-hide": "Versteek",
"watchlist-submit": "Wys",
"wlshowtime": "Wys laaste:",
"uctop": "laaste wysiging",
"month": "Vanaf maand (en vroeër):",
"year": "Vanaf jaar (en vroeër):",
- "sp-contributions-newbies": "Wys slegs bydraes van nuwe gebruikers",
- "sp-contributions-newbies-sub": "Vir nuwe gebruikers",
- "sp-contributions-newbies-title": "Bydraes van nuwe gebruikers",
"sp-contributions-blocklog": "blokkeer-logboek",
"sp-contributions-suppresslog": "onderdrukte gebruikersbydraes",
"sp-contributions-deleted": "geskrapte gebruikersbydraes",
"imgmultigoto": "Gaan na bladsy $1",
"img-lang-default": "(standaard taal)",
"img-lang-go": "OK",
- "ascending_abbrev": "op",
- "descending_abbrev": "af",
"table_pager_next": "Volgende bladsy",
"table_pager_prev": "Vorige bladsy",
"table_pager_first": "Eerste bladsy",
"apihelp-no-such-module": "cay katepa bacu \"$1\".",
"apisandbox": "bunac haku nu API",
"apisandbox-jsonly": "maydih JavaScript kya kapah pisaungay API bunak-haku.",
- "apisandbox-api-disabled": "tina calay-kakacawan(wangcan) maedeb API tuway.",
"apisandbox-intro": "isaungay tina kasabelih taneng mitanam <strong>MediaWiki web service API</strong>.\npiazih tu tatenga’ay [[mw:API:Main page|API buhci tu kamu cudad]] ngay maala pulita cesyun. tinaku:[https://www.mediawiki.org/wiki/API#A_simple_example maala angnangan-belih a lacul]. pipili’ saungay ngay maala kayadahay a satinakuan.\n\npiazihi, kanahatu tina ku bunak-haku, i tina belih sapisaungayay a saungay hakay amasumad tu ku Wiki.",
"apisandbox-submit": "miawaw tu milunguc",
"apisandbox-reset": "palawpis",
"wlheader-enotif": "mawawah tuway imyiyo(email) patakus sasahicaan.",
"wlheader-showupdated": "i tisuwan sazikuz tu ciwsace sazikuzay misumad tu kasabelih a u <strong>kibetulay</strong> paazih",
"wlnote": "isasa’ay {{PLURAL:$1|u nazikuzay a sumad|u nazikuzay <strong>$1</strong> sumad}} i inazikuzay {{PLURAL:$2|tuki|<strong>$2</strong> tuki}}, itawya $3, $4.",
- "wlshowlast": "paazih capi demaid $1 tuki $2 demiad",
"watchlist-hide": "midimut",
"watchlist-submit": "paazih",
"wlshowtime": "apaazihay a tuki-tenes:",
"uctop": "ayza",
"month": "sazikuzay demiad nabuladan:",
"year": "sazikuzay demiad mihcaan:",
- "sp-contributions-newbies": "paazih a cacay baluhay canghaw a paanin",
- "sp-contributions-newbies-sub": "paanin nu baluhay a canghaw",
- "sp-contributions-newbies-title": "misaungayay paanin nu baluhay canghaw",
"sp-contributions-blocklog": "milangat tu nasulitan nakawawan",
"sp-contributions-suppresslog": "mapasatezep paazihay a{{GENDER:$1|misaungayay}}paanin",
"sp-contributions-deleted": "masipuay tu {{GENDER:$1|misaungayay}} paanin",
"newimages-legend": "kilim",
"newimages-label": "tangan kalungangan (saca liyad a nipangangan):",
"newimages-user": "IP puenengan saca misaungayay a kalungangan",
- "newimages-newbies": "paazih a cacay baluhay canghaw a paanin",
"newimages-showbots": "paazih nay tademaw-kikay patapabaw a tangan",
"newimages-hidepatrolled": "midimut natayza tu mikibi patudud",
"noimages": "inayi’ amahicahica tu zunga.",
"img-lang-default": "(pataayaw tu kawaw a kamu)",
"img-lang-info": "paazih tina zunga i $1. $2",
"img-lang-go": "mileku",
- "ascending_abbrev": "masalaylay adidi’ay katukuh tabakiay",
- "descending_abbrev": "masalaylay tabakiay katukuh adidi’ay",
"table_pager_next": "zikuzan a belih",
"table_pager_first": "sakacacay a belih",
"table_pager_last": "sazikuzay a kasabelih",
"watchthispage": "Mbikëqyr këtë faqe",
"unwatch": "Çmbikqyre",
"watchlist-details": "{{PLURAL:$1|$1 faqe|$1 faqe}} në listën tuej të mbikëqyrjes, pa i numrue faqet e diskutimit.",
- "wlshowlast": "Trego $1 orët $2 ditët e fundit",
"watchlist-options": "Opcionet e listës së mbikëqyrjes",
"watching": "Tuj mbikqyrë...",
"unwatching": "Tuj çmbikqyrë...",
"uctop": "në krye",
"month": "Prej muejit (e mâ herët):",
"year": "Prej vjetit (e mâ herët):",
- "sp-contributions-newbies": "Trego sall kontributet e përdoruesve të rij",
"sp-contributions-blocklog": "regjistri i bllokimeve",
"sp-contributions-talk": "Bisedo",
"sp-contributions-search": "Kërko te kontributet",
"wlheader-enotif": "የ-ኢሜል ማስታወቂያ እንዲሠራ ተደርጓል።",
"wlheader-showupdated": "መጨረሻ ከጎበኟቸው ጀምሮ የተቀየሩት ገጾች በ'''ጉልህ ፊደላት''' ይታያሉ",
"wlnote": "ባለፉት <b>$2</b> ሰዓቶች የተደረጉት $1 መጨረሻ ለውጦች እታች ይገኛሉ።",
- "wlshowlast": "ያለፉት $1 ሰዓት፤ $2 ቀን፤ ይታዩ።",
"watchlist-options": "የዝርዝሩ ምርጫዎች",
"watching": "እየተጨመረ ነው...",
"unwatching": "እየተወገደ ነው...",
"uctop": "ላይኛ",
"month": "እስከዚህ ወር ድረስ፦",
"year": "እስከዚህ አመት (እ.ኤ.አ.) ድረስ፡-",
- "sp-contributions-newbies": "የአዳዲስ ተጠቃሚዎች አስተዋጽዖ ብቻ እዚህ ይታይ",
- "sp-contributions-newbies-sub": "(ለአዳዲስ ተጠቃሚዎች)",
- "sp-contributions-newbies-title": "የአዳዲስ ተጠቃሚዎች አስተዋጽኦች",
"sp-contributions-blocklog": "የማገጃ መዝገብ",
"sp-contributions-deleted": "የአባሉ የጠፉት አስተዋጽኦች",
"sp-contributions-uploads": "የተላኩ ፋይሎች",
"watchlist-details": "o pirorodan to ’a’arawen a tilid iso i, $1 ko felih (halo- kalalicay a felih )。",
"wlheader-showupdated": "O pakarikoray nisongila’an a minengneng ato nisalofan a felih i, oya <strong>kifetolay sorit </strong> ko sapasapinang.",
"wlnote": " i kalaenoay nani $3 $4 i ka’ayaway i <strong>$2</strong> mihalakaan i ’ayaw no pinapina a tatokian <strong>$1</strong> kina--- a mifalic.",
- "wlshowlast": "pahapinang to ngata $1 a tatokian $2 a romi’ad",
"watchlist-hide": " himed",
"watchlist-submit": "pahapinang",
"enotif_reset": " pahapinangen kona felih a maemin o matiri’ay to",
"nocontribs": "Awaay matama^ ko matatodongay a sapifalih",
"month": "paherekan safoladan:",
"year": "paherekan mihecaan:",
- "sp-contributions-newbies": "o nipafelian aca no faelohay cang-haw ko pahapinangen",
"sp-contributions-blocklog": " pikilokan to kalonicikeran",
"sp-contributions-logs": "nisoritan to romi’ami’ad",
"sp-contributions-talk": " kalalicay",
"show-big-image-preview": " o tata’ak no pa’ayaw a minengneng:$1。",
"show-big-image-other": " o romaay a {{PLURAL:$2||}} cyi-si-tu:$1。",
"show-big-image-size": "$1 × $2 ko kasapinang no siyang-su",
- "newimages-newbies": "o nipafelian aca no faelohay cang-haw ko pahapinangen",
"ilsubmit": " saoo’",
"metadata": "mikitedal to tatiri’en",
"metadata-help": "Onini a tang^ani, masalaloma’ ko no roma^ a lihaf, onini a lihaf i, latek o matongalay yo mipalowaday to su-wey ka-mi-la ano eca yo mipalowad to sapise-ken a kikay. Ano masomad ko satapangay a tang^an i, latek oya masongila’ay a tili, caay to kapasapingan itira toya masomaday to a tang^an.",
"wlheader-enotif": "A notificación por correu electronico ye activata",
"wlheader-showupdated": "Las pachinas cambiadas dende a suya zaguer vesita s'amuestran en '''negreta'''",
"wlnote": "Contino se i {{PLURAL:$1|amuestra o solo cambeo|amuestran os zaguers '''$1''' cambeos}} feitos en {{PLURAL:$2|a zaguer hora|as zagueras '''$2''' horas}}, o $3 a las $4.",
- "wlshowlast": "Amostrar as zagueras $1 horas, $2 días u",
"watchlist-options": "Opcions d'a lista de seguimiento",
"watching": "Cosirando...",
"unwatching": "Deixar de cosirar...",
"uctop": "zaguer cambeo",
"month": "Dende o mes (y anteriors):",
"year": "Dende l'anyo (y anteriors):",
- "sp-contributions-newbies": "Amostrar nomás as contrebucions d'os usuarios nuevos",
- "sp-contributions-newbies-sub": "Por nuevos usuarios",
- "sp-contributions-newbies-title": "Contrebucions d'os nuevos usuarios",
"sp-contributions-blocklog": "Rechistro de bloqueyos",
"sp-contributions-deleted": "contribucions d'usuario borradas",
"sp-contributions-uploads": "cargas",
"imgmultipagenext": "pachina siguient →",
"imgmultigo": "Ir-ie!",
"imgmultigoto": "Ir t'a pachina $1",
- "ascending_abbrev": "asc",
- "descending_abbrev": "desc",
"table_pager_next": "Pachina siguient",
"table_pager_prev": "Pachina anterior",
"table_pager_first": "Primera pachina",
"laggedslavemode": "'''Warnung:''' Wēnunga næbbe se tramet nīwlīca nīwunga.",
"readonly": "Ġifhord locen",
"enterlockreason": "Wrīt race þǣre forwiernunge and apinsunge þæs tīman on þǣm bēo sēo forwiernung forlǣten",
+ "readonlytext": "Se gecyþneshord is nu gelocen wiþ niwu þing and gewrixlungu, ic gewene þe swylc biþ for gecyþneshorduphealde, þæræfter wille he beon eft gewuna.\n\nSe gesamnungþegn se loced hine geaf þas glesing: $1",
"missingarticle-rev": "(nīwung#: $1)",
"internalerror": "Inweard wōh",
"internalerror_info": "Inweard wōh: $1",
"unwatchthispage": "Ablinnan behealdunge",
"watchlist-details": "{{PLURAL:$1|Þǣr is $1 tramet|Þǣr sind $1 trameta}} on þīnum behealdunggetæle, nā sunderlīce arīmedum mōtunga trametum.",
"wlnote": "Niðer {{PLURAL:$1|is sēo nīwoste andwendung|sind þā nīwostan '''$1''' andwendunga}} in {{PLURAL:$2|þǣre nīwostan tīde|þǣm nīwostum '''$2''' tīda}}, fram $4 of $3.",
- "wlshowlast": "Īwan þā nīwostan $1 tīda $2 daga",
"watchlist-options": "Behealdungtæles cyras",
"watching": "Behealdende...",
"unwatching": "Ablinnende behealdunge...",
"watchlist-details": " {{PLURAL:$1|$1 पृष्ठ}} आपन॑ के ध्यानसूची म॑ छै (वार्ता पृष्ठऽ के अलावा)।",
"wlheader-showupdated": "आपन॑ के देखला गेला के बाद जोन पृष्ठऽ म॑ बदलाव होतै, ओकरऽ कड़ी <strong>गहरा</strong> रंग के दिखतै।",
"wlnote": "$3 क॑ $4 बजे तलक पिछला <strong>$2</strong> {{PLURAL:$2|घंटा|घंटां}} म॑ {{PLURAL:$1|हुआ एक|होलै <strong>$1</strong>}} परिवर्तन निम्न {{PLURAL:$1|छै|छैं}}।",
- "wlshowlast": "पिछला $1 घंटा $2 दिन देखऽ",
"watchlist-options": "ध्यानसूची विकल्प",
"watching": "ध्यान दय रहलॊ छै...",
"unwatching": "ध्यान हटाय रहलॊ छियै...",
"uctop": "मौजूदा",
"month": "इ महिना स॑ (आरू पुरान॑):",
"year": "इ साल स॑ (आरू पुरानऽ):",
- "sp-contributions-newbies": "सिर्फ नया सदस्यॊ के योगदान दर्शाबॊ",
"sp-contributions-blocklog": "ब्लॉक सूची",
"sp-contributions-uploads": "अपलोड",
"sp-contributions-logs": "लॉग सूची",
"nocreate-loggedin": "أنت لا تمتلك الصلاحية لإنشاء صفحات جديدة.",
"sectioneditnotsupported-title": "تعديل الأقسام غير مدعوم",
"sectioneditnotsupported-text": "تعديل الأقسام غير مدعوم في هذه الصفحة",
+ "modeleditnotsupported-title": "التحرير غير مدعوم",
+ "modeleditnotsupported-text": "التحرير غير مدعوم لنموذج المحتوى $1.",
"permissionserrors": "خطأ في السماح",
"permissionserrorstext": "لا تمتلك الصلاحية لفعل هذا، {{PLURAL:$1||للسبب التالي|للسببين التاليين|للأسباب التالية}}:",
"permissionserrorstext-withaction": "ليست لك الصلاحية ل$2; لل{{PLURAL:$1||سبب التالي|سببين التاليين|أسباب التالية}}:",
"content-model-json": "جسون",
"content-json-empty-object": "كائن فارغ",
"content-json-empty-array": "مصفوفة فارغة",
+ "unsupported-content-model": "<strong>تحذير:</strong> نموذج المحتوى $1 غير مدعوم في هذا الويكي.",
+ "unsupported-content-diff": "الفروق غير مدعومة لنموذج المحتوى $1.",
+ "unsupported-content-diff2": "الفروق بين نموذجي المحتوى $1 و$2 غير مدعومة في هذا الويكي.",
"deprecated-self-close-category": "صفحات تستخدم وسوم HTML غير صالحة",
"deprecated-self-close-category-desc": "هذه الصفحة تحتوي على وسوم HTML مغلقة ذاتيا، مثل <code><b/></code> أو <code><span/></code>. سلوك هذه سيتغير سريعا ليكون متوافقا مع معيار HTML5، لذا فاستخدامهم في نص الويكي ينبغي أن يتم الاستغناء عنه.",
"duplicate-args-warning": "<strong>تنبيه:</strong> المدخل \"$3\" ل[[:$1]] المستعمل في [[:$2]] مكرر. آخر قيمة مكرر منه هي المعتمدة.",
"apihelp-no-such-module": "الوحدة \"$1\" غير موجودة.",
"apisandbox": "ملعب API",
"apisandbox-jsonly": "الجافا سكريبت مطلوبة لاستخدام ملعب API",
- "apisandbox-api-disabled": "واجهة برمجة التطبيق API معطلة في هذا الموقع.",
"apisandbox-intro": "استخدم هذه الصفحة للتجربة ب<strong>MediaWiki web service API</strong>.\nارجع إلى [[mw:API:Main page|توثيق الAPI]] للمزيد من التفاصيل حول استخدام الAPI. مثال: [https://www.mediawiki.org/wiki/API#A_simple_example احصل على محتوى صفحة رئيسية]. اختر فعلا لترى المزيد من الأمثلة.\n\nلاحظ أنه، على الرغم من أن هذا ملعب، فالأفعال التي تقوم بها على هذه الصفحة ربما تعدل الويكي.",
"apisandbox-submit": "عمل الطلب",
"apisandbox-reset": "إفراغ",
"wlheader-enotif": "الإخطار بالبريد الإلكتروني مُفعّل.",
"wlheader-showupdated": "الصفحات التي تم تحريرها بعد مطالعتك إياها آخر مرة عناوينها بالخط <strong>الغليظ</strong>.",
"wlnote": "بالأسفل {{PLURAL:$1|لا توجد تغييرات|التغيير الأخير|آخر تغييرين|آخر <strong>$1</strong> تغييرات|آخر <strong>$1</strong> تغييرا|آخر <strong>$1</strong> تغيير}} في {{PLURAL:$2||<strong>الساعة</strong> الماضية|<strong>الساعتين</strong> الماضيتين|ال<strong>$2</strong> ساعات الماضية|ال<strong>$2</strong> ساعة الماضية}} وفقاً ل$3، $4.",
- "wlshowlast": "عرض آخر $1 ساعات $2 يوما",
"watchlist-hide": "إخفاء",
"watchlist-submit": "أظهر",
"wlshowtime": "الفترة الزمنية للعرض:",
"sessionfailure": "يبدو أنه هناك مشكلة في جلسة الدخول الخاصة بك؛\nلذلك فقد ألغيت هذه العملية كإجراء احترازي ضد الاختراق.\nمن فضلك أعد إرسال الاستمارة مرة أخرى.",
"changecontentmodel": "تغيير نموذج المحتوى لصفحة",
"changecontentmodel-legend": "غير نموذج المحتوى",
- "changecontentmodel-title-label": "عنوان الصفحة",
+ "changecontentmodel-title-label": "عنوان الصفحة:",
"changecontentmodel-current-label": "نموذج المحتوى الحالي:",
- "changecontentmodel-model-label": "نموذج محتوى جديد",
+ "changecontentmodel-model-label": "نموذج محتوى جديد:",
"changecontentmodel-reason-label": "السبب:",
"changecontentmodel-submit": "تغيير",
"changecontentmodel-success-title": "نموذج المحتوى تم تغييره",
"month": "من شهر (وأقدم):",
"year": "من سنة (وأقدم):",
"date": "من تاريخ (وأقدم):",
- "sp-contributions-newbies": "اعرض مساهمات الحسابات الجديدة فقط",
- "sp-contributions-newbies-sub": "للحسابات الجديدة",
- "sp-contributions-newbies-title": "مساهمات المستخدم للحسابات الجديدة",
"sp-contributions-blocklog": "سجل المنع",
"sp-contributions-suppresslog": "مساهمات {{GENDER:$1|المستخدم|المستخدمة}} المخفية",
"sp-contributions-deleted": "مساهمات {{GENDER:$1|المستخدم|المستخدمة}} المحذوفة",
"newimages-legend": "المرشح",
"newimages-label": "اسم الملف (أو جزء منه):",
"newimages-user": "عنوان الأيبي أو اسم المستخدم",
- "newimages-newbies": "اعرض مساهمات الحسابات الجديدة فقط",
"newimages-showbots": "أظهر التحميلات بواسطة البوتات",
"newimages-hidepatrolled": "أخف المرفوعات المنظورة",
"newimages-mediatype": "نوع الوسيط:",
"img-lang-default": "(اللغة الافتراضية)",
"img-lang-info": "ترجم هذه الصورة إلى $1. $2",
"img-lang-go": "اذهب",
- "ascending_abbrev": "تصاعدي",
- "descending_abbrev": "تنازلي",
"table_pager_next": "الصفحة التالية",
"table_pager_prev": "الصفحة السابقة",
"table_pager_first": "الصفحة الأولى",
"watchlist-details": "{{PLURAL:$1|$1 ܦܐܬܐ|$1 ܦܐܬܬ̈ܐ}} ܒܪ̈ܗܝܬܟ, ܫܒܘܩ ܡܢ ܦܐܬܬ̈ܐ ܕܡܡܠܠܐ.",
"wlheader-showupdated": "ܦܐܬܬ̈ܐ ܕܐܫܬܚܠܦܢ ܡܢ ܒܬܪ ܣܘܥܪܢܐ ܐܚܪܝܐ ܠܗܝܢ ܡܬܓܠܚܢ ܒܣܪܛܐ '''ܚܠܝܡܐ'''",
"wlnote": "ܠܬܚܬ {{PLURAL:$1|ܫܘܚܠܦܐ ܐܚܪܝܐ| '''$1''' ܫܘܚܠܦ̈ܐ ܐܚܪ̈ܝܐ}} {{PLURAL:$2|ܒܫܥܬܐ ܐܚܪܝܬܐ|'''$2''' ܒܫܥܬ̈ܐ ܐܚܪ̈ܝܬܐ}}, ܠܦܘܬ $3, $4.",
- "wlshowlast": "ܚܘܝ $1 ܫܥܬ̈ܐ $2 ܝܘܡܬ̈ܐ ܐܚܪ̈ܝܐ",
"watchlist-options": "ܨܒܝܢܝܘܬ̈ܐ ܕܪ̈ܗܝܬܐ",
"watching": "ܪܗܝܐ...",
"unwatching": "ܠܚܝ ܪܗܝܐ...",
"uctop": "ܗܫܝܐ",
"month": "ܡܢ ܝܪܚܐ ܕ (ܘܡܢ ܩܕܡ ܗܝܕܝܢ):",
"year": "ܡܢ ܫܢܬ (ܘܡܢ ܩܕܡ ܗܝܕܝܢ):",
- "sp-contributions-newbies": "ܚܘܝ ܫܘܬܦܘ̈ܬܐ ܕܚܘܫܒܢ̈ܐ ܚܕ̈ܬܐ ܒܠܚܘܕ",
- "sp-contributions-newbies-sub": "ܠܚܘܫܒܢ̈ܐ ܚܕ̈ܬܐ",
- "sp-contributions-newbies-title": "ܫܘܬܦܘ̈ܬܐ ܕܡܦܠܚܢܐ ܠܚܘܫܒܢ̈ܐ ܚܕ̈ܬܐ",
"sp-contributions-blocklog": "ܣܓܠܐ ܕܚܪܡܐ",
"sp-contributions-deleted": "ܫܘܬܦܘ̈ܬܐ ܫܝ̈ܦܬܐ ܕܡܦܠܚܢܐ",
"sp-contributions-uploads": "ܡܣܩܬ̈ܐ",
"imgmultipagenext": "← ܫܘܚܠܦܐ ܕܒܬܪ",
"imgmultigo": "ܙܠ!",
"imgmultigoto": "ܙܠ ܠܦܐܬܐ $1",
- "ascending_abbrev": "ܡܣܩܐܝܬ",
- "descending_abbrev": "ܡܚܬܐܝܬ",
"table_pager_next": "ܦܐܬܐ ܕܒܬܪ",
"table_pager_prev": "ܦܐܬܐ ܕܩܕܡ",
"table_pager_first": "ܦܐܬܐ ܩܕܡܝܬܐ",
"unwatchthispage": "Llaytuwelan",
"notanarticle": "Trokiñdungu wülngiñ nu",
"watchlist-details": "{{PLURAL:$1|$1 wülngiñ}} tami llaytun wif mew. Inantukulay nütramkawün ñi wülngiñ.",
- "wlshowlast": "Pengelün kalekünun rupalu $1 ora, $2 antü",
"watchlist-options": "Llaytun wif ñi dullin",
"watching": "Llaytumekey...",
"unwatching": "Llaytumekewelay...",
"uctop": "wente",
"month": "Küyeṉ:",
"year": "Tripantu:",
- "sp-contributions-newbies": "Pengelün weke kellufe ñi wirin müten",
"sp-contributions-blocklog": "Katrüntukun wirintukun",
"sp-contributions-uploads": "Püramngelu",
"sp-contributions-logs": "Wirintukun",
"watch": "تبع",
"unwatch": "ما تزيدش تعس",
"watchlist-details": "{{PLURAL:$1||باجه وحده|باجتين|$1 باجات|$1 باجه}} في ليستت مراقبتك، (زدلها باجات النقاش).",
- "wlshowlast": "بين آخر $1 سوايع $2 يامات",
"watchlist-submit": "ورّي",
"wlshowhideminor": "تبديلة خفيفة",
"wlshowhidepatr": "$1 التبديلات المعسوسه",
"uctop": "ذ الوقت",
"month": "من شهر (وأقدم):",
"year": "من عام (وأقدم):",
- "sp-contributions-newbies": "اعرض مشاركات الحسابات الجديده برك",
"sp-contributions-blocklog": "ريجيسترالمنع",
"sp-contributions-uploads": "مرفوعات",
"sp-contributions-logs": "ريجيسترات",
"watchlist-details": "{{PLURAL:$1|ṣefḫa weḫda|$1 de ṣ-ṣefḫaṫ}} kaynin fe l-lista dyal s-suivi dyalṫek, bla ma nḫesbo ṣ-ṣefḫaṫ dyal n-niqaċ.",
"wlheader-enotif": "l-iĝlam bl-email mtloq.",
"wlheader-showupdated": "ṣ-ṣfaḫi lli ṫġyyeraṫ mn aĥir ẓiyaṛa ṫaĝk mkṫoba b-ĥatt '''ġliḍ'''",
- "wlshowlast": "Werri l-$1 de s-swayeĝ o l-$2 iyam l-leĥĥrin, ola werri",
"watchlist-options": "Lé-Opsyon de l-lista dyal s-suivi",
"watching": "Kayraqeb...",
"unwatching": "Nihayaṫ 's-suivi...",
"uctop": "l-foq",
"month": "Men ċher (o qdem)",
"year": "Men ĝam (o men qbel)",
- "sp-contributions-newbies": "وري غير المساهمات ديال المستخدمين الجداد",
- "sp-contributions-newbies-sub": "Le ḫsabaṫ jdad",
- "sp-contributions-newbies-title": "mosahamat lmostkhdim lilhassabat jdida",
"sp-contributions-blocklog": "Ṫariĥ l-blokajaṫ",
"sp-contributions-deleted": "mosahamaṫ memḫiya",
"sp-contributions-uploads": "ṫḫmilaṫ",
"file-info-png-looped": "mlfof",
"newimages-legend": "Filter",
"newimages-label": "smiyt lfichier olla chwiya mnno:",
- "newimages-newbies": "وري غير المساهمات ديال المستخدمين الجداد",
"noimages": "walo maytchaf.",
"ilsubmit": "Qelleb",
"bydate": "hassab tarikh",
"imgmultipagenext": "sfha jaya →",
"imgmultigo": "sir !",
"imgmultigoto": "sir lsfha $1",
- "ascending_abbrev": "tassaaodi",
- "descending_abbrev": "tanazoli",
"table_pager_next": "Ṣefḫa li jaya",
"table_pager_prev": "sfha li sbqat",
"table_pager_first": "sfha lowla",
"wlheader-enotif": "*خاصية الاعلام بالايميل متفعلة",
"wlheader-showupdated": "الصفحات اللى اتغيرت بعد زيارتك ليها اخر مرة معروضة بالخط <strong>التخين</strong>",
"wlnote": "تحت فى {{PLURAL:$1|آخر تغيير|آخر <strong>$1</strong> تغيير}} فى آخر {{PLURAL:$2|ساعه|<strong>$1</strong> ساعه}}، من الوقت $3، $4.",
- "wlshowlast": "عرض اخر $1 ساعات $2 ايام",
"watchlist-options": "اختيارات قايمة المراقبة",
"watching": "بيراقب...",
"unwatching": "بيبطل مراقبه...",
"uctop": "آخر تعديل",
"month": "من شهر (واللى قبل كده):",
"year": "من سنة (واللى قبل كده):",
- "sp-contributions-newbies": "عرض مساهمات الحسابات الجديدة بس",
- "sp-contributions-newbies-sub": "للحسابات الجديده",
- "sp-contributions-newbies-title": "مساهمات اليوزر للحسابات الجديدة",
"sp-contributions-blocklog": "سجل المنع",
"sp-contributions-deleted": "تعديلات {{GENDER:$1|اليوزر}} الممسوحه",
"sp-contributions-uploads": "مرفوعات",
"imgmultipagenext": "الصفحه اللى بعد كده →",
"imgmultigo": "روح!",
"imgmultigoto": "روح لصفحة $1",
- "ascending_abbrev": "طالع",
- "descending_abbrev": "نازل",
"table_pager_next": "الصفحه اللى بعد كده",
"table_pager_prev": "الصفحة اللى فاتت",
"table_pager_first": "أول صفحة",
"wlheader-enotif": "ইমেইল জাননী সক্ৰিয় কৰা হৈছে।",
"wlheader-showupdated": "আপোনাৰ শেষ পৰিদৰ্শনৰ পিছত সলনি হোৱা পৃষ্ঠাসমূহ '''গাঢ়''' আখৰত দেখুওৱা হৈছে।",
"wlnote": "তলত $3, $4 তাৰিখত বিগত {{PLURAL:$2|১ ঘণ্টাত|<strong>$2</strong> ঘণ্টাত}} সংঘটিত {{PLURAL:$1|শেহতীয়া এটা পৰিৱৰ্তন|শেহতীয়া <strong>$1টা</strong> পৰিৱৰ্তন}} দেখুওৱা হ'ল।",
- "wlshowlast": "যোৱা $1 ঘণ্টা $2 দিন চাওক",
"wlshowhidecategorization": "পৃষ্ঠা শ্ৰেণীকৰণ",
"watchlist-options": "লক্ষ্য-তালিকা পছন্দসমূহ",
"watching": "চকু দিয়া হৈছে.....",
"uctop": "বৰ্তমান",
"month": "এই মাহৰ পৰা (আৰু আগৰ):",
"year": "এই বছৰৰ পৰা (আৰু আগৰ):",
- "sp-contributions-newbies": "কেৱল নতুন একাউন্টৰ বৰঙণিসমূহ দেখুৱাওক",
- "sp-contributions-newbies-sub": "নতুন একাউন্টৰ কাৰণে",
- "sp-contributions-newbies-title": "নতুন একাউন্টৰ বাবে সদস্যৰ বৰঙণি",
"sp-contributions-blocklog": "বাৰণ সূচী",
"sp-contributions-deleted": "বিলোপ কৰা সদস্যৰ বৰঙণিসমূহ",
"sp-contributions-uploads": "আপল'ডসমূহ",
"imgmultigoto": "$1 পৃষ্ঠালৈ যাওক",
"img-lang-default": "(ডিফল্ট ভাষা)",
"img-lang-go": "যাওক",
- "ascending_abbrev": "আৰোহণ",
- "descending_abbrev": "অৱতৰণ",
"table_pager_next": "পৰৱৰ্তী পৃষ্ঠা",
"table_pager_prev": "পূৰ্বৱৰ্তী পৃষ্ঠা",
"table_pager_first": "প্ৰথম পৃষ্ঠা",
"watchthis": "Vixilar esta páxina",
"savearticle": "Guardar la páxina",
"savechanges": "Guardar los cambios",
- "publishpage": "Publicar la páxina",
+ "publishpage": "Espublizar páxina",
"publishchanges": "Espublizar los cambeos",
"savearticle-start": "Guardar la páxina...",
"savechanges-start": "Guardar los cambios...",
- "publishpage-start": "Publicar la páxina...",
- "publishchanges-start": "Publicar los cambios...",
+ "publishpage-start": "Espublizar páxina...",
+ "publishchanges-start": "Espublizar los cambeos...",
"preview": "Vista previa",
"showpreview": "Amosar previsualización",
"showdiff": "Amosar cambeos",
"nocreate-loggedin": "Nun tienes permisu pa crear páxines nueves.",
"sectioneditnotsupported-title": "Nun hai sofitu pa editar seición",
"sectioneditnotsupported-text": "La edición de seición nun tien sofitu nesta páxina.",
+ "modeleditnotsupported-title": "Ensin encontu pa edición",
+ "modeleditnotsupported-text": "Nun hai encontu pa la edición nel modelu de conteníu $1.",
"permissionserrors": "Fallu de permisos",
"permissionserrorstext": "Nun tien permisu pa facer eso {{PLURAL:$1|pol siguiente motivu|polos siguientes motivos}}:",
"permissionserrorstext-withaction": "Nun tienes permisu pa $2 {{PLURAL:$1|pol siguiente motivu|polos siguientes motivos}}:",
"content-model-css": "CSS",
"content-json-empty-object": "Oxetu baleru",
"content-json-empty-array": "Matriz balera",
+ "unsupported-content-model": "<strong>Atención:</strong> El modelu de conteníu $1 nun tien encontu nesta wiki.",
+ "unsupported-content-diff": "Nun hai encontu de diffs pal modelu de conteníu $1.",
+ "unsupported-content-diff2": "Esta wiki nun tien encontu pa diffs ente los modelos de conteníu $1 y $2.",
"deprecated-self-close-category": "Páxines qu'utilicen etiquetes HTML autozarraes inválides",
"deprecated-self-close-category-desc": "Esta páxina contien etiquetes HTML autozarraes inválides, tales como <code><b/></code> o <code><span/></code>. El comportamientu d'estes va camudar llueu pa ser coherente cola especificación d'HTML5, polo qu'el so usu nel testu wiki ta en desusu.",
"duplicate-args-warning": "<strong>Avisu:</strong> [[:$1]] llama a [[:$2]] con más d'un valor pal parámetru «$3». Sólo va usase l'últimu valor dau.",
"search-interwiki-more-results": "más resultaos",
"search-relatedarticle": "Rellacionáu",
"search-invalid-sort-order": "Nun se reconoció la ordenación por $1, aplicaráse la ordenación predeterminada. Los tipos d'ordenación válidos son: $2",
+ "search-unknown-profile": "Nun se reconoz el perfil de busca $1; va aplicase'l perfil de busca predetermináu.",
"searchrelated": "rellacionáu",
"searchall": "toos",
"showingresults": "Abaxo s'{{PLURAL:$1|amuesa hasta <strong>un</strong> resultáu|amuesen <strong>$1</strong> resultaos}}, principando por #<strong>$2</strong>.",
"rcfilters-filter-showlinkedto-label": "Amosar los cambios nes páxines qu'enllacen a",
"rcfilters-filter-showlinkedto-option-label": "<strong>Páxines qu'enllacen a</strong> la páxina seleicionada",
"rcfilters-target-page-placeholder": "Escribe'l nome de la páxina (o categoría)",
+ "rcfilters-allcontents-label": "Tol conteníu",
+ "rcfilters-alldiscussions-label": "Tolos alderiques",
"rcnotefrom": "Abaxo {{PLURAL:$5|tá'l cambiu|tan los cambios}} dende'l <strong>$3</strong>, a les <strong>$4</strong> (s'amuesen un máximu de <strong>$1</strong>).",
"rclistfromreset": "Reaniciar la seleición de data",
"rclistfrom": "Amosar los nuevos cambios dende'l $3 a les $2",
"apihelp-no-such-module": "Nun s'alcuentra'l módulu «$1».",
"apisandbox": "Zona de pruebes API",
"apisandbox-jsonly": "Necesítase JavaScript pa usar la zona de pruebes de la API.",
- "apisandbox-api-disabled": "La API ta desactivada nesti sitiu.",
"apisandbox-intro": "Usa esta páxina pa esperimentar cola <strong>API de serviciu web de MediaWiki</strong>.\nConsulta [[mw:API:Main page|la documentación de la API]] pa más detalles tocante al so usu. Exemplu: [https://www.mediawiki.org/wiki/API#A_simple_example llamar al conteníu d'una Páxina principal]. Seleiciona una aición pa ver más exemplos.\n\nTen presente que, anque esto ye una zona de pruebes, les aiciones que faigas nesta páxina puen camudar la wiki.",
"apisandbox-submit": "Facer solicitú",
"apisandbox-reset": "Llimpiar",
"wlheader-enotif": "La notificación per corréu electrónicu ta activada.",
"wlheader-showupdated": "Les páxines que camudaron dende que les visitasti anteriormente amuesense en '''negrina'''",
"wlnote": "Abaxo {{PLURAL:$1|tá'l caberu cambiu|tan los caberos <strong>$1</strong> cambios}} {{PLURAL:$2|na cabera hora|nes caberes <strong>$2</strong> hores}}, a día $3, a les $4.",
- "wlshowlast": "Amosar les últimes $1 hores, los últimos $2 díes",
"watchlist-hide": "Anubrir",
"watchlist-submit": "Amosar",
"wlshowtime": "Periodu de tiempu a amosar:",
"changecontentmodel": "Cambiar el modelu de conteníu d'una páxina",
"changecontentmodel-legend": "Cambiar el modelu de conteníu",
"changecontentmodel-title-label": "Títulu de la páxina",
+ "changecontentmodel-current-label": "Modelu de conteníu actual:",
"changecontentmodel-model-label": "Nuevu modelu de conteníu",
"changecontentmodel-reason-label": "Motivu:",
"changecontentmodel-submit": "Camudar",
"month": "Dende'l mes (y anteriores):",
"year": "Dende l'añu (y anteriores):",
"date": "Dende la fecha (y anteriores):",
- "sp-contributions-newbies": "Amosar namái les contribuciones de cuentes nueves",
- "sp-contributions-newbies-sub": "Pa cuentes nueves",
- "sp-contributions-newbies-title": "Contribuciones d'usuariu pa cuentes nueves",
"sp-contributions-blocklog": "rexistru de bloqueos",
"sp-contributions-suppresslog": "collaboraciones {{GENDER:$1|del usuariu|de la usuaria}} suprimíes",
"sp-contributions-deleted": "collaboraciones {{GENDER:$1|del usuariu|de la usuaria}} desaniciaes",
"block-log-flags-angry-autoblock": "autobloquéu ameyoráu activáu",
"block-log-flags-hiddenname": "nome d'usuariu anubríu",
"range_block_disabled": "La capacidá d'alministrador pa crear bloqueos d'intervalos ta desactivada.",
+ "ipb-prevent-user-talk-edit": "Tien de permitise editar la páxina d'alderique propia nun bloquéu parcial, sacantes qu'incluya una torga nel espaciu de nomes Usuariu alderique.",
"ipb_expiry_invalid": "El tiempu de caducidá nun ye válidu.",
"ipb_expiry_old": "La fecha de caducidá ta pasada.",
"ipb_expiry_temp": "Los bloqueos a nomes d'usuariu tapecíos tienen de ser permanentes.",
"move-page-legend": "Treslladar páxina",
"movepagetext": "Usando'l siguiente formulariu vas renomar una páxina, treslladando'l so historial al nuevu nome.\nEl nome vieyu va convertise nuna páxina de redireición al títulu nuevu.\nPues actualizar les redireiciones qu'enllacien al títulu orixinal automáticamente.\nSi prefieres nun lo facer, asegúrate de que nun dexes [[Special:DoubleRedirects|redireiciones dobles]] o [[Special:BrokenRedirects|rotes]].\nTu yes el responsable de facer que los enllaces queden apuntando au se supón que tienen d'apuntar.\n\nRecuerda que la páxina <strong>nun</strong> va movese si yá hai una páxina col nuevu títulu, a nun ser que la mesma seya una redireición y nun tenga historial.\nEsto significa que pues volver a renomar una páxina col nome orixinal si t'enquivoques, y nun pues sobreescribir una páxina yá esistente.\n\n<strong>Nota:</strong>\nEsti pue ser un cambéu importante ya inesperáu pa una páxina popular;\npor favor, asegúrate d'entender les consecuencies de lo que vas facer enantes de siguir.",
"movepagetext-noredirectfixer": "Usando'l siguiente formulariu vas renomar una páxina, treslladando'l so historial al nuevu nome.\nEl nome vieyu va convertise nuna redireición al nuevu.\nAsegúrate de que nun dexes [[Special:DoubleRedirects|redireiciones dobles]] o [[Special:BrokenRedirects|rotes]].\nTu yes el responsable de facer que los enllaces queden apuntando au se supón qu'han apuntar.\n\nRecuerda que la páxina <strong>nun</strong> va movese si yá hai una páxina col nuevu títulu, a nun ser que tea balera o seya una redireición que nun tenga historial.\nEsto significa que pues volver a renomar una páxina col nome orixinal si t'enquivoques, y que nun pues sobreescribir una páxina yá esistente.\n\n<strong>Nota:</strong>\nEsti pue ser un cambéu importante y inesperáu pa una páxina popular;\npor favor, asegúrate d'entender les consecuencies de lo que vas facer enantes de siguir.",
+ "movepagetext-noredirectsupport": "Usando'l siguiente formulariu cambiaráse'l nome d'una páxina treslladando tol so historial al nome nuevu.\nYes responsable d'asegurate de que tolos enllaces siguen apuntando escontra onde tendríen de facelo.\n\nRecuerda que la páxina <strong>nun</strong> va treslladase si yá esiste una páxina col títulu nuevu.\nEsto significa que puedes devolver una páxina al so títulu orixinal si cometes un error, y que nun vas poder sustituir una páxina esistente.\n\n<strong>Atención:</strong>\nEsti pué ser un cambéu drásticu ya inesperáu para una páxina popular;\nasegúrate d'entender les consecuencies antes de siguir alantre.",
"movepagetalktext": "Si marques esti cuadru, la páxina d'alderique asociada va treslladase automáticamente al títulu nuevu, a nun ser que yá esista una páxina d'alderique non vacia allí.\n\nNesti casu tendrás que treslladar o fusionar la páxina manualmente si lo desees.",
"moveuserpage-warning": "'''Atención:''' Tas a piques de mover una páxina d'usuariu. Atalanta que namái se va mover la páxina y que ''nun'' se va renomar l'usuariu.",
"movecategorypage-warning": "<strong>Avisu:</strong> Tas a piques de treslladar una páxina de categoría. Ten en cuenta que sólo se treslladará la páxina y que cualquier páxina que tuviera na categoría antigua <em>nun</em> se recategorizará na nueva.",
"move-subpages": "Treslladar les subpáxines (hasta $1)",
"move-talk-subpages": "Treslladar les subpáxines de la páxina d'alderique (hasta $1)",
"movepage-page-exists": "La páxina $1 yá esiste y nun puede sustituise automáticamente.",
+ "movepage-source-doesnt-exist": "La páxina $1 nun esiste polo que nun puede treslladase.",
"movepage-page-moved": "Treslladóse la páxina $1 a $2.",
"movepage-page-unmoved": "Nun pudo treslladase la páxina $1 a $2.",
"movepage-max-pages": "Treslladóse'l máximu de $1 {{PLURAL:$1|páxina|páxinees}} y nun van treslladase más automáticamente.",
"delete_and_move_reason": "Desaniciada pa facer sitiu pa treslladar dende «[[$1]]»",
"selfmove": "El títulu ye'l mesmu;\nnun puede treslladase una páxina a ella mesma.",
"immobile-source-namespace": "Nun pueden treslladase páxines nel espaciu de nomes «$1».",
+ "immobile-source-namespace-iw": "Les páxines d'otres wikis nun pueden treslladase dende esta.",
"immobile-target-namespace": "Nun pueden treslladase páxines al espaciu de nomes «$1».",
"immobile-target-namespace-iw": "Nun puedes mover una páxina a un enllaz d'Interwiki.",
"immobile-source-page": "Esta páxina nun ye treslladable.",
"immobile-target-page": "Nun puede treslladase a esi títulu de destín.",
+ "movepage-invalid-target-title": "El nome solicitáu nun ye válidu.",
"bad-target-model": "El destín deseáu utiliza un modelu de conteníu diferente. Nun se pue convertir de $1 a $2.",
"imagenocrossnamespace": "Nun puede treslladase un ficheru a un espaciu de nomes que nun ye de ficheros.",
"nonfile-cannot-move-to-file": "Nun se pue treslladar más que ficheros al espaciu de nomes de ficheros",
"tooltip-ca-nstab-category": "Ver la páxina de categoría",
"tooltip-minoredit": "Marcar como una edición menor",
"tooltip-save": "Guardar los cambios",
- "tooltip-publish": "Publicar los cambeos",
+ "tooltip-publish": "Espublizar los cambeos",
"tooltip-preview": "Vista previa de los cambios, ¡usa esto enantes de guardar!",
"tooltip-diff": "Amuesa los cambios que fixisti nel testu.",
"tooltip-compareselectedversions": "Ver les diferencies ente les dos revisiones seleicionaes d'esta páxina.",
"newimages-legend": "Peñera",
"newimages-label": "Nome d'archivu (o una parte d'él):",
"newimages-user": "Direición IP o nome d'usuariu",
- "newimages-newbies": "Amosar namái les contribuciones de cuentes nueves",
"newimages-showbots": "Ver les xubíes de los bots",
"newimages-hidepatrolled": "Despintar les entraes patrullaes",
"newimages-mediatype": "Tipu de mediu:",
"img-lang-default": "(llingua predeterminada)",
"img-lang-info": "Representar esta imaxe en $1. $2",
"img-lang-go": "Dir",
- "ascending_abbrev": "asc",
- "descending_abbrev": "desc",
"table_pager_next": "Páxina siguiente",
"table_pager_prev": "Páxina anterior",
"table_pager_first": "Primera páxina",
"permanentlink": "Enllaz permanente",
"permanentlink-revid": "ID de la revisión",
"permanentlink-submit": "Dir a la revisión",
+ "newsection": "Seición nueva",
+ "newsection-page": "Páxina de destín",
+ "newsection-submit": "Dir a páxina",
"dberr-problems": "¡Sentímoslo! Esti sitiu ta esperimentando dificultaes téuniques.",
"dberr-again": "Tenta esperar dellos minutos y recargar.",
"dberr-info": "(Nun hai accesu a la base de datos: $1)",
"linkaccounts": "Enllazar cuentes",
"linkaccounts-success-text": "Enllazóse la cuenta.",
"linkaccounts-submit": "Enllazar cuentes",
+ "cannotunlink-no-provider-title": "Nun hai cuentes enllazaes que desenllazar",
+ "cannotunlink-no-provider": "Nun hai cuentes enllazaes que puedan desenllazase.",
"unlinkaccounts": "Desenllazar cuentes",
"unlinkaccounts-success": "Desenllazóse la cuenta.",
"authenticationdatachange-ignored": "Nun se xestionó'l cambéu de los datos d'autentificacion. ¿Seique, nun se configuró un fornidor?",
"edit-error-short": "Error: $1",
"edit-error-long": "Errores:\n\n$1",
"specialmute": "Silenciar",
+ "specialmute-success": "Anováronse les tos preferencies de silenciu. Mira tolos usuarios silenciaos [[Special:Preferences|nes tos preferencies]].",
"specialmute-submit": "Confirmar",
+ "specialmute-label-mute-email": "Silenciar los correos electrónicos d'esti usuariu",
+ "specialmute-header": "Escueye les tos preferencies de silenciu pa <b>{{BIDI:[[User:$1|$1]]}}</b>.",
+ "specialmute-error-invalid-user": "Nun s'atopó'l nome d'usuariu solicitáu.",
+ "specialmute-error-no-options": "Les funciones de silenciu nun tán disponibles. Esto pué asoceder porque: nun confirmasti la to direición de corréu o un alministrador de la wiki desactivó funciones de corréu y/o de llista prieta de corréu pa esta wiki.",
+ "specialmute-email-footer": "P'alministrar les preferencies de corréu electrónicu pal usuariu {{BIDI:$2}} visita <$1>.",
+ "specialmute-login-required": "Anicia sesión pa cambiar les tos preferencies de silenciu.",
+ "mute-preferences": "Preferencies de silenciu",
"revid": "revisión $1",
"pageid": "ID de páxina $1",
"interfaceadmin-info": "$1\n\nLos permisos pa editar los ficheros CSS, JS y JSON globales del sitiu dixebráronse apocayá del permisu <code>editinterface</code>. Si nun entiendes por qué recibes esti error, llei [[mw:MediaWiki_1.32/interface-admin]].",
"blanknamespace": "(Аслияб)",
"contributions": "{{GENDER:$1|ГӀахьалчиясул}} хӀалтӀи",
"mycontris": "Дур хӀалтӀи",
- "sp-contributions-newbies": "ГІицІго, цІиял гІахьалчагІаз гьабураб хІалтІи бихьизабизе",
"sp-contributions-talk": "гьоркьоб лъей",
"sp-contributions-userrights": "ГІахьалчиясул ихтиярал",
"sp-contributions-search": "ХІалтІи хъирщизе",
"wlheader-enotif": "Email walzera tir tegisa.",
"wlheader-showupdated": "Bu betayanu mali rinafa ironokafa worara tir <strong>sulatcalakorafu</strong>.",
"wlnote": "Valeveon tigid <strong>$1</strong> bocafa betara mali {{PLURAL:$2|ironokaf bartiv|<strong>$2</strong> ironokaf bartiv}}, wetce ra ke $3, $4.",
- "wlshowlast": "Nedira va ironokaf $1 bartiv isu $2 viel",
"watchlist-options": "Suzdaxolkeem",
"watching": "Nedis...",
"unwatching": "Menedis...",
"uctop": "noelaf",
"month": "Mali aksat (is logaveon) :",
"year": "Mali ilana (is logaveon) :",
- "sp-contributions-newbies": "Anton nedira va warzafavesikaf webekseem",
- "sp-contributions-newbies-sub": "Tori warzaf favesikeem",
"sp-contributions-blocklog": "Elekara va \"log\" bu",
"sp-contributions-deleted": "Sulayan favesikaf webeks",
"sp-contributions-uploads": "kalvajara",
"imgmultipagenext": "direbu →",
"imgmultigo": "Askí !",
"imgmultigoto": "Grablera kal $1 bu",
- "ascending_abbrev": "tid-",
- "descending_abbrev": "tit-",
"table_pager_next": "Radimefu bu",
"table_pager_prev": "Abduefu bu",
"table_pager_first": "Taneafu bu",
"apihelp-no-such-module": "मोड्युल \"$1\" नाइ मिला ।",
"apisandbox": "एपीआई प्रयोगस्थल",
"apisandbox-jsonly": "एपीआई प्रयोगपृष्ठ का उपयोग करने हेतु जावास्क्रिप्ट अनिवार्य है।",
- "apisandbox-api-disabled": "इ साइट पे ए.पी.आइ अक्षम है ।",
"apisandbox-intro": "इस पृष्ठ का उपयोग <strong>मीडियाविकि वेब एपीआई</strong> के लिए करें। इसके उपयप्ग हेतु देखें: [[mw:API:Main page|एपीआई प्रलेखन]] उदाहरण: [https://www.mediawiki.org/wiki/API#A_simple_example मुख्यपृष्ठ के सामग्री हेतु]",
"apisandbox-submit": "अनुरोध करा जाय",
"apisandbox-reset": "स्पष्ट",
"wlheader-enotif": "ई-मेल नोटिफ़िकेशन सक्षम है।",
"wlheader-showupdated": "पन्ना जवन आपकय द्वारा देखय जाएक बाद बदलि गा है '''बोल्ड''' मे देखाइ।",
"wlnote": "$3 को $4 बजे तक पिछले <strong>$2</strong> {{PLURAL:$2|घंटे|घंटों}} में {{PLURAL:$1|हुआ एक|हुए <strong>$1</strong>}} परिवर्तन निम्न {{PLURAL:$1|है|हैं}}।",
- "wlshowlast": "पिछला $1 घंटा $2 दिन देखा जाय",
"watchlist-hide": "लुकुवावा",
"watchlist-submit": "देखावा",
"wlshowtime": "अंतिम दिखाएँ:",
"month": "इ महिन्नासे (औ पुरान):",
"year": "इ सालसे (औ पुरान):",
"date": "दिनांक से (प्रारम्भ)",
- "sp-contributions-newbies": "खालि नँवा सदस्यन् कय योगदान देखावा जाय",
- "sp-contributions-newbies-sub": "नँवा सदस्यन कय खर्तीन",
- "sp-contributions-newbies-title": "नँवा सदस्यन् कय योगदान",
"sp-contributions-blocklog": "ब्लॉक सूची",
"sp-contributions-suppresslog": "छुपाए गए {{GENDER:$1|सदस्य}} के योगदान",
"sp-contributions-deleted": "हटाए गए {{GENDER:$1|सदस्य}} योगदान",
"newimages-legend": "छनना",
"newimages-label": "फाइल नाँव (या ओकर अंश):",
"newimages-user": "आईपी पता या सदस्यनाम",
- "newimages-newbies": "केवल नये खातों के योगदान दिखायें",
"newimages-showbots": "बाट कय अपलोड देखावा जाय",
"newimages-hidepatrolled": "जाँचा हुआ अपलोड छुपाएँ",
"newimages-mediatype": "मीडिया प्रकार:",
"img-lang-default": "(डिफ़ॉल्ट भाषा)",
"img-lang-info": "इस चित्र को $1. $2 में ढालें",
"img-lang-go": "जावा जाय",
- "ascending_abbrev": "asc",
- "descending_abbrev": "desc",
"table_pager_next": "अगला पन्ना",
"table_pager_prev": "पिछला पन्ना",
"table_pager_first": "पहिला पन्ना",
"viewyourtext": "Bu səhifəyə <strong>etdiyiniz dəyişikliklərin</strong> mənbəyinə baxa və köçürə bilərsiniz.",
"protectedinterface": "Bu səhifədə proqram təminatı üçün sistem məlumatları var və sui-istifadənin qarşısını almaq üçün mühafizə olunmalıdır.",
"editinginterface": "<strong>Diqqət:</strong> Siz proqram təminatı üçün interfeys mətni olan səhifəni redaktə edirsiniz.\nOnun dəyişdirilməsi digər istifadəçilərin interfeysinin xarici görünüşünə təsir göstərəcək.",
- "translateinterface": "Bütün vikilər üçün tərcümələri əlavə etmək və ya dəyişmək üçün, xahiş edirik MediaWiki lokallaşdırma layihəsi [https://translatewiki.net/ translatewiki.net]-i istifadə edin.",
+ "translateinterface": "Bütün vikilərə tərcümələr əlavə etmək və ya onları dəyişmək üçün xahiş edirik, MediaWiki lokallaşdırma layihəsi olan [https://translatewiki.net/ translatewiki.net] saytından istifadə edin.",
"cascadeprotected": "Bu səhifə mühafizə olunub, çünki o, kaskad mühafizə olunan {{PLURAL:$1|aşağıdakı səhifədə|aşağıdakı səhifələrdə}} istifadə edilib:\n$2",
"namespaceprotected": "Sizin adlarında $1 olan məqalələrdə redaktə etməyə icazəniz yoxdur.",
"customcssprotected": "Bu səhifəni redaktə etmə izniniz yoxdur, çünki bu səhifə başqa bir istifadəçinin fərdi parametrlərinə sahibdir.",
"wlheader-enotif": "E-məktubla bildiriş aktivdir.",
"wlheader-showupdated": "Sizin son ziyarətinizdən sonra edilən dəyişikliklər '''qalın şriftlə''' göstərilmişdir.",
"wlnote": "Aşağıda $3 tarixi və saat $4 üçün olan son {{PLURAL:$2|bir saatda|<strong>$2</strong> saatda}} edilmiş {{PLURAL:$1|son bir dəyişiklik|son <strong>$1</strong> dəyişiklik}} göstərilmişdir.",
- "wlshowlast": "Son $1 saatı $2 günü göstər",
"watchlist-hide": "Gizlət",
"watchlist-submit": "Göstər",
"wlshowhideminor": "kiçik redaktələr",
"uctop": "hal-hazırkı",
"month": "Ay",
"year": "Axtarışa bu tarixdən etibarən başla:",
- "sp-contributions-newbies": "Ancaq yeni istifadəçilərin fəaliyyətlərini göstər",
- "sp-contributions-newbies-sub": "Yeni istifadəçilər üçün",
- "sp-contributions-newbies-title": "Yeni hesablar üçün istifadəçi fəaliyyətləri",
"sp-contributions-blocklog": "bloklama qeydləri",
"sp-contributions-deleted": "silinmiş istifadəçi fəaliyyətləri",
"sp-contributions-uploads": "yüklənənlər",
"imgmultigo": "Seç!",
"imgmultigoto": "$1 səhifəyə get",
"img-lang-go": "Get",
- "ascending_abbrev": "artma sırasına görə",
- "descending_abbrev": "azalma sırasına görə",
"table_pager_next": "Sonrakı səhifə",
"table_pager_prev": "Əvvəlki səhifə",
"table_pager_first": "İlk səhifə",
"wlheader-enotif": "ایمیل ایله بیلدیریش آچیلیبدیر.",
"wlheader-showupdated": "سون گؤروشونوزدن سوْنرا ائدیلن دییشیکلیکلر '''قالین''' گؤرسدیلیبدیر.",
"wlnote": "آشاغیداکی {{PLURAL:$1|بیر ديَیشیکلیک|<strong>$1</strong> ديَیشیکلیک}} سون {{PLURAL:$2|ساعتدا|<strong>$2</strong> ساعتدا}} ائدیلمیشدیر. $3، $4",
- "wlshowlast": "سون $1 ساعات $2 گون گؤستر",
"watchlist-hide": "گیزلت",
"wlshowtime": "بو تاریخه قدر گؤستر:",
"wlshowhideminor": "کیچیک دَییشدیرمهلر",
"uctop": "ایندیکی",
"month": "بۇ آیدان (و قاباقجا):",
"year": "بۇ ایلدن (و قاباقجا):",
- "sp-contributions-newbies": "تکجه یئنی ایشلدنلرین چالیشمالارینی گؤستر",
- "sp-contributions-newbies-sub": "یئنی ایستیفادهچیلر اوچون",
- "sp-contributions-newbies-title": "یئنی حسابلار اوچون ایستیفادهچی فالیتلری",
"sp-contributions-blocklog": "باغلاما ژورنالی",
"sp-contributions-suppresslog": "باسدیریلمیش ایشلدن فعالیتلری",
"sp-contributions-deleted": "سیلینمیش ایشلدن چالیشمالاری",
"img-lang-default": "(وارساییلان دیل)",
"img-lang-info": "بو عکسی $1-ده گؤستر. $2",
"img-lang-go": "گئت",
- "ascending_abbrev": "آرتما سیراسینا گؤره",
- "descending_abbrev": "آزالما سیراسینا گؤره",
"table_pager_next": "سوْنراکی صفحه",
"table_pager_prev": "قاباقکی صفحه",
"table_pager_first": "بیرینجی صفحه",
"category-empty": "<em>Был категория әлегә буш.</em>",
"hidden-categories": "{{PLURAL:$1|Йәшерен категория|Йәшерен категориялар}}",
"hidden-category-category": "Йәшерен категориялар",
- "category-subcat-count": "{{PLURAL:$2|Был категорияла тик киләһе эске категория ғына бар.|Барлығы $2 категориянан, был категорияла киләһе {{PLURAL:$1|эске категория|$1 эске категория}} күрһәтелә.}}",
+ "category-subcat-count": "{{PLURAL:$2|1=Был категорияла бер генә эске категория бар.|Был категориялағы барыһы $2 эске категорияның {{PLURAL:$1|$1 эске категорияһы}} күрһәтелгән.}}",
"category-subcat-count-limited": "Был категорияға киләһе {{PLURAL:$1|эске категория|$1 эске категория}} ингән.",
- "category-article-count": "{{PLURAL:$2|1=Ð\91Ñ\8bл каÑ\82егоÑ\80иÑ\8fла беÑ\80 генÓ\99 биÑ\82 баÑ\80.|Ð\9aаÑ\82егоÑ\80иÑ\8fлаÒ\93Ñ\8b $2 биÑ\82Ñ\82ең $1 биÑ\82е күрһәтелгән.}}",
+ "category-article-count": "{{PLURAL:$2|1=Ð\91Ñ\8bл каÑ\82егоÑ\80иÑ\8fла беÑ\80 генÓ\99 биÑ\82 баÑ\80.|Ð\91Ñ\8bл каÑ\82егоÑ\80иÑ\8fла бÑ\83лÒ\93ан $2 биÑ\82Ñ\82ең {{PLURAL:$1|$1 биÑ\82е}} күрһәтелгән.}}",
"category-article-count-limited": "Был категорияла {{PLURAL:$1|$1 бит}} бар.",
"category-file-count": "{{PLURAL:$2|Был категорияла бер генә файл бар.|Категориялағы $2 файлдың {{PLURAL:$1|$1 файлы күрһәтелгән}}.}}",
"category-file-count-limited": "Был категорияла {{PLURAL:$1|$1 файл}} бар.",
"apihelp-no-such-module": "«$1» модуле табылмаған.",
"apisandbox": "API һынау урыны",
"apisandbox-jsonly": " API-һынап ҡарау урыны өсөн JavaScript талап ителә.",
- "apisandbox-api-disabled": "Был сайтта API һүндерелгән.",
"apisandbox-intro": "Был битте <strong>MediaWiki API</strong> менән тәжрибәләр өсөн ҡулланығыҙ. API ҡулланыуҙа тулыраҡ мәғлүмәт өсөн [[mw:API:Main page| API документацияһы]] мөрәжәғәт итегеҙ. Мәҫәлән, [https://www.mediawiki.org/wiki/API#A_simple_example Баш биттең йөкмәткеһен нисек алырға]. Башҡа миҫалдарҙы ҡарау өсөн ғәмәл һайлағыҙ. Иғтибар, тәжрибәләр өсөн ҡулланылһа ла, был биттә башҡарылған ғәмәлдәр викиға үҙгәрештәр индерә ала.",
"apisandbox-submit": "Һоратыу яһарға",
"apisandbox-reset": "Таҙарт",
"wlheader-enotif": "Электрон почта аша белдереү индерелгән.",
"wlheader-showupdated": "Һеҙҙең аҙаҡҡы кереүегеҙҙән һуң үҙгәргән биттәр '''ҡалын''' шрифт менән күрһәтелгән.",
"wlnote": "Түбәндә $3 $4 ваҡытына тиклем аҙаҡҡы {{PLURAL:$2|1=сәғәт|'''$2''' сәғәт}} эсендә эшләнгән {{PLURAL:$1|1=үҙгәртеү|'''$1''' үҙгәртеү}} күрһәтелгән.",
- "wlshowlast": "Һуңғы $1 сәғәт $2 көн эсендәгеһен күрһәтеү",
"watchlist-hide": "Йәшереү",
"watchlist-submit": "Күрһәтергә",
"wlshowtime": "Күрһәтеү өсөн ваҡыт арауығы",
"uctop": "ағымдағы",
"month": "Айҙан башлап (һәм элегерәк):",
"year": "Йылдан башлап (һәм элегерәк):",
- "sp-contributions-newbies": "Яңы иҫәп яҙмалары башҡарған эште генә күрһәтергә",
- "sp-contributions-newbies-sub": "Яңы иҫәп яҙмалары өсөн",
- "sp-contributions-newbies-title": "Яңы теркәлгән ҡатнашыусылар башҡарған эш",
"sp-contributions-blocklog": "блоклау яҙмалары",
"sp-contributions-suppresslog": "{{GENDER:$1|Ҡатнашыусы}} юйылған өлөшө",
"sp-contributions-deleted": "{{GENDER:$1|Ҡатнашыусы}} юйылған үҙгәртеүҙәре",
"newimages-legend": "Һайлау",
"newimages-label": "Файл исеме (йәки өлөшө):",
"newimages-user": "Ҡатнашыусының исеме һәм IP-адресы",
- "newimages-newbies": "Яңы иҫәп яҙмалары индергән өлөштө генә күрһәтергә",
"newimages-showbots": "Роботтан тейегәнде күрһәтергә",
"newimages-hidepatrolled": "Патрулләнгән күсереүҙәрҙе йәшерергә",
"newimages-mediatype": "Медиа төрө:",
"img-lang-default": "(килешеү буйынса тел)",
"img-lang-info": "Был рәсемде $1 $2 телдәрендә күрһәтергә",
"img-lang-go": "Күсергә",
- "ascending_abbrev": "үҫеүгә табан",
- "descending_abbrev": "кәмеүгә табан",
"table_pager_next": "Киләһе бит",
"table_pager_prev": "Алдағы бит",
"table_pager_first": "Беренсе бит",
"tog-watchlisthideliu": "engkebang suntingan penganggen malebu log ring kepahan pangiwasan",
"tog-watchlisthideanons": "engkebangsuntingan penganggen tan maadan ring kepahan pangiwasan",
"tog-watchlisthidepatrolled": "engkebang panguwahan mapatrol kepahan pangiwasan",
+ "tog-watchlisthidecategorization": "Engkebang katégorisasi kacané",
"tog-ccmeonemails": "kirimang titiang salinan email sane kirimang titiang ring anak lianan",
"tog-diffonly": "sampunang katampilang daging lembar ring ungkur binanne suntingan",
"tog-showhiddencats": "tampilang golongan sane kaengkebang",
"pagecategories": "{{PLURAL:$1|Kategori}}",
"category_header": "Kaca ring ketegori \"$1\"",
"subcategories": "Subkategori",
- "category-media-header": "lembar ring golongan \"$1\"",
+ "category-media-header": "Média ring kategori \"$1\"",
"category-empty": "\"mangkin, nenten madaging lembar utawi pekakas ring golongan puniki\"",
"hidden-categories": "{{plural:$1|punduhan sane kaengkebang| punduhan sane kaengkebang}}",
"hidden-category-category": "Kategori mengkeb",
"category-article-count": "{{PLURAL:$2|golongan puniki madue{{PLURAL:$1|$1 lembar}}, saking total $2.}}",
"category-file-count": "{{PLURAL:$2|golongan puniki madue{{PLURAL:$1|$1 lembar}}, saking total $2.}}",
"listingcontinuesabbrev": "lant.",
+ "index-category": "Lembar sane maindeks",
"noindex-category": "Lembar sane nenten maindeks",
"broken-file-category": "Suratan sane ngelah pranala usak",
"about": "Indik",
"article": "Kaca daging",
"newwindow": "(bukak ring jendela anyar)",
- "cancel": "Buwung",
+ "cancel": "Wangdé",
"moredotdotdot": "Lianan...",
"mypage": "Kaca",
"mytalk": "Pabligbagan",
"talk": "Pabligbagan",
"views": "Pakantenan",
"toolbox": "Pekakas",
+ "tool-link-emailuser": "Kirim surel ring {{GENDER:$1|pengguna}} puniki",
"imagepage": "Cingak kaca berkas",
"mediawikipage": "Cingak kaca séwalapatra",
"templatepage": "Cingak kaca cétakan",
"jumpto": "Lanturang ka:",
"jumptonavigation": "navigasi",
"jumptosearch": "rereh",
+ "pool-errorunknown": "Iwang sané durung kauningin",
"aboutsite": "Indik {{SITENAME}}",
"aboutpage": "Project:Indik",
"copyrightpage": "{{ns:project}}:hak cipta",
"ok": "OK",
"retrievedfrom": "Kapolihang saking \"$1\"",
"youhavenewmessages": "{{PLURAL:$3|Jero madué}} $1 ($2)",
- "youhavenewmessagesfromusers": "{{PLURAL:$4|You have}} $1 ring {{PLURAL:$3|another user|$3 users}} ($2).",
+ "youhavenewmessagesfromusers": "{{PLURAL:$4|Ida dané madué}} $1 saking {{PLURAL:$3|$3 sang anganggé lianan}} ($2).",
"youhavenewmessagesmanyusers": "Jero madué $1 saking akéh sang anganggé ($2).",
"newmessageslinkplural": "{{PLURAL:$1|séwalapatra anyar abesik|999=séwalapatra anyar}}",
"youhavenewmessagesmulti": "Ida dané madué séwalapatra anyar ring $1",
"confirmable-no": "Nénten",
"viewdeleted": "Cingak $1?",
"restorelink": "{{PLURAL:$1|siki uahan sané kausapin|$1 uahan sané kausapin}}",
+ "feedlinks": "Asupan:",
+ "feed-invalid": "Tipe permintaan asupan tusing beneh.",
"site-atom-feed": "$1 \"atom feed\"",
"page-atom-feed": "$1 \"atom feed\"",
"red-link-title": "$1 (kaca nénten wénten)",
"nospecialpagetext": "<strong>Ida nagih kaca pinih luwih sane nenten patut.</strong>\n\nWacakan kaca pinih luwih dados kacingak ring [[Special:SpecialPages|{{int:specialpages}}]].",
"error": "Kaiwangan",
"databaseerror": "Database kaluputan",
+ "databaseerror-query": "Kueri: $1",
+ "databaseerror-function": "Pungsi: $1",
+ "databaseerror-error": "Pelih: $1",
"missing-article": "data utama nenten prasida nemu tulisan saking lembar sane sepatutne wenten, inggih punika $1, $2\n\nindike puniki biasane keranayang olih pranala kaon nuju pabenahan sane dumun lembar sane sampun kaicalang\n\nyening nenten puniki sane ngranayang, ida dane minab sampun manggihin kaiwangang ring sajeroning piranti lunak.\nDurus sadokang indik puniki rin silih sinunggil anak \n\n[[Special:ListUsers/sysop|Pengurus]], antuk ngetik alamat URL sane katuju",
"missingarticle-rev": "(pabenahan#:$1)",
"badtitle": "murda sane nenten manut",
"pt-createaccount": "Ngaryanin akun",
"pt-userlogout": "Medal log",
"botpasswords-label-create": "Ngae",
- "botpasswords-label-cancel": "Buungan",
+ "botpasswords-label-cancel": "Wangdé",
"botpasswords-label-delete": "Usap",
"botpasswords-label-resetpassword": "Nyumu kruna sandi",
+ "resetpass-submit-cancel": "Wangdé",
"passwordreset": "Nyumu kruna sandi",
"bold_sample": "teks puniki mesurat tebel",
"bold_tip": "teks puniki mesurat tebel",
"prefs-help-email-others": "ida dane prasida milih anggen ngalugrain anak lianan ngubungin ida dane majalaran lembar penganggen utawi pangraos nenten ja perlu ngagah indik padewekan ida dane",
"prefs-editor": "Sang anguah",
"group-bot": "Bot",
+ "group-sysop": "Prajuru",
"grouppage-bot": "{{ns:project}}:Bot",
"right-edit": "Uah kaca",
"right-writeapi": "nganggén API sasuratan",
"action-browsearchive": "rereh kaca sané kausapin",
"action-editprotected": "uah kaca sané kasaibin \"{{int:protect-level-sysop}}\"",
"action-editsemiprotected": "uah kaca sané kasaibin \"{{int:protect-level-autoconfirmed}}\"",
- "nchanges": "$1{{PLURAL:$1|panguwahan|uwah-uwahan}}",
+ "nchanges": "$1 {{PLURAL:$1|uahan}}",
"enhancedrc-history": "babad",
"recentchanges": "Uahan sané mangkin",
"recentchanges-legend": "Opsi uahan sané mangkin",
"recentchanges-label-minor": "Punika uahan alit",
"recentchanges-label-bot": "Uahan puniki kalaksanayang antuk bot",
"recentchanges-label-unpatrolled": "Uahan puniki durung kapatroli",
- "recentchanges-label-plusminus": "Pagentos akeh kaca manut ring bita",
+ "recentchanges-label-plusminus": "Agengnyané kacané kauahin antuk akéhnyané bita puniki",
"recentchanges-legend-heading": "<strong>Legenda:</strong>",
"recentchanges-legend-newpage": "{{int:recentchanges-label-newpage}} (taler cingak [[Special:NewPages|bacakan kaca anyar]])",
"recentchanges-submit": "Sinahang",
"rcfilters-activefilters-show": "Sinahang",
"rcfilters-savedqueries-remove": "Usap",
+ "rcfilters-savedqueries-cancel-label": "Wangdé",
"rcfilters-filter-minor-label": "Uahan alit",
"rcfilters-filter-major-label": "Uahan tan alit",
"rcfilters-filter-pageedits-label": "Uahan kaca",
"uploadlogpage": "Log unggahan",
"filedesc": "Ringkesan",
"savefile": "Raksa berkas",
+ "upload-dialog-button-cancel": "Wangdé",
"upload-dialog-button-save": "Raksa",
"backend-fail-delete": "Tan prasida ngusapin berkas \"$1\".",
"license": "kepahan lugra",
"filehist-datetime": "Tanggal/Galah",
"filehist-thumb": "Miniatur",
"filehist-thumbtext": "miniatur anggen versi ring $1",
+ "filehist-nothumb": "Tusing ade miniatur",
"filehist-user": "Sang anganggé",
"filehist-dimensions": "ukuran",
"filehist-comment": "tureksa",
"imagelinks": "Panganggén depukan",
"linkstoimage": "{{PLURAL:$1|Kaca|$1 kaca}} ring sor puniki nganggén depukan puniki:",
"nolinkstoimage": "Nénten wénten kaca sané nganggén berkas puniki.",
+ "linkstoimage-redirect": "$1 (gingsiran berkas) $2",
"sharedupload-desc-here": "Depukan puniki mawit saking $1 lan minab kaanggén olih proyék-proyék sané lianan. Déskripsinnyané ring [$2 kaca déskripsi depukannyané] kaarahin ring ungkur puniki.",
"filepage-nofile": "Nentén wénten berkas sané mamurda sakadi punika",
"shared-repo-name-wikimediacommons": "Wikimedia Commons",
"watchlistfor2": "Anggén $1 $2",
"watch": "cingak",
"unwatch": "tan sida maninjo",
- "watchlist-details": "{{PLURAL:$1|$1 lembar}} ring paninjoan ida dane, nenten sareng lembar wacana.",
- "wlshowlast": "Sinahang $1 jam $2 rahina sané lintang",
+ "watchlist-details": "{{PLURAL:$1|$1 kaca}} wénten ring bacakan pantauan ida dané (rumasuk kaca pabligbagan).",
"watchlist-submit": "Sinahang",
"wlshowhideminor": "uahan alit",
"watchlist-options": "milih kepahan peninjo",
"actioncomplete": "pelaksanan sampun wusan",
"actionfailed": "pelaksana luput",
"dellogpage": "log pangapus",
+ "rollback-confirmation-no": "Wangdé",
"rollbacklink": "mabalik",
"rollbacklinkcount": "balikang $1 {{PLURAL:$1|suratan}}",
"changecontentmodel-title-label": "Murda kaca",
"uctop": "sane mangkin",
"month": "Saking sasih (miwah sadurungnyané)",
"year": "Saking warsa (miwah sadurungnyané):",
- "sp-contributions-newbies": "Cingak pituut wantah saking akun anyar",
"sp-contributions-blocklog": "log pemblokiran",
"sp-contributions-deleted": "pituut {{GENDER:$1|sang anganggé}} sané kausapin",
"sp-contributions-uploads": "unggahan",
"whatlinkshere-title": "lembar-lembar sane maduwe pranala kaping \"$1\"",
"whatlinkshere-page": "Kaca:",
"linkshere": "lembar puniki maduwe pranala ke '''$2'''",
- "nolinkshere": "lembar puniki maduwe pranala ke '''$2'''",
+ "nolinkshere": "Nénten wénten kaca sané madué pranala ring <strong>$2</strong>.",
"isredirect": "Kaca gingsiran",
"istemplate": "sareng kasurat",
"isimage": "pranala pupulan-pupulan",
"tooltip-ca-unprotect": "Uah saiban kaca puniki",
"tooltip-ca-delete": "Usap kaca puniki",
"tooltip-ca-move": "Gingsirang kaca puniki",
- "tooltip-ca-watch": "imbuhin lembar niki ring daftar paninjoan ida dane",
+ "tooltip-ca-watch": "Imbuhin kaca puniki ring bacakan pantauan ida dané",
"tooltip-ca-unwatch": "apus lembar niki ring daftar paninjoan ida dane",
"tooltip-search": "Rereh ring {{SITENAME}}",
"tooltip-search-go": "Rereh kaca sané mapeséngan pateh sakadi puniki yéning wénten",
"tooltip-search-fulltext": "Rereh kaca sané madaging sesuratan puniki",
"tooltip-p-logo": "Cingak kaca utama",
- "tooltip-n-mainpage": "nuju lembar sane utama",
+ "tooltip-n-mainpage": "Cingak kaca utama",
"tooltip-n-mainpage-description": "Cingak kaca utama",
"tooltip-n-portal": "Indik proyék, sané prasida kalaksanayang, genah ngrereh wantuan",
"tooltip-n-currentevents": "Rereh pidarta indik kawéntenan sané pinih anyar",
"tooltip-t-upload": "Unggahang depukan",
"tooltip-t-specialpages": "Bacakan makasami kaca kusus",
"tooltip-t-print": "Vérsi cétak kaca puniki",
- "tooltip-t-permalink": "Pranala ajeg kaanggen ngubah lembar puniki",
+ "tooltip-t-permalink": "Pranala ajeg anggén révisinnyané kacané puniki",
"tooltip-ca-nstab-main": "Cingak kaca daging",
"tooltip-ca-nstab-user": "Cingak kaca sang anganggé",
"tooltip-ca-nstab-special": "Puniki kaca kusus tur nénten prasida kauwah",
"pageinfo-firstuser": "Sang makarya kaca",
"pageinfo-firsttime": "Galah ritatkala ngripta kaca",
"pageinfo-lastuser": "Panguwah sané pinih anyar",
- "pageinfo-lasttime": "Galah antuk uwahan sané pinih anyar",
+ "pageinfo-lasttime": "Galah antuk uahan sané pinih anyar",
"pageinfo-edits": "Akéh nomer sané kauwah",
"pageinfo-authors": "Akéh nomer makasami antuk panyurat sané lianan",
"pageinfo-recent-edits": "Akéh nomer sané kauwah (ring $1 sané sampun lintang)",
"previousdiff": "← Uahan sadurungnyané",
"nextdiff": "Uahan sané pinih anyar →",
"widthheightpage": "$1 × $2, $3 {{PLURAL:$3|kaca}}",
- "file-info-size": "$1x$2 piksel, ukuran depukan: $3, tipe MIME:$4",
+ "file-info-size": "$1x$2 piksel, agengnyané depukan: $3, soroh MIME:$4",
+ "file-info-size-pages": "$1 × $2 piksel, agengnyané berkas: $3, soroh MIME: $4, $5 {{PLURAL:$5|kaca}}",
"file-nohires": "tan kasayagaang ukuran sane lewih ageng",
- "svg-long-desc": "pupulan SVG, nominal $1 × $2 piksel, geden pupulan: $3",
+ "svg-long-desc": "Berkas SVG, jimbarnyané $1 × $2 piksel, agengnyané berkas: $3",
"show-big-image": "Depukan sujati",
- "show-big-image-preview": "agengnyané pratuduh:$1",
+ "show-big-image-preview": "Agengnyané pratuduh puniki: $1.",
"show-big-image-other": "{{PLURAL:$2|Resolusi}} iianan: $1.",
"show-big-image-size": "$1 × $2 piksel",
"sunday-at": "Redite jam $1",
"metadata-fields": "Widang métadata gambar sané kacantumang ring séwalapatra puniki jagi kalebuang ring tampilan kaca gambar ri tatkala tabél métadata kacenikang.\nSané lianan jagi kasenetang.\n* make\n* model\n* datetimeoriginal\n* exposuretime\n* fnumber\n* isospeedratings\n* focallength\n* artist\n* copyright\n* imagedescription\n* gpslatitude\n* gpslongitude\n* gpsaltitude",
"namespacesall": "samian",
"monthsall": "samian",
+ "confirmemail_invalidated": "Konfirmasi alamat email kawangdéang",
"imgmultipagenext": "kaca salanturnyané →",
"imgmultigo": "Ngrereh",
"imgmultigoto": "Nuju kaca $1",
"logentry-protect-protect": "$1 {{GENDER:$2|nyaibin}} $3 $4",
"logentry-upload-upload": "$1 {{GENDER:$2|ngunggahang}} $3",
"logentry-upload-overwrite": "$1 {{GENDER:$2|ngunggahang}} vèrsi anyar saking $3",
+ "feedback-cancel": "Wangdé",
"feedback-message": "Séwalapatra:",
"searchsuggest-search": "Rereh ring {{SITENAME}}",
"duration-days": "$1 {{PLURAL:$1|rahina}}",
"wlheader-enotif": "Da E-Mail-Benoochrichtigungsdeanst is aktivierd.",
"wlheader-showupdated": "Seitn mid no ned oogschaugtn Endarunga wean '''fett''' gschriem.",
"wlnote": "Es {{PLURAL:$1|foigt de letzte Endarung|foign de letztn <strong>$1</strong> Endarunga}} vo de letztn {{PLURAL:$2|Stunde|<strong>$2</strong> Stundn}}. Stand: $3, $4 Uah.",
- "wlshowlast": "Zoag de Endarunga vo de letztn $1 Stund, $2 Dog.",
"watchlist-options": "Mei Beobochta: Optiona",
"watching": "Beówochten ...",
"unwatching": "Néd Beówochten",
"uctop": "aktuell",
"month": "und Monad:",
"year": "Bis zan Joar:",
- "sp-contributions-newbies": "Nua Beidräg vo de neichn Nutza ozoagn",
- "sp-contributions-newbies-sub": "Fyr Neiling",
"sp-contributions-blocklog": "Sperrlogbuach",
"sp-contributions-deleted": "Gléschde Beitrég",
"sp-contributions-uploads": "Affeglodane Datein",
"imgmultipagenext": "naxde Seiten →",
"imgmultigo": "OK",
"imgmultigoto": "Gee zua Seiten $1",
- "ascending_abbrev": "auf",
- "descending_abbrev": "ob",
"table_pager_next": "Naxde Seiten",
"table_pager_prev": "Vurherige Seiten",
"table_pager_first": "Erste Seiten",
"tog-fancysig": "امضاءَ په داب ویکی متنی بزان(بی اتوماتیکی لینک)",
"tog-uselivepreview": "پیشنمایش بدون نیاز به بروزرسانی صفحه",
"tog-forceeditsummary": "من آ هال دی وهدی وارد کتن یک هالیکین خلاصه ی اصلاح",
- "tog-watchlisthideown": "منی اصلاحات آ چه لیست چارگ پناه کن",
+ "tog-watchlisthideown": "منی ٹگلان چہ چارگء لیستئا پناہ کن",
"tog-watchlisthidebots": "اصلاحات بوت چه لیست چارگ پناه کن",
"tog-watchlisthideminor": "هوردین اصلاحات چه لیست چارگ پناه کن",
"tog-watchlisthideliu": "اصلاحات چه وارد بوتگین کاربران چه لیست چارگان پناه کن",
"mimetype": "نوع مایم:",
"download": "آیرگیزگ",
"unwatchedpages": "نه چارتگین صفحات",
- "listredirects": "Ù\84Û\8cست غÛ\8cر Ù\85ستÙ\82Û\8cÙ\85ان",
+ "listredirects": "Ù\86اتÙ\90Ú\86Ú©Ý\94Úº Ù\84Û\8cستان",
"listduplicatedfiles": "فهرست همهٔ پروندهها بههمراه تکراریها",
"listduplicatedfiles-summary": "این فهرست پروندههایی با نسخههای اخیر این پرونده تکراری است که نسخههای اخبر سایر پروندهها است. فقط پروندههای محلی در نظر گرفته شدهاند.",
"listduplicatedfiles-entry": "[[:File:$1|$1]][[$3|{{PLURAL:$2|یک تکرار|$2 تکرار}}]] دارد.",
"listusers-submit": "پیش دار",
"listusers-noresult": "هچ کابری در گیزگ نه بوت.",
"listusers-blocked": "(بند بیتگ)",
- "activeusers": "لیست کاربران فعال",
+ "activeusers": "کنشدارݔں کارزورۏکانء لیست",
"activeusers-count": "$1 {{PLURAL:$1|اصلاح|اصلاح}} نوکین",
"activeusers-from": "پیشدار کاربرانی که شروع بنت گون :",
"activeusers-noresult": "هچ کاربری درگیزگ نه بیت",
"listgrouprights-group": "گروه",
"listgrouprights-rights": "حقوق",
"listgrouprights-helppage": "Help: حقوق گروه",
- "listgrouprights-members": "(لیست اعضا)",
+ "listgrouprights-members": "(ھۏرݔنانء لیست)",
"listgrouprights-addgroup": "تونیت اضافه کنت {{PLURAL:$2|گروه|گروهان}}: $1",
"listgrouprights-removegroup": "تونیت بزوریت {{PLURAL:$2|گروهء|گروهانء}}: $1",
"listgrouprights-addgroup-all": "تونیت کل گروهان اضافه کنت",
"wlheader-enotif": "اخطار ایمیل فعالنت.",
"wlheader-showupdated": "صفحات که عوض بوتگنت چه شمی آهری چارتن '''پررنگ''' پیش دراگ بنت.",
"wlnote": "جهلء {{PLURAL:$1|آهرین تغییر هست|آهرین هست'''$1''' تغییرات}} ته آهرین {{PLURAL:$2|ساعت|'''$2''' ساعات}}.",
- "wlshowlast": "پیش دار آهرین $1 ساعات $2 روچان",
"watchlist-options": "چارگء لیستء گزینہئاں",
"watching": "چارگئں",
"unwatching": "چارگ نہ بیتگ",
"uctop": "بالا",
"month": "چه ماه(و پیش تر):",
"year": "چه سال(و پیشتر)",
- "sp-contributions-newbies": "پیش دار فقط مشارکتان نوکین حسایانء",
- "sp-contributions-newbies-sub": "په نوکین حسابان",
- "sp-contributions-newbies-title": "مشارکتان کاربر په نوکین حسابان",
"sp-contributions-blocklog": "محدود کتن ورود",
"sp-contributions-deleted": "مشارکتان حذف بوتءِ کاربر",
"sp-contributions-logs": "سیاهگ",
"imgmultipagenext": "اݔدگہ تاک →",
"imgmultigo": "برا!",
"imgmultigoto": "برو به صفحه $1",
- "ascending_abbrev": "بالادی",
- "descending_abbrev": "جهلادی",
"table_pager_next": "اݔدگہ تاک",
"table_pager_prev": "پیشگین صفحه",
"table_pager_first": "اولی صفحه",
"apihelp-no-such-module": "Module \"$1\" dai natagpuan.",
"apisandbox": "Kahong-buhangin kan API",
"apisandbox-jsonly": "Kaipuhan an JavaScript para magamit an API sandbox.",
- "apisandbox-api-disabled": "An API dae pinagpagana sa sityong ini.",
"apisandbox-intro": "Gamitong ining pahina sa pag-eksperimento kan '''MediaWiki web service API'''.\nKonsultaron an [[mw:API:Main page|the API documentation]] para sa iba pang mga detalye sa paggamit kan API. Ehemplo: [https://www.mediawiki.org/wiki/API#A_simple_example kuahon an laman kan Pangenot na Pahina]. Magpili nin aksyon tanganing hilngon an mga kadagdagan na mga ehemplo.",
"apisandbox-submit": "Maghimo nin kahagadan",
"apisandbox-reset": "Klaro",
"wlheader-enotif": "E-surat na paisi pinagpaandar na.",
"wlheader-showupdated": "Mga pahina na pinagriliwat poon kaidtong huri kang nagbisita sainda ipinapatanaw na '''mahîbog'''",
"wlnote": "Sa ibaba kan {{PLURAL:$1|huring pagbabago|mga huring <strong>$1</strong> pagbabago}} sa nakalihis na {{PLURAL:$2|oras|'''$2''' mga oras}}, magpoon pa kan $3, $4.",
- "wlshowlast": "Ipahilíng an nakalihis na $1 na mga oras mga $2 na mga aldaw",
"watchlist-hide": "Itago",
"watchlist-submit": "Ipahiling",
"wlshowhideminor": "Sadit na kaliwatan",
"month": "Poon bulan (asin mas amay):",
"year": "Poon taon (asin mas amay):",
"date": "Poon bulan (asin mas amay):",
- "sp-contributions-newbies": "Ipahiling an mga kaarambagan kan mga baguhong panindog sana",
- "sp-contributions-newbies-sub": "Para sa mga bàgong account",
- "sp-contributions-newbies-title": "Mga kontribusyon kan paragamit para sa baguhon an mga panindog",
"sp-contributions-blocklog": "Bagáton an katalaanan",
"sp-contributions-suppresslog": "pinagpurang mga kontribusyon kan {{GENDER:$1|paragamit}}",
"sp-contributions-deleted": "pinagpurang mga kontribusyon kan {{GENDER:$1|paragamit}}",
"newimages-legend": "An saraan",
"newimages-label": "Ngaran nin sagunson (o sarong parte kaini):",
"newimages-user": "Estada kan IP o ngaran-parágamit:",
- "newimages-newbies": "Ipahiling an mga kaarambagan kan mga baguhong panindog sana",
"newimages-showbots": "Ipahiling an mga karga kan bot",
"newimages-hidepatrolled": "Itago an mga patroladong mga karga",
"newimages-mediatype": "Uri kan media:",
"img-lang-default": "(panugmad na lengguwahe)",
"img-lang-info": "Giboha ining imahe sa $1. $2",
"img-lang-go": "Dumani",
- "ascending_abbrev": "skt",
- "descending_abbrev": "ba",
"table_pager_next": "Sunod na páhina",
"table_pager_prev": "Nakaaging páhina",
"table_pager_first": "Enot na páhina",
"blockednoreason": "прычына не пазначана",
"blockedtext-composite": "<strong>Вашае імя ўдзельніка ці IP-адрас былі заблякаваныя.</strong>\n\nПададзеная прычына:\n\n:<em>$2</em>.\n\n* Пачатак блякаваньня: $8\n* Сканчэньне найдаўжэйшага з блякаваньняў: $6\n\n* $5\n\nВаш цяперашні IP-адрас — $3.\nКалі ласка, дадайце ўсе падрабязнасьці, прыведзеныя вышэй, у запыты, што вы будзеце рабіць.",
"blockedtext-composite-ids": "Адпаведныя ідэнтыфікатары блякаваньня: $1 (ваш IP-адрас таксама можа знаходзіцца ў чорным сьпісе)",
+ "blockedtext-composite-no-ids": "Ваш ІП-адрас наяўны ў некалькіх чорных сьпісах",
"blockedtext-composite-reason": "Маецца некалькі блякаваньняў вашага рахунку і/ці IP-адрасу",
"whitelistedittext": "Вам трэба $1, каб рэдагаваць старонкі.",
"confirmedittext": "Вы мусіце пацьвердзіць Ваш адрас электроннай пошты перад рэдагаваньнем старонак. Калі ласка, пазначце і пацьвердзіце адрас электроннай пошты праз Вашы [[Special:Preferences|налады]].",
"nocreate-loggedin": "Вы ня маеце дазволу на стварэньне новых старонак.",
"sectioneditnotsupported-title": "Рэдагаваньне сэкцыяў не падтрымліваецца",
"sectioneditnotsupported-text": "Рэдагаваньне сэкцыяў не падтрымліваецца на гэтай старонцы.",
+ "modeleditnotsupported-title": "Рэдагаваньне ня падтрымоўваецца",
+ "modeleditnotsupported-text": "Рэдагаваньне ня падтрымоўваецца для мадэлі са зьместам $1",
"permissionserrors": "Памылка дазволу",
"permissionserrorstext": "Вы ня маеце дазволу на гэтае дзеяньне з {{PLURAL:$1|1=наступнай прычыны|наступных прычынаў}}:",
"permissionserrorstext-withaction": "Вы ня маеце дазволу на $2 з {{PLURAL:$1|1=наступнай прычыны|наступных прычынаў}}:",
"content-model-css": "CSS",
"content-json-empty-object": "Пусты аб’ект",
"content-json-empty-array": "Пусты масіў",
+ "unsupported-content-model": "<strong>Увага:</strong> Мадэль са зьместам $1 ня падтрымоўвацца на гэтай вікі.",
"deprecated-self-close-category": "Старонкі зь няслушнымі самазакрытымі HTML-тэгамі",
"deprecated-self-close-category-desc": "Старонка ўтрымлівае няслушныя самазакрытыя HTML-тэгі, такія як <code><b/></code> ці <code><span/></code>. Іх паводзіны ў хуткім часе будуць зьмененыя ў адпаведнасьці з спэцыфікацыяй HTML5, таму іх ўжываньне ў вікітэксьце лічыцца састарэлым.",
"duplicate-args-warning": "<strong>Папярэджаньне:</strong> [[:$1]] выклікае [[:$2]] з больш чым адным значэньнем парамэтру «$3». Толькі апошняе з пададзеных значэньняў будзе ўжытае.",
"rcfilters-clear-all-filters": "Ачысьціць усе фільтры",
"rcfilters-show-new-changes": "Праглядзець новыя зьмены з $1",
"rcfilters-search-placeholder": "Фільтар зьменаў (ужывайце мэню ці пошук дзеля назвы фільтру)",
+ "rcfilters-search-placeholder-mobile": "Фільтары",
"rcfilters-invalid-filter": "Няслушны фільтар",
"rcfilters-empty-filter": "Няма актыўных фільтраў. Паказаны ўвесь унёсак.",
"rcfilters-filterlist-title": "Фільтры",
"rcfilters-filter-showlinkedto-label": "Паказаць зьмены старонак, якія спасылаюцца на",
"rcfilters-filter-showlinkedto-option-label": "<strong>Старонкі, якія спасылаюцца на</strong> абраную старонку",
"rcfilters-target-page-placeholder": "Увядзіце назву старонкі (ці катэгорыі)",
+ "rcfilters-allcontents-label": "Увесь зьмест",
+ "rcfilters-alldiscussions-label": "Усе абмеркаваньні",
"rcnotefrom": "Ніжэй {{PLURAL:$5|знаходзіцца зьмена|знаходзяцца зьмены}} з <strong>$4 $3</strong> (да <strong>$1</strong> на старонку).",
"rclistfromreset": "Скінуць выбар даты",
"rclistfrom": "Паказаць зьмены з $2 $3",
"apihelp-no-such-module": "Модуль «$1» ня знойдзены.",
"apisandbox": "Пясочніца API",
"apisandbox-jsonly": "Для выкарыстаньня API-пясочніцы патрэбны JavaScript.",
- "apisandbox-api-disabled": "API адключаны на гэтым сайце.",
"apisandbox-intro": "Выкарыстоўвайце гэтую старонку для экспэрымэнтаў з <strong>API вэб-сэрвісу MediaWiki</strong>.\nЗьвяртайцеся да [[mw:API:Main page|дакумэнтацыі API]] для дадатковай інфармацыі па выкарыстаньні API. Напрыклад, [https://www.mediawiki.org/wiki/API#A_simple_example як атрымаць зьмест галоўнай старонкі]. Абярыце дзеяньне, каб пабачыць болей узораў.\n\nЗьвярніце ўвагу, што нягледзячы на тое, што гэта пясочніца, вашыя дзеяньні могуць унесьці зьмены ў вікі.",
"apisandbox-submit": "Зрабіць запыт",
"apisandbox-reset": "Ачысьціць",
"wlheader-enotif": "Апавяшчэньне праз электронную пошту ўключанае.",
"wlheader-showupdated": "Старонкі, зьмененыя з часу вашага апошняга візыту, вылучаныя <strong>тоўстым</strong> шрыфтам.",
"wlnote": "Ніжэй {{PLURAL:$1|паказаная <strong>$1</strong> апошняя зьмена|паказаныя <strong>$1</strong> апошнія зьмены|паказаныя <strong>$1</strong> апошніх зьменаў}} за <strong>$2</strong> {{PLURAL:$2|гадзіну|гадзіны|гадзінаў}}, па стане на $4 $3.",
- "wlshowlast": "Паказаць за апошнія $1 гадзінаў, $2 дзён",
"watchlist-hide": "Схаваць",
"watchlist-submit": "Паказаць",
"wlshowtime": "Пэрыяд часу для паказу:",
"changecontentmodel": "Зьмена мадэлі зьместу старонкі",
"changecontentmodel-legend": "Зьмена мадэлі зьместу",
"changecontentmodel-title-label": "Назва старонкі",
+ "changecontentmodel-current-label": "Бягучая мадэль зьместу:",
"changecontentmodel-model-label": "Новая мадэль зьместу",
"changecontentmodel-reason-label": "Прычына:",
"changecontentmodel-submit": "Зьмяніць",
"month": "Ад месяца (і раней):",
"year": "Ад году (і раней):",
"date": "З даты (і раней):",
- "sp-contributions-newbies": "Паказаць унёсак толькі з новых рахункаў",
- "sp-contributions-newbies-sub": "Унёсак пачынаючых",
- "sp-contributions-newbies-title": "Унёсак удзельнікаў з новых рахункаў",
"sp-contributions-blocklog": "журнал блякаваньняў",
"sp-contributions-suppresslog": "выдалены ўнёсак {{GENDER:$1|удзельніка|удзельніцы}}",
"sp-contributions-deleted": "выдалены ўнёсак {{GENDER:$1|удзельніка|удзельніцы}}",
"newimages-legend": "Фільтар",
"newimages-label": "Назва файла (альбо яе частка):",
"newimages-user": "IP-адрас ці імя ўдзельніка",
- "newimages-newbies": "Паказаць толькі ўнёсак з новых рахункаў",
"newimages-showbots": "Паказаць загружаныя робатамі",
"newimages-hidepatrolled": "Схаваць патруляваныя загрузкі",
"newimages-mediatype": "Тып мэдыя:",
"img-lang-default": "(мова па змоўчаньні)",
"img-lang-info": "Паказаць гэтую выяву наступнай мовай: $1. $2",
"img-lang-go": "Паказаць",
- "ascending_abbrev": "узраст.",
- "descending_abbrev": "зьмянш.",
"table_pager_next": "Наступная старонка",
"table_pager_prev": "Папярэдняя старонка",
"table_pager_first": "Першая старонка",
"permanentlink": "Сталая спасылка",
"permanentlink-revid": "Ідэнтыфікатар вэрсіі",
"permanentlink-submit": "Перайсьці да вэрсіі",
+ "newsection": "Новы разьдзел",
+ "newsection-page": "Мэтавая старонка",
+ "newsection-submit": "Перайсьці да старонкі",
"dberr-problems": "Прабачце! На гэтым сайце ўзьніклі тэхнічныя цяжкасьці.",
"dberr-again": "Паспрабуйце пачакаць некалькі хвілінаў і абнавіць.",
"dberr-info": "(Немагчыма злучыцца з базай зьвестак: $1)",
"botpasswords-existing": "Наяўныя паролі робатаў",
"botpasswords-createnew": "Стварыць новы пароль робата",
"botpasswords-editexisting": "Рэдагаваць наяўны пароль робата",
+ "botpasswords-label-needsreset": "(пароль патрабуе скідвання)",
"botpasswords-label-appid": "Назва робата:",
"botpasswords-label-create": "Стварыць",
"botpasswords-label-update": "Абнавіць",
"botpasswords-restriction-failed": "Уваход не выкананы з-за абмежаванняў на пароль робата.",
"botpasswords-invalid-name": "Паказанае імя ўдзельніка не ўтрымлівае падзяляльнік паролю робата (\"$1\").",
"botpasswords-not-exist": "Удзельнік \"$1\" не мае паролю для робата з назвай \"$2\".",
+ "botpasswords-needs-reset": "Пароль для робата \"$1\", які належыць {{GENDER:$2|удзельніку|удзельніцы}} \"$2\", мусіць быць скінуты.",
"resetpass_forbidden": "Не дазволена мяняць паролі",
"resetpass_forbidden-reason": "Не дазволена мяняць паролі: $1",
"resetpass-no-info": "Трэба ўвайсці ў сістэму, каб звяртацца да гэтай старонкі наўпрост.",
"resetpass-expired": "Ваш пароль пратэрмінаваны. Калі ласка, устанавіце новы пароль для ўваходу ў сістэму.",
"resetpass-expired-soft": "Ваш пароль пратэрмінаваны і яго трэба замяніць. Калі ласка, выберыце новы пароль зараз, ці націсніце \"{{int:authprovider-resetpass-skip-label}}\", каб змяніць яго пазней.",
"resetpass-validity": "Ваш пароль няверны: $1 \n\nКалі ласка, устанавіце новы пароль для ўваходу ў сістэму.",
- "resetpass-validity-soft": "Ваш пароль недапушчальны: $1\n\nКалі ласка, выберыце новы пароль зараз, або націсніце \"{{int:authprovider-resetpass-skip-label}}\", каб скінуць яго пазней.",
+ "resetpass-validity-soft": "Ваш пароль недапушчальны: $1\n\nКалі ласка, выберыце новы пароль зараз, або націсніце \"{{int:authprovider-resetpass-skip-label}}\", каб змяніць яго пазней.",
"passwordreset": "Выслаць мне новы пароль",
"passwordreset-text-one": "Запоўніце гэту форму, каб атрымаць часовы пароль па эл.пошце.",
"passwordreset-text-many": "{{PLURAL:$1|Запоўніце адно з палёў, каб атрымаць тымчасовы пароль па электроннай пошце.}}",
"autoblockedtext": "Ваш адрас IP быў аўтаматычна заблакаваны, таму што ім карыстаўся ўдзельнік, заблакаваны адміністратарам $1.\nПададзеная прычына блоку:\n\n:''$2''\n\n* Блок пастаўлены: $8\n* Блок канчаецца: $6\n* Атрымальнік блоку: $7\n\nВы можаце звярнуцца да $1 або да аднаго з іншых [[{{MediaWiki:Grouppage-sysop}}|адміністратараў]], каб паразмаўляць пра гэты блок.\n\nВы не зможаце дзеля гэтага карыстацца функцыяй ''{{:{{ns:mediawiki}}:emailuser/be}}'', калі гэта вам забаронена, або калі вы не наставілі правільнага пацверджанага адрасу эл.пошты ў сваіх [[Special:Preferences|настаўленнях]].\n\nВаш адрас IP: $3. Ваш нумар блоку: $5. Падавайце ўсе гэтыя звесткі ў кожным сваім звароце адносна гэтага блоку.",
"systemblockedtext": "Вашае імя ўдзельніка ці IP-адрас былі аўтаматычна заблакаваныя MediaWiki.\nЗ наступнай прычыны:\n\n:<em>$2</em>\n\n* Пачатак блакіроўкі: $8\n* Заканчэнне блакіроўкі: $6\n* Мэта блакіравання: $7\n\nВаш цяперашні IP-адрас — $3.\nКалі ласка, уключайце ўсе пададзеныя вышэй дэталі ва ўсе запыты, што вы робіце.",
"blockednoreason": "прычына не вызначана",
+ "blockedtext-composite-no-ids": "Ваш IP-адрас наяўны ў некалькіх чорных спісах",
+ "blockedtext-composite-reason": "Маецца некалькі блакіровак вашага рахунку і/ці IP-адрасу",
"whitelistedittext": "Належыць $1 каб правіць старонкі.",
"confirmedittext": "Вам трэба пацвердзіць свой адрас эл.пошты перад тым, як правіць старонкі.\nВызначце і пацвердзіце адрас ў сваіх [[Special:Preferences|настáўленнях]].",
"nosuchsectiontitle": "Няма такога падраздзелу",
"nocreate-loggedin": "Вам не дазволена ствараць новыя старонкі.",
"sectioneditnotsupported-title": "Праўка раздзелу не падтрымліваецца",
"sectioneditnotsupported-text": "Праўка раздзелу не падтрымліваецца на гэтай старонцы.",
+ "modeleditnotsupported-title": "Рэдагаванне не падтрымліваецца",
+ "modeleditnotsupported-text": "Рэдагаванне не падтрымліваецца для мадэлі змесціва $1.",
"permissionserrors": "Памылка доступу",
"permissionserrorstext": "Вам не дазволена гэтага рабіць, з наступн{{PLURAL:$1|ай прычыны|ых прычын}}:",
"permissionserrorstext-withaction": "Вам не дазволена $2, з-за наступ{{PLURAL:$1|най прычыны|ных прычын}}:",
"editpage-invalidcontentmodel-text": "Мадэль змесціва \"$1\" не падтрымліваецца.",
"editpage-notsupportedcontentformat-title": "Фармат змесціва не падтрымліваецца",
"editpage-notsupportedcontentformat-text": "Фармат змесціва $1 не падтрымліваецца мадэллю змесціва $2.",
+ "slot-name-main": "Галоўная",
"content-model-wikitext": "вікі-тэкст",
"content-model-text": "звычайны тэкст",
"content-model-javascript": "JavaScript",
"content-model-css": "CSS",
"content-json-empty-object": "Пусты аб’ект",
"content-json-empty-array": "Пусты масіў",
+ "unsupported-content-model": "<strong>Увага:</strong> Мадэль змесціва $1 не падтрымліваецца на гэтай вікі.",
+ "unsupported-content-diff": "Адрозненні не падтрымліваюцца для мадэлі змесціва $1.",
+ "unsupported-content-diff2": "Адрозненні між мадэлямі змесціва $1 і $2 не падтрымліваюцца на гэтай вікі.",
"deprecated-self-close-category": "Старонкі з недапушчальнымі самазакрытымі HTML-тэгамі",
"deprecated-self-close-category-desc": "Старонка ўтрымлівае недапушчальныя самазакрытыя HTML-тэгі, такія як <code><b/></code> ці <code><span/></code>. Іх паводзіны ў хуткім часе будуць зменены ў адпаведнасці з спецыфікацыяй HTML5, таму іх ужыванне ў вікітэксце лічыцца састарэлым.",
"duplicate-args-warning": "<strong>Увага:</strong> [[:$1]] выклікае [[:$2]] з больш чым адным значэннем для параметра \"$3\". Толькі апошняе з пададзеных значэнняў будзе ўжытае.",
"rcfilters-clear-all-filters": "Ачысціць усе фільтры",
"rcfilters-show-new-changes": "Паказаць навейшыя змяненні з $1",
"rcfilters-search-placeholder": "Змяненні фільтра (выкарыстоўвайце меню ці шукайце па назве фільтра)",
+ "rcfilters-search-placeholder-mobile": "Фільтры",
"rcfilters-invalid-filter": "Недапушчальны фільтр",
"rcfilters-empty-filter": "Няма актыўных фільтраў. Паказваюцца ўсе праўкі.",
"rcfilters-filterlist-title": "Фільтры",
"rcfilters-preference-help": "Адкатвае рэдызайн інтэрфейсу 2017 года і ўсе інструменты, дададзеныя з тых часоў.",
"rcfilters-watchlist-preference-label": "Выкарыстоўваць інтэрфейс без JavaScript",
"rcfilters-watchlist-preference-help": "Адкатвае рэдызайн інтэрфейсу 2017 года і ўсе інструменты, дададзеныя з тых часоў.",
+ "rcfilters-filter-showlinkedfrom-label": "Паказаць змены на старонках, на якія спасылаецца",
+ "rcfilters-filter-showlinkedto-label": "Паказаць змены старонак, якія спасылаюцца на",
+ "rcfilters-target-page-placeholder": "Увядзіце назву старонкі (ці катэгорыі)",
+ "rcfilters-allcontents-label": "Увесь змест",
+ "rcfilters-alldiscussions-label": "Усе абмеркаванні",
"rcnotefrom": "Ніжэй {{PLURAL:$5|паказана змяненне|паказаны змены}} з <strong>$3, $4</strong> (не больш за <strong>$1</strong>).",
"rclistfrom": "Паказаць змены з $3 $2",
"rcshowhideminor": "$1 дробныя праўкі",
"apihelp-no-such-module": "Модуль \"$1\" не знойдзены.",
"apisandbox": "Пясочніца API",
"apisandbox-jsonly": "Каб выкарыстоўваць пясочніцу API, патрэбны JavaScript.",
- "apisandbox-api-disabled": "API адключаны на гэтым сайце.",
"apisandbox-submit": "Зрабіць запыт",
"apisandbox-reset": "Ачысціць",
"apisandbox-retry": "Паўтарыць",
"wlheader-enotif": "Працуе апавяшчанне праз эл.пошту.",
"wlheader-showupdated": "Старонкі, якія былі зменены пасля вашага апошняга наведвання, паказаны <strong>абрысам шрыфту</strong>.",
"wlnote": "Ніжэй {{PLURAL:$1|паказана апошняя <strong>$1</strong> змена|паказаны апошнія <strong>$1</strong> змены|паказаны апошнія <strong>$1</strong> змен}} за {{PLURAL:$2|апошнюю|апошнія|апошнія}} <strong>$2</strong> {{PLURAL:$2|гадзіну|гадзіны|гадзін}}, на момант часу $3 $4.",
- "wlshowlast": "Паказваць апошнія $1 гадз. $2 дзён",
"watchlist-hide": "Схаваць",
"watchlist-submit": "Паказаць",
"wlshowtime": "Перыяд часу для паказу:",
"sessionfailure": "Магчыма, ёсць праблемы з вашым сеансам працы ў сістэме. Таму вам было адмоўлена ў выкананні дзеяння, каб засцерагчыся ад захопу сеанса.\n\nВярніцеся на папярэднюю старонку, перазагрузіце яе і тады паспрабуйце зноў.",
"changecontentmodel": "Змяніць мадэль змесціва старонкі",
"changecontentmodel-legend": "Змяніць мадэль змесціва",
- "changecontentmodel-title-label": "Назва старонкі",
- "changecontentmodel-model-label": "Новая мадэль змесціва",
+ "changecontentmodel-title-label": "Назва старонкі:",
+ "changecontentmodel-current-label": "Бягучая мадэль змесціва:",
+ "changecontentmodel-model-label": "Новая мадэль змесціва:",
"changecontentmodel-reason-label": "Прычына:",
"changecontentmodel-submit": "Змяніць",
"changecontentmodel-success-title": "Мадэль змесціва была зменена",
"contribsub2": "Для $1 ($2)",
"contributions-subtitle": "Для {{GENDER:$3|$1}}",
"contributions-userdoesnotexist": "Уліковы запіс удзельніка \"$1\" не зарэгістраваны.",
+ "negative-namespace-not-supported": "Прасторы назваў з адмоўнымі значэннямі не падтрымліваюцца.",
"nocontribs": "Не знойдзена змен, адпаведных зададзеным параметрам.",
"uctop": "апошн.",
"month": "Ад месяца (і раней):",
"year": "Ад года (і раней):",
"date": "Ад даты (і раней):",
- "sp-contributions-newbies": "Паказваць толькі ўклады з новых рахункаў",
- "sp-contributions-newbies-sub": "З новых рахункаў",
- "sp-contributions-newbies-title": "Уклады ўдзельнікаў з новых рахункаў",
"sp-contributions-blocklog": "блакіроўкі",
"sp-contributions-suppresslog": "схаваны ўклад {{GENDER:$1|удзельніка|удзельніцы}}",
"sp-contributions-deleted": "сцёрты ўклад {{GENDER:$1|удзельніка|удзельніцы}}",
"blocklink": "заблакаваць",
"unblocklink": "адблакаваць",
"change-blocklink": "змяніць блок",
+ "empty-username": "(імя ўдзельніка недаступна)",
"contribslink": "уклад",
"emaillink": "адправіць ліст",
"autoblocker": "Аўтаматычны блок, таму што вашым адрасам IP нядаўна карыстаўся \"[[User:$1|$1]]\".\nПрычына блакіроўкі ўдзельніка $1: \"$2\"",
"fix-double-redirects": "Абнавіць усе перасылкі, якія вядуць да пачатковай назвы",
"move-leave-redirect": "Пакінуць перасылку са старой назвы",
"protectedpagemovewarning": "<strong>Папярэджанне:</strong> Гэта старонка была змешчана пад ахову; пераназваць яе могуць толькі ўдзельнікі з паўнамоцтвамі адміністратараў.\nНіжэй для даведкі прыведзена апошні запіс журнала:",
- "semiprotectedpagemovewarning": "<strong>Ð\97аÑ\9eвага:</strong> Ð\93Ñ\8dÑ\82а Ñ\81Ñ\82аÑ\80онка бÑ\8bла змеÑ\88Ñ\87ана пад аÑ\85овÑ\83; пеÑ\80аноÑ\81Ñ\96Ñ\86Ñ\8c Ñ\8fе пад Ñ\96нÑ\88Ñ\83Ñ\8e назвÑ\83 могÑ\83Ñ\86Ñ\8c Ñ\82олÑ\8cкÑ\96 заÑ\80Ñ\8dгÑ\96Ñ\81Ñ\82Ñ\80аваныя ўдзельнікі.\nНіжэй для даведкі прыведзена апошні запіс журнала:",
+ "semiprotectedpagemovewarning": "<strong>Ð\97аÑ\9eвага:</strong> Ð\93Ñ\8dÑ\82а Ñ\81Ñ\82аÑ\80онка бÑ\8bла змеÑ\88Ñ\87ана пад аÑ\85овÑ\83; пеÑ\80аноÑ\81Ñ\96Ñ\86Ñ\8c Ñ\8fе пад Ñ\96нÑ\88Ñ\83Ñ\8e назвÑ\83 могÑ\83Ñ\86Ñ\8c Ñ\82олÑ\8cкÑ\96 аÑ\9eÑ\82апаÑ\86веÑ\80джаныя ўдзельнікі.\nНіжэй для даведкі прыведзена апошні запіс журнала:",
"move-over-sharedrepo": "Файл з назвай [[:$1]] ёсць у агульным сховішчы. Файл, перанесены пад такую назву, будзе перамагаць файл з агульнага сховішча.",
"file-exists-sharedrepo": "Такая назва файла ўжо выкарыстана ў агульным сховішчы.\nВыберыце іншую назву.",
"export": "Экспартаваць старонкі",
"tooltip-summary": "Дайце кароткае апісанне",
"common.css": "/** CSS, упісаны сюды, будзе дзейнічаць на карыстальнікаў усіх світаў */",
"group-autoconfirmed.css": "/* Размешчаны тут CSS будзе прымяняцца для аўтапацверджаных удзельнікаў */",
+ "common.json": "/* JSON-код, упісаны сюды, будзе выконвацца для кожнага чытача, на кожным счытванні старонкі. */",
"common.js": "/* Яваскрыпт, упісаны сюды, будзе выконвацца для кожнага чытача, на кожным счытванні старонкі. */",
"group-autoconfirmed.js": "/* Размешчаны тут код JavaScript будзе прымяняцца для толькі аўтапацверджаных удзельнікаў */",
"anonymous": "Ананімны{{PLURAL:$1| ўдзельнік|я ўдзельнікі}} на пляцоўцы {{SITENAME}}",
"pageinfo-category-subcats": "Колькасць падкатэгорый",
"pageinfo-category-files": "Колькасць файлаў",
"pageinfo-user-id": "Ідэнтыфікатар удзельніка",
+ "pageinfo-file-hash": "Хэш-значэнне",
"markaspatrolleddiff": "Пазначыць як ухваленае",
"markaspatrolledtext": "Пазначыць старонку як ухваленую",
"markaspatrolledtext-file": "Пазначыць версію файла як ухваленую",
"newimages-legend": "Фільтр",
"newimages-label": "Назва файла (або яе частка):",
"newimages-user": "Адрас IP або імя ўдзельніка",
- "newimages-newbies": "Паказаць толькі ўклады з новых рахункаў",
"newimages-showbots": "Паказваць укладанні ботамі",
"newimages-hidepatrolled": "Без паказу ўхваленых ўкладанняў",
"newimages-mediatype": "Тып медиафайла:",
"img-lang-default": "(прадвызначаная мова)",
"img-lang-info": "Паказаць гэту выяву на мове $1. $2",
"img-lang-go": "Перайсці",
- "ascending_abbrev": "да больш.",
- "descending_abbrev": "да менш.",
"table_pager_next": "Наступная старонка",
"table_pager_prev": "Папярэдняя старонка",
"table_pager_first": "Першая старонка",
"redirect-file": "Назва файла",
"redirect-logid": "ID журнала",
"redirect-not-exists": "Значэнне не знойдзена",
+ "redirect-not-numeric": "Значэнне не лікавае",
"fileduplicatesearch": "Пошук дублікатных файлаў",
"fileduplicatesearch-summary": "Пошук дублікатных файлаў на падставе іх хэшаў.",
"fileduplicatesearch-filename": "Назва файла:",
"tags-edit-chosen-placeholder": "Выберыце біркі",
"tags-edit-chosen-no-results": "Не знойдзена бірак, якія б адпавядалі запыту",
"tags-edit-reason": "Прычына:",
+ "tags-edit-success": "Змены былі дастасаваныя.",
"tags-edit-nooldid-title": "Недапушчальная мэтавая версія",
"tags-edit-nooldid-text": "Вы або не пазначылі мэтавую версію для выканання гэтай функцыі, або пазначаная версія не існуе.",
"tags-edit-none-selected": "Калі ласка, выберыце прынамсі адну бірку для дадання ці выдалення.",
"permanentlink": "Пастаянная спасылка",
"permanentlink-revid": "ідэнтыфікатар праўкі",
"permanentlink-submit": "Перайсці да версіі",
+ "newsection-page": "Мэтавая старонка",
+ "newsection-submit": "Перайсці на старонку",
"dberr-problems": "Прабачце, на пляцоўцы здарыліся тэхнічныя цяжкасці.",
"dberr-again": "Паспрабуйце перачытаць праз некалькі хвілін.",
"dberr-info": "(Немагчыма звязацца з базай даных: $1)",
"htmlform-time-placeholder": "ЧЧ:ММ:СС",
"htmlform-datetime-placeholder": "ГГГГ-ММ-ДД ЧЧ:ММ:СС",
"htmlform-date-invalid": "Указанае вамі значэнне не похоже на дату. Паспрабуйце выкарыстоўваць фармат ГГГГ-ММ-ДД.",
+ "htmlform-time-invalid": "Указанае вамі значэнне не похоже на час. Паспрабуйце выкарыстоўваць фармат ГГ:ХХ:СС.",
"htmlform-datetime-invalid": "Вамі выбрана значэнне не падобна на дату і час. Паспрабуйце выкарыстоўваць фармат ГГГГ-ММ-ДД ГГ-ММ-СС.",
"htmlform-title-badnamespace": "[[:$1]] не ў прасторы назваў \"{{ns:$2}}\".",
"htmlform-title-not-creatable": "\"$1\" - немагчымы загаловак для старонкі",
"logentry-delete-restore": "$1 {{GENDER:$2|аднавіў|аднавіла}} старонку $3 ($4)",
"logentry-delete-restore-nocount": "$1 {{GENDER:$2|аднавіў|аднавіла}} старонку $3",
"restore-count-revisions": "{{PLURAL:$1|1 версія|$1 версіі|$1 версій}}",
+ "restore-count-files": "{{PLURAL:$1|1 файл|$1 файлы|$1 файлаў}}",
"logentry-delete-event": "$1 {{GENDER:$2|змяніў|змяніла}} бачнасць {{PLURAL:$5|запісу журнала|$5 запісаў журнала}} $3: $4",
"logentry-delete-revision": "$1 {{GENDER:$2|змяніў|змяніла}} бачнасць {{PLURAL:$5|версіі|$5 версій|$5 версій}} старонкі $3: $4",
"logentry-delete-event-legacy": "$1 {{GENDER:$2|змяніў|змяніла}} бачнасць запісаў журнала $3",
"expandtemplates": "Разгортванне шаблонаў",
"expand_templates_intro": "Гэта адмысловая старонка бярэ тэкст і разгортвае ў ім усе шаблоны рэкурсіўна.\nТаксама разгортвае падтрыманыя функцыі парсера кшталту\n<code><nowiki>{{</nowiki>#language:…}}</code> і зменныя віду\n<code><nowiki>{{</nowiki>CURRENTDAY}}</code>.\nФактычна, яна разгортвае ў пэўнай ступені ўсё ў двайных фігурных дужках.",
"expand_templates_title": "Загаловак старонкі, для {{FULLPAGENAME}} і г.д.:",
- "expand_templates_input": "Уваходны тэкст:",
+ "expand_templates_input": "Уваходны вікітэкст:",
"expand_templates_output": "Вынік",
"expand_templates_xml_output": "Выніковы XML",
"expand_templates_html_output": "Выніковы зыходны код HTML",
"expand_templates_generate_xml": "Паказаць дрэва сінтаксічнага аналізу XML",
"expand_templates_generate_rawhtml": "Паказаць зыходны код HTML",
"expand_templates_preview": "Перадпаказ",
- "expand_templates_input_missing": "Трэба ўвесці хоць які-небудзь тэкст.",
+ "expand_templates_input_missing": "Трэба ўвесці хоць які-небудзь вікітэкст.",
"pagelanguage": "Змяніць мову старонкі",
"pagelang-name": "Старонка",
"pagelang-language": "Мова",
"mediastatistics-header-executable": "Выкананыя",
"mediastatistics-header-archive": "Сціснутыя фарматы",
"mediastatistics-header-total": "Усе файлы",
+ "json-error-unknown": "Узнікла праблема з JSON. Памылка: $1",
"json-error-state-mismatch": "Недапушчальны або некарэктны JSON",
"json-error-syntax": "Памылка сінтаксісу",
"headline-anchor-title": "Спасылка на гэты раздзел",
"log-action-filter-contentmodel-change": "Змяненне мадэлі змесціва",
"log-action-filter-contentmodel-new": "Стварэнне старонкі з нестандартнай мадэллю змесціва",
"log-action-filter-delete-delete": "Выдаленне старонкі",
+ "log-action-filter-delete-delete_redir": "Перазапіс перасылкі",
"log-action-filter-delete-restore": "Узнаўленне старонкі",
"log-action-filter-delete-event": "Выдаленне лога",
"log-action-filter-delete-revision": "Выдаленне перагляду",
"log-action-filter-suppress-reblock": "Скрыванне ўдзельніка праз паўторнае блакіраванне",
"log-action-filter-upload-upload": "Новая загрузка",
"log-action-filter-upload-overwrite": "Паўторная загрузка",
+ "log-action-filter-upload-revert": "Адкаціць",
"authmanager-authn-not-in-progress": "Праверка сапраўднасці не выконваецца або сесія перадачы дадзеных была страчана. Калі ласка, пачніце зноў з самага пачатку.",
"authmanager-authn-no-primary": "Прадастаўленыя ўліковыя дадзеныя не могуць быць завераны.",
"authmanager-authn-no-local-user": "Пададзеныя ўліковыя дадзеныя не звязаныя з ніводным удзельнікам на гэтай Вікі.",
"authmanager-authn-autocreate-failed": "Аўтаматычнае стварэнне лакальнага ўліковага запісу не ўдалося: $1",
"authmanager-change-not-supported": "Прадастаўленыя ўліковыя дадзеныя не могуць быць зменены, як нішто не будзе іх выкарыстоўваць.",
"authmanager-create-disabled": "стварэнне рахунка не дазволена",
- "authmanager-create-from-login": "Каб стварыць уліковы запіс, калі ласка, запоўніце палі ніжэй.",
+ "authmanager-create-from-login": "Каб стварыць уліковы запіс, калі ласка, запоўніце палі.",
"authmanager-create-not-in-progress": "Праверка сапраўднасці не выконваецца або сесія перадачы дадзеных была страчана. Калі ласка, пачніце зноў з самага пачатку.",
"authmanager-create-no-primary": "Прадастаўленыя ўліковыя дадзеныя не могуць быць выкарыстаны для стварэння ўліковага запісу.",
"authmanager-link-no-primary": "Прадастаўленыя ўліковыя дадзеныя не могуць быць выкарыстаны для прывязкі рахунку.",
"revid": "версія $1",
"pageid": "ID старонкі $1",
"pagedata-title": "Дадзеныя старонкі",
+ "passwordpolicies-group": "Група",
+ "passwordpolicies-policies": "Палітыкі",
"passwordpolicies-policyflag-forcechange": "мусіць быць зменены пры ўваходзе",
"passwordpolicies-policyflag-suggestchangeonlogin": "прапанаваць змяненне пры ўваходзе"
}
"apihelp-no-such-module": "Модул „$1“ не беше намерен.",
"apisandbox": "Пясъчник за API",
"apisandbox-jsonly": "Необходим е JavaScript, за да използвате API пясъчника.",
- "apisandbox-api-disabled": "API е изключен за този сайт.",
"apisandbox-submit": "Направи запитване",
"apisandbox-reset": "Изчистване",
"apisandbox-retry": "Повторен опит",
"wlheader-enotif": "Известяването по е-поща е включено.",
"wlheader-showupdated": "Страниците, които са били променени след последния път, когато сте ги посетили, са показани в <strong>получер</strong>.",
"wlnote": "{{PLURAL:$1|Показана е последната промяна|Показани са последните <strong>$1</strong> промени}} през {{PLURAL:$2|последния час|последните <strong>$2</strong> часа}}, започвайки от $3, $4.",
- "wlshowlast": "Показване на последните $1 часа $2 дни",
"watchlist-hide": "Скриване",
"watchlist-submit": "Показване",
"wlshowtime": "Период от време за показване:",
"month": "От месец (и по-рано):",
"year": "От година (и по-рано):",
"date": "От дата (и по-рано):",
- "sp-contributions-newbies": "Показване само на приносите на нови потребители",
- "sp-contributions-newbies-sub": "За нови сметки",
- "sp-contributions-newbies-title": "Потребителски приноси за нови сметки",
"sp-contributions-blocklog": "дневник на блокиранията",
"sp-contributions-deleted": "изтрити приноси на {{GENDER:$1|потребител}}",
"sp-contributions-uploads": "качвания",
"newimages-legend": "Филтриране",
"newimages-label": "Име на файл (или част от него):",
"newimages-user": "IP-адрес или потребителско име",
- "newimages-newbies": "Показване на приносите само на нови потребители",
"newimages-showbots": "Показване на качвания от ботове",
"newimages-hidepatrolled": "Скриване на патрулираните качвания",
"newimages-mediatype": "Файлов тип:",
"img-lang-opt": "$2 ($1)",
"img-lang-default": "(език по подразбиране)",
"img-lang-go": "Отваряне",
- "ascending_abbrev": "възх",
- "descending_abbrev": "низх",
"table_pager_next": "Следваща страница",
"table_pager_prev": "Предишна страница",
"table_pager_first": "Първа страница",
"wlheader-enotif": "ایمیل ئی ناتیپشن پئال اینت.",
"wlheader-showupdated": "تاکدیمان که شه شمی آخیرین دیستینا پد تغیر بوته انت '''پررنگ''' نشان داته بیئنت.",
"wlnote": "بئ جهلگا {{PLURAL:$1|تغییری|<strong>$1</strong> تغییری}} که بئ {{PLURAL:$2|سائت|<strong>$2</strong> سائت}} دیمتیرا انجام بوته موجود اینت، آخیرین بازیابی تاریخ: $3، $4",
- "wlshowlast": "نشان داتین آخیرئین $1 سائت $2 روچئ",
"watchlist-hide": "چیهر داتین",
"watchlist-options": "واچلیستئ آپشن",
"watching": "بئ دیستینئ حالا...",
"uctop": "انونین نخسه",
"month": "به اي ماهای تا (و دیمتیر شه آیی):",
"year": "به اي سالئ تا (و دیمتیر شه آیی):",
- "sp-contributions-newbies": "فقط نوکین مشارکتان نشان داته بیئنت",
- "sp-contributions-newbies-sub": "په نوک کاران",
- "sp-contributions-newbies-title": "په نوک کارین حسابانی خاتیرا کار زوروکئ شراکت ئان",
"sp-contributions-blocklog": "بلاک بوته ئینئانی کورمجاه",
"sp-contributions-suppresslog": "کار زوروکئ کومک اوشتاته انت",
"sp-contributions-deleted": "{{GENDER:$1|کار زوروکئ}} پاک بوتهئین دستکاریان",
"img-lang-default": "(پیشفرض ئین زبان)",
"img-lang-info": "ارایه کورتین ای اکسی بی $1 . $2",
"img-lang-go": "برا",
- "ascending_abbrev": "صعودی",
- "descending_abbrev": "نزولی",
"table_pager_next": "دیگرین تاکدیم",
"table_pager_prev": "دیمتیرین تاکدیم",
"table_pager_first": "اولین تاکدیم",
"watchlist-details": "{{PLURAL:$1|$1 पन्ना}} राउर धियानसूची में बा (आ वार्ता पन्ना)।",
"wlheader-showupdated": "राउर अंतिम विजिट के बाद जवना पन्ना सभ में बदलाव भइल बा ऊ <strong>मोट अच्छर</strong> में देखावल जात बाड़ें।",
"wlnote": "नीचे $3, $4 तक ले, आखिरी {{PLURAL:$2|घंटा|<strong>$2</strong> घंटा}} में भइल {{PLURAL:$1|अंतिम बदलाव बा|अंतिम <strong>$1</strong> बदलाव बाड़ें}}।",
- "wlshowlast": "पछिला $1 घंटा $2 दिन देखावल जाय",
"watchlist-hide": "छिपावल जाय",
"watchlist-submit": "देखावल जाय",
"wlshowtime": "डिस्प्ले के समय सीमा:",
"uctop": "वर्तमान",
"month": "महीना से (आ ओ से पहिले):",
"year": "साल से (आ ओ से पहिले):",
- "sp-contributions-newbies": "खाली नया खाता के योगदान देखीं।",
- "sp-contributions-newbies-sub": "नया खाता खातिर",
- "sp-contributions-newbies-title": "नया खाता खातिर प्रयोगकर्ता के योगदान।",
"sp-contributions-blocklog": "ब्लॉक लॉग",
"sp-contributions-deleted": "हटावल जा चुकल {{GENDER:$1|प्रयोगकर्ता}} योगदान",
"sp-contributions-uploads": "अपलोड",
"wlheader-enotif": "Suril pamadahan dipajahi.",
"wlheader-showupdated": "Tutungkaran nang ba-ubah tumatan ilangan tauncit Pian ditampaiakan dalam <strong>hurup kandal</strong>.",
"wlnote": "Dibawah ngini adalah {{PLURAL:$1|paubahan pahabisan|<strong>$1</strong> paubahan pahabisan}} dalam {{PLURAL:$2|sajam|<strong>$2</strong> jam}} par $3, $4.",
- "wlshowlast": "Tampaiakan $1 jam $2 hari pahabisan",
"watchlist-options": "Pilihan daptar itihan",
"watching": "Maitihi...",
"unwatching": "Kada jadi maitihi...",
"uctop": "wayah ini",
"month": "Matan bulan (wan sabalumnya):",
"year": "Matan tahun (wan sabalumnya):",
- "sp-contributions-newbies": "Tampaiakan sumbangan papamakai hanyar haja",
- "sp-contributions-newbies-sub": "Gasan akun hanyar",
- "sp-contributions-newbies-title": "Sumbangan pamakai gasan akun hanyar",
"sp-contributions-blocklog": "Log blukir",
"sp-contributions-deleted": "Tahapus sumbangan pamuruk",
"sp-contributions-uploads": "unggahan",
"imgmultipagenext": "halaman salanjutnya →",
"imgmultigo": "Tulak!",
"imgmultigoto": "Tulak ka tungkaran $1",
- "ascending_abbrev": "naik",
- "descending_abbrev": "turun",
"table_pager_next": "Tungkaran salanjutnya",
"table_pager_prev": "Tungkaran sabalumnya",
"table_pager_first": "Tungkaran panambaian",
"nocreate-loggedin": "আপনার নতুন পাতা তৈরি করার অনুমোদন নেই।",
"sectioneditnotsupported-title": "অনুচ্ছেদ সম্পাদনা সমর্থন করে না",
"sectioneditnotsupported-text": "এই সম্পাদনা পাতায় অনুচ্ছেদ সম্পাদনা সমর্থন করে না",
+ "modeleditnotsupported-title": "সম্পাদনা সমর্থিত নয়",
+ "modeleditnotsupported-text": "বিষয়বস্তুর রূপ $1-এর জন্য সম্পাদনা করা সমর্থিত নয়।",
"permissionserrors": "অনুমতি ত্রুটি",
"permissionserrorstext": "নিন্মলিখিত {{PLURAL:$1|কারণটির|কারণগুলির}} জন্য আপনার এটা করার অনুমতি নেই:",
"permissionserrorstext-withaction": "আপনার $2 অনুমতি নেই, যার {{PLURAL:$1|কারণটি|কারণগুলি}} হল:",
"content-model-css": "সিএসএস",
"content-json-empty-object": "খালি বস্তু",
"content-json-empty-array": "খালি অ্যারে",
+ "unsupported-content-model": "<strong>সতর্কতা:</strong> এই উইকিতে বিষয়বস্তুর রূপ $1 সমর্থিত নয়।",
+ "unsupported-content-diff": "বিষয়বস্তুর রূপ $1-এর জন্য পার্থক্য দেখানো সমর্থিত নয়।",
"deprecated-self-close-category": "অবৈধ স্ব-বন্ধকৃত এইচটিএমএল ট্যাগ ব্যবহার করা পাতা",
"deprecated-self-close-category-desc": "এই পাতাটি অবৈধ স্ব-বন্ধকৃত এইচটিএমএল ট্যাগ ধারন করে, যেমন <code><b/></code> বা <code><span/></code>। এইচটিএমএল৫-এর নির্দিষ্টকরণের সঙ্গে সামঞ্জস্যপূর্ণ হতে এইসবের আচরণ শীঘ্রই পরিবর্তন করা হবে, তাই উইকিপাঠ্যে তাদের ব্যবহার অবচিত হয়েছে।",
"duplicate-args-warning": "<strong>সতর্কীকরণ:</strong> \"$3\" প্যারামিটারের জন্য একের অধিক মানসহ [[:$1]] [[:$2]] কে আহ্বান করছে। শুধুমাত্র প্রদত্ত শেষ মান ব্যবহৃত হবে।",
"rcfilters-filter-showlinkedto-label": "এটিতে সংযোগকারী পাতাসমূহের পরিবর্তন দেখান",
"rcfilters-filter-showlinkedto-option-label": "নির্বাচিত পাতাটিতে <strong>সংযোগকারী পাতাসমূহ</strong>",
"rcfilters-target-page-placeholder": "একটি পাতার নাম (বা বিষয়শ্রেণী) লিখুন",
+ "rcfilters-allcontents-label": "সকল বিষয়বস্তু",
+ "rcfilters-alldiscussions-label": "সকল আলোচনা",
"rcnotefrom": "<strong>$2</strong>টা থেকে সংঘটিত পরিবর্তনগুলি (সর্বোচ্চ <strong>$1টি</strong> দেখানো হয়েছে)।",
"rclistfromreset": "তারিখ নির্বাচন পুনঃস্থাপন করুন",
"rclistfrom": "$2, $3 তারিখের পর সংঘটিত নতুন পরিবর্তনগুলো দেখাও",
"apihelp-no-such-module": "মডিউল \"$1\" পাওয়া যায়নি।",
"apisandbox": "এপিআই খেলাঘর",
"apisandbox-jsonly": "API খেলাঘর ব্যবহার করতে জাভাস্ক্রিপ্ট প্রয়োজন।",
- "apisandbox-api-disabled": "এপিআই এই সাইটে নিষ্ক্রিয় করা আছে।",
"apisandbox-intro": "<strong>মিডিয়াউইকি ওয়েব সেবা এপিআই</strong> নিয়ে পরীক্ষানিরীক্ষা চালাতে এই পাতাটি ব্যবহার করুন। \nএপিআই ব্যবহারের উপর বিস্তারিত জানতে [[mw:API:Main page|এপিআই নথিপত্র]] দেখুন।\nউদাহরণ: [https://www.mediawiki.org/wiki/API#A_simple_example প্রধান পাতার বিষয়বস্তু পান]। আরও উদাহরণ দেখার জন্য একটি কর্ম নির্বাচন করুন।\n\nলক্ষ করুন যে যদিও এটি একটি খেলাঘর, তা সত্ত্বেও এই পাতায় করা আপনার সম্পাদনাগুলি উইকিতে পরিবর্তন সাধন করতে পারে।",
"apisandbox-submit": "অনুরোধ করুন",
"apisandbox-reset": "পরিষ্কার",
"wlheader-enotif": "ইমেল বিজ্ঞপ্তি সক্রিয় করা আছে।",
"wlheader-showupdated": "আপনার শেষ আগমনের পর থেকে যেসব পাতায় পরিবর্তন হয়েছে সেগুলি '''গাঢ়''' করে দেখানো হয়েছে।",
"wlnote": "নিচে $3, $4 তারিখ থেকে বিগত {{PLURAL:$2|১ ঘন্টায়|<strong>$2</strong> ঘন্টায়}} সংঘটিত {{PLURAL:$1|শেষ ১টি পরিবর্তন|শেষ <strong>$1টি</strong> পরিবর্তন}} দেখানো হল।",
- "wlshowlast": "সর্বশেষ $1 ঘণ্টা $2 দিনে দেখাও",
"watchlist-hide": "লুকিয়ে রাখা হোক",
"watchlist-submit": "দেখাও",
"wlshowtime": "প্রদর্শনের সময় কাল:",
"changecontentmodel": "একটি পাতার বিষয়বস্তুর রূপ পরিবর্তন",
"changecontentmodel-legend": "বিষয়বস্তুর রূপ পরিবর্তন করুন",
"changecontentmodel-title-label": "পাতার শিরোনাম",
+ "changecontentmodel-current-label": "বর্তমান বিষয়বস্তুর রূপ:",
"changecontentmodel-model-label": "পাতার বিষয়বস্তুর প্রতিরূপ",
"changecontentmodel-reason-label": "কারণ:",
"changecontentmodel-submit": "পরিবর্তন করুন",
"month": "এই মাস (বা তার আগে) থেকে:",
"year": "এই বছর (বা তার আগে) থেকে:",
"date": "এই তারিখ (বা তার আগে) থেকে:",
- "sp-contributions-newbies": "শুধু নতুন অ্যাকাউন্টের অবদানসমূহ দেখাও",
- "sp-contributions-newbies-sub": "নতুন অ্যাকাউন্টের জন্য",
- "sp-contributions-newbies-title": "নতুন অ্যাকাউন্টের ব্যবহারকারী অবদান",
"sp-contributions-blocklog": "বাধা দানের লগ",
"sp-contributions-suppresslog": "গোপনকৃত {{GENDER:$1|ব্যবহারকারীর}} অবদান",
"sp-contributions-deleted": "মুছে ফেলা {{GENDER:$1|ব্যবহারকারীর}} অবদান",
"immobile-target-namespace-iw": "পাতা স্থানান্তরের ক্ষেত্রে ইন্টারউইকি লিংক ব্যবহার করা যাবে না।",
"immobile-source-page": "এই পাতাটির স্থানান্তর সম্ভব নয়।",
"immobile-target-page": "গন্তব্য শিরোনামে স্থানান্তর করা যাবে না।",
+ "movepage-invalid-target-title": "অনুরোধকৃত নামটি অবৈধ।",
"bad-target-model": "আকাঙ্ক্ষিত গন্তব্যটি একটি ভিন্ন সামগ্রীর মডেল ব্যবহার করে। $1 থেকে $2-এ রূপান্তর করা যাবে না।",
"imagenocrossnamespace": "কোনো ফাইল ফাইলনয় এমন নামস্থানে স্থানান্তর সম্ভব নয়",
"nonfile-cannot-move-to-file": "কোনো ফাইলনয় এমন কোনো পাতা ফাইল নামস্থানে স্থানান্তর সম্ভব নয়",
"newimages-legend": "ছাঁকনি",
"newimages-label": "ফাইলের নাম (অথবা এর কোন অংশ):",
"newimages-user": "আইপি ঠিকানা বা ব্যবহারকারী নাম",
- "newimages-newbies": "শুধু নতুন অ্যাকাউন্টের অবদানসমূহ দেখান",
"newimages-showbots": "বটের আপলোড দেখান",
"newimages-hidepatrolled": "টহলকৃত আপলোড লুকানো হোক",
"newimages-mediatype": "মিডিয়ার ধরন:",
"confirm-unwatch-top": "এই পাতাটি আপনার নজরতালিকা থেকে সরিয়ে ফেলতে ইচ্ছুক?",
"confirm-rollback-button": "ঠিক আছে",
"confirm-rollback-top": "এই পাতায় করা সম্পাদনাগুলি প্রত্যাবর্তন করবেন?",
+ "confirm-rollback-bottom": "এই ক্রিয়াটি তাত্ক্ষণিকভাবে এই পাতায় নির্বাচিত পরিবর্তনগুলি রোলব্যাক করবে।",
"confirm-mcrrestore-title": "সংশোধনটি পুনরুদ্ধার করুন",
"confirm-mcrundo-title": "একটি পরিবর্তন পূর্বাবস্থায় আনুন",
"mcrundofailed": "পূর্বাবস্থায় ফেরা ব্যর্থ হয়েছে",
"img-lang-default": "(ডিফল্ট ভাষা)",
"img-lang-info": "$1 এ ছবিটি রেন্ডার করো। $2",
"img-lang-go": "যাও",
- "ascending_abbrev": "আরোহণ",
- "descending_abbrev": "অবতরণ",
"table_pager_next": "পরবর্তী পাতা",
"table_pager_prev": "পূর্ববর্তী পাতা",
"table_pager_first": "প্রথম পাতা",
"watchthispage": "དྲ་ངོས་འདི་ལ་གཟིགས།",
"unwatch": "མི་བལྟ་བ།",
"unwatchthispage": "བལྟ་བ་མཚམས་འཇོག",
- "wlshowlast": "འདས་བའི་དུས་ཚོད་ $1 ནང་ཚུན་ ཉིན་མ་ $2 ནང་ཚུན་ སྟོན།",
"watchlist-options": "ལྟ་ཐོའི་འདེམས་ཚན།",
"watching": "ལྟ་ཐོར་འཇུག་བཞིན་པ་་་",
"unwatching": "ལྟ་ཐོ་ལས་འདོར་བཞིན་པ་་་",
"unwatch": "তালাবি নেই",
"unwatchthispage": "তালাবি এরাদেনা",
"watchlist-details": "{{PLURAL:$1|$1 পাতা|$1 পাতাহানি}} তর তালাবিত আসে, য়্যারির পাতা ধরানি নাসে।",
- "wlshowlast": "গেলগা $1 ঘন্টা $2 দিনর দেখাদে",
"watchlist-options": "তালাবিত আসে পাতার পছনহানি",
"watching": "চা...",
"unwatching": "নাউচা...",
"uctop": "গজ",
"month": "মাহাহানাত্ত (বারো অতার আগেত্ত):",
"year": "বসরেত্ত (বারো অতার আগেত্ত):",
- "sp-contributions-newbies": "হুদ্দা নুৱা একাউন্টর অবদানহানি দেহাদে",
- "sp-contributions-newbies-sub": "নুৱা একাউন্টর কা",
"sp-contributions-blocklog": "থেপকরিসি লগ",
"sp-contributions-uploads": "আপলোডহানি",
"sp-contributions-logs": "লগহানি",
"imgmultipagenext": "থাঙনার পাতাহান →",
"imgmultigo": "হাত!",
"imgmultigoto": "$1 পাতাহাত যাগা",
- "ascending_abbrev": "কাহানি",
- "descending_abbrev": "লামানি",
"table_pager_next": "থাঙনার পাতাহান",
"table_pager_prev": "আগাকার পাতাহান",
"table_pager_first": "পয়লাকর পাতাহান",
"watchlist-details": "{{PLURAL:$1|$1 بٱلٛگاْ|$1 بٱلٛگیٱل}} مؽن لیست دیناگری ایسا,هؽڌا",
"wlheader-showupdated": "بٱلٛگیٱلؽ کاْ دیناتٱر زاْ آخرین ساٛل اؽسا آلشڌ آڤیڌ ناْ<strong>پورٱنڳ</strong> نماونیڌاْ آڤیڌناْ",
"wlnote": "ڤاْ لٱم {{PLURAL:$1|آلشڌؽ|<strong>$1</strong> آلشڌؽ}} کاْ ڤاْ {{PLURAL:$2|سات|<strong>$2</strong> سات}} رٱئڌاْ انجوم آڤؽڌ مۉجۊڌ هؽڌا،ؤرگار دوکرٱت ڤینی دینائی: $3، $4",
- "wlshowlast": "نماونیڌن ٱخیری $1 سات $2 رۊز",
"watchlist-hide": "قام کردن",
"watchlist-submit": "نشوݩ دائن",
"wlshowhideminor": "هیرداْ ڤیرایشت",
"uctop": "تازاْ باو",
"month": "ز ای ما (دینداترس):",
"year": "ز ٱمسال (و سال دینداتری):",
- "sp-contributions-newbies": "فٱقٱت هومیاریٱلی کاْ ز هساڤٱل تاز بیڌناْ دیاری کو.",
- "sp-contributions-newbies-sub": "سی حسابهای کاربری تازه",
"sp-contributions-blocklog": "پهرستنوماْ قولف ڤابیڌاْ",
"sp-contributions-uploads": "سوڤارکردٱل",
"sp-contributions-logs": "پاْرستنۊماْیٱل",
"imgmultigo": "رۉڤا",
"imgmultigoto": "رٱئڌن ڤاٛ بٱلٛگاْ $1",
"img-lang-go": "رۉ",
- "ascending_abbrev": "ری ڤا رو",
- "descending_abbrev": "ری ڤا دڤوݩ",
"table_pager_next": "بٱلگاْ نيايی",
"table_pager_prev": "بٱلگاْ دیندایی",
"table_pager_first": "سرتال",
"apihelp-no-such-module": "N'eo ket bet kavet ar vodulenn \"$1\".",
"apisandbox": "Poull-traezh API",
"apisandbox-jsonly": "Rekis eo JavaScript evit implijout poull-traezh an API.",
- "apisandbox-api-disabled": "Diweredekaet eo API war al lec'hienn-mañ.",
"apisandbox-intro": "Grit gant ar bajenn-mañ evit amprouiñ <strong>servij Web API MediaWiki</strong>.\nKit da deuler ur sell war [[mw:API:Main page|teuliadur API]] evit gouzout hiroc'h war an doare da embreger API. Da skouer :\n[https://www.mediawiki.org/wiki/API#A_simple_example gwelet danvez ur bajenn zegemer]. Dibabit un oberiadenn bennak evit gwelet skouerioù all.\n\nNotit mat : ha pa vefe ar bajenn-mañ ur poull-traezh, an oberiadennoù a rit amañ a c'hall kemmañ ar wiki.",
"apisandbox-submit": "Sevel ar goulenn",
"apisandbox-reset": "Riñsañ",
"wlheader-enotif": "Gweredekaet eo ar c'has posteloù.",
"wlheader-showupdated": "E '''tev''' emañ merket ar pajennoù bet kemmet abaoe ar wezh ziwezhañ hoc'h eus sellet outo",
"wlnote": "Setu aze {{PLURAL:$1|ar c'hemm diwezhañ|ar '''$1''' kemm diwezhañ}} c'hoarvezet e-kerzh an {{PLURAL:$2|eurvezh|'''$2''' eurvezh}} diwezhañ, d'an $3 da $4.",
- "wlshowlast": "Diskouez an $1 eurvezh $2 devezh diwezhañ",
"watchlist-hide": "Kuzhat",
"watchlist-submit": "Diskouez",
"wlshowtime": "Prantad amzer war wel :",
"month": "Abaoe miz (hag a-raok) :",
"year": "Abaoe bloaz (hag a-raok) :",
"date": "Abaoe an (hag a-raok) :",
- "sp-contributions-newbies": "Diskouez hepken degasadennoù ar c'hontoù nevez",
- "sp-contributions-newbies-sub": "Evit an implijerien nevez",
- "sp-contributions-newbies-title": "Degasadennoù implijer evit ar c'hontoù nevez",
"sp-contributions-blocklog": "Roll ar stankadennoù",
"sp-contributions-suppresslog": "degasadennoù diverket {{GENDER:$1|an implijer|an implijerez}}",
"sp-contributions-deleted": "degasadennoù diverket {{GENDER:$1|an implijer|an implijerez}}",
"img-lang-default": "(yezh dre ziouer)",
"img-lang-info": "Diskouez ar skeudenn-mañ e $1. $2",
"img-lang-go": "Mont",
- "ascending_abbrev": "pignat",
- "descending_abbrev": "diskenn",
"table_pager_next": "Pajenn war-lerc'h",
"table_pager_prev": "Pajenn gent",
"table_pager_first": "Pajenn gentañ",
"apihelp-no-such-module": "Modul \"$1\" nije pronađen.",
"apisandbox": "API pješčanik",
"apisandbox-jsonly": "Upotreba API pješčanika zahtijeva JavaScript.",
- "apisandbox-api-disabled": "API je onemogućen na ovom sajtu.",
"apisandbox-submit": "Postavi zahtjev",
"apisandbox-reset": "Očisti",
"apisandbox-retry": "Pokušaj ponovo",
"wlheader-enotif": "Uključeno je obavještenje e-poštom.",
"wlheader-showupdated": "Stranice koje su izmijenjene otkad ste ih posljednji put posjetili istaknute su <strong>podebljanim slovima</strong>.",
"wlnote": "Ispod {{PLURAL:$1|je posljednja izmjena|su <strong>$1</strong> posljednje izmjene|su <strong>$1</strong> posljednjih izmjena}} načinjenih {{PLURAL:$2|posljednjeg sata|u posljednjih <strong>$2</strong> sata|u posljednjih <strong>$2</strong> sati}}, od $3, $4.",
- "wlshowlast": "Prikaži posljednjih $1 sati $2 dana",
"watchlist-hide": "Sakrij",
"watchlist-submit": "Prikaži",
"wlshowtime": "Vremensko razdoblje za prikaz:",
"month": "Od mjeseca (i ranije):",
"year": "Od godine (i ranije):",
"date": "Od datuma (i ranije):",
- "sp-contributions-newbies": "Prikaži samo doprinose novih korisnika",
- "sp-contributions-newbies-sub": "Za nove korisnike",
- "sp-contributions-newbies-title": "Doprinosi novih korisnika",
"sp-contributions-blocklog": "zapisnik blokiranja",
"sp-contributions-suppresslog": "izbrisani doprinosi {{GENDER:$1|korisnika|korisnice}}",
"sp-contributions-deleted": "izbrisani doprinosi {{GENDER:$1|korisnika|korisnice}}",
"newimages-legend": "Filter",
"newimages-label": "Ime datoteke (ili dio imena):",
"newimages-user": "IP-adresa ili korisničko ime",
- "newimages-newbies": "Prikaži doprinose samo novih računa",
"newimages-showbots": "Prikaži datoteke koje su postavili botovi",
"newimages-hidepatrolled": "Sakrij patrolirana postavljanja",
"newimages-mediatype": "Vrsta datoteke:",
"img-lang-default": "(podrazumijevani jezik)",
"img-lang-info": "Prikaži ovu sliku u $1. $2",
"img-lang-go": "Idi",
- "ascending_abbrev": "rast",
- "descending_abbrev": "opad",
"table_pager_next": "Sljedeća stranica",
"table_pager_prev": "Prethodna stranica",
"table_pager_first": "Prva stranica",
"watchlist-details": "{{PLURAL:$1|$1 page is|$1 alaman}} i pamataanmu (dot alaman parkobaran).",
"wlheader-showupdated": "Laman na madung iubah sian parpudi Amu ligi, ipatidaon i huruf <strong> naapal </strong>.",
"wlnote": "Itoruon {{PLURAL:$1|is the last change|ima parpudi<strong>$1</strong> parubaan}} i {{PLURAL:$2|hour|<strong>$2</strong> jom}}, i $3, $4.",
- "wlshowlast": "Patidaon parpudi $1 jom $2 ari",
"watchlist-options": "Opsi pamataan",
"enotif_reset": "Tandai sude alaman namadung iligi",
"dellogpage": "Apus log",
"uctop": "sonnari",
"month": "Tingon bulan (dot nasolpu)",
"year": "Tingon taon (dot nasolpu)",
- "sp-contributions-newbies": "Patidaon kontribusi ni akun nabaru sajope",
"sp-contributions-blocklog": "Log blokir",
"sp-contributions-uploads": "Unggah",
"sp-contributions-logs": "Log",
"emailccme": "Padarhi ako sa kopya ku kanakong mensahe",
"emailsenttext": "A kanimong email naipadara na.",
"watchlistfor2": "Para sa $1 $2",
- "wlshowlast": "Ipabayad a huring $1 mga oras $2 mga aldow",
"delete-confirm": "Puraon a $1",
"deleteotherreason": "Iba/rugang na rason:",
"protect-otherreason": "Iba/rugang na rason:",
"uctop": "nguwan",
"month": "Poon bulan (anggan nauna):",
"year": "Poon taon (anggan nauna):",
- "sp-contributions-newbies-sub": "Para sa mga bagong account",
"sp-contributions-deleted": "napurang mga ambag ka user",
"sp-contributions-uploads": "mga karga",
"sp-contributions-logs": "mga loog",
"apihelp-no-such-module": "No s’ha trobat el mòdul «$1».",
"apisandbox": "Pàgina de proves de l'API",
"apisandbox-jsonly": "Es necessita JavaScript per utilitzar l'espai de proves API.",
- "apisandbox-api-disabled": "L'API està desactivada en aquest lloc.",
"apisandbox-intro": "Utilitzeu aquesta pàgina per experimentar amb l'<strong>API de servei web de MediaWiki</strong>.\nVegeu la [[mw:API:Main page|documentació de l'API]] per a més informació sobre l'ús de l'API. Exemple: [https://www.mediawiki.org/wiki/API#A_simple_example recuperar el contingut d'una Pàgina Principal]. Seleccioneu una acció per veure més exemples.\n\nTingueu en compte que, encara que això és una pàgina de proves, les accions que feu en aquesta pàgina poden modificar la wiki.",
"apisandbox-submit": "Fes sol·licitud",
"apisandbox-reset": "Neteja",
"wlheader-enotif": "La notificació per correu electrònic està habilitada.",
"wlheader-showupdated": "Les pàgines que s'han canviat des de la vostra darrera visita es mostren en '''negreta'''.",
"wlnote": "A sota hi ha {{PLURAL:$1|el darrer canvi|els darrers <strong>$1</strong> canvis}} en {{PLURAL:$2|la darrera hora|les <strong>$2</strong> darreres hores}}, a $4 del $3.",
- "wlshowlast": "Mostra les darreres $1 hores, els darrers $2 dies",
"watchlist-hide": "Amaga",
"watchlist-submit": "Mostra",
"wlshowtime": "Període de temps per mostrar:",
"month": "Mes (i anteriors):",
"year": "Any (i anteriors):",
"date": "Des de la data (i abans):",
- "sp-contributions-newbies": "Mostra les contribucions dels usuaris novells",
- "sp-contributions-newbies-sub": "Per a novells",
- "sp-contributions-newbies-title": "Contribucions dels comptes d'usuari més nous",
"sp-contributions-blocklog": "Registre de blocatges",
"sp-contributions-suppresslog": "contribucions suprimides de {{GENDER:$1|l'usuari|la usuària}}",
"sp-contributions-deleted": "contribucions de {{GENDER:$1|l’usuari|la usuària}} suprimides",
"newimages-legend": "Nom del fitxer",
"newimages-label": "Nom de fitxer (o part d'ell):",
"newimages-user": "Adreça IP o nom d'usuari",
- "newimages-newbies": "Mostra només les contribucions dels comptes nous",
"newimages-showbots": "Mostra les càrregues dels bots",
"newimages-hidepatrolled": "Amaga les càrregues patrullades",
"newimages-mediatype": "Tipus multimèdia:",
"img-lang-default": "(llengua per defecte)",
"img-lang-info": "Dibuixa aquesta imatge en $1. $2",
"img-lang-go": "Vés-hi",
- "ascending_abbrev": "asc",
- "descending_abbrev": "desc",
"table_pager_next": "Pàgina següent",
"table_pager_prev": "Pàgina anterior",
"table_pager_first": "Primera pàgina",
"watchlist-details": "Nṳ̄ gì găng-sê-dăng {{PLURAL:$1|ô $1 gó|dŭ liāng ô $1 gó}} hiĕk-miêng (bău-guák tō̤-lâung-hiĕk).",
"wlheader-enotif": "Ī-gĭng kŭi kó̤ diêng-piĕ tŭng-dĭ.",
"wlheader-showupdated": "Ṳ̀-guō ô diê-siŏh-hiĕk, găk nṳ̄ muōi-muōi siŏh-huòi káng guó cī-hâiu, bô ké̤ṳk nè̤ng gāi kó̤, hī-siŏh-hiĕk gì biĕu-dà̤ cêu-sê <strong>cū-tā̤</strong>.",
- "wlshowlast": "顯示最$1點鐘$2日",
"watchlist-options": "監視單選項",
"watching": "監視...",
"deletepage": "刪頁",
"uctop": "當前",
"month": "趁月(共更早):",
"year": "趁年(共更早):",
- "sp-contributions-newbies": "囇顯示新開賬戶其貢獻",
- "sp-contributions-newbies-sub": "才來其",
"sp-contributions-blocklog": "封鎖日誌",
"sp-contributions-deleted": "乞刪唻其{{GENDER:$1|用戶}}貢獻",
"sp-contributions-uploads": "上傳",
"imgmultipagenext": "下蜀頁 →",
"imgmultigo": "去!",
"imgmultigoto": "Kó̤ {{PLURAL:$1|tàu-siŏh-hiĕk|dâ̤ $1 hiĕk}}",
- "ascending_abbrev": "升",
- "descending_abbrev": "降",
"table_pager_next": "下蜀頁",
"table_pager_prev": "前蜀頁",
"table_pager_first": "頭頁",
"wlheader-enotif": "Электронан поште хаамаш байтар латина ду.",
"wlheader-showupdated": "Хийцам бина агӀонаш '''Ӏаьржа''' шрифтцан билгальяха ю.",
"wlnote": "Гойту <strong>$2</strong> {{plural:$2|сахьтчохь}} бина {{PLURAL:$1|тӀеххьара '''$1''' хийцам}}, хан $3 $4",
- "wlshowlast": "Гайта тӀаьххьара $1 сахьт $2 де",
"watchlist-hide": "Къайлаяккха",
"watchlist-submit": "Гайта",
"wlshowtime": "Гаран хенан мур:",
"uctop": "карара",
"month": "Баттачохь (я хьалхе):",
"year": "Шерачохь (я хьалхе):",
- "sp-contributions-newbies": "Керла декъашхойн къинхьегам бен ма гайта",
- "sp-contributions-newbies-sub": "Керла декъашхойн дӀаяздаршкара",
- "sp-contributions-newbies-title": "Дукху хан йоцуш кхоьллинчу декъашхойн дӀаяздарийн къинхьегам",
"sp-contributions-blocklog": "блоктоьхнарш",
"sp-contributions-suppresslog": "Декъашхочун дӀабаьккхина къинхьегам",
"sp-contributions-deleted": "дӀадяхна нийсдарш",
"newimages-summary": "ХӀокху белхан агӀона чохь гойтуш ю дукха хан йоццуш чуяьхна файлаш.",
"newimages-legend": "Луьттург",
"newimages-user": "Декъашхочун цӀе я IP-адрес",
- "newimages-newbies": "Керла декъашхойн къинхьегам бен ма гайта",
"newimages-showbots": "Гайта боташ чуяьхна файлаш",
"newimages-hidepatrolled": "Къайлаяха патруль йина файлаш",
"newimages-mediatype": "Медиа тайпа:",
"img-lang-default": "(Ӏадйитаран кепаца болу мотт)",
"img-lang-info": "Гайта хӀара сурт $1 $2 маттахь",
"img-lang-go": "Кхочушдé",
- "ascending_abbrev": "гар",
- "descending_abbrev": "йина",
"table_pager_next": "ТӀаьхьа йогӀу агӀо",
"table_pager_prev": "Хьалха йоьду агӀо",
"table_pager_first": "Хьалхара агӀо",
"watchthispage": "Bantayi kining panid",
"unwatch": "Pasagdi",
"watchlist-details": "{{PLURAL:$1|$1 ka panid|$1 ka mga panid}} ang imong gibantayan, way labot ang mga panid sa hisgot.",
- "wlshowlast": "Ipakita ang miaging $1 ka oras $2 ka mga adlaw",
"watchlist-hide": "Tagoa",
"watchlist-options": "Mga opsyon sa akong gibantayan",
"watching": "Gibantayan...",
"uctop": "hitaas",
"month": "Gikan sa bulan (ug mas sayo pa):",
"year": "Gikan sa tuig (ug mas sayo pa):",
- "sp-contributions-newbies": "Ipakita lamang ang mga tampo sa mga bag-ong gumagamit",
"sp-contributions-blocklog": "log sa block",
"sp-contributions-talk": "Hisgot",
"sp-contributions-search": "Pangitaa ang mga tampo",
"watchthispage": "Pulan este na påhina",
"unwatch": "Basta mapulan",
"watchlist-details": "{{PLURAL:$1|$1 påhina|$1 na påhina siha}} un pupulan, sin i påhinan kombetsasion siha.",
- "wlshowlast": "Na'annok $1 na ora yan $2 na diha siha gi halacha",
"watching": "Mamulan...",
"unwatching": "Pumapara mamulan...",
"deletepage": "Na'suha i påhina",
"uctop": "sanhilo'",
"month": "Ginen i mes (yan eståba):",
"year": "Ginen i sakkan (yan eståba):",
- "sp-contributions-newbies-sub": "Para i mannuebu na kuenta siha",
"sp-contributions-blocklog": "Na'påra i log",
"sp-contributions-talk": "Kuentusi",
"sp-contributions-submit": "Aligao",
"wlheader-enotif": "ئاگاداری بە ئیمەیل چالاکە.",
"wlheader-showupdated": "ئەو پەڕانە کە لە پاش دوایین سەردانت دەستکاری کراون بە <strong>ئەستوور</strong> نیشان دراون.",
"wlnote": "خوارەوە {{PLURAL:$1|دوایین گۆڕانکارییە|دوایین <strong>$1</strong> گۆڕانکارییە}} لە دوایین {{PLURAL:$2|کاتژمێر|<strong>$2</strong> کاتژمێر}}دا ھەتا $4ی $3.",
- "wlshowlast": "دوایین $1 کاتژمێری $2 ڕۆژ نیشان بدە",
"watchlist-hide": "شاردراوە",
"watchlist-submit": "نیشاندان",
"wlshowtime": "ماوەی کات بۆ نیشاندان:",
"month": "لە مانگی (و پێشترەوە):",
"year": "لە ساڵی (و پێشترەوە):",
"date": "لە ڕێکەوتی (و پێشترەوە)",
- "sp-contributions-newbies": "تەنیا بەشدارییەکانی ھەژمارە نوێکان نیشان بدە",
- "sp-contributions-newbies-sub": "بۆ ھەژمارە نوێکان",
- "sp-contributions-newbies-title": "بەشدارییەکانی بەکارھێنەر بۆ ھەژمارە نوێکان",
"sp-contributions-blocklog": "لۆگی بەربەستن",
"sp-contributions-deleted": "بەشدارییە سڕاوەکانی {{GENDER:$1|بەکارھێنەر}}",
"sp-contributions-uploads": "بارکردنەکان",
"imgmultigoto": "بڕۆ بۆ پەڕەی $1",
"img-lang-default": "(زمانی بنچینەیی)",
"img-lang-go": "بڕۆ",
- "ascending_abbrev": "بەرەوە ژوور",
- "descending_abbrev": "بەرەوە ژێر",
"table_pager_next": "پەڕەی داهاتوو",
"table_pager_prev": "پەڕەی پێشوو",
"table_pager_first": "پەرەی یەکەم",
"watchlistfor2": "Per $1 ($2)",
"watch": "Suvità",
"unwatch": "Ùn suvità micca",
- "wlshowlast": "Mustrà l'ùltime $1 ore $2 ghjorni",
"enotif_reset": "Marcà tutte e pagine visitate",
"created": "creatu",
"changed": "cambiatu",
"uctop": "attuale",
"month": "Da u mese (è nanzu):",
"year": "Da l'annu (è nanzu):",
- "sp-contributions-newbies": "Mustrà solu e mudifiche di i novi cuntributori",
"sp-contributions-talk": "discussione",
"sp-contributions-search": "Ricercà e cuntribuzione",
"sp-contributions-username": "Adrizzu IP o nome di cuntributore",
"watchthispage": "Bantayan ang mini nga pahina",
"unwatch": "Di pagbantayan",
"watchlist-details": "{{PLURAL:$1|$1 ka pahina|$1 ka mga pahina}} sa imo listahan sang ginabantayan, wala madala ang mga pahina sang istoryahanay.",
- "wlshowlast": "Ipakita ang nagligad nga $1 ka mga oras $2 ka mga adlaw",
"watchlist-options": "Pililian para sa listahan sang mga ginabantayan",
"watching": "Ginabantayan...",
"unwatching": "Wala ginabantayan...",
"uctop": "ibabaw",
"month": "Halin sa bulan (kag sa mas timprano):",
"year": "Halin sa tu-ig (kag sa mas timprano):",
- "sp-contributions-newbies": "Ipakita lang gid ang mga kontribusyon sang mga bag-o nga account",
"sp-contributions-blocklog": "Lista sang pagbangga",
"sp-contributions-search": "Mangita sang mga nabulig",
"sp-contributions-username": "IP address ukon hayo (username):",
"wlheader-enotif": "E-mail иле хабер берюв ачылды.",
"wlheader-showupdated": "Сонъки зияретинъизден сонъ денъиштирильген саифелер '''къалын арифлернен''' косьтерильди.",
"wlnote": "Ашагъыда саат $3, $4 ичюн сонъки {{PLURAL:$2|1=саат|'''$2''' саат}} ичинде япылгъан сонъки {{PLURAL:$1|1=денъиштирме|'''$1''' денъиштирме}} косьтериле.",
- "wlshowlast": "Сонъки $1 саат ичюн, $2 кунь ичюн я да косьтер",
"watchlist-options": "Козетюв джедвели сазламалары",
"watching": "Козетюв джедвелине кирсетильмекте...",
"unwatching": "Козетюв джедвелинден ёкъ этильмекте...",
"uctop": "сонъки",
"month": "Бу ай (ве ондан эрте):",
"year": "Бу сене (ве ондан эрте):",
- "sp-contributions-newbies": "Тек янъы къулланыджыларнынъ исселерини косьтер",
- "sp-contributions-newbies-sub": "Янъы къулланыджылар ичюн",
"sp-contributions-blocklog": "Блок этюв журналы",
"sp-contributions-talk": "музакере",
"sp-contributions-userrights": "къулланыджы акъларыны идаре этюв",
"imgmultipagenext": "сонъраки саифе →",
"imgmultigo": "Бар",
"imgmultigoto": "$1 саифесине бар",
- "ascending_abbrev": "кичиктен буюкке",
- "descending_abbrev": "буюктен кичикке",
"table_pager_next": "Сонъраки саифе",
"table_pager_prev": "Эвельки саифе",
"table_pager_first": "Ильк саифе",
"wlheader-enotif": "E-mail ile haber berüv açıldı.",
"wlheader-showupdated": "Soñki ziyaretiñizden soñ deñiştirilgen saifeler '''qalın ariflernen''' kösterildi.",
"wlnote": "Aşağıda saat $3, $4 içün soñki {{PLURAL:$2|saat|'''$2''' saat}} içinde yapılğan soñki {{PLURAL:$1|deñiştirme|'''$1''' deñiştirme}} kösterile.",
- "wlshowlast": "Soñki $1 saat içün, $2 kün içün ya da köster",
"watchlist-options": "Közetüv cedveli sazlamaları",
"watching": "Közetüv cedveline kirsetilmekte...",
"unwatching": "Közetüv cedvelinden yoq etilmekte...",
"uctop": "soñki",
"month": "Bu ay (ve ondan erte):",
"year": "Bu sene (ve ondan erte):",
- "sp-contributions-newbies": "Tek yañı qullanıcılarnıñ isselerini köster",
- "sp-contributions-newbies-sub": "Yañı qullanıcılar içün",
"sp-contributions-blocklog": "Blok etüv jurnalı",
"sp-contributions-talk": "muzakere",
"sp-contributions-userrights": "qullanıcı aqlarını idare etüv",
"imgmultipagenext": "soñraki saife →",
"imgmultigo": "Bar",
"imgmultigoto": "$1 saifesine bar",
- "ascending_abbrev": "kiçikten büyükke",
- "descending_abbrev": "büyükten kiçikke",
"table_pager_next": "Soñraki saife",
"table_pager_prev": "Evelki saife",
"table_pager_first": "İlk saife",
"Jan Růžička",
"Jaroslav Cerny",
"Slepi",
- "Tchoř"
+ "Tchoř",
+ "SimonV"
]
},
"tog-underline": "Podtrhávat odkazy:",
"apihelp-no-such-module": "Modul „$1“ nebyl nalezen.",
"apisandbox": "Pískoviště API",
"apisandbox-jsonly": "Pro použití pískoviště API je nutný JavaScript.",
- "apisandbox-api-disabled": "API je na tomto webu vypnuto.",
"apisandbox-intro": "Pomocí této stránky můžete experimentovat s <strong>webovými službami MediaWiki API</strong>.\nPodrobnosti využití API najdete v [[mw:API:Main page|jeho dokumentaci]]. Příklad: [https://www.mediawiki.org/wiki/API#A_simple_example získání obsahu Hlavní stránky]. Další příklady uvidíte vybráním parametru action.\n\nUvědomte si, že přestože jste na pískovišti, mohou akce provedené na této stránce wiki změnit.",
"apisandbox-submit": "Odeslat požadavek",
"apisandbox-reset": "Vyčistit",
"wlheader-enotif": "Upozorňování e-mailem je zapnuto.",
"wlheader-showupdated": "Stránky, které se změnily od vaší poslední návštěvy, jsou zobrazeny <strong>tučně</strong>.",
"wlnote": "Níže {{PLURAL:$1|je poslední změna|jsou poslední <strong>$1</strong> změny|je posledních <strong>$1</strong> změn}} za {{PLURAL:$2|poslední hodinu|poslední <strong>$2</strong> hodiny|posledních <strong>$2</strong> hodin}} do $4, $3.",
- "wlshowlast": "Ukázat posledních $1 hodin $2 dnů",
"watchlist-hide": "Skrýt",
"watchlist-submit": "Zobrazit",
"wlshowtime": "Zobrazené období:",
"sessionfailure": "Nastal problém s vaším přihlášením;\nvámi požadovaná činnost byla zrušena jako prevence před neoprávněným přístupem.\nStiskněte tlačítko „zpět“, obnovte stránku, ze které jste přišli, a zkuste činnost znovu.",
"changecontentmodel": "Změnit model obsahu stránky",
"changecontentmodel-legend": "Změnit model obsahu",
- "changecontentmodel-title-label": "Název stránky",
+ "changecontentmodel-title-label": "Název stránky:",
"changecontentmodel-current-label": "Současný model obsahu:",
- "changecontentmodel-model-label": "Nový model obsahu",
+ "changecontentmodel-model-label": "Nový model obsahu:",
"changecontentmodel-reason-label": "Důvod:",
"changecontentmodel-submit": "Změnit",
"changecontentmodel-success-title": "Model obsahu byl změněn",
"month": "Do měsíce:",
"year": "Do roku:",
"date": "Od data (a dříve):",
- "sp-contributions-newbies": "Zobrazit příspěvky nově založených účtů",
- "sp-contributions-newbies-sub": "Noví uživatelé",
- "sp-contributions-newbies-title": "Příspěvky nových uživatelů",
"sp-contributions-blocklog": "kniha zablokování",
"sp-contributions-suppresslog": "utajené příspěvky {{GENDER:$1|uživatele|uživatelky}}",
"sp-contributions-deleted": "smazané editace {{GENDER:$1|uživatele|uživatelky}}",
"newimages-legend": "Filtr",
"newimages-label": "Název souboru (nebo jeho část):",
"newimages-user": "IP adresa nebo uživatelské jméno",
- "newimages-newbies": "Zobrazit pouze příspěvky nových účtů",
"newimages-showbots": "Zobrazit soubory načtené roboty",
"newimages-hidepatrolled": "Skrýt prověřená načtení souborů",
"newimages-mediatype": "Typ média:",
"img-lang-default": "(implicitní jazyk)",
"img-lang-info": "Vykreslit tento obrázek v jazyce $1 $2",
"img-lang-go": "Provést",
- "ascending_abbrev": "vzest.",
- "descending_abbrev": "sest.",
"table_pager_next": "Následující stránka",
"table_pager_prev": "Předchozí stránka",
"table_pager_first": "První stránka",
"watchlist-details": "{{PLURAL:$1|Starna je |$1 Starnë są}} na twòji lësce ùzérónych starnów (diskùsëji téż)",
"wlheader-showupdated": "Artiklë jakczé òstałë zmienioné òd Twòji slédny wizytë są wëapratnioné <strong>pògrëbieniém</strong>",
"wlnote": "Niżi môsz wëskrzënioné {{PLURAL:$1|slédną zmianã|<strong>$1</strong> slédnëch zmianów}} zrobioné òb {{PLURAL:$2|gòdzënã|<strong>$2</strong> gòdzënë/gòdzënów}}, rëchùjąc òd $3 dnia $4.",
- "wlshowlast": "Wëskrzëni zjinaczi z $1 gòdzënów $2 dni",
"wlshowhidecategorization": "kategòrizacjã strón",
"watchlist-options": "Òptacëje ùzérónych",
"watching": "Ùzéróm...",
"uctop": "aktualnô",
"month": "Òd miesąca (ë wczasni):",
"year": "Òd rokù (ë wczasni):",
- "sp-contributions-newbies": "Pòkażë edicëjã blós nowich brëkòwników",
- "sp-contributions-newbies-sub": "Dlô nowich brëkòwników",
"sp-contributions-blocklog": "historëjô blokòwaniô",
"sp-contributions-deleted": "rëmniãtô robòta {{GENDER:$1|brëkòwnika|brëkòwniczczi}}",
"sp-contributions-uploads": "Wësłóné lopczi",
"wlheader-enotif": "Galluogwyd hysbysiadau trwy e-bost.",
"wlheader-showupdated": "Mae tudalennau sydd wedi newid ers i chi eu gweld ddiwethaf wedi'u '''hamlygu'''.",
"wlnote": "Isod, {{PLURAL:$1|yw'r golygiad diweddaraf |yw'r golygiadau diweddaraf <strong>$1</strong> changes}} yn y {{PLURAL:$2|hour|<strong>$2</strong> awr}}, fel ag y mae ar $3, $4.",
- "wlshowlast": "Dangoser newidiadau'r $1 awr ddiwethaf neu'r $2 {{PLURAL:$2|diwrnod|diwrnod|ddiwrnod|diwrnod|diwrnod|diwrnod}} diwethaf neu'r newidiadau.",
"watchlist-hide": "Cuddio",
"watchlist-submit": "Dangos",
"wlshowtime": "Dangos y cyfnod:",
"uctop": "cyfredol",
"month": "Cyfraniadau hyd at fis (ac yn gynharach):",
"year": "Cyfraniadau hyd at y flwyddyn (ac yn gynharach):",
- "sp-contributions-newbies": "Dangos cyfraniadau gan gyfrifon newydd yn unig",
- "sp-contributions-newbies-sub": "Ar gyfer cyfrifon newydd",
- "sp-contributions-newbies-title": "Cyfraniadau defnyddwyr ar gyfer cyfrifon newydd",
"sp-contributions-blocklog": "lòg blocio",
"sp-contributions-suppresslog": "atal cyfraniadau'r {{GENDER:$1|defnyddiwr}}",
"sp-contributions-deleted": "cyfraniadau a ddilewyd gan y {{GENDER:$1|defnyddiwr}}",
"newimages-legend": "Hidlo",
"newimages-label": "Enw'r ffeil (neu ran ohono):",
"newimages-user": "Cyfeiriad IP neu enw defnyddiwr",
- "newimages-newbies": "Dangos cyfraniadau cyfrifon newydd yn unig",
"newimages-showbots": "Dangoswch uwchlwythiadau'r botiaid",
"newimages-hidepatrolled": "Cuddio uwchlwythiadau gwaith a ddilyswyd gan olygydd profiadol",
"newimages-mediatype": "Math o gyfrwng:",
"img-lang-default": "(diofyn)",
"img-lang-info": "Cynhyrchu'r ddelwedd yn yr iaith $1. $2",
"img-lang-go": "Cynhyrcher",
- "ascending_abbrev": "esgynnol",
- "descending_abbrev": "am lawr",
"table_pager_next": "Tudalen nesaf",
"table_pager_prev": "Tudalen gynt",
"table_pager_first": "Tudalen gyntaf",
"rcfilters-filter-showlinkedto-label": "Vis ændringer på sider der linker til",
"rcfilters-filter-showlinkedto-option-label": "<strong>Sider som linker til</strong> den valgte side",
"rcfilters-target-page-placeholder": "Indtast et sidenavn (eller en kategori)",
+ "rcfilters-allcontents-label": "Alt indhold",
"rcnotefrom": "Nedenfor er op til '''$1''' {{PLURAL:$5|ændring|ændringer}} siden '''$2''' vist.",
"rclistfromreset": "Nulstil datovalg",
"rclistfrom": "Vis nye ændringer startende fra den $3 kl. $2",
"apihelp-no-such-module": "Modul \"$1\" ikke fundet.",
"apisandbox": "API-sandkassen",
"apisandbox-jsonly": "JavaScript kræves for at bruge API-sandkassen.",
- "apisandbox-api-disabled": "API er deaktiveret på dette websted.",
"apisandbox-intro": "Brug denne side til at eksperimentere med '''MediaWiki web service API'''.\nVi henviser til [https://www.mediawiki.org/wiki/API:Main_page dokumentationen af API] for yderligere oplysninger om brug af API. Eksempel: [https://www.mediawiki.org/wiki/API#A_simple_example få indholdet af en forside]. Vælg en handling at se flere eksempler.\n\nBemærk, at selv om dette er en sandkasse, vil handlinger du udfører på denne side redigere wikien.",
"apisandbox-submit": "Lav forespørgsel",
"apisandbox-reset": "Ryd",
"wlheader-enotif": "E-mail-underretning er slået til.",
"wlheader-showupdated": "Sider, der er ændret siden dit sidste besøg, er vist med '''fed skrift'''.",
"wlnote": "Nedenfor ses {{PLURAL:$1|den seneste ændring|de seneste <strong>$1</strong> ændringer}} i {{PLURAL:$2|den sidste time|de sidste <strong>$2</strong> timer}} op til den $3 kl. $4.",
- "wlshowlast": "Vis de seneste $1 timer $2 dage",
"watchlist-hide": "Skjul",
"watchlist-submit": "Vis",
"wlshowtime": "Vis seneste:",
"sessionfailure-title": "Sessionsfejl",
"sessionfailure": "Der lader til at være et problem med din loginsession; denne handling blev annulleret som en sikkerhedsforanstaltning mod kapring af sessionen. Genindsend venligst formularen.",
"changecontentmodel-legend": "Ændr indholdsmodel",
- "changecontentmodel-title-label": "Sidetitel",
- "changecontentmodel-model-label": "Ny indholdsmodel",
+ "changecontentmodel-title-label": "Sidetitel:",
+ "changecontentmodel-model-label": "Ny indholdsmodel:",
"changecontentmodel-reason-label": "Begrundelse:",
"changecontentmodel-submit": "Ændr",
"changecontentmodel-success-title": "Indholdsmodellen blev ændret",
"month": "Fra måned (og tidligere):",
"year": "Fra år (og tidligere):",
"date": "Fra dato (og tidligere):",
- "sp-contributions-newbies": "Vis kun bidrag fra nye brugere",
- "sp-contributions-newbies-sub": "Fra nye kontoer",
- "sp-contributions-newbies-title": "Brugerbidrag fra nye konti",
"sp-contributions-blocklog": "blokeringslog",
"sp-contributions-suppresslog": "undertrykte {{GENDER:$1|brugerbidrag}}",
"sp-contributions-deleted": "slettede {{GENDER:$1|brugerbidrag}}",
"newimages-legend": "Filter",
"newimages-label": "Filnavn (eller en del af det):",
"newimages-user": "IP-adresse eller brugernavn",
- "newimages-newbies": "Vis kun bidrag fra nye konti",
"newimages-showbots": "Vis oplægninger af robotter",
"newimages-hidepatrolled": "Skjul patruljerede uploads",
"newimages-mediatype": "Medietype:",
"img-lang-default": "(standardsprog)",
"img-lang-info": "Gengiv dette billede på $1. $2",
"img-lang-go": "Udfør",
- "ascending_abbrev": "op",
- "descending_abbrev": "ned",
"table_pager_next": "Næste side",
"table_pager_prev": "Forrige side",
"table_pager_first": "Første side",
"apihelp-no-such-module": "Modul „$1“ nicht gefunden.",
"apisandbox": "API-Spielwiese",
"apisandbox-jsonly": "Zur Nutzung der API-Spielwiese ist JavaScript erforderlich.",
- "apisandbox-api-disabled": "Die API wurde auf diesem Wiki deaktiviert.",
"apisandbox-intro": "Diese Seite kannst du für Versuche mit der <strong>MediaWiki-API</strong> verwenden.\nDie [[mw:API:Main page|Dokumentation zur API]] enthält weitere Hinweise zu ihrer Nutzung. Beispiel: [https://www.mediawiki.org/wiki/API:Main_page/de#Ein_einfaches_Beispiel Den Inhalt der Hauptseite abrufen]. Wähle für weitere Beispiele eine der verfügbaren Aktionen.\n\nObwohl dies eine Spielwiese ist, bedenke, dass Aktionen, die du auf dieser Seite durchführst, das Wiki verändern.",
"apisandbox-submit": "Anfrage ausführen",
"apisandbox-reset": "Leeren",
"wlheader-enotif": "Der E-Mail-Benachrichtigungsdienst ist aktiviert.",
"wlheader-showupdated": "Seiten mit noch nicht gesehenen Änderungen werden '''fett''' dargestellt.",
"wlnote": "Es {{PLURAL:$1|folgt die letzte Änderung|folgen die letzten <strong>$1</strong> Änderungen}} der letzten {{PLURAL:$2|Stunde|<strong>$2</strong> Stunden}}. Stand: $3, $4 Uhr.",
- "wlshowlast": "Zeige die Änderungen der letzten $1 Stunden, $2 Tage.",
"watchlist-hide": "Ausblenden",
"watchlist-submit": "Anzeigen",
"wlshowtime": "Anzuzeigende Zeitperiode:",
"month": "und Monat:",
"year": "bis Jahr:",
"date": "Von Datum (und früher):",
- "sp-contributions-newbies": "Zeige nur Beiträge neuer Benutzer",
- "sp-contributions-newbies-sub": "Von neuen Benutzern",
- "sp-contributions-newbies-title": "Benutzerbeiträge von neuen Benutzern",
"sp-contributions-blocklog": "Sperr-Logbuch",
"sp-contributions-suppresslog": "Unterdrückte {{GENDER:$1|Benutzerbeiträge}}",
"sp-contributions-deleted": "Gelöschte {{GENDER:$1|Benutzerbeiträge}}",
"newimages-legend": "Filter",
"newimages-label": "Dateiname (oder ein Teil davon):",
"newimages-user": "IP-Adresse oder Benutzername",
- "newimages-newbies": "Nur Beiträge neuer Benutzerkonten anzeigen",
"newimages-showbots": "Von Bots hochgeladene Dateien anzeigen",
"newimages-hidepatrolled": "Kontrollierte Dateien ausblenden",
"newimages-mediatype": "Medientyp:",
"img-lang-default": "(Standardsprache)",
"img-lang-info": "Dieses Bild in $1 rendern. $2",
"img-lang-go": "Los",
- "ascending_abbrev": "auf",
- "descending_abbrev": "ab",
"table_pager_next": "Nächste Seite",
"table_pager_prev": "Vorherige Seite",
"table_pager_first": "Erste Seite",
"apihelp": "Peştiya APIyi",
"apihelp-no-such-module": "Modulê \"$1\" nêvineya.",
"apisandbox": "API qumdor",
- "apisandbox-api-disabled": "API na site de dewre ra veciyayo.",
"apisandbox-submit": "Bıwazê",
"apisandbox-reset": "Bestere",
"apisandbox-retry": "Anciya bıcerrebne",
"wlheader-enotif": "E-mail xeber dayiş abiyo.",
"wlheader-showupdated": "ziyaretê şıma ye peyini de vuryayişê peli pê '''nuşteyo qalıni''' mocyayo.",
"wlnote": "$3 saete $4 ra dıme {{PLURAL:$2|yew saete de|'''$2''' saetan de}} {{PLURAL:$1|vurnayışo peyên|vurnayışê '''$1''' peyêni}} cêrderê.",
- "wlshowlast": "Peyni de $1 seata u $2 roca bıasne",
"watchlist-hide": "Bınımne",
"watchlist-submit": "Bımocne",
"wlshowtime": "Periyoda zemani asenayışi:",
"month": "Aşme:",
"year": "Serre:",
"date": "Tarix ra (û raver):",
- "sp-contributions-newbies": "Tenya iştırakanê karberanê newan bımotne",
- "sp-contributions-newbies-sub": "Qe hesebê newe",
- "sp-contributions-newbies-title": "Hesabanê neweyan rê iştırakê karberi",
"sp-contributions-blocklog": "qeydê kılitkerdışi",
"sp-contributions-suppresslog": "İştirakê {{GENDER:$1|karberiyê}} degusneyayey",
"sp-contributions-deleted": "iştırakê {{GENDER:$1|karberi}} esterdi",
"img-lang-default": "(zıwano hesabiyaye)",
"img-lang-info": "Resimé $1, $2 ya teké pé ke.",
"img-lang-go": "Şo",
- "ascending_abbrev": "berz",
- "descending_abbrev": "nızm",
"table_pager_next": "Pela bahdoyêne",
"table_pager_prev": "Pela veri",
"table_pager_first": "Pela sıfteyêne",
"suppress": "Doglědowanje",
"querypage-disabled": "Toś ten specialny bok jo z wugbaśowych pśicynow znjemóžnjony.",
"apisandbox": "API-grajkanišćo",
- "apisandbox-api-disabled": "API jo se na toś tom sedle znjemóžnił.",
"apisandbox-intro": "Wužyj toś ten bok, aby z '''websłužbu Mediawiki API''' eksperimentěrował.\nGlědaj [https://www.mediawiki.org/wiki/API:Main_page API-dokumentaciju] za dalšne drobnostki za wužywanje API. Pśikład: [https://www.mediawiki.org/wiki/API#A_simple_example Wopśimjeśe głownego boka wótwołaś]. Wubjeŕ akciju, aby dalšne pśikłady wiźeł.\n\nŹiwaj na to, až, lěcrownož to jo grajkanišćo, akcije, kótarež pśewjedujoš na toś tom boku, by mógli wiki změniś.",
"apisandbox-submit": "Napšašowanje pśewjasć",
"apisandbox-reset": "Wuprozniś",
"wlheader-enotif": "E-mailowa zdźěleńska słužba jo zmóžnjona.",
"wlheader-showupdated": "Boki, kótarež su wót twójogo slědnego woglěda se změnili, pokazuju se '''tucnje'''.",
"wlnote": "{{PLURAL:$1|Slědujo slědna změna|slědujotej '''$1''' slědnej změnje|slěduju slědne '''$1''' změny}} {{PLURAL:$2|slědneje góźiny|slědneju '''$2''' góźinowu|slědnych '''$2''' góźinow}}, staw: $3, $4.",
- "wlshowlast": "Pokaž změny slědnych $1 góźinow, $2 dnjow abo (w slědnych 30 dnjach).",
"watchlist-options": "Opcije wobglědowańki",
"watching": "Wobglědowaś …",
"unwatching": "Njewobglědowaś …",
"uctop": "aktualny",
"month": "wót mjaseca (a jěsnjej):",
"year": "wót lěta (a jěsnjej):",
- "sp-contributions-newbies": "Pśinoski jano za nowych wužywarjow pokazaś",
- "sp-contributions-newbies-sub": "Za nowackow",
- "sp-contributions-newbies-title": "Wužywarske pśinoski nowych kontow",
"sp-contributions-blocklog": "Protokol blokěrowanjow",
"sp-contributions-suppresslog": "pódtłocone wužywarske pśinoski",
"sp-contributions-deleted": "Wulašowane wužywarske pśinoski",
"img-lang-default": "(standardna rěc)",
"img-lang-info": "Toś ten wobraz w $1 kresliś. $2",
"img-lang-go": "Wótpósłaś",
- "ascending_abbrev": "górjej",
- "descending_abbrev": "dołoj",
"table_pager_next": "Pśiducy bok",
"table_pager_prev": "Pjerwjejšny bok",
"table_pager_first": "Prědny bok",
"unwatch": "Awu intangan",
"unwatchthispage": "Tingkod do mongintong",
"watchlist-details": "{{PLURAL:$1|$1 bolikon|$1 bobolikon}} id lis piintangannu, bobolikon bolotok awu pinosuang.",
- "wlshowlast": "Pokitono dohuri $1 jaam $2 tadau",
"watchlist-options": "Pomilian lis piintangan",
"watching": "Piintong...",
"unwatching": "Awu piintong...",
"uctop": "id kaas",
"month": "Mantad tulan (om di tulaan po):",
"year": "Mantad toun (om di touun po):",
- "sp-contributions-newbies": "Pokitono pinotoluod di takaun kawawagu nopo.",
"sp-contributions-blocklog": "antabai log",
"sp-contributions-uploads": "poposuang",
"sp-contributions-logs": "tongolog",
"uctop": "अइलोऽ",
"month": "महिना बठे (लै पैल्ली):",
"year": "वर्ष बठे( लौ पैल्ली):",
- "sp-contributions-newbies": "नौला खाताअनाः योगदानअन लाई मात्तरी धेकाऽ",
"sp-contributions-uploads": "अपलोडअन",
"sp-contributions-logs": "लगअन",
"sp-contributions-talk": "कुरड़िकाआनी",
"watch": "Le ŋku ɖe eŋu",
"watchthispage": "Le ŋku ɖe axa sia ŋu",
"wlnote": "Afisia wofia {{PLURAL:$1|tɔtrɔ '''1''' mamlea|tɔtrɔ '''$1''' mamleawo}} le {{PLURAL:$2|gaƒoƒo mamlea si|gaƒoƒo '''$2''' mamleawo siwo}} vayi la me.",
- "wlshowlast": "Fia gaƒoƒo $1 ŋkeke $2 mamleawo.",
"deletepage": "Tutu axa sia",
"delete-confirm": "Tutu \"$1\"",
"delete-legend": "Tutui",
"uctop": "tametɔ",
"month": "Tso ɣleti (kple do ŋgɔ):",
"year": "Tso ƒe (kple do ŋgɔ):",
- "sp-contributions-newbies": "Fia ŋkɔŋlɔla yeyewo ƒe ɖɔɖɔɖowo ko.",
"sp-contributions-talk": "Nyamedzroƒe",
"sp-contributions-search": "Di nuŋɔŋlɔwo",
"sp-contributions-submit": "Dii",
"watchthispage": "Và adrē a cla pàgina ché",
"unwatch": "Andêr mìa adrē",
"watchlist-details": "La lésta 'd quî tgnû 'd ôc specêl la gh'à {{PLURAL:$1|'na pàgina (e la relatîva pàgina 'd discusiòun)|$1 pagine (e al relatîvi pàgini 'd discusiòun)}}.",
- "wlshowlast": "Fà vèder al j ûltmi $1 ōri $2 dé",
"watchlist-options": "Siēlti di tgnû sòt ôc specêl.",
"created": "creät",
"changed": "mudifegat",
"uctop": "adès",
"month": "Dal mèiş (e quî préma):",
"year": "Da l'ân (e quî préma):",
- "sp-contributions-newbies": "Fà vèder sōl i lavōr fât da j utèint nōv.",
"sp-contributions-blocklog": "blôch",
"sp-contributions-uploads": "fil carghê",
"sp-contributions-logs": "Regéster",
"confirm-unwatch-button": "Va bèin",
"imgmultigo": "Và!",
"imgmultigoto": "Và a la pàgina $1",
- "ascending_abbrev": "crès",
- "descending_abbrev": "câl",
"table_pager_first": "Préma pàgina",
"table_pager_last": "Ûltma pàgina",
"table_pager_limit_submit": "Và",
"Fitoschido",
"KATRINE1993",
"Vlad5250",
- "Sarri.greek"
+ "Sarri.greek",
+ "Kostajh"
]
},
"tog-underline": "Υπογράμμιση συνδέσμων:",
"history": "Ιστορικό σελίδας",
"history_short": "Ιστορικό",
"history_small": "ιστορικό",
- "updatedmarker": "ενημερώθηκαν από την τελευταία επίσκεψή μου",
+ "updatedmarker": "ενημερώθηκαν από την τελευταία επίσκεψή σας",
"printableversion": "Έκδοση εκτύπωσης",
"permalink": "Σταθερός σύνδεσμος",
"print": "Εκτύπωση",
"apihelp": "Βοήθεια API",
"apihelp-no-such-module": "Το Module \"$1\" δεν βρέθηκε.",
"apisandbox": "Αμμοδοχείο API",
- "apisandbox-api-disabled": "Η Διεπαφή Προγραμματισμού Εφαρμογών (API) είναι απενεργοποιημένη σε αυτήν την τοποθεσία.",
"apisandbox-intro": "Χρησιμοποιήστε αυτήν τη σελίδα για να πειραματιστείτε με το <strong>API της υπηρεσίας ιστού του MediaWiki</strong>.\nΑνατρέξτε στην [[mw:API:Main page|τεκμηρίωση του API]] για περισσότερες πληροφορίες πάνω στη χρήση του API. \nΠαράδειγμα: [https://www.mediawiki.org/wiki/API#A_simple_example λήψη του περιεχομένου της Αρχικής Σελίδας]. Επιλέξτε κάποια ενέργεια για να δείτε περισσότερα παραδείγματα.\n\nΝα σημειωθεί ότι, παρόλο που αυτό εδώ είναι αμμοδοχείο, οι ενέργειες που εκτελείτε σε αυτήν τη σελίδα μπορούν να τροποποιήσουν το wiki.",
"apisandbox-submit": "Υποβολή του αιτήματος",
"apisandbox-reset": "Εκκαθάριση",
"wlheader-enotif": "Η ειδοποίηση ηλεκτρονικού ταχυδρομείου ενεργοποιήθηκε.",
"wlheader-showupdated": "Σελίδες που έχουν υποστεί αλλαγές από την τελευταία φορά που τις επισκεφθήκατε εμφανίζονται με '''έντονους χαρακτήρες'''.",
"wlnote": "Παρακάτω είναι {{PLURAL:$1|η πιο πρόσφατη αλλαγή|οι <strong>$1</strong> πιο πρόσφατες αλλαγές}} κατά τη διάρκεια {{PLURAL:$2|της τελευταίας ώρας|των <strong>$2</strong> τελευταίων ωρών}} ως προς τις $3 στις $4.",
- "wlshowlast": "Εμφάνιση των τελευταίων $1 ωρών $2 ημερών",
"watchlist-hide": "Απόκρυψη",
"watchlist-submit": "Προβολή",
"wlshowtime": "Περίοδος χρόνου για να εμφανιστεί:",
"month": "Από το μήνα (και νωρίτερα):",
"year": "Από το έτος (και νωρίτερα):",
"date": "Από ημερομηνία (και νωρίτερα):",
- "sp-contributions-newbies": "Εμφάνιση των συνεισφορών των νέων λογαριασμών μόνο",
- "sp-contributions-newbies-sub": "Για νέους λογαριασμούς",
- "sp-contributions-newbies-title": "Συνεισφορές χρηστών για νέους λογαριασμούς",
"sp-contributions-blocklog": "αρχείο καταγραφών φραγών",
"sp-contributions-suppresslog": "διαγεγραμμένες συνεισφορές {{GENDER:$1|χρήστη|χρήστριας}}",
"sp-contributions-deleted": "διαγεγραμμένες συνεισφορές {{GENDER:$1|χρήστη|χρήστριας}}",
"newimages-legend": "Φίλτρο",
"newimages-label": "Όνομα αρχείου (ή μέρος αυτού):",
"newimages-user": "Διεύθυνση IP ή όνομα χρήστη",
- "newimages-newbies": "Εμφάνιση των συνεισφορών των νέων λογαριασμών μόνο",
"newimages-showbots": "Εμφάνιση αρχείων ανεβασμένων από ρομπότ",
"newimages-hidepatrolled": "Απόκρυψη ελεγμένων αρχείων.",
"newimages-mediatype": "Τύπος μέσου:",
"img-lang-default": "(προεπιλεγμένη γλώσσα)",
"img-lang-info": "Απόδοση της εικόνας στα $1. $2",
"img-lang-go": "Μετάβαση",
- "ascending_abbrev": "αυξ",
- "descending_abbrev": "φθιν",
"table_pager_next": "Επόμενη σελίδα",
"table_pager_prev": "Προηγούμενη σελίδα",
"table_pager_first": "Πρώτη σελίδα",
"nocreate-loggedin": "You do not have permission to create new pages.",
"sectioneditnotsupported-title": "Section editing not supported",
"sectioneditnotsupported-text": "Section editing is not supported in this page.",
+ "modeleditnotsupported-title": "Editing not supported",
+ "modeleditnotsupported-text": "Editing is not supported for content model $1.",
"permissionserrors": "Permission error",
"permissionserrorstext": "You do not have permission to do that, for the following {{PLURAL:$1|reason|reasons}}:",
"permissionserrorstext-withaction": "You do not have permission to $2, for the following {{PLURAL:$1|reason|reasons}}:",
"content-model-json": "JSON",
"content-json-empty-object": "Empty object",
"content-json-empty-array": "Empty array",
+ "unsupported-content-model": "<strong>Warning:</strong> Content model $1 is not supported on this wiki.",
+ "unsupported-content-diff": "Diffs are not supported for content model $1.",
+ "unsupported-content-diff2": "Diffs between the content models $1 and $2 are not supported on this wiki.",
"deprecated-self-close-category": "Pages using invalid self-closed HTML tags",
"deprecated-self-close-category-desc": "The page contains invalid self-closed HTML tags, such as <code><b/></code> or <code><span/></code>. The behavior of these will change soon to be consistent with the HTML5 specification, so their use in wikitext is deprecated.",
"duplicate-args-warning": "<strong>Warning:</strong> [[:$1]] is calling [[:$2]] with more than one value for the \"$3\" parameter. Only the last value provided will be used.",
"backend-fail-contenttype": "Could not determine the content type of the file to store at \"$1\".",
"backend-fail-batchsize": "The storage backend was given a batch of $1 file {{PLURAL:$1|operation|operations}}; the limit is $2 {{PLURAL:$2|operation|operations}}.",
"backend-fail-usable": "Could not read or write file \"$1\" due to insufficient permissions or missing directories/containers.",
+ "backend-fail-stat": "Could not read the status of file \"$1\".",
+ "backend-fail-hash": "Could not determine the cryptographic hash of file \"$1\".",
"filejournal-fail-dbconnect": "Could not connect to the journal database for storage backend \"$1\".",
"filejournal-fail-dbquery": "Could not update the journal database for storage backend \"$1\".",
"lockmanager-notlocked": "Could not unlock \"$1\"; it is not locked.",
"apisandbox": "API sandbox",
"apisandbox-summary": "",
"apisandbox-jsonly": "JavaScript is required to use the API sandbox.",
- "apisandbox-api-disabled": "The API is disabled on this site.",
"apisandbox-intro": "Use this page to experiment with the <strong>MediaWiki web service API</strong>.\nRefer to [[mw:API:Main page|the API documentation]] for further details of API usage. Example: [https://www.mediawiki.org/wiki/API#A_simple_example get the content of a Main Page]. Select an action to see more examples.\n\nNote that, although this is a sandbox, actions you carry out on this page may modify the wiki.",
"apisandbox-submit": "Make request",
"apisandbox-reset": "Clear",
"wlheader-enotif": "Email notification is enabled.",
"wlheader-showupdated": "Pages that have been changed since you last visited them are shown in <strong>bold</strong>.",
"wlnote": "Below {{PLURAL:$1|is the last change|are the last <strong>$1</strong> changes}} in the last {{PLURAL:$2|hour|<strong>$2</strong> hours}}, as of $3, $4.",
- "wlshowlast": "Show last $1 hours $2 days",
"watchlist-hide": "Hide",
"watchlist-submit": "Show",
"wlshowtime": "Period of time to display:",
"sessionfailure": "There seems to be a problem with your login session;\nthis action has been canceled as a precaution against session hijacking.\nPlease resubmit the form.",
"changecontentmodel" : "Change content model of a page",
"changecontentmodel-legend": "Change content model",
- "changecontentmodel-title-label": "Page title",
+ "changecontentmodel-title-label": "Page title:",
"changecontentmodel-current-label": "Current content model:",
- "changecontentmodel-model-label": "New content model",
+ "changecontentmodel-model-label": "New content model:",
"changecontentmodel-reason-label": "Reason:",
"changecontentmodel-submit": "Change",
"changecontentmodel-success-title": "The content model was changed",
"month": "From month (and earlier):",
"year": "From year (and earlier):",
"date": "From date (and earlier):",
- "sp-contributions-newbies": "Show contributions of new accounts only",
- "sp-contributions-newbies-sub": "For new accounts",
- "sp-contributions-newbies-title": "User contributions for new accounts",
"sp-contributions-blocklog": "block log",
"sp-contributions-suppresslog": "suppressed {{GENDER:$1|user}} contributions",
"sp-contributions-deleted": "deleted {{GENDER:$1|user}} contributions",
"sp-contributions-footer": "-",
"sp-contributions-footer-anon": "-",
"sp-contributions-footer-anon-range": "-",
- "sp-contributions-footer-newbies": "-",
"sp-contributions-outofrange": "Unable to show any results. The requested IP range is larger than the CIDR limit of /$1.",
"whatlinkshere": "What links here",
"whatlinkshere-title": "Pages that link to \"$1\"",
"newimages-legend": "Filter",
"newimages-label": "Filename (or a part of it):",
"newimages-user": "IP address or username",
- "newimages-newbies": "Show contributions of new accounts only",
"newimages-showbots": "Show uploads by bots",
"newimages-hidepatrolled": "Hide patrolled uploads",
"newimages-mediatype": "Media type:",
"img-lang-default": "(default language)",
"img-lang-info": "Render this image in $1. $2",
"img-lang-go": "Go",
- "ascending_abbrev": "asc",
- "descending_abbrev": "desc",
"table_pager_next": "Next page",
"table_pager_prev": "Previous page",
"table_pager_first": "First page",
"apihelp-no-such-module": "La modulo „$1” ne estis trovita.",
"apisandbox": "API testejo",
"apisandbox-jsonly": "JavaScript estas postulita por uzi la API provejon.",
- "apisandbox-api-disabled": "API estas malŝalta en ĉi tiu retejo.",
"apisandbox-intro": "Uzu tiun ĉi paĝon por eksperimenti kun <strong>Mediavikia retserva API</strong>.\nVidu [[mw:API:Main page|la API-dokumentadon]] por pli da detaloj pri la uzo de API. Ekz-e: [https://www.mediawiki.org/wiki/API#A_simple_example atingi la enhavon de la Ĉefpaĝo]. Elektu agon por vidi pliajn ekzemplojn.\n\nNotu ke, kvankam ĉi tiu estas provejo, agoj kiun vi faros en ĉi tiu paĝo povas modifi la vikion.",
"apisandbox-submit": "Fari mendon",
"apisandbox-reset": "Nuligi",
"wlheader-enotif": "Retpoŝta sciigo estas ŝalta.",
"wlheader-showupdated": "Paĝoj montriĝis per '''dikaj literoj''' kiuj estis ŝanĝitaj ekde vi laste vizitis.",
"wlnote": "Jen la {{PLURAL:$1|lasta redakto|lastaj <strong>$1</strong> redaktoj}} dum la {{PLURAL:$2|lasta horo|lastaj <strong>$2</strong> horoj}}, ekde $3, $4.",
- "wlshowlast": "Montri el lastaj $1 horoj $2 tagoj",
"watchlist-hide": "Kaŝi",
"watchlist-submit": "Montri",
"wlshowtime": "Vidigenda tempodaŭro:",
"month": "Ekde monato (kaj pli frue):",
"year": "Ekde jaro (kaj pli frue):",
"date": "Je dato (aŭ pli frue):",
- "sp-contributions-newbies": "Montri nur kontribuojn de novaj kontoj",
- "sp-contributions-newbies-sub": "Kontribuoj de novaj uzantoj. Forigitaj paĝoj ne estas montritaj.",
- "sp-contributions-newbies-title": "Kontribuoj de novaj uzantoj",
"sp-contributions-blocklog": "protokolo de forbaroj",
"sp-contributions-suppresslog": "kaŝitaj kontribuoj de {{GENDER:$1|uzanto}}",
"sp-contributions-deleted": "forigitaj kontribuoj de {{GENDER:$1|uzanto}}",
"newimages-legend": "Dosiernomo",
"newimages-label": "Dosiernomo (aŭ parto de ĝi):",
"newimages-user": "IP-adreso aŭ uzantnomo",
- "newimages-newbies": "Montri nur kotribuojn de novaj kontoj",
"newimages-showbots": "Montri alŝutojn per robotoj",
"newimages-hidepatrolled": "Malvidigi la pripatrolitajn alŝutitojn",
"newimages-mediatype": "Dosiertipo de aŭdvidaĵo:",
"img-lang-default": "(implicita lingvo)",
"img-lang-info": "Bildigi tiun ĉi bildon en $1. $2",
"img-lang-go": "Ek",
- "ascending_abbrev": "sprn",
- "descending_abbrev": "subn",
"table_pager_next": "Sekva paĝo",
"table_pager_prev": "Antaŭa paĝo",
"table_pager_first": "Unua paĝo",
"apihelp-no-such-module": "No se encontró el módulo «$1».",
"apisandbox": "Zona de pruebas de la API",
"apisandbox-jsonly": "Se requiere JavaScript para utilizar la zona de pruebas de API.",
- "apisandbox-api-disabled": "La API está desactivada en este sitio.",
"apisandbox-intro": "Usa esta página para experimentar con la <strong>API de servicio web de MediaWiki</strong>.\nPara más detalles sobre el uso de la API, visita [[mw:API:Main page|su documentación]]. Ejemplo: [https://www.mediawiki.org/wiki/API#A_simple_example obtener el contenido de una Página principal]. Selecciona una acción para ver más ejemplos.\n\nObserva que, aunque sea una página de pruebas, las acciones que realices en esta página pueden modificar el wiki.",
"apisandbox-submit": "Realizar solicitud",
"apisandbox-reset": "Limpiar",
"wlheader-enotif": "La notificación por correo está activada.",
"wlheader-showupdated": "Las páginas modificadas desde tu última visita aparecen en <strong>negrita</strong>.",
"wlnote": "A continuación {{PLURAL:$1|se muestra el último cambio|se muestran los últimos <strong>$1</strong> cambios}} en {{PLURAL:$2|la última hora|las últimas <strong>$2</strong> horas}} desde las $4 del $3.",
- "wlshowlast": "Ver los cambios de las últimas $1 horas, $2 días",
"watchlist-hide": "Ocultar",
"watchlist-submit": "Mostrar",
"wlshowtime": "Período de tiempo para mostrar:",
"month": "Desde el mes (y anteriores):",
"year": "Desde el año (y anteriores):",
"date": "Desde el día (y anteriores):",
- "sp-contributions-newbies": "Mostrar solo las contribuciones de usuarios nuevos",
- "sp-contributions-newbies-sub": "Para cuentas nuevas",
- "sp-contributions-newbies-title": "Contribuciones de usuarios nuevos",
"sp-contributions-blocklog": "registro de bloqueos",
"sp-contributions-suppresslog": "contribuciones {{GENDER:$1|del usuario|de la usuaria}} suprimidas",
"sp-contributions-deleted": "contribuciones {{GENDER:$1|del usuario|de la usuaria}} borradas",
"newimages-legend": "Filtro",
"newimages-label": "Nombre del archivo (o una parte):",
"newimages-user": "Dirección IP o nombre de usuario",
- "newimages-newbies": "Mostrar solo las contribuciones de cuentas nuevas",
"newimages-showbots": "Mostrar cargas de bots",
"newimages-hidepatrolled": "Ocultar las subidas verificadas",
"newimages-mediatype": "Tipo de medio:",
"img-lang-default": "(idioma predeterminado)",
"img-lang-info": "Renderizar esta imagen en $1. $2",
"img-lang-go": "Adelante",
- "ascending_abbrev": "asc",
- "descending_abbrev": "desc",
"table_pager_next": "Página siguiente",
"table_pager_prev": "Página anterior",
"table_pager_first": "Primera página",
"nocreate-loggedin": "Sul ei ole luba luua uusi lehekülgi.",
"sectioneditnotsupported-title": "Alaosa redigeerimine pole lubatud.",
"sectioneditnotsupported-text": "Sellel leheküljel pole alaosa redigeerimine lubatud.",
+ "modeleditnotsupported-title": "Redigeerimise toeta",
+ "modeleditnotsupported-text": "Sisumudeli $1 redigeerimise tugi puudub.",
"permissionserrors": "Loatõrge",
"permissionserrorstext": "Sul pole õigust seda teha {{PLURAL:$1|järgmisel põhjusel|järgmistel põhjustel}}:",
"permissionserrorstext-withaction": "Sul pole lubatud {{lcfirst:$2}} {{PLURAL:$1|järgmisel põhjusel|järgmistel põhjustel}}:",
"content-model-css": "CSS",
"content-json-empty-object": "Tühi objekt",
"content-json-empty-array": "Tühi massiiv",
+ "unsupported-content-model": "<strong>Hoiatus:</strong> Selles vikis puudub sisumudeli $1 tugi.",
+ "unsupported-content-diff": "Erinevuste vaates puudub sisumudeli $1 tugi.",
+ "unsupported-content-diff2": "Sisumudelite $1 ja $2 vaheliste erinevuste vaate tugi puudub selles vikis.",
"deprecated-self-close-category": "Vigaste endassesuletud HTML-siltidega leheküljed",
"deprecated-self-close-category-desc": "Leheküljel on endassesuletud HTML-silte nagu <code><b/></code> või <code><span/></code>. Nende kuvamisviis viiakse peagi vastavusse HTML5 spetsifikatsiooniga. Seetõttu selliseid silte vikitekstis enam kasutama ei peaks.",
"duplicate-args-warning": "<strong>Hoiatus:</strong> [[:$1]] kutsub malli [[:$2]] nii, et parameetrile \"$3\" vastab rohkem kui üks väärtus. Väärtustest kasutatakse ainult viimast.",
"rcfilters-filter-showlinkedto-label": "Näita muudatusi lehekülgedel, millel viidatakse leheküljele",
"rcfilters-filter-showlinkedto-option-label": "<strong>Leheküljed, mis viitavad</strong> valitud leheküljele",
"rcfilters-target-page-placeholder": "Sisesta lehekülje pealkiri (või kategooria)",
+ "rcfilters-allcontents-label": "Kõik sisu",
+ "rcfilters-alldiscussions-label": "Kõik arutelud",
"rcnotefrom": "Allpool on toodud {{PLURAL:$5|muudatus|muudatused}} alates: <strong>$3, kell $4</strong> (näidatakse kuni <strong>$1</strong> muudatust)",
"rclistfromreset": "Lähtesta kuupäeva valik",
"rclistfrom": "Näita muudatusi alates: $3, kell $2",
"apihelp-no-such-module": "Moodulit \"$1\" ei leitud.",
"apisandbox": "API liivakast",
"apisandbox-jsonly": "API liivakasti kasutamine nõuab JavaScripti.",
- "apisandbox-api-disabled": "API on selles võrgukohas keelatud.",
"apisandbox-intro": "Kasuta seda lehekülge <strong>MediaWiki API</strong> katsetamiseks.\nÜksikasjad API kasutamise kohta leiad [[mw:API:Main page|API dokumentatsioonist]]. Näide: [https://www.mediawiki.org/wiki/API#A_simple_example esilehe sisu hankimine]. Vali toiming, et näha veel näiteid.\n\nPane tähele, et kuigi siin on liivakast, võivad siin leheküljel tehtud toimingud vikit muuta.",
"apisandbox-submit": "Tee päring",
"apisandbox-reset": "Puhasta",
"wlheader-enotif": "E-posti teel teavitamine on lubatud.",
"wlheader-showupdated": "Leheküljed, mida on muudetud peale sinu viimast külastust, on '''rasvases kirjas'''.",
"wlnote": "Allpool on {{PLURAL:$1|viimane muudatus|viimased <strong>$1</strong> muudatust}} viimase {{PLURAL:$2|tunni|<strong>$2</strong> tunni}} jooksul seisuga $3, kell $4.",
- "wlshowlast": "Näita viimast $1 tundi $2 päeva.",
"watchlist-hide": "Peida",
"watchlist-submit": "Näita",
"wlshowtime": "Näita viimast:",
"sessionfailure": "Näib, et sinu sisselogimisseanss on probleemne.\nSeansiärandamise vastase ettevaatusabinõuna on see toiming tühistatud.\nPalun saada vorm uuesti.",
"changecontentmodel": "Lehekülje sisumudeli muutmine",
"changecontentmodel-legend": "Sisumudeli muutmine",
- "changecontentmodel-title-label": "Lehekülje pealkiri",
- "changecontentmodel-model-label": "Uus sisumudel",
+ "changecontentmodel-title-label": "Lehekülje pealkiri:",
+ "changecontentmodel-current-label": "Praegune sisumudel:",
+ "changecontentmodel-model-label": "Uus sisumudel:",
"changecontentmodel-reason-label": "Põhjus:",
"changecontentmodel-submit": "Muuda",
"changecontentmodel-success-title": "Sisumudel on muudetud",
"month": "Alates kuust (ja varasemad):",
"year": "Alates aastast (ja varasemad):",
"date": "Alates kuupäevast (ja varasemad):",
- "sp-contributions-newbies": "Näita ainult uute kasutajate kaastööd",
- "sp-contributions-newbies-sub": "Uute kontode kaastöö",
- "sp-contributions-newbies-title": "Uute kasutajate kaastöö",
"sp-contributions-blocklog": "blokeerimised",
"sp-contributions-suppresslog": "{{GENDER:$1|varjatud}} kaastöö",
"sp-contributions-deleted": "{{GENDER:$1|kustutatud}} kaastöö",
"block-log-flags-angry-autoblock": "Täiustatud automaatblokeerija sisse lülitatud",
"block-log-flags-hiddenname": "kasutajanimi peidetud",
"range_block_disabled": "Administraatori õigus blokeerida IP-aadresside vahemik on ära võetud.",
+ "ipb-prevent-user-talk-edit": "Kui osaline blokeering ei piira eraldi nimeruumi \"Kasutaja arutelu\" kasutust, siis peab see lubama enda arutelulehekülje redigeerimist.",
"ipb_expiry_invalid": "Vigane aegumise tähtaeg.",
"ipb_expiry_old": "Aegumistähtaeg on minevikus.",
"ipb_expiry_temp": "Peidetud kasutajanime blokeeringud peavad olema alalised.",
"lockedbyandtime": "(lukustas $1; $2, kell $3)",
"move-page": "Lehekülje \"$1\" teisaldamine",
"move-page-legend": "Lehekülje teisaldamine",
- "movepagetext": "Allolevat vormi kasutades saad lehekülje ümber nimetada. Lehekülje ajalugu tõstetakse uue pealkirja alla automaatselt.\nPraeguse pealkirjaga leheküljest saab ümbersuunamislehekülg uuele leheküljele.\nSaad senisele pealkirjale viitavad ümbersuunamised automaatselt parandada.\nKui sa seda ei tee, kontrolli, et teisaldamise tõttu ei jää maha [[Special:DoubleRedirects|kahekordseid]] ega [[Special:BrokenRedirects|katkiseid ümbersuunamisi]].\nSinu kohus on hoolitseda selle eest, et kõik jääks toimima, nagu ette nähtud.\n\nPane tähele, et lehekülge <strong>ei teisaldata</strong> juhul, kui uue pealkirjaga lehekülg on juba olemas. Erandiks on juhud, kui viimane on redigeerimisajaloota ümbersuunamislehekülg.\nSee tähendab, et kogemata ei saa üle kirjutada juba olemasolevat lehekülge, kuid saab ebaõnnestunud ümbernimetamise tagasi pöörata.\n\n<strong>Märkus:</strong>\nTegu võib olla väga loetava lehekülje jaoks tõsise ja ootamatu muudatusega;\nenne jätkamist teadvusta palun tagajärgi.",
+ "movepagetext": "Allolevat vormi kasutades saad lehekülje ümber nimetada, nii et selle ajalugu tõstetakse uue pealkirja alla.\nVana pealkirjaga leheküljest saab ümbersuunamine uue pealkirjaga leheküljele.\nSaad senisele pealkirjale viitavad ümbersuunamised automaatselt parandada.\nKui sa seda ei tee, siis kontrolli, et teisaldamise tõttu ei jää maha [[Special:DoubleRedirects|kahekordseid]] ega [[Special:BrokenRedirects|katkiseid ümbersuunamisi]].\nSinu kohus on hoolitseda selle eest, et kõik jääks toimima, nagu ette nähtud.\n\nPane tähele, et lehekülge <strong>ei teisaldata</strong> juhul, kui uue pealkirjaga lehekülg on juba olemas. Erandiks on juhud, kui viimane on redigeerimisajaloota ümbersuunamislehekülg.\nSee tähendab, et kogemata ei saa üle kirjutada juba olemasolevat lehekülge, kuid saab ebaõnnestunud ümbernimetamise tagasi pöörata.\n\n<strong>Märkus:</strong>\nTegu võib olla väga loetava lehekülje jaoks tõsise ja ootamatu muudatusega;\nenne jätkamist teadvusta palun tagajärgi.",
"movepagetext-noredirectfixer": "Allolevat vormi kasutades saad lehekülje ümber nimetada. Lehekülje ajalugu tõstetakse uue pealkirja alla automaatselt.\nPraeguse pealkirjaga leheküljest saab ümbersuunamislehekülg uuele leheküljele.\nKontrolli, et teisaldamise tõttu ei jää maha [[Special:DoubleRedirects|kahekordseid]] ega [[Special:BrokenRedirects|katkiseid ümbersuunamisi]].\nSinu kohus on hoolitseda selle eest, et kõik jääks toimima, nagu ette nähtud.\n\nPane tähele, et lehekülge <strong>ei teisaldata</strong> juhul, kui uue pealkirjaga lehekülg on juba olemas. Erandiks on juhud, kui olemasolev lehekülg on tühi või redigeerimisajaloota ümbersuunamislehekülg.\nSee tähendab, et kogemata ei saa üle kirjutada juba olemasolevat lehekülge, kuid saab ebaõnnestunud ümbernimetamise tagasi pöörata.\n\n<strong>Hoiatus!</strong>\nTegu võib olla väga loetava lehekülje jaoks tõsise ja ootamatu muudatusega;\nenne jätkamist teadvusta palun tagajärgi.",
+ "movepagetext-noredirectsupport": "Allolevat vormi kasutades saad lehekülje ümber nimetada, nii et selle ajalugu tõstetakse uue pealkirja alla.\nSinu kohus on hoolitseda selle eest, et lingid viitaks jätkuvalt sinna, kuhu vaja.\n\nPane tähele, et lehekülge <strong>ei teisaldata</strong> juhul, kui uue pealkirjaga lehekülg on juba olemas.\nSee tähendab, et kogemata ei saa üle kirjutada juba olemasolevat lehekülge, kuid saab ebaõnnestunud ümbernimetamise tagasi pöörata.\n\n<strong>Märkus:</strong>\nTegu võib olla väga loetava lehekülje jaoks tõsise ja ootamatu muudatusega;\nenne jätkamist teadvusta palun tagajärgi.",
"movepagetalktext": "Kui märgid selle ruudu, teisaldatakse arutelulehekülg automaatselt uue pealkirja alla. Seda välja arvatud juhul, kui uue pealkirja all on juba arutelulehekülg, mis pole tühi.\n\nSel juhul saad lehekülje soovi korral käsitsi teisaldada või liita.",
"moveuserpage-warning": "'''Hoiatus:''' Oled teisaldamas kasutajalehekülge. Pane tähele, et teisaldatakse ainult lehekülg ja kasutajat '''ei''' nimetata ümber.",
"movecategorypage-warning": "<strong>Hoiatus:</strong> Oled teisaldamas kategoorialehekülge. Pane palun tähele, et teisaldatakse vaid see lehekülg ja ühtegi vanas kategoorias sisalduvat lehekülge <em>ei</em> kategoriseerita ümber uude kategooriasse.",
"move-subpages": "Teisalda alamleheküljed (kuni $1)",
"move-talk-subpages": "Teisalda arutelulehekülje alamleheküljed (kuni $1)",
"movepage-page-exists": "Lehekülg $1 on juba olemas ja seda ei saa automaatselt üle kirjutada.",
+ "movepage-source-doesnt-exist": "Lehekülge \"$1\" pole olemas ja seda ei saa teisaldada.",
"movepage-page-moved": "Lehekülg $1 on teisaldatud pealkirja $2 alla.",
"movepage-page-unmoved": "Lehekülge $1 ei saanud teisaldada pealkirja $2 alla.",
"movepage-max-pages": "Teisaldatud on $1 {{PLURAL:$1|lehekülg|lehekülge}}, mis on teisaldatavate lehekülgede ülemmäär. Rohkem lehekülgi automaatselt ei teisaldata.",
"delete_and_move_reason": "Kustutatud, et tõsta asemele lehekülg \"[[$1]]\"",
"selfmove": "Sama pealkiri;\nlehekülge ei saa teisaldada iseenda asemele.",
"immobile-source-namespace": "Lehekülgi ei saa teisaldada nimeruumis $1",
+ "immobile-source-namespace-iw": "Selle viki kaudu ei saa teisaldada lehekülgi, mis asuvad teises vikis.",
"immobile-target-namespace": "Lehekülgi ei saa teisaldada nimeruumi \"$1\"",
"immobile-target-namespace-iw": "Keelelink ei ole sobiv koht lehekülje teisaldamiseks.",
"immobile-source-page": "Lehekülg ei ole teisaldatav.",
"immobile-target-page": "Soovitud pealkirja alla ei saa teisaldada.",
+ "movepage-invalid-target-title": "Päritud pealkiri on vigane.",
"bad-target-model": "Soovitud sihtlehekülje sisumudel on erinev. {{ucfirst:$1}}i ei saa teisendada $2iks.",
"imagenocrossnamespace": "Faili ei saa teisaldada mõnda muusse nimeruumi.",
"nonfile-cannot-move-to-file": "Failinimeruumi saab ainult faile teisaldada.",
"newimages-legend": "Filter",
"newimages-label": "Failinimi (või selle osa):",
"newimages-user": "IP-aadress või kasutajanimi",
- "newimages-newbies": "Näita ainult uute kontode kaastööd",
"newimages-showbots": "Näita robotite üles laaditud faile",
"newimages-hidepatrolled": "Peida kontrollitud failid",
"newimages-mediatype": "Failitüüp:",
"img-lang-default": "(vaikekeel)",
"img-lang-info": "Viimistle pilt järgmises keeles: $1. $2",
"img-lang-go": "Mine",
- "ascending_abbrev": "tõusev",
- "descending_abbrev": "laskuv",
"table_pager_next": "Järgmine lehekülg",
"table_pager_prev": "Eelmine lehekülg",
"table_pager_first": "Esimene lehekülg",
"permanentlink": "Püsilink",
"permanentlink-revid": "Redaktsiooni identifikaator",
"permanentlink-submit": "Mine redaktsiooni juurde",
+ "newsection": "Uus alaosa",
+ "newsection-page": "Sihtlehekülg",
+ "newsection-submit": "Mine leheküljele",
"dberr-problems": "Kahjuks on sellel saidil tehnilisi probleeme",
"dberr-again": "Oota mõni hetk ja laadi lehekülg uuesti.",
"dberr-info": "(Juurdepääs andmebaasile puudub: $1)",
"apihelp-no-such-module": "Ez da \"$1\" modulua aurkitu.",
"apisandbox": "API proba orria",
"apisandbox-jsonly": "API sandbox-a erabiltzeko JavaScript eskatzen da.",
- "apisandbox-api-disabled": "APIa desgaituta dago gune honetan.",
"apisandbox-intro": "Erabili orri hau <strong>MediaWiki web zerbitzuen APIa</ strong>rekin esperimentatzeko.\nIkusi [[mw:API:Main page|API dokumentazioa]] API erabilerari buruzko xehetasun gehiago lortzeko. Adibidez: [https://www.mediawiki.org/wiki/API#A_simple_example orri nagusiko edukia lortu]. Hautatu ekintza bat adibide gehiago ikusteko.\n\nKontuan izan, hau da sandbox bat bada ere, orri honetan egiten dituzun ekintzak wikiak alda ditzaketela.",
"apisandbox-submit": "Egin eskaera",
"apisandbox-reset": "Garbitu",
"wlheader-enotif": "Posta bidezko ohartarazpena gaituta dago.",
"wlheader-showupdated": "Bisitatu zenituen azken alditik aldaketak izan dituzten orriak '''letra lodiz''' nabarmenduta daude.",
"wlnote": "Jarraian ageri {{PLURAL:$1|da|dira}} azken {{PLURAL:$2|ordubeteko|<strong>$2</strong> orduko}} {{PLURAL:$1|aldaketa|<strong>$1</strong> aldaketak}}. Data: $3, $4.",
- "wlshowlast": "Erakutsi azken $1 orduak, azken $2 egunak",
"watchlist-hide": "Ezkutatu",
"watchlist-submit": "Erakutsi",
"wlshowtime": "Erakusteko denboraldia:",
"month": "Hilabetea (eta lehenagokoak):",
"year": "Urtea (eta lehenagokoak):",
"date": "Data honetatik (eta lehenagokoak):",
- "sp-contributions-newbies": "Soilik kontu berrien ekarpenak erakutsi",
- "sp-contributions-newbies-sub": "Hasiberrientzako",
- "sp-contributions-newbies-title": "Lankideen ekarpenak lankide berrietn",
"sp-contributions-blocklog": "Blokeaketa erregistroa",
"sp-contributions-suppresslog": "{{GENDER:$1|(r)en}} lankide-ekarpen ezabatuak",
"sp-contributions-deleted": "{{GENDER:$1|lankide}}-ekarpen ezabatuak",
"newimages-legend": "Iragazkia",
"newimages-label": "Fitxategia (edo bere zati bat):",
"newimages-user": "IP helbidea edo erabiltzaile-izena",
- "newimages-newbies": "Soilik kontu berrien ekarpenak erakutsi",
"newimages-showbots": "Erakutsi botek igotako fitxategiak",
"newimages-hidepatrolled": "Izkutatu patruilatutako igoerak",
"newimages-mediatype": "Media mota:",
"img-lang-default": "(berezko hizkuntza)",
"img-lang-info": "Irudi hau $1 hizkuntzarekin errendatu. $2.",
"img-lang-go": "Joan",
- "ascending_abbrev": "gor",
- "descending_abbrev": "behe",
"table_pager_next": "Hurrengo orrialdea",
"table_pager_prev": "Aurreko orrialdea",
"table_pager_first": "Lehen orrialdea",
"exif-scenetype-1": "صورة ملتقطة بشكل مباشر",
"exif-customrendered-0": "عملية عادية",
"exif-customrendered-1": "عملية حسب الطلب",
+ "exif-customrendered-2": "HDR (لم يتم حفظ النسخة الأصلية)",
+ "exif-customrendered-3": "HDR (تم حفظ النسخة الأصلية)",
+ "exif-customrendered-4": "الأصلي (لـHDR)",
+ "exif-customrendered-6": "بانوراما",
+ "exif-customrendered-7": "بورتريه HDR",
+ "exif-customrendered-8": "بورتريه",
"exif-exposuremode-0": "تعرض تلقائي",
"exif-exposuremode-1": "تعرض يدوي",
"exif-exposuremode-2": "سلسلة تلقائية",
"exif-scenetype-1": "Una imaxe fotografiada direutamente",
"exif-customrendered-0": "Procesu normal",
"exif-customrendered-1": "Procesu personalizáu",
+ "exif-customrendered-2": "HDR (nun se guardó l'orixinal)",
+ "exif-customrendered-3": "HDR (orixinal guardáu)",
+ "exif-customrendered-4": "Orixinal (pa HDR)",
+ "exif-customrendered-6": "Panorama",
+ "exif-customrendered-7": "Retratu HDR",
+ "exif-customrendered-8": "Retratu",
"exif-exposuremode-0": "Esposición automática",
"exif-exposuremode-1": "Esposición manual",
"exif-exposuremode-2": "Puesta ente paréntesis automática",
"exif-scenetype-1": "সরাসরি ফটো তোলা ছবি",
"exif-customrendered-0": "স্বাভাবিক প্রক্রিয়া",
"exif-customrendered-1": "পছন্দমাফিক প্রক্রিয়া",
+ "exif-customrendered-8": "প্রতিকৃতি",
"exif-exposuremode-0": "স্বয়ংক্রিয় আলোকসম্পাত",
"exif-exposuremode-1": "হাতে করা আলোকসম্পাত",
"exif-exposuremode-2": "স্বয়ংক্রিয় ব্র্যাকেট",
"exif-scenetype-1": "Normal",
"exif-customrendered-0": "Standard",
"exif-customrendered-1": "Brugerdefineret",
+ "exif-customrendered-4": "Oprindelig (for HDR)",
+ "exif-customrendered-8": "Portræt",
"exif-exposuremode-0": "Automatisk belysning",
"exif-exposuremode-1": "Manuel belysning",
"exif-exposuremode-2": "Belysningsrække",
"exif-scenetype-1": "A directly photographed image",
"exif-customrendered-0": "Normal process",
"exif-customrendered-1": "Custom process",
+ "exif-customrendered-2": "HDR (no original saved)",
+ "exif-customrendered-3": "HDR (original saved)",
+ "exif-customrendered-4": "Original (for HDR)",
+ "exif-customrendered-6": "Panorama",
+ "exif-customrendered-7": "Portrait HDR",
+ "exif-customrendered-8": "Portrait",
"exif-exposuremode-0": "Auto exposure",
"exif-exposuremode-1": "Manual exposure",
"exif-exposuremode-2": "Auto bracket",
"exif-scenetype-1": "Image photographiée directement",
"exif-customrendered-0": "Procédé normal",
"exif-customrendered-1": "Procédé personnalisé",
+ "exif-customrendered-2": "HDR (pas d’original enregistré)",
+ "exif-customrendered-3": "HDR (original enregistré)",
+ "exif-customrendered-4": "Original (pour HDR)",
+ "exif-customrendered-6": "Panorama",
+ "exif-customrendered-7": "Portrait HDR",
+ "exif-customrendered-8": "Portrait",
"exif-exposuremode-0": "Automatique",
"exif-exposuremode-1": "Manuelle",
"exif-exposuremode-2": "Fourchette automatique",
"exif-scenetype-1": "Unha imaxe fotografada directamente",
"exif-customrendered-0": "Procesamento normal",
"exif-customrendered-1": "Procesamento personalizado",
+ "exif-customrendered-2": "HDR (orixinal non gardado)",
+ "exif-customrendered-3": "HDR (orixinal gardado)",
+ "exif-customrendered-4": "Orixinal (para HDR)",
+ "exif-customrendered-6": "Panorama",
+ "exif-customrendered-7": "Retrato HDR",
+ "exif-customrendered-8": "Retrato",
"exif-exposuremode-0": "Exposición automática",
"exif-exposuremode-1": "Exposición manual",
"exif-exposuremode-2": "Compensación automática da exposición",
"exif-scenetype-1": "תמונה שצולמה ישירות",
"exif-customrendered-0": "תהליך רגיל",
"exif-customrendered-1": "תהליך מותאם",
+ "exif-customrendered-2": "HDR (המקור לא נשמר)",
+ "exif-customrendered-3": "HDR (המקור נשמר)",
+ "exif-customrendered-4": "מקור (עבור HDR)",
+ "exif-customrendered-6": "פנורמה",
+ "exif-customrendered-7": "HDR בתצוגת דיוקן",
+ "exif-customrendered-8": "דיוקן",
"exif-exposuremode-0": "חשיפה אוטומטית",
"exif-exposuremode-1": "חשיפה ידנית",
"exif-exposuremode-2": "מסגרת אוטומטית",
"Kwj2772",
"Mooozi",
"아라",
- "Revi"
+ "Revi",
+ "Ykhwong"
]
},
"exif-imagewidth": "너비",
"exif-scenetype-1": "직접 촬영한 그림",
"exif-customrendered-0": "일반",
"exif-customrendered-1": "사용자 지정 처리",
+ "exif-customrendered-2": "HDR (원본 저장 안 함)",
+ "exif-customrendered-3": "HDR (원본 저장)",
+ "exif-customrendered-4": "원본 (HDR용)",
+ "exif-customrendered-6": "파노라마",
"exif-exposuremode-0": "자동 노출",
"exif-exposuremode-1": "수동 노출",
"exif-exposuremode-2": "자동 노출 브래킷",
"exif-scenetype-1": "D'Bild gouf fotograféiert",
"exif-customrendered-0": "Standard",
"exif-customrendered-1": "Benotzerdefinéiert",
+ "exif-customrendered-6": "Panorama",
+ "exif-customrendered-8": "Portrait",
"exif-exposuremode-0": "Automatesch Beliichtung",
"exif-exposuremode-1": "Manuell Beliichtung",
"exif-exposuremode-2": "Beliichtungsserie",
{
"@metadata": {
"authors": [
- "RMizo"
+ "RMizo",
+ "INerdguyI"
]
},
"exif-imagewidth": "Zàuzáwng",
"exif-writer": "Ziaktu",
"exif-languagecode": "Ţawng",
"exif-iimversion": "IIM chhuah",
- "exif-iimcategory": "Pawl"
+ "exif-iimcategory": "Pawl",
+ "exif-customrendered-2": "HDR(original save a awm lo)",
+ "exif-customrendered-3": "HDR(original a in save)",
+ "exif-customrendered-4": "Original(HDR atan)",
+ "exif-customrendered-6": "Panorama",
+ "exif-customrendered-7": "Portriat HDR",
+ "exif-customrendered-8": "Thlalak"
}
"exif-scenetype-1": "Непосредно фотографирана слика",
"exif-customrendered-0": "Нормален процес",
"exif-customrendered-1": "Нестандарден процес",
+ "exif-customrendered-2": "HDR (без зачуван оригинал)",
+ "exif-customrendered-3": "HDR (со зачуван оригинал)",
+ "exif-customrendered-4": "Оригинал (за HDR)",
+ "exif-customrendered-6": "Панорама",
+ "exif-customrendered-7": "Портретен HDR",
+ "exif-customrendered-8": "Портрет",
"exif-exposuremode-0": "Автоматско изложување",
"exif-exposuremode-1": "Рачно изложување",
"exif-exposuremode-2": "Автоматски со зададен распон",
"exif-scenetype-1": "Imagem fotografada diretamente",
"exif-customrendered-0": "Processo normal",
"exif-customrendered-1": "Processo personalizado",
+ "exif-customrendered-2": "HDR (nenhum original salvo)",
+ "exif-customrendered-3": "HDR (original salvo)",
+ "exif-customrendered-4": "Original (para HDR)",
+ "exif-customrendered-6": "Panorama",
+ "exif-customrendered-7": "Retrato HDR",
+ "exif-customrendered-8": "Retrato",
"exif-exposuremode-0": "Exposição automática",
"exif-exposuremode-1": "Exposição manual",
"exif-exposuremode-2": "Bracket automático",
"exif-scenetype-1": "Imagem fotografada diretamente",
"exif-customrendered-0": "Processo normal",
"exif-customrendered-1": "Processo personalizado",
+ "exif-customrendered-2": "HDR (original não gravado)",
+ "exif-customrendered-3": "HDR (original gravado)",
+ "exif-customrendered-4": "Original (para HDR)",
+ "exif-customrendered-6": "Panorama",
+ "exif-customrendered-7": "Retrato HDR",
+ "exif-customrendered-8": "Retrato",
"exif-exposuremode-0": "Exposição automática",
"exif-exposuremode-1": "Exposição manual",
"exif-exposuremode-2": "Bracket automático",
"exif-scenetype-1": "See also:\n* {{msg-mw|Exif-scenetype}}\n* {{msg-mw|Exif-scenetype-1}}",
"exif-customrendered-0": "{{exif-qqq}}\n\nSee also:\n* {{msg-mw|Exif-customrendered}}\n* {{msg-mw|Exif-customrendered-0}}\n* {{msg-mw|Exif-customrendered-1}}",
"exif-customrendered-1": "{{exif-qqq}}\n\nSee also:\n* {{msg-mw|Exif-customrendered}}\n* {{msg-mw|Exif-customrendered-0}}\n* {{msg-mw|Exif-customrendered-1}}",
+ "exif-customrendered-2": "{{exif-qqq}}\n\nSee also:\n* {{msg-mw|Exif-customrendered}}",
+ "exif-customrendered-3": "{{exif-qqq}}\n\nSee also:\n* {{msg-mw|Exif-customrendered}}",
+ "exif-customrendered-4": "{{exif-qqq}}\n\nSee also:\n* {{msg-mw|Exif-customrendered}}",
+ "exif-customrendered-6": "{{exif-qqq}}\n\nSee also:\n* {{msg-mw|Exif-customrendered}}",
+ "exif-customrendered-7": "{{exif-qqq}}\n\nSee also:\n* {{msg-mw|Exif-customrendered}}",
+ "exif-customrendered-8": "{{exif-qqq}}\n\nSee also:\n* {{msg-mw|Exif-customrendered}}",
"exif-exposuremode-0": "{{exif-qqq}}\n{{Related|Exif-exposuremode}}",
"exif-exposuremode-1": "{{exif-qqq}}\n{{Related|Exif-exposuremode}}",
"exif-exposuremode-2": "{{exif-qqq}}\n\nA type of exposure mode shown as part of the metadata on image description pages. The Wikipedia article on [[w:Bracketing#Exposure_bracketing|bracketing]] says that 'auto bracket' is a camera exposure setting which automatically takes a series of pictures at slightly different light exposures.\n\n{{Related|Exif-exposuremode}}",
"exif-photometricinterpretation-3": "Paletă",
"exif-photometricinterpretation-4": "Mască de transparență",
"exif-photometricinterpretation-5": "Separat (Probabil CMYK)",
+ "exif-photometricinterpretation-8": "CIE L*a*b*",
+ "exif-photometricinterpretation-9": "CIE L*a*b* (codare ICC)",
+ "exif-photometricinterpretation-10": "CIE L*a*b* (codare ITU)",
"exif-unknowndate": "Dată necunoscută",
"exif-orientation-1": "Normală",
"exif-orientation-2": "Oglindită orizontal",
"exif-scenetype-1": "Fotografije dirette",
"exif-customrendered-0": "Processe normele",
"exif-customrendered-1": "Processe personalizzete",
+ "exif-customrendered-2": "HDR (nisciune origgenale reggistrate)",
+ "exif-customrendered-3": "HDR (origgenale reggistrate)",
+ "exif-customrendered-4": "Origgenale (pe HDR)",
+ "exif-customrendered-6": "Panorameche",
+ "exif-customrendered-7": "Ritratte HDR",
+ "exif-customrendered-8": "Ritratte",
"exif-exposuremode-0": "Auto esposizione",
"exif-exposuremode-1": "Esposizione a mane",
"exif-exposuremode-2": "Bracketing automateche",
"exif-bitspersample": "Bitůw na průbka",
"exif-compression": "Metoda kompresyji",
"exif-photometricinterpretation": "Interpretacyjo fotůmetryčno",
- "exif-orientation": "Uorjyntacyjo uobrozu",
+ "exif-orientation": "Ôriyntacyjŏ",
"exif-samplesperpixel": "Průbek na piksel",
"exif-planarconfiguration": "Rozkuod danych",
"exif-ycbcrsubsampling": "Podprůbkowańe Y do C",
"exif-ycbcrpositioning": "Rozmješčyńy Y i C",
- "exif-xresolution": "Rozdźelčość w poźůmje",
- "exif-yresolution": "Rozdźelčość w pjůńy",
+ "exif-xresolution": "Rozdzielczość we poziōmie",
+ "exif-yresolution": "Rodzielczość we piōnie",
"exif-stripoffsets": "Přesůńjyńće pasůw uobrazu",
"exif-rowsperstrip": "Ličba wjeršy na pas uobrazu",
"exif-stripbytecounts": "Ličba bajtůw na pas uobrazu",
"exif-primarychromaticities": "Kolory třech barw guůwnych",
"exif-ycbcrcoefficients": "Maćeř wspůučynńikůw transformacyji barw ze RGB na YCbCr",
"exif-referenceblackwhite": "Wartość půnktu uodńyśyńo čerńi i bjeli",
- "exif-datetime": "Data i čas modyfikacyji plika",
+ "exif-datetime": "Data i czas modyfikacyje zbioru",
"exif-imagedescription": "Titel uobrozka",
"exif-make": "Producynt fotoaparatu",
"exif-model": "Model fotoaparatu",
- "exif-software": "Ůžyte uoprůgramowańy",
+ "exif-software": "Użyte ôprogramowanie",
"exif-artist": "Autor",
"exif-copyright": "Wuaśćićel praw autorskych",
- "exif-exifversion": "Wersyja standardu Exif",
+ "exif-exifversion": "Wersyjŏ Exif",
"exif-flashpixversion": "Uobsůgiwano wersyjo Flashpix",
- "exif-colorspace": "Přestřyń kolorůw",
+ "exif-colorspace": "Przestrzyń farbōw",
"exif-componentsconfiguration": "Značyńy skuadowych",
"exif-compressedbitsperpixel": "Skůmpresowanych bitůw na piksel",
"exif-pixelxdimension": "Prawidłowa szyrzka uobrozu",
"exif-pixelydimension": "Prawidłowo wyżka uobrozu",
"exif-usercomment": "Kůmyntoř užytkowńika",
"exif-relatedsoundfile": "Powjůnzany plik audjo",
- "exif-datetimeoriginal": "Data i čas utwořyńo uoryginouu",
- "exif-datetimedigitized": "Data i čas zeskanowańo",
+ "exif-datetimeoriginal": "Data i czas stworzyniŏ ôryginału",
+ "exif-datetimedigitized": "Data i czas digitalizacyje",
"exif-subsectime": "Data i čas modyfikacyji pliku – uuamki sekůnd",
"exif-subsectimeoriginal": "Data i čas utwořyńo uoryginouu – uuamki sekůnd",
"exif-subsectimedigitized": "Data i čas zeskanowańo – uuamki sekůnd",
"exif-gpsdifferential": "Korekcyjo růžńicy GPS",
"exif-compression-1": "ńyskůmpresowany",
"exif-unknowndate": "ńyznano data",
- "exif-orientation-1": "normalno",
+ "exif-orientation-1": "Normalno",
"exif-orientation-2": "odbiće we źřadle w poźůmje",
"exif-orientation-3": "uobroz uobrůcůny uo 180°",
"exif-orientation-4": "uodbiće we źřadle w pjůńy",
"exif-samplesperpixel": "Төс өлешләре саны",
"exif-xresolution": "Ятма ачыклык",
"exif-yresolution": "Асма ачыклык",
+ "exif-rowsperstrip": "Бер бүлемдә юллар саны",
+ "exif-stripbytecounts": "Кысылган бүлемдә байтлар саны",
"exif-datetime": "Файл үзгәреше датасы һәм вакыты",
"exif-imagedescription": "Сурәт атамасы",
"exif-make": "Камера җитештерүчесе",
"exif-software": "Кулланылган программа",
"exif-artist": "Автор",
"exif-copyright": "Авторлык хокукы иясе",
- "exif-exifversion": "Exif Ñ\8eÑ\80амаÑ\81ы",
+ "exif-exifversion": "Exif Ñ\87Ñ\8bгаÑ\80Ñ\8bÑ\88ы",
"exif-flashpixversion": "FlashPix ярашлы юрамасы",
"exif-colorspace": "Төсләр киңлеге",
"exif-componentsconfiguration": "Төсләр төзелешенең конфигурациясе",
"exif-gpslongitude": "Озынлык",
"exif-gpsaltituderef": "Югарылык индексы",
"exif-gpsaltitude": "Югарылык",
- "exif-gpstimestamp": "UTC буенча вакыт",
+ "exif-gpstimestamp": "GPS вакыты (атом сәгате)",
"exif-gpssatellites": "Кулланылган иярченнәр тасвирламасы",
"exif-gpsstatus": "Алгычның статусы һәм төшерү вакыты",
"exif-gpsmeasuremode": "Урнашуны билгеләү ысулы",
"exif-gpsdop": "Билгеләүнең дөреслеге",
"exif-gpsspeedref": "Тизлекне исәпләү берәмлеге",
"exif-gpsspeed": "Хәрәкәт тизлеге",
- "exif-gpsdatestamp": "Дата",
+ "exif-gpsdatestamp": "GPS датасы",
"exif-keywords": "Иң мөһиме",
+ "exif-headline": "Башисем",
"exif-source": "Чыганак",
+ "exif-contact": "Элемтә өчен мәгълүмат",
"exif-writer": "Язучы",
"exif-languagecode": "Тел",
"exif-iimversion": "IIM юрамасы",
"exif-iimcategory": "Төркем",
"exif-iimsupplementalcategory": "Өстәмә төркемнәр",
+ "exif-datetimereleased": "Чыгарылу вакыты",
"exif-identifier": "Идентификатор",
"exif-label": "Билгеләү",
"exif-copyrighted": "Авторлык хокукы халәте",
"exif-copyrightowner": "Авторлык хокукы иясе",
"exif-usageterms": "Куллану шартлары",
+ "exif-photometricinterpretation-0": "Ак һәм кара (ак — 0)",
+ "exif-photometricinterpretation-1": "Ак һәм кара (кара — 0)",
+ "exif-unknowndate": "Билгесез вакыт",
"exif-orientation-1": "Гадәти",
"exif-orientation-3": "180° ка борылган",
+ "exif-planarconfiguration-1": "«chunky» форматы",
+ "exif-planarconfiguration-2": "«planar» форматы",
"exif-componentsconfiguration-0": "барлыкта юк",
"exif-exposureprogram-0": "Билгесез",
"exif-exposureprogram-1": "Кулдан җайлау режимы",
"exif-meteringmode-0": "Билгесез",
"exif-meteringmode-1": "Уртача",
"exif-meteringmode-3": "Нокталы",
- "exif-meteringmode-4": "Ð\9cÑ\83лÑ\8cÑ\82инокталы",
+ "exif-meteringmode-4": "Ð\9aүп нокталы",
"exif-meteringmode-5": "Паттернлы",
"exif-meteringmode-6": "Өлешләтә",
"exif-meteringmode-255": "Башка",
"exif-gpsdop-moderate": "Уртача ($1)",
"exif-gpsdop-fair": "Ярыйсы ($1)",
"exif-gpsdop-poor": "Начар ($1)",
+ "exif-objectcycle-a": "Иртән генә",
+ "exif-objectcycle-p": "Кичен генә",
+ "exif-objectcycle-b": "Иртән һәм кичен",
"exif-dc-date": "Дата(лар)",
"exif-dc-publisher": "Нәшир",
"exif-dc-relation": "Бәйле медиа",
"exif-dc-type": "Медиа төре",
"exif-rating-rejected": "Кире кагылды",
"exif-isospeedratings-overflow": "65535 тән күбрәк",
+ "exif-iimcategory-fin": "Экономика һәм бизнес",
+ "exif-iimcategory-evn": "Әйләнә-тирәдәге мохит",
"exif-iimcategory-hth": "Сәламәтлек",
"exif-iimcategory-lab": "Хезмәт",
+ "exif-iimcategory-pol": "Сәясәт",
+ "exif-iimcategory-rel": "Дин һәм иман",
+ "exif-iimcategory-sci": "Фән һәм техника",
+ "exif-iimcategory-spo": "Спорт",
"exif-iimcategory-wea": "Һава торышы",
"exif-urgency-normal": "Гадәти ($1)",
"exif-urgency-low": "Түбән ($1)",
"PhiLiP",
"Qiyue2001",
"Xiaomingyan",
- "神樂坂秀吉"
+ "神樂坂秀吉",
+ "予弦"
]
},
"exif-imagewidth": "宽度",
"exif-scenetype-1": "直接照像圖片",
"exif-customrendered-0": "一般程序",
"exif-customrendered-1": "自訂程序",
+ "exif-customrendered-2": "HDR(原始未儲存)",
+ "exif-customrendered-3": "HDR(原始已儲存)",
+ "exif-customrendered-4": "原始(用於 HDR)",
+ "exif-customrendered-6": "全景",
+ "exif-customrendered-7": "人像 HDR",
+ "exif-customrendered-8": "人像",
"exif-exposuremode-0": "自動曝光",
"exif-exposuremode-1": "手動曝光",
"exif-exposuremode-2": "自動包圍曝光",
"wlheader-enotif": "Se premitin notificacionis pol email.",
"wlheader-showupdated": "Las páhinas que s'án emburacau dendi la úrtima vezi que las visoreasti son muestrás en '''negrina'''",
"wlnote": "Embahu {{PLURAL:$1|es el úrtimu chambu|son los úrtimus '''$1''' chambus}} enas úrtimas {{PLURAL:$2|oras|'''$2''' oras}}.",
- "wlshowlast": "Muestral úrtimus $1 oras $2 dias",
"watchlist-options": "Ocionis de la mi lista e seguimientu",
"watching": "Vehilandu...",
"unwatching": "Abaldonandu la vehiláncia en...",
"uctop": "úrtimu chambu",
"month": "Mes:",
"year": "Añu:",
- "sp-contributions-newbies": "Solu muestral los endirguis de cuentas nuevas",
- "sp-contributions-newbies-sub": "Pa nuevas cuentas",
"sp-contributions-blocklog": "Rustrihu e tarugus",
"sp-contributions-deleted": "Contribucionis el usuáriu esborrás",
"sp-contributions-logs": "rustrijus",
"revdelete-unsuppress": "حذف محدودیتها در بازبینیهای ترمیمشده",
"revdelete-log": "دلیل:",
"revdelete-submit": "اعمال بر {{PLURAL:$1|نسخهٔ|نسخههای}} انتخاب شده",
- "revdelete-success": "Ù¾Û\8cداÛ\8cÛ\8c Ù\86سخÙ\87 بÙ\87â\80\8cرÙ\88ز شد.",
+ "revdelete-success": "Ù¾Û\8cداÛ\8cÛ\8c Ù\86سخÙ\87 رÙ\88زآÙ\85د شد.",
"revdelete-failure": "'''پیدایی نسخهها قابل به روز کردن نیست:'''\n$1",
"logdelete-success": "تغییر پیدایی مورد انجام شد.",
"logdelete-failure": "'''پیدایی سیاههها قابل تنظیم نیست:'''\n$1",
"apihelp-no-such-module": "پودمان «$1» یافت نشد.",
"apisandbox": "گودال ماسهبازی رابط برنامهنویسی",
"apisandbox-jsonly": "برای استفاده از صفحهٔ تمرین رابط برنامهنویسی به جاوااسکریپت نیاز دارید.",
- "apisandbox-api-disabled": "رابط برنامهنویسی در این تارنما غیرفعال شدهاست.",
"apisandbox-intro": "از این صفحه برای آزمایش <strong>خدمات وب رابط برنامهنویسی مدیاویکی</strong> استفاده کنید.\nبرای جزئیات بیشتر دربارهٔ نحوهٔ استفاده از رابط برنامهنویسی به [[mw:API:Main page|مستندات رابط برنامهنویسی]] رجوع کنید. مثال: [https://www.mediawiki.org/wiki/API#A_simple_example دریافت محتوای صفحهٔ اصلی]. برای دیدن مثالهای بیشتر عملکردی را انتخاب کنید.",
"apisandbox-submit": "ایجاد درخواست",
"apisandbox-reset": "پاککردن",
"wlheader-enotif": "ایمیلهای اعلان فعال است.",
"wlheader-showupdated": "صفحههایی که پس از آخرین بازدید شما تغییر کردهاند <strong>پررنگ</strong> نمایش داده شدهاند.",
"wlnote": "در زیر {{PLURAL:$1|تغییری|<strong>$1</strong> تغییری}} که در {{PLURAL:$2|ساعت|<strong>$2</strong> ساعت}} گذشته انجام شده موجود است، تاریخ آخرین بازیابی: $3، $4",
- "wlshowlast": "نمایش آخرین $1 ساعت $2 روز",
"watchlist-hide": "نهفتن",
"watchlist-submit": "نمایش",
"wlshowtime": "نمایش بازهٔ زمانی:",
"exbeforeblank": "محتوای صفحه قبل از خالیکردن این بود: «$1»",
"delete-confirm": "حذف «$1»",
"delete-legend": "حذف",
- "historywarning": "<strong>هشدار:</strong> صفحهای که در حال پاک کردن آن هستید دارای یک تاریخچه همراه با $1 {{PLURAL:$1|بازبینی|بازبینی}} است:",
+ "historywarning": "<strong>هشدار:</strong> صفحهای که در حال حذف کردن آن هستید دارای تاریخچهای شامل $1 {{PLURAL:$1|نسخه}} است:",
"historyaction-submit": "نمایش نسخهها",
"confirmdeletetext": "شما در حال حذف کردن یک صفحه یا تصویر از پایگاههای داده همراه با تمام تاریخچهٔ آن هستید.\nلطفاً این عمل را تأیید کنید و اطمینان حاصل کنید که عواقب این کار را میدانید و این عمل را مطابق با [[{{MediaWiki:Policy-url}}|سیاستها]] انجام میدهید.",
"actioncomplete": "عمل انجام شد",
"rollback-success": "ویرایشهای {{GENDER:$3|$1}} واگردانی شد؛\nصفحه به آخرین ویرایش {{GENDER:$4|$2}} برگردانده شد.",
"sessionfailure-title": "خطای نشست کاربری",
"sessionfailure": "به نظر میرسد مشکلی در مورد نشست کاربری شما وجود دارد؛\nعمل درخواست شده در اقدامی پیشگیرانه در برابر ربودهشدن اطلاعات نشست کاربری، لغو شد.\nلطفاً فرم را از نو بارگذاری کنید.",
- "changecontentmodel": "Ù\88Û\8cراÛ\8cØ´ Ù\86Ù\85Ù\88Ù\86Ù\87 محتوای یک صفحه",
+ "changecontentmodel": "Ù\88Û\8cراÛ\8cØ´ Ù\85دÙ\84 محتوای یک صفحه",
"changecontentmodel-legend": "تغییر نوع محتوی",
"changecontentmodel-title-label": "عنوان صفحه",
- "changecontentmodel-model-label": "Ù\86Ù\85Ù\88Ù\86Ù\87 محتوای جدید",
+ "changecontentmodel-model-label": "Ù\85دÙ\84 محتوای جدید",
"changecontentmodel-reason-label": "دلیل:",
"changecontentmodel-submit": "تغییر",
"changecontentmodel-success-title": "نمونه محتوی تغییر یافت",
"log-name-contentmodel": "سیاهه تغییر نمونه محتوی",
"log-description-contentmodel": "این صفحه تغییرات محتوی صفحاتی که با محتوی غیر از پیشفرض ایجاد شدهاند، را فهرست میکند.",
"logentry-contentmodel-new": "صفحهٔ $3 با استفاده از مدلهای محتوایی غیر پیشفرض «$5» توسط $1 {{GENDER:$2|ساخته شد}}",
- "logentry-contentmodel-change": "Ù\86Ù\85Ù\88Ù\86Ù\87 محتوای صفحهٔ $3 از \"$4\" به \"$5\" توسط $1 {{GENDER:$2|تغییر داده شد}}",
+ "logentry-contentmodel-change": "Ù\85دÙ\84 محتوای صفحهٔ $3 از \"$4\" به \"$5\" توسط $1 {{GENDER:$2|تغییر داده شد}}",
"logentry-contentmodel-change-revertlink": "واگردانی",
"logentry-contentmodel-change-revert": "واگردانی",
"protectlogpage": "سیاههٔ محافظت",
"month": "در این ماه (و پیش از آن):",
"year": "در این سال (و پیش از آن):",
"date": "از تاریخ (و زودتر):",
- "sp-contributions-newbies": "فقط مشارکتهای تازهکاران نمایش داده شود",
- "sp-contributions-newbies-sub": "برای تازهکاران",
- "sp-contributions-newbies-title": "مشارکتهای کاربری برای حسابهای تازهکار",
"sp-contributions-blocklog": "سیاههٔ بستهشدنها",
"sp-contributions-suppresslog": "مشارکتهای فرونشانیشده {{GENDER:$1|کاربر}}",
"sp-contributions-deleted": "مشارکتهای حذفشدهٔ {{GENDER:$1|کاربر}}",
"newimages-legend": "پالودن",
"newimages-label": "نام پرونده (یا قسمتی از آن):",
"newimages-user": "نشانی آیپی یا نام کاربری",
- "newimages-newbies": "فقط مشارکتهای کاربران جدید نمایش داده شود",
"newimages-showbots": "نمایش بارگذاریها توسط رباتها",
"newimages-hidepatrolled": "مخفی کردن بارگذاری گشتزنها",
"newimages-mediatype": "نوع رسانه",
"img-lang-default": "(زبان پیشفرض)",
"img-lang-info": "ارائه این تصویر در $1 . $2",
"img-lang-go": "برو",
- "ascending_abbrev": "صعودی",
- "descending_abbrev": "نزولی",
"table_pager_next": "صفحهٔ بعدی",
"table_pager_prev": "صفحهٔ قبل",
"table_pager_first": "صفحهٔ نخست",
"apihelp-no-such-module": "Moduulia ”$1” ei löydy.",
"apisandbox": "API-hiekkalaatikko",
"apisandbox-jsonly": "JavaScript vaaditaan API-hiekkalaatikon käyttämiseen.",
- "apisandbox-api-disabled": "API on poistettu käytöstä tällä sivustolla.",
"apisandbox-intro": "Käytä tätä sivua kokeillaksesi <strong>MediaWikin verkkopalvelun API:a</strong>.\n[[mw:API:Main page|API-dokumentaatio]] kertoo lisää API:en käytöstä. Esimerkki: [https://www.mediawiki.org/wiki/API#A_simple_example hae etusivun sisältö]. Valitse toiminto nähdäksesi lisää esimerkkejä.\n\nHuomioi, että vaikka tämä on hiekkalaatikko, sivulla suorittamasi toiminnot saattavat muokata wikiä.",
"apisandbox-submit": "Tee pyyntö",
"apisandbox-reset": "Tyhjennä",
"wlheader-enotif": "Sähköposti-ilmoitus on käytössä.",
"wlheader-showupdated": "Sivut, joita on muokattu viimeisen käyntisi jälkeen, on <strong>lihavoitu</strong>.",
"wlnote": "Alla {{PLURAL:$1|on viimeisin muutos|ovat viimeisimmät <strong>$1</strong> muutosta}} edellisen {{PLURAL:$2|tunnin|<strong>$2</strong> tunnin}} ajalta $3 kello $4 lukien.",
- "wlshowlast": "Näytä edelliset $1 tuntia tai $2 päivää",
"watchlist-hide": "Piilota",
"watchlist-submit": "Näytä",
"wlshowtime": "Näytettävä aikajakso:",
"month": "Alkaen kuukaudesta (ja aiemmin):",
"year": "Vuosi",
"date": "Alkaen päivämäärästä (ja sitä aiemmat):",
- "sp-contributions-newbies": "Näytä uusien tulokkaiden muutokset",
- "sp-contributions-newbies-sub": "Uusien käyttäjien muokkaukset",
- "sp-contributions-newbies-title": "Uusien käyttäjien muokkaukset",
"sp-contributions-blocklog": "estoloki",
"sp-contributions-suppresslog": "häivytetyt {{GENDER:$1|käyttäjän}} muokkaukset",
"sp-contributions-deleted": "poistetut {{GENDER:$1|käyttäjän}} muokkaukset",
"newimages-legend": "Suodatin",
"newimages-label": "Tiedostonimi (tai osa siitä)",
"newimages-user": "IP-osoite tai käyttäjänimi:",
- "newimages-newbies": "Näytä vain uusien käyttäjien muokkaukset",
"newimages-showbots": "Näytä bottien tekemät tallennukset",
"newimages-hidepatrolled": "Piilota tarkastetut tiedostotallennukset",
"newimages-mediatype": "Median tyyppi:",
"img-lang-default": "(oletuskieli)",
"img-lang-info": "Näytä tämä kuva kielellä $1. $2",
"img-lang-go": "Suorita",
- "ascending_abbrev": "nouseva",
- "descending_abbrev": "laskeva",
"table_pager_next": "Seuraava sivu",
"table_pager_prev": "Edellinen sivu",
"table_pager_first": "Ensimmäinen sivu",
"pager-older-n": "{{PLURAL:$1|eldri 1|eldri $1}}",
"suppress": "Yvirlit",
"apisandbox": "API sandkassin",
- "apisandbox-api-disabled": "API er ikki virkið á hesi heimasíðuni.",
"apisandbox-intro": "Nýt hesa síðu til at royna teg við '''MediaWiki web service API'''.\nVíst verður til [https://www.mediawiki.org/wiki/API:Main_page API documentasjónina] fyri smálutir um nýtslu av API.\nDømi: [https://www.mediawiki.org/wiki/API#A_simple_example heinta innihaldið frá einari høvuðssíðu]. Vel eina handling fyri at síggja fleiri dømi.\n\nLegg til merkis, at sjálvt um hetta er ein sandkassi, so kunnu broytingar ið tú gert her, broyta wiki'ina.",
"apisandbox-submit": "Kom við fyrispurningi",
"apisandbox-reset": "Rudda",
"wlheader-enotif": "Tað ber nú til at senda teldupost.",
"wlheader-showupdated": "Síður sum eru broyttar síðan tú seinast vitjaði tær, eru vístar við '''feitum'''.",
"wlnote": "Niðanfyri {{PLURAL:$1|stendur seinasta broytingin|standa seinastu '''$1''' broytingarnar}} seinasta/u {{PLURAL:$2| tíman|'''$2''' tímarnar}} hin $3 kl. $4",
- "wlshowlast": "Vís seinastu $1 tímar $2 dagar",
"watchlist-options": "Møguleikar í ansingarlistanum",
"watching": "Eftirlitir...",
"unwatching": "Strikar eftirlit...",
"uctop": "verandi",
"month": "Frá mánaði (og áðrenn):",
"year": "Frá ár (og áðrenn):",
- "sp-contributions-newbies": "Vís bert íkast frá nýggjum kontoum",
- "sp-contributions-newbies-sub": "Fyri nýggjar kontur",
- "sp-contributions-newbies-title": "Brúkaraíkøst viðvíkjandi nýggjum kontum",
"sp-contributions-blocklog": "bannagerðabók",
"sp-contributions-deleted": "slettaði brúkaraíkøst",
"sp-contributions-uploads": "uploads",
"imgmultipagenext": "næsta síða →",
"imgmultigo": "Far!",
"imgmultigoto": "Far til síðu $1",
- "ascending_abbrev": "upp",
- "descending_abbrev": "nið",
"table_pager_next": "Næsta síða",
"table_pager_prev": "Fyrrverandi síða",
"table_pager_first": "Fyrsta síða",
"nocreate-loggedin": "Vous n'avez pas la permission de créer de nouvelles pages.",
"sectioneditnotsupported-title": "Modification de section non prise en charge",
"sectioneditnotsupported-text": "La modification d’une section n’est pas prise en charge pour cette page.",
+ "modeleditnotsupported-title": "Modification non supportée",
+ "modeleditnotsupported-text": "La modification n’est pas supportée pour le modèle de contenu $1.",
"permissionserrors": "Erreur de permissions",
"permissionserrorstext": "Vous n'avez pas la permission d'effectuer l'opération demandée pour {{PLURAL:$1|la raison suivante|les raisons suivantes}} :",
"permissionserrorstext-withaction": "Vous ne pouvez pas $2, pour {{PLURAL:$1|la raison suivante|les raisons suivantes}} :",
"content-model-json": "JSON",
"content-json-empty-object": "Objet vide",
"content-json-empty-array": "Tableau vide",
+ "unsupported-content-model": "<strong>Attention :</strong> Le modèle de contenu $1 n’est pas supporté sur ce wiki.",
+ "unsupported-content-diff": "Les diffs ne sont pas supportés pour le modèle de contenu $1.",
+ "unsupported-content-diff2": "Les diffs entre les modèles de contenu $1 et $2 ne sont pas supportés sur ce wiki.",
"deprecated-self-close-category": "Pages utilisant des balises HTML auto-fermantes non valides",
"deprecated-self-close-category-desc": "La page contient des balises HTML auto-fermantes non valides, comme <code><b/></code> ou <code><span/></code>. Le comportement de celles-ci changera prochainement pour être en accord avec la spécification HTML5, donc leur utilisation dans le wikitexte est désuète.",
"duplicate-args-warning": "<strong>Avertissement :</strong> [[:$1]] appelle [[:$2]] avec plus d'une valeur pour le paramètre « $3 ». Seule la dernière valeur fournie sera utilisée.",
"apihelp-no-such-module": "Le module « $1 » est introuvable.",
"apisandbox": "Bac à sable de l'API",
"apisandbox-jsonly": "Le bac à sable de l'API nécessite JavaScript",
- "apisandbox-api-disabled": "L'API est désactivé sur ce site.",
"apisandbox-intro": "Utilisez cette page pour expérimenter l’<strong>API webservice de MediaWiki</strong>.\nReportez-vous à [[mw:API:Main page|la documentation de l’API]] pour plus de détails sur l’utilisation de l’API. Exemple: [https://www.mediawiki.org/wiki/API#A_simple_example obtenir le contenu d'une page principale]. Choisissez une option pour voir d'autres exemples.",
"apisandbox-submit": "Envoyer la requête",
"apisandbox-reset": "Effacer",
"wlheader-enotif": "La notification par courriel est activée.",
"wlheader-showupdated": "Les pages qui ont été modifiées depuis votre dernière visite sont affichées en <strong>gras</strong>.",
"wlnote": "Ci-dessous {{PLURAL:$1|figure la dernière modification effectuée|figurent les <strong>$1</strong> dernières modifications effectuées}} durant {{PLURAL:$2|la dernière heure|les <strong>$2</strong> dernières heures}}, jusqu'au $3, $4.",
- "wlshowlast": "Montrer les dernières $1 heures, les derniers $2 jours",
"watchlist-hide": "Masquer",
"watchlist-submit": "Lister",
"wlshowtime": "Période affichée :",
"sessionfailure": "Votre session de connexion semble avoir des problèmes ;\ncette action a été annulée en prévention d'un piratage de session.\nVeuillez soumettre le formulaire de nouveau.",
"changecontentmodel": "Modifier le modèle de contenu d’une page",
"changecontentmodel-legend": "Modifier le modèle de contenu",
- "changecontentmodel-title-label": "Titre de la page",
+ "changecontentmodel-title-label": "Titre de la page :",
"changecontentmodel-current-label": "Modèle de contenu actuel :",
- "changecontentmodel-model-label": "Nouveau modèle de contenu",
+ "changecontentmodel-model-label": "Nouveau modèle de contenu :",
"changecontentmodel-reason-label": "Motif :",
"changecontentmodel-submit": "Modifier",
"changecontentmodel-success-title": "Le modèle de contenu a été modifié",
"month": "À partir du mois (et précédents) :",
"year": "À partir de l'année (et précédentes) :",
"date": "À partir du (et antérieurement) :",
- "sp-contributions-newbies": "Ne montrer que les contributions des nouveaux utilisateurs",
- "sp-contributions-newbies-sub": "Parmi les nouveaux comptes",
- "sp-contributions-newbies-title": "Contributions d'utilisateurs parmi les nouveaux comptes",
"sp-contributions-blocklog": "journal des blocages",
"sp-contributions-suppresslog": "contributions de l'{{GENDER:$1|utilisateur|utilisatrice}} supprimées",
"sp-contributions-deleted": "contributions de l’{{GENDER:$1|utilisateur|utilisatrice}} supprimées",
"newimages-legend": "Filtre",
"newimages-label": "Nom du fichier (ou une partie de celui-ci) :",
"newimages-user": "Adresse IP ou nom d'utilisateur",
- "newimages-newbies": "Afficher uniquement les contributions des nouveaux comptes",
"newimages-showbots": "Afficher les imports faits par des robots",
"newimages-hidepatrolled": "Masquer les téléversements patrouillés",
"newimages-mediatype": "Type de média :",
"img-lang-default": "(langue par défaut)",
"img-lang-info": "Afficher cette image en $1 $2.",
"img-lang-go": "Lancer",
- "ascending_abbrev": "crois.",
- "descending_abbrev": "décr.",
"table_pager_next": "Page suivante",
"table_pager_prev": "Page précédente",
"table_pager_first": "Première page",
"tag-filter": "Filtrer les [[Special:Tags|balises]] :",
"tag-filter-submit": "Filtrer",
"tag-list-wrapper": "[[Special:Tags|{{PLURAL:$1|Balise|Balises}}]] : $2",
- "tag-mw-contentmodelchange": "modification du modèle de contenu",
+ "tag-mw-contentmodelchange": "Modification du modèle de contenu",
"tag-mw-contentmodelchange-description": "Modifications qui [https://www.mediawiki.org/wiki/Special:MyLanguage/Help:ChangeContentModel changent le modèle de contenu] d'une page",
"tag-mw-new-redirect": "Nouvelle redirection",
"tag-mw-new-redirect-description": "Modifications qui créent une nouvelle redirection ou transforment une page en redirection",
"tag-mw-changed-redirect-target-description": "Modifications qui changent la cible d’une redirection",
"tag-mw-blank": "Blanchiment",
"tag-mw-blank-description": "Modifications qui suppriment le contenu des pages",
- "tag-mw-replace": "Remplacé",
+ "tag-mw-replace": "Contenu remplacé",
"tag-mw-replace-description": "Modifications qui enlèvent plus de 90% du contenu des pages",
"tag-mw-rollback": "Révocation",
"tag-mw-rollback-description": "Modifications qui annulent des modifications existantes en utilisant le lien de révocation (''rollback'')",
"apihelp-no-such-module": "Lo modulo « $1 » est entrovâblo.",
"apisandbox": "Bouèta de sabla API",
"apisandbox-jsonly": "La bouèta de sabla API at fôta de JavaScript.",
- "apisandbox-api-disabled": "L’API est dèsactivâ sur cél seto.",
"apisandbox-intro": "Empleyéd cela pâge por èprovar lo <strong>sèrviço Vouèbe API de MediaWiki</strong>.\nNen rèferâd-vos a la [[mw:API:Main page|documentacion de l’API]] por més de dètalys dessus l’usâjo de l’API. Ègzemplo : [https://www.mediawiki.org/wiki/API#A_simple_example avêr lo contegnu d’una pâge principâla]. Chouèsésséd un’accion por vêre d’ôtros ègzemplos.\n\nNotâd que, quand ben qu’o est na bouèta de sabla, les accions que vos féte sur cela pâge pôvont changiér lo vouiqui.",
"apisandbox-submit": "Fâre la demanda",
"apisandbox-reset": "Vouedar",
"wlheader-enotif": "La notificacion per mèssageria èlèctronica est activâye.",
"wlheader-showupdated": "Les pâges que sont étâyes changiêes dês voutra dèrriére vesita sont montrâyes en <strong>grôs</strong>.",
"wlnote": "Vê-que {{PLURAL:$1|lo dèrriér changement fêt|los <strong>$1</strong> dèrriérs changements fêts}} pendent {{PLURAL:$2|l’hora passâye|les <strong>$2</strong> hores passâyes}}, tant qu’u $3 a $4.",
- "wlshowlast": "Montrar les $1 hores passâyes, los $2 jorns passâs",
"watchlist-hide": "Cachiér",
"watchlist-submit": "Montrar",
"wlshowtime": "Temps a fâre vêre :",
"uctop": "d’ora",
"month": "Dês lo mês (et devant) :",
"year": "Dês l’an (et devant) :",
- "sp-contributions-newbies": "Montrar ren que les contribucions des novéls utilisators",
- "sp-contributions-newbies-sub": "Entre-mié los comptios novéls",
- "sp-contributions-newbies-title": "Contribucions d’utilisators entre-mié los comptios novéls",
"sp-contributions-blocklog": "jornâl des blocâjos",
"sp-contributions-suppresslog": "contribucions d’utilisators rèprimâyes",
"sp-contributions-deleted": "contribucions d’utilisators suprimâyes",
"img-lang-default": "(lengoua per dèfôt)",
"img-lang-info": "Montrar cel’émâge en $1 $2.",
"img-lang-go": "Emmodar",
- "ascending_abbrev": "crès.",
- "descending_abbrev": "dècr.",
"table_pager_next": "Pâge aprés",
"table_pager_prev": "Pâge devant",
"table_pager_first": "Premiére pâge",
"wlheader-enotif": "Di e-mail siinst as aktiif.",
"wlheader-showupdated": "Nei feranert sidjen wurd '''fäät''' uunwiset.",
"wlnote": "Diar {{PLURAL:$1|stäänt det leetst feranrang|stun a leetst <strong>$1</strong> feranrangen}} faan a leetst {{PLURAL:$2|stünj|<strong>$2</strong> stünjen}}. Stant: $3, klook $4.",
- "wlshowlast": "Wise a feranrangen faan a leetst $1 stünjen, $2 daar.",
"watchlist-submit": "Wise",
"watchlist-options": "Iinstelangen för't uunwisin",
"watching": "Uun't uug behual ...",
"uctop": "aktuel",
"month": "faan muun (of iarer):",
"year": "faan juar (of iarer):",
- "sp-contributions-newbies": "Wise bluas bidracher faan nei brükern",
- "sp-contributions-newbies-sub": "Faan nei brükern",
- "sp-contributions-newbies-title": "Brükerbidracher faan nei brükern",
"sp-contributions-blocklog": "Sper-Logbuk",
"sp-contributions-suppresslog": "Fersteecht {{GENDER:$1|brükerbidracher}}",
"sp-contributions-deleted": "Stregen {{GENDER:$1|brüker}} bidracher",
"img-lang-default": "(standard spriak)",
"img-lang-info": "Detdiar bil uun $1 amwerke. $2",
"img-lang-go": "Widjer",
- "ascending_abbrev": "ap",
- "descending_abbrev": "deel",
"table_pager_next": "Naist sidj",
"table_pager_prev": "Leetst sidj (turag)",
"table_pager_first": "Iarst sidj",
"wlheader-enotif": "Notifiche par pueste eletroniche ativade.",
"wlheader-showupdated": "Lis pagjinis gambiadis de ultime volte che tu lis âs cjaladis a son mostradis in '''gruessut'''",
"wlnote": "Ca sot {{PLURAL:$1|al è il cambiament plui recent|a son i '''$1''' cambiaments plui recents}} {{PLURAL:$2|inte ultime ore|intes '''$2''' oris passadis}}.",
- "wlshowlast": "Mostre ultimis $1 oris $2 zornadis",
"watchlist-options": "Opzions pe liste dai tignûts di voli",
"watching": "Daûr a zontâ aes pagjinis tignudis di voli...",
"unwatching": "Daûr a gjavâ des pagjinis tignudis di voli...",
"uctop": "atuâl",
"month": "Scomençant dal mês (e prime):",
"year": "Scomençant dal an (e prime):",
- "sp-contributions-newbies": "Mostre dome i contribûts dai gnûfs utents",
- "sp-contributions-newbies-sub": "Pai gnûfs utents",
"sp-contributions-blocklog": "Regjistri dai blocs",
"sp-contributions-deleted": "contribûts dal utent eliminâts",
"sp-contributions-uploads": "cjamadis",
"imgmultipagenext": "pagjine sucessive →",
"imgmultigo": "Va!",
"imgmultigoto": "Va ae pagjine $1",
- "ascending_abbrev": "asc",
- "descending_abbrev": "disc",
"table_pager_next": "Pagjine sucessive",
"table_pager_prev": "Pagjine precedente",
"table_pager_first": "Prime pagjine",
"wlheader-enotif": "E-mailnotifikaasje is ynskeakele.",
"wlheader-showupdated": "Siden dy't wizige binne nei't jo dy it lêst besocht hawwe, wurde <strong>fet</strong> werjûn.",
"wlnote": "Hjirûnder {{PLURAL:$1|stiet de lêste feroaring|steane de lêste <strong>$1</strong> feroarings}} fan 'e lêste {{PLURAL:$2|oere|<strong>$2</strong> oeren}}, sûnt $3, $4.",
- "wlshowlast": "Lit feroarings sjen fan de lêste $1 oeren $2 dagen",
"watchlist-hide": "Ferbergje",
"watchlist-submit": "Werjaan",
"wlshowtime": "Tiidsperioade fan werjefte:",
"month": "Fan moanne (en earder):",
"year": "Fan jier (en earder):",
"date": "Fan datum (en earder):",
- "sp-contributions-newbies": "Allinne bydragen fan nije akkounts besjen",
- "sp-contributions-newbies-sub": "Foar nije akkounts",
- "sp-contributions-newbies-title": "Bydragen fan nije meidoggers",
"sp-contributions-blocklog": "útslútloch",
"sp-contributions-deleted": "wiske {{GENDER:$1|meidogger}}bydragen",
"sp-contributions-uploads": "opladen",
"wlheader-enotif": "Cumasaíodh fógraí riomhphoist.",
"wlheader-showupdated": "Tá '''cló trom''' ar leathanaigh a athraíodh ón uair is deireanaí a d'fhéach tú orthu.",
"wlnote": "Is {{PLURAL:$1|é seo thíos an t-athrú is déanaí|iad seo thíos an <strong>'''$1'''</strong> athrú is déanaí}} {{PLURAL:$2|san uair an chloig dheireanach|sa '''$2''' uair an chloig dheireanacha}}.",
- "wlshowlast": "Líon na n-uaireanta is déanaí le taispeáint: $1. Líon na laethanta is déanaí le taispeáint: $2.",
"watchlist-submit": "Taispeáin",
"wlshowhideminor": "mionathruithe",
"wlshowhidebots": "botaí",
"uctop": "reatha",
"month": "Ón mhí seo (agus níos luaithe):",
"year": "Ón bhliain seo (agus níos luaithe):",
- "sp-contributions-newbies": "Taispeáin iarrachtaí ó chuntais nua amháin",
- "sp-contributions-newbies-sub": "Le cuntais nua",
- "sp-contributions-newbies-title": "Iarrachtaí úsáideora do chuntais nua",
"sp-contributions-blocklog": "Log coisc",
"sp-contributions-suppresslog": "iarrachtaí {{GENDER:$1|user}} folaithe",
"sp-contributions-deleted": "dréachtaí {{GENDER:$1|úsáideora}} scriosta",
"newimages": "Gailearaí na n-íomhánna nua",
"imagelisttext": "Tá liosta thíos de {{PLURAL:$1|comhad amháin|$1 comhaid $2}}.",
"newimages-label": "Comhadainm (nó cuid de):",
- "newimages-newbies": "Taispeáin iarrachtaí ó chuntais nua amháin",
"noimages": "Tada le feiceáil.",
"ilsubmit": "Cuardaigh",
"bydate": "de réir dáta",
"watchthispage": "Bak bu sayfaya",
"unwatch": "Durgun sayfa izlemää",
"watchlist-details": "Diil konuşmaa sayfaları {{PLURAL:$1|$1 sayfa|$1 sayfa}} bakmaa listanızda.",
- "wlshowlast": "Bitki $1 saati $2 günü göster",
"watchlist-options": "İzlemäk listası opţiyaları",
"watching": "Bakılêr...",
"unwatching": "Durgundurulêr...",
"uctop": "bitki",
"month": "Ay:",
"year": "Yıl:",
- "sp-contributions-newbies": "Sadä eni esap açan kullanıcıların katılmaklarını göster",
- "sp-contributions-newbies-sub": "Eni kullanıcılara deyni",
"sp-contributions-blocklog": "Köstek jurnalı",
"sp-contributions-talk": "Konuşmaa",
"sp-contributions-search": "Katılmakları aara",
"wlheader-enotif": "启动嘞email通知功能。",
"wlheader-showupdated": "上回倷眵𠮶页面改动𠮶部分用'''粗体'''显到",
"wlnote": "下底系最近'''$2'''钟头内𠮶最晏'''$1'''道修改:",
- "wlshowlast": "显示近来$1钟头$2日𠮶改动",
"watchlist-options": "监视清单选项",
"watching": "眏到...",
"unwatching": "莫眏到...",
"uctop": "头上",
"month": "从个月 (或更早):",
"year": "从个年 (或更早):",
- "sp-contributions-newbies": "单显到新用户𠮶贡献",
- "sp-contributions-newbies-sub": "新用户𠮶贡献",
"sp-contributions-blocklog": "封锁记录",
"sp-contributions-uploads": "上载",
"sp-contributions-logs": "日志",
"imgmultipageprev": "← 上页",
"imgmultipagenext": "下页 →",
"imgmultigo": "确定!",
- "ascending_abbrev": "增",
- "descending_abbrev": "减",
"table_pager_next": "下页",
"table_pager_prev": "上页",
"table_pager_first": "首页",
"wlheader-enotif": "啟動哩email通知功能。",
"wlheader-showupdated": "上回倷眵嗰頁面改動嗰部分用'''粗體'''顯到",
"wlnote": "下底係最近'''$2'''鐘頭內嗰最晏'''$1'''道修改:",
- "wlshowlast": "顯示箇日子$1鐘頭$2日嗰改動",
"watchlist-options": "監視清單選項",
"watching": "眏到...",
"unwatching": "莫眏到...",
"uctop": "頭上",
"month": "從箇月 (或更早):",
"year": "從箇年 (或更早):",
- "sp-contributions-newbies": "單顯到新用戶嗰貢獻",
- "sp-contributions-newbies-sub": "新用戶嗰貢獻",
"sp-contributions-blocklog": "封鎖記錄",
"sp-contributions-uploads": "上載",
"sp-contributions-logs": "日誌",
"imgmultipageprev": "← 上頁",
"imgmultipagenext": "下頁 →",
"imgmultigo": "確定!",
- "ascending_abbrev": "增",
- "descending_abbrev": "減",
"table_pager_next": "下頁",
"table_pager_prev": "上頁",
"table_pager_first": "首頁",
"watchlist-details": "{{PLURAL:$1|$1 paj sa|$1}} annan zòt lis di swivi (plis paj-ya di diskisyon).",
"wlheader-showupdated": "Paj-ya ki modifyé dipi zòt dannyé vizit sa afiché an <strong>gra</strong>.",
"wlnote": "Anba {{PLURAL:$1|ka figiré dannyé modifikasyon-an ki éfègtchwé|ka figiré <strong>$1</strong> dannyé modifikasyon-yan ki éfègtchwé}} douran {{PLURAL:$2|dannyé lò-a|<strong>$2</strong> dannyé lò-ya}}, jouk $3, $4.",
- "wlshowlast": "Montré dannyé $1 lò, dannyé $2 jou",
"watchlist-options": "Opsyon di lis di swivi",
"enotif_reset": "Marké tout paj-ya kou vizité",
"dellogpage": "Journal dé siprésyon",
"uctop": "atchwèl",
"month": "Apati di mwè (ké anvan) :",
"year": "Apati di lannen (ké anvan) :",
- "sp-contributions-newbies": "Montré ren ki kontribisyon-yan dé nouvèl itilizatò",
"sp-contributions-blocklog": "journal dé blokaj",
"sp-contributions-uploads": "enpòr",
"sp-contributions-logs": "journal",
"wlheader-enotif": "Tha brathan-naidheachd air a' phost-d an comas.",
"wlheader-showupdated": "Tha clò <strong>trom</strong> air duilleagan a chaidh atharrachadh on turas mu dheireadh a thadhail thu orra.",
"wlnote": "Chì thu gu h-ìosal {{PLURAL:$1|a' $1 mhùthadh|an $1 mhùthadh|na $1 mùthaidhean|am $1 mùthadh}} mu dheireadh san {{PLURAL:$2|$2 uair a thìde|$2 uair a thìde|$2 uairean a thìde|$2 uair a thìde}} mu dheireadh, mar a bha e $3, $4.",
- "wlshowlast": "Seall na $1 uairean a thìde mu dheireadh $2 làithean mu dheireadh",
"watchlist-hide": "Falaich",
"watchlist-options": "Roghainnean mo chlàir-faire",
"watching": "'Ga chur air a' chlàr-fhaire...",
"uctop": "làithreach",
"month": "On mhìos (agus na bu tràithe):",
"year": "On bhliadhna (agus na bu tràithe):",
- "sp-contributions-newbies": "Seall obair le cunntasan ùra a-mhàin",
- "sp-contributions-newbies-sub": "Airson cunntasan ùra",
- "sp-contributions-newbies-title": "Obair le cunntasan ùra",
"sp-contributions-blocklog": "an loga bacaidh",
"sp-contributions-suppresslog": "obair {{GENDER:$1|a’ chleachdaiche}} a chaidh a mhùchadh",
"sp-contributions-deleted": "obair {{GENDER:$1|a’ chleachdaiche}} a chaidh a sguabadh às",
"img-lang-default": "(an cànan tùsail)",
"img-lang-info": "Reandaraich an dealbh seo sa: $1. $2",
"img-lang-go": "Siuthad",
- "ascending_abbrev": "a' dìreadh",
- "descending_abbrev": "a' teàrnadh",
"table_pager_next": "An ath-dhuilleag",
"table_pager_prev": "An duilleag roimhpe",
"table_pager_first": "A' chiad duilleag",
"systemblockedtext": "O seu nome de usuario ou enderezo IP foi bloqueado automaticamente polo sistema MediaWiki.\nO motivo do bloqueo é:\n\n:<em>$2</em>\n\n* Comezo do bloqueo: $8\n* Expiración do bloqueo: $6\n* Destinatario do bloqueo: $7\n\nO seu enderezo IP actual é $3.\nPor favor, inclúa todos estes detalles en calquera consulta que realice.",
"blockednoreason": "non se deu ningunha razón",
"blockedtext-composite": "<strong>O seu nome de usuario ou enderezo IP foron bloqueados.</strong>\n\nO motivo dado é:\n\n:<em>$2</em>.\n\n* Comezo do bloqueo: $8\n* Remate do bloqueo máis longo: $6\n\n* $5\n\nO seu enderezo IP actual é $3.\nPor favor, inclúa todos os detalles de arriba en calquera contacto sobre este asunto.",
+ "blockedtext-composite-no-ids": "O seu enderezo IP aparece en múltiples listas negras",
"blockedtext-composite-reason": "Existen varios bloqueos contra a súa conta ou enderezo IP",
"whitelistedittext": "Debe $1 para poder editar páxinas.",
"confirmedittext": "Debe confirmar o correo electrónico antes de comezar a editar. Por favor, configure e dea validez ao correo mediante as súas [[Special:Preferences|preferencias de usuario]].",
"apihelp-no-such-module": "Non se atopou o módulo \"$1\".",
"apisandbox": "Zona de probas API",
"apisandbox-jsonly": "É preciso activar o JavaScript para usar a zona de probas.",
- "apisandbox-api-disabled": "API está desactivado neste sitio.",
"apisandbox-intro": "Use esta páxina para experimentar co <strong>servizo web da API de MediaWiki</strong>.\nConsulte a [[mw:API:Main page| documentación da API]] para obter máis información sobre o uso da API. Exemplo: [https://www.mediawiki.org/wiki/API#A_simple_example obter o contido dunha páxina de inicio]. Seleccione unha acción para ollar máis exemplos.\n\nTeña en conta que, aínda que esta é unha páxina de probas, as accións que realice nesta páxina poden modificar o wiki.",
"apisandbox-submit": "Facer a solicitude",
"apisandbox-reset": "Limpar",
"wlheader-enotif": "A notificación por correo electrónico está activada.",
"wlheader-showupdated": "As páxinas que cambiaron desde a súa última visita móstranse en <strong>letra grosa</strong>.",
"wlnote": "A continuación {{PLURAL:$1|está a última modificación|están as últimas <strong>$1</strong> modificacións}} {{PLURAL:$2|na última hora|nas últimas <strong>$2</strong> horas}} ata o $3 ás $4.",
- "wlshowlast": "Amosar as últimas $1 horas e os últimos $2 días",
"watchlist-hide": "Agochar",
"watchlist-submit": "Amosar",
"wlshowtime": "Período de tempo a amosar:",
"month": "Desde o mes de (e anteriores):",
"year": "Desde o ano (e anteriores):",
"date": "Dende a data (e anteriores):",
- "sp-contributions-newbies": "Amosar só as contribucións das contas de usuario novas",
- "sp-contributions-newbies-sub": "Contribucións dos usuarios novos",
- "sp-contributions-newbies-title": "Contribucións dos usuarios novos",
"sp-contributions-blocklog": "rexistro de bloqueos",
"sp-contributions-suppresslog": "contribucións {{GENDER:$1|do usuario|da usuaria}} suprimidas",
"sp-contributions-deleted": "contribucións {{GENDER:$1|do usuario|da usuaria}} borradas",
"newimages-legend": "Filtro",
"newimages-label": "Nome do ficheiro (ou parte del):",
"newimages-user": "Enderezo IP ou nome de usuario",
- "newimages-newbies": "Amosar só as contribucións das contas de usuario novas",
"newimages-showbots": "Amosar as cargas feitas por bots",
"newimages-hidepatrolled": "Agochar as subidas patrulladas",
"newimages-mediatype": "Tipo de ficheiro multimedia",
"img-lang-default": "(lingua por defecto)",
"img-lang-info": "Renderizar esta imaxe en $1. $2",
"img-lang-go": "Amosar",
- "ascending_abbrev": "asc",
- "descending_abbrev": "desc",
"table_pager_next": "Páxina seguinte",
"table_pager_prev": "Páxina anterior",
"table_pager_first": "Primeira páxina",
"permanentlink": "Ligazón permanente",
"permanentlink-revid": "ID da revisión",
"permanentlink-submit": "Ir á revisión",
+ "newsection": "Nova sección",
+ "newsection-page": "Páxina de destino",
"newsection-submit": "Ir á páxina",
"dberr-problems": "Sentímolo! Este sitio está experimentando dificultades técnicas.",
"dberr-again": "Por favor, agarde uns minutos e logo probe a cargar de novo a páxina.",
"watch": "नदर दवरात",
"unwatch": "पळोवंक नासलें",
"watchlist-details": "लक्ष {{PLURAL:$1|$1वळेरींतलें|$1 वळेंरींतली}} {{PLURAL:$1|$1पान|$1 पानां}} उलोवपाची पानां सोडून",
- "wlshowlast": "फाटलें $1 वरांचें $2 दिसांचें दाखयात",
"watchlist-options": "सादुरवळेरींतलो पर्याय",
"delete-legend": "काडून उडयात",
"actioncomplete": "क्रिया पुराय जाल्या",
"uctop": "हालीचें",
"month": "ह्या म्हयन्या सावन (आनी आदलें):",
"year": "ह्या वर्सा सावन (आनी आदलें):",
- "sp-contributions-newbies": "फकत नव्या खात्यांचीं योगदानां दाखयात",
"sp-contributions-blocklog": "कार्यवळेरी आडायात",
"sp-contributions-uploads": "अपलोड",
"sp-contributions-logs": "लॉग",
"watchlist-details": "Tujea Sadurvollerint {{PLURAL:$1|$1 pan asa|$1 panam asat}} (te-bhair ulovpachim panam asat).",
"wlheader-showupdated": "Tujea fatle bhette san bodol'lean tim panam '''datt''' dakhoileant.",
"wlnote": "Sokoil {{PLURAL:$1|ho nimanno bodol|hem nimanneo <strong>$1</strong> bodol}} nimannea {{PLURAL:$2|horan|<strong>$2</strong> horanim}}, $3, $4 porian.",
- "wlshowlast": "Xevottchim $1 voram $2 dis dakhoi",
"watchlist-options": "Sadurvollericheo poryay",
"watching": "Disht dovortanv...",
"unwatching": "Disht kaddthanv...",
"uctop": "atachem",
"month": "Mhoinea savn (ani adichem):",
"year": "Hea vorsa savn (ani adichem):",
- "sp-contributions-newbies": "Fokot novea khateachim yogdanam dakhoi",
"sp-contributions-blocklog": "addavnniache sotr",
"sp-contributions-uploads": "upload",
"sp-contributions-logs": "sotr",
"watchlist-details": "{{PLURAL:$1|$1 halaman}} to dputari he'awasiyamu (duhengiyo halaman lo'iya).",
"wlheader-showupdated": "Halaman ma loboli'a to pulitiyo nila'omu mowali bilohela to <strong>bold</strong>.",
"wlnote": "To tibawa botiye {{PLURAL:$1|loboli'a|<strong>$1</strong> loboli'a}} pulitiyo to delomo {{PLURAL:$2|jam|<strong>$2</strong> jam}}, per $3, $4.",
- "wlshowlast": "Popobilohe $1 jam $2 dulahe pulitiyo",
"watchlist-options": "Tulawoto daputari he'awasiyalo",
"enotif_reset": "Tuwoti nga'amila halaman ma nila'o",
"dellogpage": "Log loluluto",
"uctop": "masatiya",
"month": "Lonto hulalo (wawu to'udiipo)",
"year": "Lonto taawunu (wawu to'udiipo)",
- "sp-contributions-newbies": "Popobilohe bo lonto ta ohu'uwo bohu",
"sp-contributions-blocklog": "bubuli log",
"sp-contributions-uploads": "u diletohu",
"sp-contributions-logs": "log",
"unwatch": "𐌿𐌽𐍅𐌹𐍄",
"watchlist-details": "{{PLURAL:$1|$1 𐌻𐌰𐌿𐍆𐍃|$1 𐌻𐌰𐌿𐌱𐍉𐍃}} 𐌰𐌽𐌰 𐌸𐌴𐌹𐌽𐌰𐌹 𐍅𐌹𐍄𐌰𐍅𐌹𐌺𐍉𐌽 (𐌾𐌰𐌷 𐌲𐌰𐍅𐌰𐌿𐍂𐌳𐌾𐌴 𐌻𐌰𐌿𐌱𐍉𐍃)",
"wlheader-showupdated": "𐌻𐌰𐌿𐌱𐍉𐍃 𐌸𐌰𐌹𐌴𐌹 𐌹𐌽𐌼𐌰𐌹𐌳𐌹𐌳𐌰𐌹 𐍃𐌹𐌽𐌳 𐍆𐍂𐌰𐌼 𐌰𐍆𐍄𐌿𐌼𐌹𐍃𐍄𐌰𐌼𐌼𐌰 𐌼𐌴𐌻𐌰 𐌸𐌰𐍄𐌴𐌹 𐌲𐌰𐍅𐌴𐌹𐍃𐍉𐌳𐌴𐍃 𐌱𐌰𐌽𐌳𐍅𐌹𐌳𐌰𐌹 𐍃𐌹𐌽𐌳 𐌹𐌽 <strong>𐍃𐍅𐌹𐌽𐌸𐌰𐌹𐌼 𐌱𐍉𐌺𐍉𐌼</strong>.",
- "wlshowlast": "𐌱𐌰𐌽𐌳𐍅𐌴𐌹 𐌰𐍆𐍄𐌿𐌼𐌹𐍃𐍄𐍉𐍃 $1 𐍈𐌴𐌹𐌻𐍉𐍃, 𐌰𐍆𐍄𐌿𐌼𐌹𐍃𐍄𐌰𐌹 $2 𐌳𐌰𐌲𐍉𐍃",
"watching": "𐍅𐌹𐍄𐌰𐌽𐌳𐍃...",
"unwatching": "𐌿𐌽𐍅𐌹𐍄𐌰𐌽𐌳𐍃...",
"created": "𐌲𐌰𐍃𐌺𐌰𐍀𐌾𐌰𐌽",
"uctop": "𐌷𐌰𐌿𐌱𐌹𐌸",
"month": "𐍆𐍂𐌰𐌼 𐌼𐌴𐌽𐍉𐌸 (𐌾𐌰𐌷 𐌰𐌹𐍂𐌹𐍃):",
"year": "𐍆𐍂𐌰𐌼 𐌾𐌴𐍂𐌰 (𐌾𐌰𐌷 𐌰𐌹𐍂𐌹𐍃):",
- "sp-contributions-newbies-sub": "𐌽𐌹𐌿𐌾𐌰𐌹𐌼 𐍂𐌰𐌷𐌽𐌴𐌹𐌽𐌹𐌼",
"sp-contributions-blocklog": "𐍆𐌰𐌿𐍂𐌳𐌰𐌼𐌼𐌴𐌹𐌽𐌰𐌹𐍃 𐌲𐌰𐍆𐌰𐍃𐍄𐌰𐌹𐌽𐍃.",
"sp-contributions-uploads": "𐌰𐍄𐌱𐌰𐌹𐍂𐌹𐌳𐍉𐍃 𐍅𐌰𐌹𐌷𐍄𐍃",
"sp-contributions-logs": "𐌻𐌰𐌿𐌲𐌰",
"watchlist-details": "{{PLURAL:$1|$1 δέλτος|$1 δέλτοι}} ἐφορωμέναι, ἄνευ τῶν δέλτων διαλέξεως περιλαμβανομένων.",
"wlheader-enotif": "Σύστημα εἰδήσεως μέσῳ ἠλ-ἐπιστολῶν ἐνεργόν.",
"wlnote": "Κατωτέρω {{PLURAL:$1|ἐστὶν ἡ ὑστάτη μεταβολὴ|εἰσὶν αἱ ὑστάται '''$1''' μεταβολαὶ}} ἐν {{PLURAL:$2|τῇ ὑστάτῃ μίᾳ ὥρᾳ|ταῖς ὑστάταις '''$2''' ὥραις}}.",
- "wlshowlast": "Ἐμφάνισις τῶν τελευταίων $1 ὡρῶν $2 ἡμερῶν",
"watchlist-options": "Ἐπιλογαὶ ἐφοροδιαλογῆς",
"watching": "Ἐφορῶν...",
"unwatching": "Ἀνεφορῶν...",
"uctop": "ἄκρον",
"month": "Μήν:",
"year": "Ἔτος:",
- "sp-contributions-newbies": "Δεικνύναι ἐράνους νέων λογισμῶν μόνον",
- "sp-contributions-newbies-sub": "Ἔρανοι νέων χρωμένων",
- "sp-contributions-newbies-title": "Ἔρανοι χρωμένου διὰ νέους λογισμούς",
"sp-contributions-blocklog": "αἱ ἀποκλῄσεις",
"sp-contributions-deleted": "διεγραμμένοι ἔρανοι χρωμένου",
"sp-contributions-uploads": "ἐπιφορτώσεις",
"imgmultipagenext": "ἡ δέλτος ἡ ἑπομένη →",
"imgmultigo": "Ἰέναι!",
"imgmultigoto": "Μεταβαίνειν εἰς δέλτον $1",
- "ascending_abbrev": "ἀναβ",
- "descending_abbrev": "καταβ",
"table_pager_next": "ἡ δέλτος ἡ ἑπομένη",
"table_pager_prev": "Δέλτος προτέρα",
"table_pager_first": "Ἡ δέλτος ἡ πρώτη",
"apihelp": "API-Hilff",
"apihelp-no-such-module": "Ds Modul «$1» lat sech nid la finde.",
"apisandbox": "API-Sandchaschte",
- "apisandbox-api-disabled": "D API isch uf däm Wiki deaktiviert wore.",
"apisandbox-intro": "Die Syte chasch bruche fir Versuech mit dr '''MediaWiki-API'''.\nIn dr [https://www.mediawiki.org/wiki/API:Main_page/de Dokumäntation zue dr API] het s no meh Hiiwys zue ihre Nutzig. Byschpel: [https://www.mediawiki.org/wiki/API:Main_page/de#Beispiel Dr Inhalt vu dr Hauptsyte abruefe]. Fir meh Byschpel eini vu dr verfiegbare Aktionen uuswehle.",
"apisandbox-submit": "Aafrog uusfiere",
"apisandbox-reset": "Lääre",
"wlheader-enotif": "E-Mail-Benachrichtigung isch aktiviert.",
"wlheader-showupdated": "Syte, wo syt em letste Bsuech hei gänderet, sy <strong>fett</strong> dargstellt.",
"wlnote": "Unde {{PLURAL:$1|steit di letsti Änderig|stöh di letste <strong>$1</strong> Änderigen}} us {{PLURAL:$2|der letste Stund|de letste <strong>$2</strong> Stunde}}. Stand: $3, $4 Uhr.",
- "wlshowlast": "Zeig di letste $1 Stunden und $2 Täg",
"watchlist-options": "Aazeigoptione",
"watching": "Am beobachte …",
"unwatching": "Nümm am beobachten …",
"uctop": "aktuell",
"month": "u Monet:",
"year": "bis Jahr:",
- "sp-contributions-newbies": "Zeig nume Biträg vo neie Benutzer",
- "sp-contributions-newbies-sub": "vo nöji Benützer",
- "sp-contributions-newbies-title": "Benutzerbyytreg vu neije Benutzer",
"sp-contributions-blocklog": "Sperrlogbuech",
"sp-contributions-suppresslog": "underdrückti Benutzerbyträg",
"sp-contributions-deleted": "gleschti Bytreg",
"img-lang-default": "(Standardsproch)",
"img-lang-info": "Des Bild in $1 rendere. $2",
"img-lang-go": "Gang",
- "ascending_abbrev": "uf",
- "descending_abbrev": "ab",
"table_pager_next": "Näggschti Syte",
"table_pager_prev": "Vorderi Syte",
"table_pager_first": "Erschti Syte",
"wlheader-enotif": "ઈમેલ સૂચના પદ્ધતિ સક્રીય કરાઈ.",
"wlheader-showupdated": "તમારી છેલ્લી મુલાકાત પછી બદલાયેલાં પાના '''ઘાટા''' અક્ષરો વડે દર્શાવ્યાં છે.",
"wlnote": "નીચે $3, $4 વાગ્યા સુધીના છેલ્લા {{PLURAL:$2|એક કલાક|<strong>$2</strong> કલાક}}માં થયેલા {{PLURAL:$1|ફેરફાર|<strong>$1</strong> ફેરફારો }} દર્શાવ્યા છે.",
- "wlshowlast": "છેલ્લા $1 કલાકો $2 દિવસો બતાવો",
"watchlist-hide": "છુપાવો",
"watchlist-submit": "બતાવો",
"wlshowhidecategorization": "પાનાનું વર્ગીકરણ",
"uctop": "વર્તમાન",
"month": "આ મહિનાથી (અને તેના પહેલાનાં) →",
"year": "આ વર્ષથી (અને તેના પહેલાનાં) →",
- "sp-contributions-newbies": "માત્ર નવા ખુલેલાં ખાતાઓનું યોગદાન બતાવો",
- "sp-contributions-newbies-sub": "નવા ખાતાઓ માટે",
- "sp-contributions-newbies-title": "નવા ખાતાના સભ્યોનું યોગદાન",
"sp-contributions-blocklog": "પ્રતિબંધ સૂચિ",
"sp-contributions-deleted": "{{GENDER:$1|સભ્ય}}ના ભૂંસેલા યોગદાનો",
"sp-contributions-uploads": "ખાસ યોગદાન / ચડાવેલ ફાઇલ",
"newimages-summary": "આ ખાસ પાનું છેવટની ચડાવેલા વફાઈલા બતાવે છે",
"newimages-legend": "ચાળણી",
"newimages-label": "ફાઈલનામ (કે તેનો ભાગ)",
- "newimages-newbies": "માત્ર નવા ખુલેલાં ખાતાઓનું યોગદાન બતાવો",
"noimages": "જોવા માટે કશું નથી.",
"ilsubmit": "શોધો",
"bydate": "તારીખ પ્રમાણે",
"imgmultigoto": "પાના $1 પર જાવ",
"img-lang-default": "(મૂળભુત ભાષા)",
"img-lang-go": "જાઓ",
- "ascending_abbrev": "ચડતો ક્ર્મ",
- "descending_abbrev": "ઉતરતો ક્ર્મ",
"table_pager_next": "આગળનું પાનું",
"table_pager_prev": "પાછળનું પાનું",
"table_pager_first": "પહેલું પાનું",
"notanarticle": "Cha nel eh shoh ny ghuillag cummal",
"notvisiblerev": "Va'n aavriwnys scryssit",
"watchlist-details": "Ta {{PLURAL:$1|$1 duillag|$1 duillag|$1 ghuillag|$1 duillagyn}} er dty rolley arrey, faagail magh duillagyn resoonaght.",
- "wlshowlast": "Taishbyn ny kied $1 ooryn $2 laaghyn s'jerree",
"watchlist-options": "Reihyn da'n rolley arrey",
"watching": "Jannoo arrey...",
"unwatching": "Stap y chur er arrey...",
"uctop": "baare",
"month": "Veih'n vee (as ny s'aa):",
"year": "Veih'n vlein (as ny s'aa):",
- "sp-contributions-newbies": "Taishbyn cohortyssyn ec coontyssyn noa ny lomarcan",
- "sp-contributions-newbies-sub": "Son coontyssyn noa",
"sp-contributions-blocklog": "Lioar chooishyn ny glassaghyn magh",
"sp-contributions-talk": "resoonaght",
"sp-contributions-userrights": "Reireydys kiartyn ymmydeyr",
"watchthispage": "Bin sawun wannan shafi",
"unwatch": "Daina bin sawu",
"watchlist-details": "{{PLURAL:$1|$1 shafi|$1 shafuna}} kan jerinku na bin sawu, banda shafunan mahawara.",
- "wlshowlast": "Nuna awowi $1 kwanaki $2 na ƙarshe",
"watchlist-options": "Saituttukan jerin bin sawu",
"watching": "Bin sawun...",
"unwatching": "Daina bin sawu...",
"uctop": "sama",
"month": "Tun daga wata (da gabansa):",
"year": "Tun daga shekara (da gabanta):",
- "sp-contributions-newbies": "Nuna gudummuwar sabbin akwantoci kawai",
"sp-contributions-blocklog": "rajistan hani",
"sp-contributions-search": "Nemo gudummuwa",
"sp-contributions-username": "Adireshin IP ko sunan ma'aikaci:",
"wlheader-enotif": "Yí-kîn khí-thung email thûng-tî kûng-nèn.",
"wlheader-showupdated": "Chhai ngì song-chhṳ kiám-sṳ heu yû pûn chhùng-siû ko ke vùn-chông chiông-voi hién-sṳ vi '''chhû-thí'''.",
"wlnote": "Yî-ha he chui-khiûn <b>$2</b> séu-sṳ̀ nui-ke chui-heu $1-chhṳ chin-siû.",
- "wlshowlast": "展示最近$1隻鐘頭,$2日或嘅更改。",
"watchlist-options": "監視列表選項",
"watching": "監視中...",
"unwatching": "停止監視中...",
"uctop": "(最新修改)",
"month": "Chhiùng liá-ngie̍t (fe̍t hàn kha-chó):",
"year": "Chhiùng liá-ngièn (fe̍t hàn kha-chó):",
- "sp-contributions-newbies": "單淨展示新建用戶嘅貢獻",
- "sp-contributions-newbies-sub": "新手",
"sp-contributions-blocklog": "封禁日誌",
"sp-contributions-uploads": "上傳",
"sp-contributions-logs": "日誌",
"imgmultipageprev": "← sông yit-chông",
"imgmultipagenext": "hâ yit-chông →",
"imgmultigo": "確定!",
- "ascending_abbrev": "Suk-siá chen",
- "descending_abbrev": "Suk-siá-kám",
"table_pager_next": "Hâ yit-chông",
"table_pager_prev": "Sông yit-chông",
"table_pager_first": "Thi-yit-chông",
"watchthispage": "E nānā pono i kēia mea",
"unwatch": "Kiaʻi ʻole",
"watchlist-details": "{{PLURAL:$1|$1 ʻaoʻao|$1 mau ʻaoʻao}} a kāu papakiaʻi, me ʻole ke koe ʻana o nā ʻaoʻao walaʻau.",
- "wlshowlast": "Hōʻike $1 hola aku nei $2 lā aku nei",
"watchlist-options": "Nā Koho papakiaʻi",
"watching": "Kia‘i nei...",
"unwatching": "Ke wehe nei i ke kiaʻi...",
"uctop": "okamanawa",
"month": "Mai ka mahina (mamua aku nei nō hoʻi):",
"year": "Mai ka makahiki (mamua aku nei nō hoʻi):",
- "sp-contributions-newbies": "Hōʻike i nā hāʻawina o nā moʻokāki hou wale nō",
"sp-contributions-blocklog": "moʻolelo hoʻopale",
"sp-contributions-deleted": "nā ha‘awina o ka inoa mea ho‘ohana i holoi ‘ia",
"sp-contributions-uploads": "nā hoʻouka",
"img-lang-default": "(ʻōlelo paʻamau)",
"img-lang-info": "Hana i kēia kiʻi ma ka $1. $2",
"img-lang-go": "Kele",
- "ascending_abbrev": "Pilu",
- "descending_abbrev": "Pila",
"table_pager_next": "ʻAoʻao hou aʻe",
"table_pager_prev": "ʻAoʻao aku nei",
"table_pager_first": "ʻAoʻao mua",
"nocreate-loggedin": "אין לך הרשאה ליצור דפים חדשים.",
"sectioneditnotsupported-title": "עריכת פסקאות אינה נתמכת",
"sectioneditnotsupported-text": "עריכת פסקאות אינה נתמכת בדף זה.",
+ "modeleditnotsupported-title": "העריכה אינה נתמכת",
+ "modeleditnotsupported-text": "העריכה אינה נתמכת למודל התוכן $1.",
"permissionserrors": "שגיאת הרשאה",
"permissionserrorstext": "אין באפשרותך לבצע פעולה זו, {{PLURAL:$1|מהסיבה הבאה|מהסיבות הבאות}}:",
"permissionserrorstext-withaction": "אין באפשרותך $2, {{PLURAL:$1|מהסיבה הבאה|מהסיבות הבאות}}:",
"content-model-css": "CSS",
"content-json-empty-object": "אובייקט ריק",
"content-json-empty-array": "מערך ריק",
+ "unsupported-content-model": "<strong>אזהרה:</strong> מודל התוכן $1 אינו נתמך בוויקי הזה.",
+ "unsupported-content-diff": "השוואות אינן נתמכות במודל התוכן $1.",
+ "unsupported-content-diff2": "השוואות בין מודל התוכן $1 לבין מודל $2 אינן נתמכות בוויקי הזה.",
"deprecated-self-close-category": "דפים שמשתמשים בתגיות HTML עם סגירה עצמית בלתי־תקינה",
"deprecated-self-close-category-desc": "הדף מכיל תגיות HTML עם סגירה עצמית בלתי־תקינה, כגון <code dir=\"ltr\"><b/></code> או <code dir=\"ltr\"><span/></code>. ההתנהגות של תגיות אלה תשתנה בקרוב לצורך תאימות עם מפרט HTML5, ולכן יש להימנע משימוש בהן בקוד ויקי.",
"duplicate-args-warning": "<strong>אזהרה:</strong> [[:$1]] קורא לדף [[:$2]] עם יותר מערך אחד עבור הפרמטר \"$3\". ייעשה שימוש רק בערך האחרון.",
"apihelp-no-such-module": "המודול \"$1\" לא נמצא.",
"apisandbox": "ארגז החול של ה־API",
"apisandbox-jsonly": "דרוש JavaScript כדי להשתמש בארגז החול של ה־API.",
- "apisandbox-api-disabled": "API אינו פעיל באתר הזה.",
"apisandbox-intro": "ניתן להשתמש בדף הזה כדי להתנסות בשימוש ב<strong>שירות ה־API המבוסס Web של מדיה־ויקי</strong>.\nאפשר לעיין ב[[mw:API:Main page|תיעוד של ה־API]] (באנגלית) למידע נוסף על שימוש ב־API. למשל: [https://www.mediawiki.org/wiki/API#A_simple_example איך לקבל את התוכן של העמוד הראשי]. יש לבחור באחת הפעולות (actions) לדוגמאות נוספות.\n\nלתשומת לבך: אף על פי שמדובר ב\"ארגז חול\", פעולות שנעשות כאן עשויות לשנות את התוכן של אתר הוויקי.",
"apisandbox-submit": "ביצוע הבקשה",
"apisandbox-reset": "ניקוי",
"wlheader-enotif": "התראות דוא\"ל מופעלות.",
"wlheader-showupdated": "דפים שהשתנו מאז ביקורך האחרון בהם מוצגים ב<strong>הדגשה</strong>.",
"wlnote": "להלן {{PLURAL:$1|השינוי האחרון|<strong>$1</strong> השינויים האחרונים}} {{PLURAL:$2|בשעה האחרונה|בשעתיים האחרונות|ב־<strong>$2</strong> השעות האחרונות}}, עד $4, $3.",
- "wlshowlast": "הצגת $1 שעות אחרונות $2 ימים אחרונים",
"watchlist-hide": "הסתרת",
"watchlist-submit": "הצגה",
"wlshowtime": "תקופת זמן לצפייה:",
"sessionfailure": "נראה שיש בעיה בחיבור שלך לאתר;\nפעולה זו בוטלה כאמצעי זהירות נגד התחזות לתקשורת ממחשבך.\nנא לשלוח מחדש את הטופס.",
"changecontentmodel": "שינוי מודל התוכן של דף",
"changecontentmodel-legend": "שינוי מודל התוכן",
- "changecontentmodel-title-label": "שם הדף",
+ "changecontentmodel-title-label": "שם הדף:",
"changecontentmodel-current-label": "מודל התוכן הנוכחי:",
- "changecontentmodel-model-label": "מודל התוכן החדש",
+ "changecontentmodel-model-label": "מודל התוכן החדש:",
"changecontentmodel-reason-label": "סיבה:",
"changecontentmodel-submit": "שינוי",
"changecontentmodel-success-title": "מודל התוכן שוּנה",
"month": "עד החודש:",
"year": "עד השנה:",
"date": "עד התאריך:",
- "sp-contributions-newbies": "הצגת תרומות של משתמשים חדשים בלבד",
- "sp-contributions-newbies-sub": "עבור משתמשים חדשים",
- "sp-contributions-newbies-title": "תרומות של משתמשים חדשים",
"sp-contributions-blocklog": "יומן חסימות",
"sp-contributions-suppresslog": "תרומות {{GENDER:$1|משתמש|משתמשת}} מועלמות",
"sp-contributions-deleted": "תרומות {{GENDER:$1|משתמש|משתמשת}} מחוקות",
"newimages-legend": "סינון",
"newimages-label": "שם הקובץ (או חלק ממנו):",
"newimages-user": "כתובת IP או שם משתמש",
- "newimages-newbies": "הצגת תרומות של משתמשים חדשים בלבד",
"newimages-showbots": "הצגת העלאות שבוצעו על־ידי בוטים",
"newimages-hidepatrolled": "הסתרת העלאות בדוקות",
"newimages-mediatype": "סוג המדיה:",
"img-lang-default": "(שפת ברירת המחדל)",
"img-lang-info": "הצגת תמונה זו בשפה $1. $2",
"img-lang-go": "הצגה",
- "ascending_abbrev": "עולה",
- "descending_abbrev": "יורד",
"table_pager_next": "הדף הבא",
"table_pager_prev": "הדף הקודם",
"table_pager_first": "הדף הראשון",
"apihelp-no-such-module": "मॉड्यूल \"$1\" नहीं मिला",
"apisandbox": "एपीआई प्रयोगस्थल",
"apisandbox-jsonly": "एपीआई प्रयोगपृष्ठ का उपयोग करने हेतु जावास्क्रिप्ट अनिवार्य है।",
- "apisandbox-api-disabled": "इस स्थल पर ए०पी०आई० सक्षम नहीं हैं।",
"apisandbox-intro": "इस पृष्ठ का उपयोग <strong>मीडियाविकि वेब एपीआई</strong> के लिए करें। इसके उपयप्ग हेतु देखें: [[mw:API:Main page|एपीआई प्रलेखन]] उदाहरण: [https://www.mediawiki.org/wiki/API#A_simple_example मुख्यपृष्ठ के सामग्री हेतु]",
"apisandbox-submit": "अनुरोध करें",
"apisandbox-reset": "स्पष्ट",
"wlheader-enotif": "ई-मेल नोटिफ़िकेशन सक्षम हैं।",
"wlheader-showupdated": "आपके देखे जाने के बाद जिन पृष्ठों में बदलाव होगा, उनकी कड़ी <strong>गहरे</strong> रंग की दिखेगी।",
"wlnote": "$3 को $4 बजे तक पिछले <strong>$2</strong> {{PLURAL:$2|घंटे|घंटों}} में {{PLURAL:$1|हुआ एक|हुए <strong>$1</strong>}} परिवर्तन निम्न {{PLURAL:$1|है|हैं}}।",
- "wlshowlast": "पिछले $1 घंटे $2 दिन देखें",
"watchlist-hide": "छुपाएँ",
"watchlist-submit": "दिखाएँ",
"wlshowtime": "अंतिम दिखाएँ:",
"month": "इस महिनेसे (और पुरानें):",
"year": "इस सालसे (और पुराने):",
"date": "दिनांक से (प्रारम्भ)",
- "sp-contributions-newbies": "सिर्फ़ नये सदस्यों के योगदान दर्शायें",
- "sp-contributions-newbies-sub": "नये सदस्योंके लिये",
- "sp-contributions-newbies-title": "नए सदस्यों द्वारा योगदान",
"sp-contributions-blocklog": "अवरोध सूची",
"sp-contributions-suppresslog": "छुपाए गए {{GENDER:$1|सदस्य}} के योगदान",
"sp-contributions-deleted": "हटाए गए {{GENDER:$1|सदस्य}} योगदान",
"newimages-legend": "छननी",
"newimages-label": "संचिका नाम (या उसका अंश):",
"newimages-user": "आईपी पता या सदस्यनाम",
- "newimages-newbies": "केवल नये खातों के योगदान दिखायें",
"newimages-showbots": "बॉट के अपलोड दिखाइये",
"newimages-hidepatrolled": "जाँचा हुआ अपलोड छुपाएँ",
"newimages-mediatype": "मीडिया प्रकार:",
"img-lang-default": "(डिफ़ॉल्ट भाषा)",
"img-lang-info": "इस चित्र को $1. $2 में ढालें",
"img-lang-go": "जाएं",
- "ascending_abbrev": "asc",
- "descending_abbrev": "ज़ानकारी",
"table_pager_next": "अगला पृष्ठ",
"table_pager_prev": "पिछला पृष्ठ",
"table_pager_first": "पहला पृष्ठ",
"apihelp-no-such-module": "Module \"$1\" ke paawa nai gais hae.",
"apisandbox": "API sandbox",
"apisandbox-jsonly": "JavaScript is required to use the API sandbox.",
- "apisandbox-api-disabled": "Ii site pe API disabled hai.",
"apisandbox-intro": "Use this page to experiment with the <strong>MediaWiki web service API</strong>.\nRefer to [[mw:API:Main page|the API documentation]] for further details of API usage. Example: [https://www.mediawiki.org/wiki/API#A_simple_example get the content of a Main Page]. Select an action to see more examples.\n\nNote that, although this is a sandbox, actions you carry out on this page may modify the wiki.",
"apisandbox-submit": "Request karo",
"apisandbox-reset": "Clear karo",
"wlheader-enotif": "E-mail notification ke enable kar dewa gais hai.",
"wlheader-showupdated": "Panna jiske aap ke pichhla visit ke ke baad badal dewa gais hia ke '''bold''' me dekhawa jaawe hai.",
"wlnote": "Niche ke {{PLURAL:$1|pahile waala badlao hai| pahile <strong>$1</strong> badlao hai}} pichhle {{PLURAL:$2|ghanta|<strong>$2</strong> ghanta}} me as of $3, $4.",
- "wlshowlast": "Pichhla $1 ghanta $2 din ke dekhao",
"watchlist-hide": "Lukao",
"watchlist-submit": "Dekhao",
"wlshowtime": "Kon samay ke display karaa jaae:",
"uctop": "abhi waala",
"month": "Mahina se (aur pahile):",
"year": "Saal se (aur pahile):",
- "sp-contributions-newbies": "Khaali nawaa account ke yogdaan dekhao",
- "sp-contributions-newbies-sub": "Nawaa account khatir",
- "sp-contributions-newbies-title": "Nawaa account ke sadasya ke yogdaan",
"sp-contributions-blocklog": "Suchi roko",
"sp-contributions-suppresslog": "{{GENDER:$1|sadasya}} ke yogdaan jiske suppress karaa gais hae",
"sp-contributions-deleted": "Mitawa gais {{GENDER:$1|sadasya}} ke yogdaan",
"newimages-legend": "Chaalo",
"newimages-label": "Filename (nai to iske ek hissa):",
"newimages-user": "IP Address, nai to username",
- "newimages-newbies": "Khaali nawaa account ke yogdaan dekhao",
"newimages-showbots": "Bots se upload dekhawa jaae hae",
"newimages-hidepatrolled": "Patrolled uploads ke lukao",
"newimages-mediatype": "Media type:",
"img-lang-default": "(default bhasa)",
"img-lang-info": "Ii chaapa ke $1. $2 me render karo",
"img-lang-go": "Jaao",
- "ascending_abbrev": "chhota se barraa",
- "descending_abbrev": "barraa se chhota",
"table_pager_next": "Aage waala panna",
"table_pager_prev": "Pahile waala panna",
"table_pager_first": "Pahila panna",
"watchthispage": "Bantayan ining panid",
"unwatch": "Di maglantaw",
"watchlist-details": "{{PLURAL:$1|$1 pahina|$1 mga pahina}} sa imo nga lista sang paglantaw, indi ang pag-isip sang imo ginahambal nga mga pahina.",
- "wlshowlast": "Ipakita ang nagligad nga $1 oras $2 adlaw",
"watchlist-options": "Pililian sa lista sang nagalantaw",
"watching": "Nagalantaw...",
"unwatching": "Di-paglantaw...",
"uctop": "ibabaw",
"month": "Halin sa bulan (kag sang timprano):",
"year": "Halin sa tu-ig (kag sang timprano):",
- "sp-contributions-newbies": "Ipakita ang mga kontribusyon sang mga bag-o nga akawnts lamang",
"sp-contributions-blocklog": "pugong log",
"sp-contributions-uploads": "Mga ginkarga",
"sp-contributions-logs": "Mga lista",
"wlheader-enotif": "Uključeno je izvješćivanje e-poštom.",
"wlheader-showupdated": "Stranice koje su promijenjene od Vašeg posljednjeg posjeta prikazane su '''podebljano'''.",
"wlnote": "Niže {{PLURAL:$1|0=nema ijedna izmjena načinjena|je posljednja izmjena načinjena|su <strong>$1</strong> posljednje izmjene načinjene|su <strong>$1</strong> posljednjih izmjena načinjenih}} {{PLURAL:$2|0=u zadanom roku|posljednjega sata|u posljednja <strong>$2</strong> sata|u posljednjih <strong>$2</strong> sati}}, zaključno do $3 u $4.",
- "wlshowlast": "Prikaži posljednjih $1 sati $2 dana",
"watchlist-hide": "Sakrij",
"watchlist-submit": "Prikaži",
"wlshowtime": "Vremensko razdoblje za prikaz:",
"month": "Od mjeseca (i ranije):",
"year": "Od godine (i ranije):",
"date": "Do nadnevka (i prije):",
- "sp-contributions-newbies": "Prikaži samo doprinose novih suradnika",
- "sp-contributions-newbies-sub": "Za nove suradnike",
- "sp-contributions-newbies-title": "Doprinosi novih suradnika",
"sp-contributions-blocklog": "evidencija blokiranja",
"sp-contributions-suppresslog": "izbrisani doprinosi {{GENDER:$1|suradnika|suradnice}}",
"sp-contributions-deleted": "izbrisani doprinosi {{GENDER:$1|suradnika|suradnice}}",
"newimages-legend": "Filtar",
"newimages-label": "Naziv datoteke (ili njen dio):",
"newimages-user": "IP adresa ili suradničko ime",
- "newimages-newbies": "Prikaži doprinose samo novih suradnika",
"newimages-showbots": "Prikaži datoteke koje su postavili botovi",
"newimages-hidepatrolled": "Sakrij ophođena postavljanja",
"newimages-mediatype": "Vrsta datoteke:",
"imgmultigoto": "Idi na stranicu $1",
"img-lang-default": "(zadani jezik)",
"img-lang-go": "Idi",
- "ascending_abbrev": "rast",
- "descending_abbrev": "pad",
"table_pager_next": "Sljedeća stranica",
"table_pager_prev": "Prethodna stranica",
"table_pager_first": "Prva stranica",
"permanentlink": "Trajna poveznica",
"permanentlink-revid": "ID inačice (oldid)",
"permanentlink-submit": "Idi na inačicu",
+ "newsection": "Novi odlomak",
+ "newsection-page": "Ciljna stranica",
+ "newsection-submit": "Pođi na stranicu",
"dberr-problems": "Ispričavamo se! Ova stranica ima tehničkih poteškoća.",
"dberr-again": "Pričekajte nekoliko minuta i ponovno učitajte.",
"dberr-info": "(Ne mogu pristupiti bazi podataka: $1)",
"suppress": "Oversight (Üwerwächtung)",
"querypage-disabled": "Die Spezialseit woard aus Gründe von der Leistungserhaltung deaktiviert.",
"apisandbox": "API-Spielwies",
- "apisandbox-api-disabled": "Die API woard uff dem Wiki deaktiviert.",
"apisandbox-intro": "Die Seit kannst du für Versuche mit der '''MediaWiki-API''' verwenne.\nDie [https://www.mediawiki.org/wiki/API:Main_page/de Dokumentation zur API] enthält weitre Hinweise zu ihrer Nutzung. Beispiel: [https://www.mediawiki.org/wiki/API:Main_page/de#Ein_einfaches_Beispiel Den Inhalt der Hauptseit abrufe]. Für weitre Beispiele en von der verfüchbare Aktione auswähle.\n\nObwohl das en Spielwies ist, bedenke, dass Aktione, wo du uff der Seit doorrichführst, das Wiki verännre.",
"apisandbox-submit": "Oonfroch ausführe",
"apisandbox-reset": "Leere",
"watchlist-details": "Du beobachtest {{PLURAL:$1|en Seit|$1 Seite}}, ohne dass Diskussionsseite getrennt gezählt werre.",
"wlheader-enotif": "Der E-Mail-Benachrichtigungsdienst ist aktiviert.",
"wlheader-showupdated": "Seite mit noch net gesiehne Ännrunge werre'''fett''' dorgestellt.",
- "wlshowlast": "Zeich die Ännrunge von der letzte $1 Stunde, $2 Tooch.",
"watchlist-options": "Oonzeichoptione",
"watching": "Beobachte …",
"unwatching": "Netmehr beobachte …",
"uctop": "aktuell",
"month": "und Monat:",
"year": "bis Joahr (und früher):",
- "sp-contributions-newbies": "Zeich nuar Beiträche von neier Benutzer",
- "sp-contributions-newbies-sub": "Von neie Benutzer",
- "sp-contributions-newbies-title": "Benutzerbeiträch von neie Benutzer",
"sp-contributions-blocklog": "Sperr-Logbuch",
"sp-contributions-suppresslog": "Unnerdrückte Benutzerbeiträch",
"sp-contributions-deleted": "Abgewischt Beiträch",
"img-lang-default": "(Standardsproch)",
"img-lang-info": "Das Bild in $1 rendre. $2",
"img-lang-go": "Los, geh",
- "ascending_abbrev": "uff",
- "descending_abbrev": "ab",
"table_pager_next": "Nächste Seit",
"table_pager_prev": "Vorrich Seit",
"table_pager_first": "Earschte Seit",
"apihelp": "API-pomoc",
"apihelp-no-such-module": "Modul \"$1\" njeje so namakał.",
"apisandbox": "API-hrajkanišćo",
- "apisandbox-api-disabled": "API je so na tutym sydle znjemóžnił.",
"apisandbox-intro": "Wužij tutu stronu, zo by z '''websłužbu Mediawiki API''' eksperimentował.\nHlej [https://www.mediawiki.org/wiki/API:Main_page API-dokumentaciju] za dalše podrobnosće za wužiwanje API. Přikład: [https://www.mediawiki.org/wiki/API#A_simple_example Wobsah hłowneje strony wotwołać]. Wubjer akciju, zo by dalše přikłady widźał.\n\nDźiwaj na to, zo, hačrunjež to je hrajkanišćo, akcije, kotrež na tutej stronje přewjedźeš, móhli wiki změnić.",
"apisandbox-submit": "Naprašowanje přewjesć",
"apisandbox-reset": "Wuprózdnić",
"wlheader-enotif": "E-mejlowa zdźělenska słužba je zmóžnjena.",
"wlheader-showupdated": "Strony, kotrež su so po twojim poslednim wopyće změnili, so '''tučne''' pokazuja.",
"wlnote": "Deleka {{PLURAL:$1|je poslednja změna|stej poslednjej <strong>$1</strong> změnje|su poslednje <strong>$1</strong> změny|je poslednich <strong>$1</strong> změnow}} za {{PLURAL:$2|poslednju hodźinu|poslednje <strong>$2</strong> hodźinje|poslednje <strong>$2</strong> hodźiny|poslednich <strong>$2</strong> hodźin}}, staw : $3, $4.",
- "wlshowlast": "Změny zańdźenych $1 hodźin, $2 dnjow, pokazać",
"wlshowtime": "Perioda, kotraž ma so pokazać:",
"watchlist-options": "Opcije wobkedźbowankow",
"watching": "Wobkedźbuju…",
"uctop": "aktualny",
"month": "wot měsaca (a do toho):",
"year": "wot lěta (a do toho):",
- "sp-contributions-newbies": "jenož přinoški nowačkow pokazać",
- "sp-contributions-newbies-sub": "Za nowačkow",
- "sp-contributions-newbies-title": "Wužiwarske přinoški za nowe konta",
"sp-contributions-blocklog": "protokol zablokowanjow",
"sp-contributions-suppresslog": "potłóčene wužiwarske přinoški",
"sp-contributions-deleted": "wušmórnjene wužiwarske přinoški",
"img-lang-default": "(standardna rěč)",
"img-lang-info": "Tutón wobraz w $1 rysować. $2",
"img-lang-go": "Wotpósłać",
- "ascending_abbrev": "postupowacy",
- "descending_abbrev": "zestupowacy",
"table_pager_next": "přichodna strona",
"table_pager_prev": "předchadna strona",
"table_pager_first": "prěnja strona",
"watchthispage": "Swiv paj sa a",
"unwatch": "Pa swiv ankò",
"watchlist-details": "W ap swiv {{PLURAL:$1|paj|paj}}, san konte paj diskisyon yo.",
- "wlshowlast": "Montre dènye $1 è yo, dènye $2 jou yo, oubyen .",
"watchlist-options": "Opsyon pou lis swivi",
"watching": "Swiv...",
"unwatching": "Fini swiv paj sa a...",
"uctop": "tèt",
"month": "depi mwa (ak mwa anvan yo) :",
"year": "Depi lane (ak anvan tou) :",
- "sp-contributions-newbies": "Montre sèlman kontribisyon nouvo itilizatè yo",
- "sp-contributions-newbies-sub": "Pou nouvo kont yo",
"sp-contributions-blocklog": "jounal blokaj yo",
"sp-contributions-talk": "Diskite",
"sp-contributions-search": "Chache kontribisyon yo",
"apihelp-no-such-module": "A(z) „$1\" modul nem található.",
"apisandbox": "API homokozó",
"apisandbox-jsonly": "Az API-homokozó használatához JavaScriptre van szükség.",
- "apisandbox-api-disabled": "API le van tiltva ezen az oldalon.",
"apisandbox-intro": "Ezen az oldalon kísérletezhetsz a <strong>MediaWiki web service API</strong>-val.\nA használattal kapcsolatos további részletek az [[mw:API:Main page|API-dokumentációnál]] találhatók. Példa: [https://www.mediawiki.org/wiki/API#A_simple_example olvasd el a főoldal tartalomjegyzékét]. További példákért válassz egy tevékenységet!\n\nFigyelj rá, hogy bár ez csak egy „homokozó”, ettől még az általad végzett műveletek módosíthatják a wikit!",
"apisandbox-submit": "Kérés végrehajtása",
"apisandbox-reset": "Törlés",
"wlheader-enotif": "Az e-mailen keresztül történő értesítés engedélyezve.",
"wlheader-showupdated": "Azok a lapok, amelyek megváltoztak, mióta utoljára megnézted őket, '''vastagítva''' láthatók.",
"wlnote": "Alább {{PLURAL:$1|az utolsó változás|az utolsó <strong>$1</strong> változás}} látható az elmúlt {{PLURAL:$2|órában|<strong>$2</strong> órában}}, $3 $4-kor.",
- "wlshowlast": "Az elmúlt $1 órában | $2 napon történt változtatások legyenek láthatóak",
"watchlist-hide": "Elrejtés",
"watchlist-submit": "Megjelenítés",
"wlshowtime": "Időszak:",
"month": "E hónap végéig:",
"year": "Eddig az évig:",
"date": "Eddig a dátumig:",
- "sp-contributions-newbies": "Csak a nemrég regisztrált szerkesztők közreműködéseit mutassa",
- "sp-contributions-newbies-sub": "Új szerkesztők lapjai",
- "sp-contributions-newbies-title": "Új szerkesztők közreműködései",
"sp-contributions-blocklog": "Blokkolási napló",
"sp-contributions-suppresslog": "elrejtett {{GENDER:$1|felhasználók}} közreműködései",
"sp-contributions-deleted": "törölt {{GENDER:$1|szerkesztések}}",
"newimages-legend": "Fájlnév",
"newimages-label": "Fájlnév (vagy annak részlete):",
"newimages-user": "IP-cím vagy felhasználónév",
- "newimages-newbies": "Csak az újonnan regisztrált szerkesztők közreműködéseinek mutatása",
"newimages-showbots": "Botos feltöltések mutatása",
"newimages-hidepatrolled": "Ellenőrzött szerkesztések elrejtése",
"newimages-mediatype": "Médiatípus:",
"img-lang-default": "(alapértelmezett nyelv)",
"img-lang-info": "Kép feldolgozása $1 nyelven. $2",
"img-lang-go": "Mehet",
- "ascending_abbrev": "növ",
- "descending_abbrev": "csökk",
"table_pager_next": "Következő oldal",
"table_pager_prev": "Előző oldal",
"table_pager_first": "Első oldal",
"wlheader-enotif": "Էլ-փոստով տեղեկացումը միացված է։",
"wlheader-showupdated": "Էջերը, որոնք փոփոխվել են ձեր վերջին այցից հետո, բերված են '''թավատառ'''։",
"wlnote": "Ստորև բերված {{PLURAL:$1|է վերջին փոփոխությունը|են վերջին '''$1''' փոփոխությունները}} վերջին <strong>$2</strong> ժամվա ընթացքում՝ $3, $4֊ի դրությամբ։",
- "wlshowlast": "Ցուցադրել վերջին $1 ժամերը $2 օրերը",
"watchlist-hide": "Թաքցնել",
"watchlist-submit": "Ցույց տալ",
"wlshowtime": "Ցուցադրելու ժամանակահատվածը.",
"uctop": "վերջինը",
"month": "Սկսած ամսից (և վաղ)՝",
"year": "Սկսած տարեթվից (և վաղ)՝",
- "sp-contributions-newbies": "Ցույց տալ միայն նորաստեղծ հաշիվներից կատարված ներդրումները",
- "sp-contributions-newbies-sub": "Նոր մասնակցային հաշիվներից",
- "sp-contributions-newbies-title": "Նոր մասնակիցների ներդրումներ",
"sp-contributions-blocklog": "արգելափակման տեղեկամատյան",
"sp-contributions-deleted": "մասնակցի ջնջված ներդրում",
"sp-contributions-uploads": "բեռնումներ",
"imgmultigo": "Անցնե՛լ",
"imgmultigoto": "Անցնել $1 էջը",
"img-lang-go": "Անցնել",
- "ascending_abbrev": "աճմ. կարգ.",
- "descending_abbrev": "նվազ",
"table_pager_next": "Հաջորդ էջ",
"table_pager_prev": "Նախորդ էջ",
"table_pager_first": "Առաջին էջ",
"watchlist-details": "Ձեր հսկողութեան ցանկը ունի {{PLURAL:$1|$1 էջ}}` (առաւել քննարկման էջեր)։",
"wlheader-showupdated": "Ձեր վերջին այցելութենէն ետք փոփոխուած Էջերը տրուած են <strong>շեշտուած տառերով<strong>։",
"wlnote": "Ներքեւ տրուած {{PLURAL:$1|է վերջին փոփոխութիւնը|են վերջին '''$1''' փոփոխութիւնները}} վերջին <strong>$2</strong> ժամուան ընթացքին՝ $3, $4ի դրութեամբ։",
- "wlshowlast": "Ցոյց տալ վերջին $1 ժամերը $2 օրերը",
"watchlist-hide": "Թաքցնել",
"watchlist-submit": "Ցուցնել",
"watchlist-options": "Հսկողութեան ացանկի նախընտրութիւններ",
"uctop": "ընթացիկ",
"month": "Սկսած ամիսէն (եւ աւելի վաղ)՝",
"year": "Սկսեալ տարիէն (եւ աւելի վաղ)՝",
- "sp-contributions-newbies": "Ցոյց տալ միայն նոր հաշիւներէ եղած ներդրումները",
"sp-contributions-blocklog": "արգելակումներու տեղեկատետր",
"sp-contributions-uploads": "վերբեռնումներ",
"sp-contributions-logs": "Տեղեկատետրեր",
"nocreate-loggedin": "Tu non ha le permission de crear nove paginas.",
"sectioneditnotsupported-title": "Modification de sectiones non supportate",
"sectioneditnotsupported-text": "Non es possibile modificar sectiones individual in iste pagina de modification.",
+ "modeleditnotsupported-title": "Modification non supportate",
+ "modeleditnotsupported-text": "Non es possibile modificar contento del modello $1.",
"permissionserrors": "Error de permission",
"permissionserrorstext": "Tu non ha le permission de facer isto, pro le sequente {{PLURAL:$1|motivo|motivos}}:",
"permissionserrorstext-withaction": "Tu non ha le permission de $2, pro le sequente {{PLURAL:$1|motivo|motivos}}:",
"content-model-css": "CSS",
"content-json-empty-object": "Objecto vacue",
"content-json-empty-array": "Array vacue",
+ "unsupported-content-model": "<strong>Attention:</strong> Le modello de contento $1 non es supportate sur iste wiki.",
+ "unsupported-content-diff": "Non es possibile monstrar differentias pro contento del modello $1.",
+ "unsupported-content-diff2": "Non es possibile monstrar differentias inter contento del modellos $1 e $2 sur iste wiki.",
"deprecated-self-close-category": "Paginas que usa etiquettas HTML auto-claudite non valide",
"deprecated-self-close-category-desc": "Le pagina contine etiquettas HTML auto-claudite non valide, como <code><b/></code> o <code><span/></code>. Le comportamento de istes cambiara proximemente pro esser in accordo con le specification HTML5, dunque lor uso in wikitexto es obsolete.",
"duplicate-args-warning": "<strong>Attention:</strong> [[:$1]] appella [[:$2]] con plure valores pro le parametro \"$3\". Solmente le ultime valor fornite essera usate.",
"right-editmyusercss": "Modificar le proprie files CSS de usator",
"right-editmyuserjson": "Modificar le files JSON del proprie usator",
"right-editmyuserjs": "Modificar le files JavaScript del proprie usator",
+ "right-editmyuserjsredirect": "Modificar le proprie paginas JavaScript de usator que es redirectiones",
"right-viewmywatchlist": "Vider le proprie observatorio",
"right-editmywatchlist": "Modificar le proprie observatorio. Remarca que alcun actiones totevia adde paginas mesmo sin iste derecto.",
"right-viewmyprivateinfo": "Vider le proprie datos private (p.ex. adresse de e-mail, nomine real)",
"action-editmyusercss": "modificar le files CSS del proprie usator",
"action-editmyuserjson": "modificar le files JSON del proprie usator",
"action-editmyuserjs": "modificar le files JavaScript del proprie usator",
+ "action-editmyuserjsredirect": "modificar le proprie paginas JavaScript de usator que es redirectiones",
"action-viewsuppressed": "vider versiones celate pro tote le usatores",
"action-hideuser": "blocar un nomine de usator, celante lo del publico",
"action-ipblock-exempt": "contornar le blocadas de adresses IP, blocadas automatic e blocadas de intervallos IP",
"rcfilters-clear-all-filters": "Rader tote le filtros",
"rcfilters-show-new-changes": "Vider le modificationes apportate desde $1",
"rcfilters-search-placeholder": "Filtrar le modificationes (usa le menu o cerca le nomine del filtro)",
+ "rcfilters-search-placeholder-mobile": "Filtros",
"rcfilters-invalid-filter": "Filtro non valide",
"rcfilters-empty-filter": "Nulle filtro active. Tote le contributiones es monstrate.",
"rcfilters-filterlist-title": "Filtros",
"rcfilters-filter-showlinkedto-label": "Monstrar modificationes sur paginas que liga a",
"rcfilters-filter-showlinkedto-option-label": "<strong>Paginas que liga verso</strong> le pagina seligite",
"rcfilters-target-page-placeholder": "Entra le nomine de un pagina (o categoria)",
+ "rcfilters-allcontents-label": "Tote le contento",
+ "rcfilters-alldiscussions-label": "Tote le discussiones",
"rcnotefrom": "Ecce le {{PLURAL:$5|modification|modificationes}} a partir del <strong>$3 a $4</strong> (usque a <strong>$1</strong> entratas monstrate).",
"rclistfromreset": "Reinitialisar selection de data",
"rclistfrom": "Monstrar nove modificationes a partir del $3 a $2",
"apihelp-no-such-module": "Modulo \"$1\" non trovate.",
"apisandbox": "Cassa de sablo pro API",
"apisandbox-jsonly": "JavaScript es necessari pro usar le cassa a sablo del API.",
- "apisandbox-api-disabled": "Le API ha essite disactivate in iste sito.",
"apisandbox-intro": "Usa iste pagina pro experimentar con le <strong>API de servicio web de MediaWiki</strong>.\nConsulta [[mw:API:Main page|le documentation del API]] pro ulterior detalios concernente le uso del API. Per exemplo: [https://www.mediawiki.org/wiki/API#A_simple_example obtener le contento de un Pagina principal]. Selige un action pro vider altere exemplos.\n\nAttention: Ben que isto es un cassa a sablo, le actiones que tu exeque in iste pagina pote modificar tote le wiki.",
"apisandbox-submit": "Facer requesta",
"apisandbox-reset": "Rader",
"wlheader-enotif": "Le notification via e-mail es active.",
"wlheader-showupdated": "Le paginas que ha essite modificate post tu ultime visita se monstra in litteras '''grasse'''.",
"wlnote": "Ecce le ultime {{PLURAL:$1|modification|<strong>$1</strong> modificationes}} durante le ultime {{PLURAL:$2|hora|<strong>$2</strong> horas}}, a partir del $3 a $4.",
- "wlshowlast": "Monstrar le ultime $1 horas $2 dies",
"watchlist-hide": "Celar",
"watchlist-submit": "Monstrar",
"wlshowtime": "Periodo de tempore a monstrar:",
"sessionfailure": "Il pare haber un problema con tu session;\niste action ha essite cancellate como precaution contra le robamento de sessiones.\nPer favor, resubmitte le formulario.",
"changecontentmodel": "Cambiar le modello de contento de un pagina",
"changecontentmodel-legend": "Cambiar modello de contento",
- "changecontentmodel-title-label": "Titulo del pagina",
- "changecontentmodel-model-label": "Nove modello de contento",
+ "changecontentmodel-title-label": "Titulo del pagina:",
+ "changecontentmodel-current-label": "Modello de contento actual:",
+ "changecontentmodel-model-label": "Nove modello de contento:",
"changecontentmodel-reason-label": "Motivo:",
"changecontentmodel-submit": "Cambiar",
"changecontentmodel-success-title": "Le modello de contento ha essite cambiate",
"month": "A partir del mense (e anterior):",
"year": "A partir del anno (e anterior):",
"date": "A partir del data (e anterior):",
- "sp-contributions-newbies": "Monstrar contributiones de nove contos solmente",
- "sp-contributions-newbies-sub": "Pro nove contos",
- "sp-contributions-newbies-title": "Contributiones de nove contos de usator",
"sp-contributions-blocklog": "Registro de blocadas",
"sp-contributions-suppresslog": "contributiones supprimite del {{GENDER:$1|usator}}",
"sp-contributions-deleted": "contributiones delite del {{GENDER:$1|usator}}",
"newimages-legend": "Filtro",
"newimages-label": "Nomine del file (o un parte de illo):",
"newimages-user": "Adresse de IP o nomine de usator",
- "newimages-newbies": "Monstrar contributiones de nove contos solmente",
"newimages-showbots": "Monstrar files incargate per robots",
"newimages-hidepatrolled": "Celar le files incargate patruliate",
"newimages-mediatype": "Typo de multimedia:",
"img-lang-default": "(lingua predefinite)",
"img-lang-info": "Presentar iste imagine in $1. $2",
"img-lang-go": "Va",
- "ascending_abbrev": "asc",
- "descending_abbrev": "desc",
"table_pager_next": "Sequente pagina",
"table_pager_prev": "Precedente pagina",
"table_pager_first": "Prime pagina",
"tog-hideminor": "Sembunyikan suntingan kecil di perubahan terbaru",
"tog-hidepatrolled": "Sembunyikan suntingan terpatroli di perubahan terbaru",
"tog-newpageshidepatrolled": "Sembunyikan halaman terpatroli dari daftar halaman baru",
- "tog-hidecategorization": "Sembunyikan pengategorian halaman",
+ "tog-hidecategorization": "Sembunyikan pengkategorian halaman",
"tog-extendwatchlist": "Kembangkan daftar pantauan untuk menunjukkan semua perubahan, tidak hanya yang terbaru",
"tog-usenewrc": "Kelompokkan suntingan di tampilan perubahan terbaru dan daftar pantauan berdasarkan halaman",
"tog-numberheadings": "Beri nomor judul secara otomatis",
"timezoneregion-indian": "Samudera Hindia",
"timezoneregion-pacific": "Samudera Pasifik",
"allowemail": "Izinkan pengguna lain mengirim surel kepada saya",
- "email-allow-new-users-label": "Izinkan email dari pengguna baru",
+ "email-allow-new-users-label": "Izinkan surel dari pengguna baru",
"email-blacklist-label": "Cegah para pengguna ini mengirim saya surel:",
"prefs-searchoptions": "Cari",
"prefs-namespaces": "Ruang nama",
"rcfilters-days-show-days": "$1 {{PLURAL:$1|hari|hari}}",
"rcfilters-days-show-hours": "$1 {{PLURAL:$1|jam|jam}}",
"rcfilters-highlighted-filters-list": "Disorot: $1",
- "rcfilters-quickfilters": "Saringan tersimpan",
- "rcfilters-quickfilters-placeholder-title": "Tidak ada penyaring yang disimpan",
- "rcfilters-quickfilters-placeholder-description": "Untuk menyimpan pengaturan saringan dan menggunakannya kembali, klik ikon penanda halaman di area Penyaringan Aktif, di bawah.",
- "rcfilters-savedqueries-defaultlabel": "Saringan tersimpan",
+ "rcfilters-quickfilters": "Filter tersimpan",
+ "rcfilters-quickfilters-placeholder-title": "Tidak ada filter yang disimpan",
+ "rcfilters-quickfilters-placeholder-description": "Untuk menyimpan pengaturan filter dan menggunakannya kembali, klik ikon penanda halaman di area Filter Aktif, di bawah.",
+ "rcfilters-savedqueries-defaultlabel": "Filter tersimpan",
"rcfilters-savedqueries-rename": "Ubah nama",
"rcfilters-savedqueries-setdefault": "Tetapkan sebagai baku",
"rcfilters-savedqueries-unsetdefault": "Hapus sebagai baku",
"rcfilters-savedqueries-apply-and-setdefault-label": "Buat penyaringan baku",
"rcfilters-savedqueries-cancel-label": "Batalkan",
"rcfilters-savedqueries-add-new-title": "Simpan pengaturan filter ini",
- "rcfilters-savedqueries-already-saved": "Penyaringan ini telah tersimpan. Ubah pengaturan Anda untuk membuat saringan filter tersimpan baru.",
+ "rcfilters-savedqueries-already-saved": "Filter ini telah tersimpan. Ubah pengaturan Anda untuk membuat filter tersimpan baru.",
"rcfilters-restore-default-filters": "Kembalikan filter bawaan",
"rcfilters-clear-all-filters": "Hapus semua penyaringan",
"rcfilters-show-new-changes": "Tampilkan perubahan baru sejak $1",
"rcfilters-highlightbutton-title": "Sorot hasil",
"rcfilters-highlightmenu-title": "Pilih warna",
"rcfilters-highlightmenu-help": "Pilihlah warna untuk menyorot atribut ini",
- "rcfilters-filterlist-noresults": "Tidak ada penyaring ditemukan",
+ "rcfilters-filterlist-noresults": "Tidak ada filter ditemukan",
"rcfilters-noresults-conflict": "Hasil tidak ditemukan karena kriteria pencariannya bertentangan",
"rcfilters-state-message-subset": "Filter ini tidak akan berpengaruh karena hasilnya disertakan oleh {{PLURAL:$2|filter}} berikut yang lebih luas (coba soroti untuk membedakannya): $1",
"rcfilters-state-message-fullcoverage": "Memilih semua penyaringan dalam kelompok ini sama dengan tidak memilih apapun, sehingga penyaringan ini tidak memberikan hasil. Kelompok termasuk: $1",
"rcfilters-filter-user-experience-level-unregistered-description": "Penyunting yang tidak masuk log",
"rcfilters-filter-user-experience-level-newcomer-label": "Pendatang baru",
"rcfilters-filter-user-experience-level-newcomer-description": "Penyunting terdaftar yang memiliki suntingan kurang dari 10 suntingan dan aktivitas selama 4 hari.",
- "rcfilters-filter-user-experience-level-learner-label": "Pelajar",
+ "rcfilters-filter-user-experience-level-learner-label": "Pemula",
"rcfilters-filter-user-experience-level-learner-description": "Penyunting terdaftar yang pengalamannya berada antara \"pengguna baru\" dan \"pengguna berpengalaman\".",
"rcfilters-filter-user-experience-level-experienced-label": "Pengguna berpengalaman",
"rcfilters-filter-user-experience-level-experienced-description": "Penyunting terdaftar dengan lebih dari 500 suntingan dan aktivitas selama 30 hari.",
"rcfilters-filter-showlinkedto-label": "Tampilkan perubahan pada halaman yang dipautkan ke",
"rcfilters-filter-showlinkedto-option-label": "<strong>Halaman terpaut ke</strong> halaman terpilih",
"rcfilters-target-page-placeholder": "Masukkan nama halaman (atau kategori)",
+ "rcfilters-allcontents-label": "Semua konten",
+ "rcfilters-alldiscussions-label": "Semua diskusi",
"rcnotefrom": "Di bawah ini adalah {{PLURAL:$5|perubahan}} sejak <strong>$3, $4</strong> (ditampilkan sampai <strong>$1</strong> perubahan).",
"rclistfromreset": "Atur ulang pilihan tanggal",
"rclistfrom": "Perlihatkan perubahan terbaru sejak $3 $2",
"apihelp-no-such-module": "Modul \"$1\" tidak ditemukan.",
"apisandbox": "Bak pasir API",
"apisandbox-jsonly": "JavaScript dibutuhkan untuk menggunakan kotak pasir API.",
- "apisandbox-api-disabled": "API dinonaktifkan pada situs ini.",
"apisandbox-intro": "Gunakan halaman ini untuk bereksperimen dengan <strong>API layanan web MediaWiki</strong>.\nLihat [[mw:API:Main page|dokumentasi API]] untuk perincian lanjut penggunaan API. Contoh: [https://www.mediawiki.org/wiki/API#A_simple_example dapatkan konten Halaman Utama]. Pilih sebuah tindakan untuk melihat contoh lain.\n\nPerhatikan bahwa, meskipun ini adalah bak pasir, tindakan yang Anda lakukan pada halaman ini mungkin dapat mengubah wiki.",
"apisandbox-submit": "Kirim permintaan",
"apisandbox-reset": "Kosongkan",
"wlheader-enotif": "Notifikasi surel diaktifkan.",
"wlheader-showupdated": "Halaman-halaman yang telah berubah sejak kunjungan terakhir Anda ditampilkan dengan '''huruf tebal'''.",
"wlnote": "Di bawah ini adalah {{PLURAL:$1|perubahan|<strong>$1</strong> perubahan}} terakhir dalam {{PLURAL:$2|jam|<strong>$2</strong> jam}}, per $3, $4.",
- "wlshowlast": "Tampilkan $1 jam $2 hari terakhir",
"watchlist-hide": "Sembunyikan",
"watchlist-submit": "Tampilkan",
"wlshowtime": "Periode waktu untuk ditampilkan:",
"month": "Sejak bulan (dan sebelumnya):",
"year": "Sejak tahun (dan sebelumnya):",
"date": "Sejak tanggal (dan sebelumnya):",
- "sp-contributions-newbies": "Hanya dari para pengguna baru",
- "sp-contributions-newbies-sub": "Untuk pengguna baru",
- "sp-contributions-newbies-title": "Kontribusi pengguna baru",
"sp-contributions-blocklog": "log pemblokiran",
"sp-contributions-suppresslog": "kontribusi {{GENDER:$1|pengguna}} yang disembunyikan",
"sp-contributions-deleted": "kontribusi {{GENDER:$1|pengguna}} yang dihapus",
"move-page-legend": "Pindahkan halaman",
"movepagetext": "Menggunakan formulir di bawah ini akan mengubah nama suatu halaman dan memindahkan semua data sejarah ke nama baru.\nJudul lama akan menjadi halaman pengalihan ke judul baru.\nAnda dapat memperbarui pengalihan yang menuju ke judul asli secara otomatis.\nJika Anda memilih tidak, pastikan untuk memeriksa\n[[Special:DoubleRedirects|pengalihan ganda]] atau [[Special:BrokenRedirects|pengalihan rusak]].\nAnda bertanggung jawab untuk memastikan bahwa pranala terhubung ke tempat seharusnya.\n\nPerhatikan bahwa halaman '''tidak''' akan dipindah apabila telah ada halaman pada judul yang baru, kecuali bila halaman peralihan dan tidak mempunyai sejarah penyuntingan. \nIni berarti Anda dapat mengubah kembali nama halaman seperti semula apabila Anda membuat kesalahan, dan Anda tidak dapat menimpa halaman yang telah ada.\n\n'''Catatan:'''\nIni dapat mengakibatkan perubahan drastis dan tak terduga bagi halaman yang populer; pastikan Anda mengerti konsekuensinya sebelum melanjutkan.",
"movepagetext-noredirectfixer": "Formulir di bawah ini digunakan untuk mengubah nama suatu halaman dan memindahkan semua data sejarah ke nama baru.\nJudul yang lama akan menjadi halaman peralihan menuju judul yang baru.\nPastikan untuk memeriksa pengalihan [[Special:DoubleRedirects|ganda]] atau [[Special:BrokenRedirects|rusak]].\nAnda bertanggung jawab untuk memastikan bahwa pranala terus menyambung ke halaman yang seharusnya.\n\nPerhatikan bahwa halaman '''tidak''' akan dipindah apabila telah ada halaman yang menggunakan judul yang baru, kecuali bila halaman tersebut kosong atau merupakan halaman peralihan dan tidak mempunyai sejarah penyuntingan.\nIni berarti Anda dapat mengubah nama halaman kembali seperti semula apabila Anda membuat kesalahan, dan Anda tidak dapat menimpa halaman yang telah ada.\n\n'''Catatan:'''\nHal ini dapat mengakibatkan perubahan yang tak terduga dan drastis bagi halaman yang populer;\nPastikan Anda mengerti konsekuensi dari perbuatan ini sebelum melanjutkan.",
- "movepagetalktext": "Jika Anda memberikan ceklis pada kotak ini, halaman pembicaraan yang berkaitan juga akan dipindahkan secara otomatis kecuali sebuah halaman pembicaraan yang tidak kosong telah ada di bawah judul baru.\n\nDalam kasus tersebut, apabila diinginkan, Anda dapat memindahkan atau menggabungkan halaman secara manual.",
+ "movepagetalktext": "Jika Anda mencentang kotak ini, halaman pembicaraan berkaitan akan dipindahkan secara otomatis ke judul baru, kecuali halaman pembicaraan tersebut tidak kosong.\n\nDalam kasus tersebut, Anda harus memindahkan atau menggabungkan halaman secara manual.",
"moveuserpage-warning": "'''Peringatan:''' Anda tengah memindahkan halaman pengguna. Perlu diketahui bahwa hanya halaman yang akan dipindahkan namun pengguna ''tidak akan'' berganti nama.",
"movecategorypage-warning": "<strong>Peringatan:</strong> Anda akan memindahkan halaman kategori. Perlu diketahui bahwa hanya halaman yang akan dipindahkan dan setiap halaman dalam kategori lama <em>tidak</em> akan dikategorikan ulang ke yang baru.",
"movenologintext": "Anda harus menjadi pengguna terdaftar dan telah [[Special:UserLogin|masuk log]] untuk dapat memindahkan suatu halaman.",
"move-subpages": "Pindahkan subhalaman (sampai $1)",
"move-talk-subpages": "Pindahkan semua subhalaman pembicaraan (sampai $1)",
"movepage-page-exists": "Halaman $1 telah ada dan tidak dapat ditimpa secara otomatis.",
+ "movepage-source-doesnt-exist": "Halaman $1 tidak ada dan tidak dapat dipindahkan.",
"movepage-page-moved": "Halaman $1 telah dipindahkan ke $2.",
"movepage-page-unmoved": "Halaman $1 tidak dapat dipindahkan ke $2.",
"movepage-max-pages": "Sejumlah maksimum $1 {{PLURAL:$1|halaman|halaman}} telah dipindahkan dan tidak ada lagi yang akan dipindahkan secara otomatis.",
"newimages-legend": "Penyaring",
"newimages-label": "Nama berkas (atau sebagian dari nama berkas):",
"newimages-user": "Alamat IP atau nama pengguna",
- "newimages-newbies": "Tampilkan kontribusi hanya dari akun baru",
"newimages-showbots": "Tampilkan unggahan oleh bot",
"newimages-hidepatrolled": "Sembunyikan unggahan yang telah dipatroli",
"newimages-mediatype": "Tipe media:",
"img-lang-default": "(bahasa default)",
"img-lang-info": "Jadikan gambar ini dalam $1. $2",
"img-lang-go": "Tuju ke",
- "ascending_abbrev": "naik",
- "descending_abbrev": "turun",
"table_pager_next": "Halaman selanjutnya",
"table_pager_prev": "Halaman sebelumnya",
"table_pager_first": "Halaman pertama",
"htmlform-cloner-create": "Tambahkan lebih banyak",
"htmlform-cloner-delete": "Hapus",
"htmlform-cloner-required": "Paling sedikit satu nilai diperlukan.",
- "htmlform-date-placeholder": "TTTT-BB-HH",
+ "htmlform-date-placeholder": "HH-BB-TTTT",
"htmlform-time-placeholder": "JJ:MM:DD",
"htmlform-datetime-placeholder": "TTTT-BB-HH JJ:MM:DD",
"htmlform-date-invalid": "Nilai yang diberikan tidak dikenali sebagai tanggal. Coba lagi menggunakan format TTTT-BB-HH.",
"wlheader-enotif": "Li notification de e-mail es permisset.",
"wlheader-showupdated": "Págines quel hat esset mutat desde tui ultim visitation es monstrat in '''nigri'''",
"wlnote": "Infra {{PLURAL:$1|es li ultim change|es li ultim '''$1''' changes}} in li ultim {{PLURAL:$2|hor|'''$2''' hores}}.",
- "wlshowlast": "Monstra ultim $1 hores $2 dies",
"wlshowhidecategorization": "categorisation de págines",
"watchlist-options": "Optiones de liste de págines vigilat",
"watching": "Vigilant...",
"uctop": "actual",
"month": "De mensu (e anterioris):",
"year": "De annu (e anterioris):",
- "sp-contributions-newbies": "Monstar contributiones de nov contos solmen",
- "sp-contributions-newbies-sub": "Por nov contos",
"sp-contributions-blocklog": "diarium de bloc",
"sp-contributions-uploads": "cargamentes de file",
"sp-contributions-logs": "diariumes",
"preview": "Lètú",
"showpreview": "Zìwe nkirimaàtụ̀",
"showdiff": "Zi mgbanwè",
- "anoneditwarning": "'''ndụmodụ:''' Ịjighị aha gị banye. Onye ọbụla ga-ahụ akara IP gị ma ọbụrụ na-ime ndezi ebe a. Jiri aha gi banye ka ndezi niile i ga-eme gosi n'aha gi.",
+ "anoneditwarning": "<strong>ndụmodụ:</strong>Ịjighị aha gị banye. Onye ọbụla ga-ahụ akara IP gị ma ọbụrụ na-ime ndezi ebe a. Jiri <strong>[$1aha banye]</strong> m'ọbụ <strong>[$2 kepụta akanụtụ]</strong>,ndezi niile i ga-eme gosi n'aha gi.",
"missingcommenttext": "Biko tinyé ótù okwu na àlà nga.",
"summary-preview": "Hutukwá mmẹkotá:",
"subject-preview": "Ihe gbasara/Ishi ahiri I hütü ntakịrị:",
"unwatch": "A hükwàlà",
"notanarticle": "Búghị ihü ihe nọr",
"watchlist-details": "{{PLURAL:$1|ihü $1|ihü $1}} nọr na ndétu ihe Í ne lé, nke à gúgị ihü okwu.",
- "wlshowlast": "Zi nke mbu àmànị $1 chi $2",
"watchlist-options": "Nrọta ndetu nlènlé",
"watching": "O na hü...",
"unwatching": "O mele ka o na á hü kwagi...",
"uctop": "dị ùgbu â",
"month": "Shi önwa (na nke ndi mbu):",
"year": "Shi afọr (na ndi nke mbu):",
- "sp-contributions-newbies": "Zí orü áká ọ'bànifé ohúru náni",
"sp-contributions-blocklog": "kwụchi ntinyé",
"sp-contributions-deleted": "orü ọ'bànifé gbakashịrị",
"sp-contributions-uploads": "tinyere na élu.",
"svg-long-desc": "usòrò SVG, nà áhà pixel $1 × $2, ívụ usòrò: $3",
"show-big-image": "Failụ si na nke mbu",
"show-big-image-preview": "Otu nyochaa a ha:$1",
- "show-big-image-other": "Ndị ọzọ {{PLURAL:$2|mkpebi|mkpebi}}:$1.",
+ "show-big-image-other": "Ndị ọzọ {{PLURAL:$2|resolution|mkpebi}}:$1.",
"show-big-image-size": "$1 × $2 piksels",
"file-info-gif-looped": "etemte",
"newimages-legend": "Nzàtà",
"imgmultipagenext": "ihü nke di nso →",
"imgmultigo": "Gàa!",
"imgmultigoto": "Gá na ihü $1",
- "ascending_abbrev": "heé élu",
- "descending_abbrev": "ndạtạ",
"table_pager_next": "Ihü sò",
"table_pager_prev": "Ihü na àzú",
"table_pager_first": "Ihü mbu",
"apihelp-no-such-module": "Saan a nabirukan ti modulo ti \"$1\".",
"apisandbox": "Pagsubokan ti API",
"apisandbox-jsonly": "Nasken ti JavaScript tapno mausar ti pagipadasan ti API.",
- "apisandbox-api-disabled": "Ti API ket nabaldado iti daytoy a sitio.",
"apisandbox-intro": "Usaren daytoy a panid iti panagsubok ti <strong>MediaWiki a serbisio ti web ti API</strong>.\nKitaen [[mw:API:Main page|ti dokuemntasion ti API]] para iti ad-adu pay a salaysay ti panagusar ti API. Kas pagarigan: [https://www.mediawiki.org/wiki/API#A_simple_example alaen ti linaon ti Umuna a Panid]. Agpili ti maaramid tapno makakita dagiti adu pay a pagarigan.\n\nLaglagipen nga uray daytoy ket pagipadasan, dagiti tignay nga aramidem iti daytoy a panid ket mabalin a mangbaliw iti wiki.",
"apisandbox-submit": "Agaramid ti kiddaw",
"apisandbox-reset": "Dalusan",
"wlheader-enotif": "Napakabaelan ti panangipakaammo ti esurat.",
"wlheader-showupdated": "Dagiti panid a nasukatanen manipud ti kinaudi a panagsarungkarmo ket naipakita iti <strong>napuskol</strong>.",
"wlnote": "Dita baba ket {{PLURAL:$1|naudi a sinukatan|dagiti naudi a <strong>$1</strong> a sinukatan}} iti napalabas {{PLURAL:$2|nga oras|a <strong>$2</strong> nga or-oras}}, manipud idi $3, $4.",
- "wlshowlast": "Ipakita dagiti naudi a $1 nga or-oras $2 nga al-aldaw",
"watchlist-hide": "Ilemmeng",
"watchlist-submit": "Ipakita",
"wlshowtime": "Ipakita a paset ti panawen:",
"uctop": "agdama",
"month": "Manipud iti bulan (ken nasapsapa):",
"year": "Manipud iti tawen (ken nasapsapa):",
- "sp-contributions-newbies": "Iparang dagiti kontribusion dagiti kabarbaro a pakabilangan laeng",
- "sp-contributions-newbies-sub": "Para kadagiti kabarbaro a pakabilangan",
- "sp-contributions-newbies-title": "Dagiti kontribusion para kadagiti baro a pakabilangan",
"sp-contributions-blocklog": "listaan ti serra",
"sp-contributions-suppresslog": "dagiti napasardeng a kontribusion ti {{GENDER:$1|agar-aramat}}",
"sp-contributions-deleted": "dagiti naikkat a kontribusion ti {{GENDER:$1|agar-aramat}}",
"newimages-legend": "Sagat",
"newimages-label": "Nagan ti papeles (wenno pasetna) :",
"newimages-user": "Adres ti IP wenno nagan ti agar-aramat",
- "newimages-newbies": "Iparang dagiti kontribusion dagiti kabarbaro a pakabilangan laeng",
"newimages-showbots": "Ipakita dagiti naikarga babaen dagiti bot",
"newimages-hidepatrolled": "Ilemmeng dagiti panangikarga a napatruliaan",
"newimages-mediatype": "Kita ti midia:",
"img-lang-default": "(kasisigud a pagsasao)",
"img-lang-info": "Ipaay daytoy a ladawan iti $1. $2",
"img-lang-go": "Inkan",
- "ascending_abbrev": "asc",
- "descending_abbrev": "desc",
"table_pager_next": "Sumaruno a panid",
"table_pager_prev": "Napalabas a panid",
"table_pager_first": "Umuna a panid",
"watchlist-details": "Хьа зема хьаязъяьра чу $1 {{PLURAL:$1|оагIув}} я (иштта я дувцара оагIонаш а).",
"wlheader-showupdated": "Хувцаенна оагIонаш '''сома''' шрифтаца белгалъяьй.",
"wlnote": "ЛохегIа хьагойт {{PLURAL:$2|тIехьарча сахьата|тIехьарча <strong>$2</strong> сахьата}} даь хинна {{PLURAL:$1|тIехьара хувцам|тIехьара <strong>$1</strong> хувцам}} ($3 $4).",
- "wlshowlast": "Хьахьокха тIехьарча $2 ден $1 сахьатá",
"watchlist-hide": "Ма хьокха",
"watchlist-submit": "Хьахьокха",
"wlshowtime": "МалагIча ха юкъа хиннар гойта деза:",
"uctop": "карара",
"month": "Укх бетт (кхы хьалхагIа)",
"year": "Укх шер (кхы хьалхагIа):",
- "sp-contributions-newbies": "Хьахьокха алхха керда дагара йоазонашца баь бола къахьегам",
"sp-contributions-blocklog": "блок тохар",
"sp-contributions-deleted": "{{GENDER:$1|доакъашхочун}} дӀадаьккха хинна тоадар",
"sp-contributions-uploads": "файлаш",
"listredirects": "Listo di ridirektili",
"listduplicatedfiles": "Listo pri arkivi kun duplikati",
"unusedtemplates": "Neuzata shabloni",
+ "unusedtemplatestext": "Ca pagino montras omna pagini di {{ns:template}} qui ne uzesas en altra pagini.\nVoluntez serchar altra ligili a la shabloni montrata adinfre, ante efacar li.",
"unusedtemplateswlh": "altra ligili",
"randompage": "Hazarda pagino",
"randomincategory-submit": "Irez",
"wlheader-enotif": "L'informo per e-posto esas funcionanta.",
"wlheader-showupdated": "Pagini qui modifikesis pos vua lasta vizito montresas en <strong>dika literi</strong>.",
"wlnote": "Yen la maxim recenta {{PLURAL:$1|chanjo|<strong>$1</strong> chanji}} dum la lasta {{PLURAL:$2|horo|<strong>$2</strong> hori}}, de $3,$4.",
- "wlshowlast": "Montrez la lasta $1 hori $2 dii",
"watchlist-submit": "Montrez",
"wlshowhideminor": "mikra redakturi",
"wlshowhidebots": "Roboti (bots)",
"month": "De monato (e plu frue):",
"year": "De yaro (e plu frue):",
"date": "De (ed ante) la dato:",
- "sp-contributions-newbies": "Montrez nur kontributadi di la nova uzeri",
- "sp-contributions-newbies-sub": "Dil nova uzeri",
- "sp-contributions-newbies-title": "Kontributaji dil nova uzeri",
"sp-contributions-blocklog": "blokusar-registraro",
"sp-contributions-suppresslog": "efacita kontributaji dil {{GENDER:$1|uzero}}",
"sp-contributions-deleted": "efacita {{GENDER:$1|uzero}}-kontributadi",
"imgmultipagenext": "sequanta pagino →",
"imgmultigo": "Irez!",
"imgmultigoto": "Irez a pagino $1",
- "ascending_abbrev": "aces",
- "descending_abbrev": "decen",
"table_pager_next": "Sequanta pagino",
"table_pager_prev": "Antea pagino",
"table_pager_first": "Unesma pagino",
"tag-mw-contentmodelchange": "Modifiko di la kontenajo di ula modelo",
"tag-mw-contentmodelchange-description": "Redakturi qui [https://www.mediawiki.org/wiki/Special:MyLanguage/Help:ChangeContentModel modifikas la modelo di kontenajo] di ula pagino",
"tag-mw-new-redirect": "Nova ridirekto",
+ "tag-mw-new-redirect-description": "Redakturi qui kreas nova ridirekto, o chanjas kontenajo di pagino a ridirekto",
+ "tag-mw-removed-redirect": "Ridirekto efacita",
+ "tag-mw-changed-redirect-target": "Emo di ridirekto modifikata",
+ "tag-mw-changed-redirect-target-description": "Redakturi qui modifikas la skopo di ula ridirekto",
"tag-mw-blank-description": "Redakturi qui efacas pagini",
"tag-mw-replace": "Remplasita",
"tag-mw-replace-description": "Redakturi qui removas plua kam 90% de la kontenajo di ula pagino",
"apihelp-no-such-module": "Einingin \"$1\" fannst ekki.",
"apisandbox": "API sandkassi",
"apisandbox-jsonly": "Krafist er JavaScript til að geta notað API-sandkassann.",
- "apisandbox-api-disabled": " Slökkt er á API á þessum vef.",
"apisandbox-submit": "Gera fyrirspurn",
"apisandbox-reset": "Hreinsa",
"apisandbox-retry": "Reyna aftur",
"wlheader-enotif": "Tilkynning með tölvupósti er virk.",
"wlheader-showupdated": "Síðum sem hefur verið breytt síðan þú skoðaðir þær síðast eru '''feitletraðar'''.",
"wlnote": "Hér fyrir neðan {{PLURAL:$1|er síðasta <strong>$1</strong> breyting|eru síðustu <strong>$1</strong> breytingar}} {{PLURAL:$2|síðasta <strong>$2</strong> klukkutímann|síðustu <strong>$2</strong> klukkutímana}}, frá $3, $4.",
- "wlshowlast": "Sýna síðustu $1 klukkutíma, $2 daga",
"watchlist-hide": "Fela",
"watchlist-submit": "Birta",
"wlshowtime": "Tímabil sem á að birta:",
"month": "Frá mánuðinum (og fyrr):",
"year": "Frá árinu (og fyrr):",
"date": "Frá deginum (og fyrr):",
- "sp-contributions-newbies": "Sýna aðeins breytingar frá nýjum notendum",
- "sp-contributions-newbies-sub": "Fyrir nýliða",
- "sp-contributions-newbies-title": "Breytingar nýrra notenda",
"sp-contributions-blocklog": "fyrri bönn",
"sp-contributions-suppresslog": "bæld framlög {{GENDER:$1|notanda}}",
"sp-contributions-deleted": "eyddar breytingar {{GENDER:$1|notanda}}",
"newimages-legend": "Sía",
"newimages-label": "Skráarheiti (eða hluti þess):",
"newimages-user": "IP-tala eða notandanafn",
- "newimages-newbies": "Eingöngu sýna framlög frá nýjum aðgöngum",
"newimages-showbots": "Birta innsend gögn frá vélmennum",
"newimages-hidepatrolled": "Fela yfirfarnar innsendingar",
"newimages-mediatype": "Skrátegund:",
"img-lang-default": "(sjálfgefið tungumál)",
"img-lang-info": "Myndgera þessa mynd í $1. $2",
"img-lang-go": "Fara",
- "ascending_abbrev": "hækkandi",
- "descending_abbrev": "lækkandi",
"table_pager_next": "Næsta síða",
"table_pager_prev": "Fyrri síða",
"table_pager_first": "Fyrsta síðan",
"Senpremì",
"Ignazio Cannata",
"Frubino",
- "TheRukk"
+ "TheRukk",
+ "Titore",
+ "GiorgioHerbie"
]
},
"tog-underline": "Sottolinea i collegamenti:",
"blockedtitle": "Utente bloccato.",
"blocked-email-user": "<strong>Alla tua utenza è stato vietato l'invio di email. Puoi ancora modificare altre pagine di questa wiki.</strong> Puoi vedere tutti i dettagli del blocco su [[Special:MyContributions|contributi dell'utenza]].\n\nIl blocco è stato effettuato da $1.\n\nLa ragione data è <em>$2</em>.\n\n* Inizio del blocco: $8\n* Scadenza del blocco: $6\n* Destinatario del blocco: $7\n* ID Blocco #$5",
"blockedtext-partial": "<strong>Alla tua utenza o indirizzo IP è stato vietato di apportare modifiche a questa pagina. Puoi ancora modificare altre pagine di questa wiki.</strong> Puoi vedere tutti i dettagli del blocco su [[Special:MyContributions|contributi dell'utenza]].\n\nIl blocco è stato effettuato da $1.\n\nLa ragione data è <em>$2</em>.\n\n* Inizio del blocco: $8\n* Scadenza del blocco: $6\n* Destinatario del blocco: $7\n* ID Blocco #$5",
- "blockedtext": "<strong>Il tuo nome utente o indirizzo IP è stato bloccato.</strong>\n\nIl blocco è stato imposto da $1. La motivazione del blocco è la seguente: <em>$2</em>.\n\n* Inizio del blocco: $8\n* Scadenza del blocco: $6\n* Intervallo di blocco: $7\n\nSe lo si desidera, è possibile contattare $1 o un altro [[{{MediaWiki:Grouppage-sysop}}|amministratore]] per discutere del blocco.\n\nSi noti che la funzione \"{{int:emailuser}}\" non è attiva se non è stato registrato un indirizzo email valido nelle proprie [[Special:Preferences|preferenze]] o se l'utilizzo di tale funzione è stato bloccato.\n\nL'indirizzo IP attuale è $3, il numero ID del blocco è #$5.\nSi prega di specificare tutti i dettagli precedenti in qualsiasi richiesta di chiarimenti.",
+ "blockedtext": "<strong>Il tuo nome utente o indirizzo IP è stato bloccato.</strong>\n\nIl blocco è stato imposto da $1. La motivazione del blocco è la seguente: <em>$2</em>.\n\n* Inizio del blocco: $8\n* Scadenza del blocco: $6\n* Destinatario del blocco: $7\n\nSe lo si desidera, è possibile contattare $1 o un altro [[{{MediaWiki:Grouppage-sysop}}|amministratore]] per discutere del blocco.\n\nSi noti che la funzione \"{{int:emailuser}}\" non è attiva se non è stato registrato un indirizzo email valido nelle proprie [[Special:Preferences|preferenze]] o se l'utilizzo di tale funzione è stato bloccato.\n\nL'indirizzo IP attuale è $3, il numero ID del blocco è #$5.\nSi prega di specificare tutti i dettagli precedenti in qualsiasi richiesta di chiarimenti.",
"autoblockedtext": "Questo indirizzo IP è stato bloccato automaticamente perché condiviso con un altro utente, a sua volta bloccato da $1.\nLa motivazione del blocco è la seguente:\n\n:<em>$2</em>\n\n* Inizio del blocco: $8\n* Scadenza del blocco: $6\n* Intervallo di blocco: $7\n\nÈ possibile contattare $1 o un altro [[{{MediaWiki:Grouppage-sysop}}|amministratore]] per richiedere eventuali chiarimenti circa il blocco.\n\nSi noti che la funzione \"{{int:emailuser}}\" non è attiva se non è stato registrato un indirizzo e-mail valido nelle proprie [[Special:Preferences|preferenze]] e, comunque, se nell'applicare il blocco, tale funzione è stata disabilitata (per la durata del blocco).\n\nL'indirizzo IP attuale è $3, il numero ID del blocco è #$5\nSi prega di specificare tutti i dettagli qui inclusi nel compilare qualsiasi richiesta di chiarimenti.",
"systemblockedtext": "Il tuo nome utente o l'indirizzo IP è stato bloccato automaticamente da MediaWiki.\nLa motivazione del blocco è la seguente:\n\n:''$2''\n\n* Inizio del blocco: $8\n* Scadenza del blocco: $6\n* Intervallo di blocco: $7\n\nL'indirizzo IP attuale è $3.\nSi prega di specificare tutti i dettagli qui inclusi nel compilare qualsiasi richiesta di chiarimenti.",
"blockednoreason": "nessuna motivazione indicata",
"edit-conflict": "Conflitto di edizione.",
"edit-no-change": "La modifica è stata ignorata poiché non sono stati apportati cambiamenti al testo.",
"edit-slots-cannot-add": "{{PLURAL:$1|Il seguente slot non è supportato|I seguenti slot non sono supportati}} qui: $2",
+ "edit-slots-cannot-remove": "{{PLURAL:$1|Lo slot seguente è richiesto e non può essere rimosso|Gli slot seguenti sono richiesti e non possono essere rimossi}}: $2.",
+ "edit-slots-missing": "{{PLURAL:$1|Lo slot seguente è mancante|Gli slot seguenti sono mancanti}}: $2",
"postedit-confirmation-created": "La pagina è stata creata.",
"postedit-confirmation-restored": "La pagina è stata ripristinata.",
"postedit-confirmation-saved": "La modifica è stata salvata.",
"converter-manual-rule-error": "Rilevato errore nella regola manuale di conversione della lingua",
"undo-success": "Questa modifica può essere annullata.\nControlla le differenze mostrate sotto fra le due versioni per essere certo che il contenuto corrisponda a quanto desiderato, e quindi salvare le modifiche per completare la procedura di annullamento.",
"undo-failure": "Impossibile annullare la modifica a causa di un conflitto con modifiche intermedie.",
+ "undo-main-slot-only": "La modifica non può essere annullata perché comprende contenuto esterno allo slot principale.",
"undo-norev": "La modifica non può essere annullata perché non esiste o è stata cancellata.",
"undo-nochange": "Sembra che la modifica sia già stata annullata.",
"undo-summary": "Annullata la modifica $1 di [[Special:Contributions/$2|$2]] ([[User talk:$2|discussione]])",
"search-interwiki-more": "(altro)",
"search-interwiki-more-results": "altri risultati",
"search-relatedarticle": "Risultati correlati",
+ "search-invalid-sort-order": "L'ordine di visualizzazione di $1 non è riconosciuto, sarà applicato l'ordine predefinito.\nGli ordini di visualizzazione validi sono: $2",
"searchrelated": "correlati",
"searchall": "tutti",
"showingresults": "Di seguito {{PLURAL:$1|viene presentato al massimo '''1''' risultato|vengono presentati al massimo '''$1''' risultati}} a partire dal numero '''$2'''.",
"prefs-timeoffset": "Ore di differenza",
"prefs-advancedediting": "Opzioni generali",
"prefs-developertools": "Strumenti per gli sviluppatori",
- "prefs-editor": "Editore",
+ "prefs-editor": "Editor",
"prefs-preview": "Anteprima",
"prefs-advancedrc": "Opzioni avanzate",
"prefs-advancedrendering": "Opzioni avanzate",
"right-editmyusercss": "Modifica il file CSS del proprio utente",
"right-editmyuserjson": "Modifica il file JSON del proprio utente",
"right-editmyuserjs": "Modifica il file JavaScript del proprio utente",
+ "right-editmyuserjsredirect": "Modifica i propri file JavaScript che sono reindirizzamenti",
"right-viewmywatchlist": "Visualizza i propri osservati speciali",
"right-editmywatchlist": "Modifica i propri osservati speciali. Da notare che alcune azioni potranno ancora aggiungere pagine anche senza questo diritto.",
"right-viewmyprivateinfo": "Visualizza i propri dati personali (ad esempio: indirizzo email, nome vero)",
"action-changetags": "aggiungere o rimuovere specifiche etichette su singole versioni o voci di registro",
"action-deletechangetags": "cancellare le etichette dal database",
"action-purge": "aggiornare questa pagina",
+ "action-apihighlimits": "usare limiti più alti per le interrogazioni API",
+ "action-autoconfirmed": "non essere soggetto al limite di azioni per IP",
+ "action-bigdelete": "cancellare pagine con cronologie lunghe",
+ "action-blockemail": "impedire a un utente di inviare email",
+ "action-bot": "essere trattato come processo automatizzato",
+ "action-editprotected": "modificare pagine protette con \"{{int:protect-level-sysop}}\"",
"action-editinterface": "modificare l'interfaccia utente",
"action-editusercss": "modificare i file CSS di altri utenti",
"action-edituserjson": "modificare i file JSON di altri utenti",
"action-editmyusercss": "modificare i propri file CSS",
"action-editmyuserjson": "modificare i propri file JSON",
"action-editmyuserjs": "modificare i propri file JavaScript",
+ "action-viewsuppressed": "vedere versioni nascoste a qualsiasi utente",
+ "action-hideuser": "bloccare un nome utente, nascondendolo al pubblico",
+ "action-ipblock-exempt": "ignorare i blocchi IP, blocchi automatici e blocchi ad intervalli",
+ "action-noratelimit": "non essere soggetto a limiti di intervallo",
+ "action-reupload-own": "sovrascrivere file esistenti caricati da qualcuno",
+ "action-override-export-depth": "esportare pagine che includono pagine collegate fino ad una profondità di 5",
+ "action-suppressredirect": "non creare reindirizzamenti da pagine sorgente quando si spostano le pagine",
"nchanges": "$1 {{PLURAL:$1|modifica|modifiche}}",
"enhancedrc-since-last-visit": "$1 {{PLURAL:$1|dall'ultima visita}}",
"enhancedrc-history": "cronologia",
"rcfilters-filter-showlinkedto-label": "Mostra le modifiche alle pagine che collegano a",
"rcfilters-filter-showlinkedto-option-label": "<strong>Pagine con collegamenti a</strong> la pagina selezionata",
"rcfilters-target-page-placeholder": "Inserisci il nome di una pagina (o categoria)",
+ "rcfilters-allcontents-label": "Tutti i contenuti",
"rcfilters-alldiscussions-label": "Tutte le discussioni",
"rcnotefrom": "Di seguito {{PLURAL:$5|è elencata la modifica apportata|sono elencate le modifiche apportate}} a partire da <strong>$3, $4</strong> (mostrate fino a <strong>$1</strong>).",
"rclistfromreset": "Reimposta la selezione della data",
"uploadbtn": "Carica",
"reuploaddesc": "Torna al modulo per il caricamento.",
"upload-tryagain": "Invia la descrizione del file modificato",
+ "upload-tryagain-nostash": "Invia file ricaricato e descrizione modificata",
"uploadnologin": "Accesso non effettuato",
"uploadnologintext": "Per caricare file è necessario $1.",
"upload_directory_missing": "La directory di upload ($1) non esiste e non può essere creata dal server web.",
"uploadstash-bad-path": "Il percorso non esiste.",
"uploadstash-bad-path-invalid": "Il percorso non è valido.",
"uploadstash-bad-path-unknown-type": "Tipo sconosciuto \"$1\".",
+ "uploadstash-bad-path-unrecognized-thumb-name": "Nome anteprima non riconosciuto.",
"uploadstash-file-not-found-no-thumb": "Non è stato possibile ottenere la miniatura.",
+ "uploadstash-file-not-found-no-local-path": "Nessun percorso locale per l'elemento scalato.",
+ "uploadstash-file-not-found-no-object": "Impossibile creare un oggetto del file locale per l'anteprima.",
"uploadstash-file-not-found-no-remote-thumb": "Recupero della miniatura fallito: $1\nURL = $2",
+ "uploadstash-not-logged-in": "Nessun utente connesso, i file devono appartenere agli utenti.",
+ "uploadstash-no-extension": "L'estensione è nulla.",
"uploadstash-zero-length": "Il file ha lunghezza zero.",
"invalid-chunk-offset": "Offset della parte non valido.",
"img-auth-accessdenied": "Accesso negato",
"move": "Sposta",
"movethispage": "Sposta questa pagina",
"unusedimagestext": "In questo elenco sono presenti i file caricati e non usati nel sito.\nPotrebbero essere presenti immagini che sono usate da altri siti con un collegamento diretto.",
+ "unusedimagestext-categorizedimgisused": "I file seguenti esistono ma non sono integrati in alcuna pagina. Le immagini categorizzate sono considerate come usate nonostante non siano integrate in alcuna pagina. Si prega di notare che altri siti web potrebbero collegarsi ad un file con un URL diretto, e potrebbero cioè essere ancora elencati qui nonostante siano in uso attivo.",
"unusedcategoriestext": "Le seguenti pagine testuali esistono, sebbene le categorie corrispondenti siano vuote.",
"notargettitle": "Dati mancanti",
"notargettext": "Non è stata indicata una pagina o un utente in relazione al quale eseguire l'operazione richiesta.",
"apihelp-no-such-module": "Modulo \"$1\" non trovato.",
"apisandbox": "Pagina di prova API",
"apisandbox-jsonly": "È richiesto JavaScript per utilizzare la sandbox API.",
- "apisandbox-api-disabled": "Le funzionalità API sono disabilitate su questo sito.",
"apisandbox-intro": "Utilizza questa pagina per fare pratica con le <strong>API web service MediaWiki</strong>.\nPer ulteriori dettagli di utilizzo delle API, fai riferimento alla [[mw:API:Main page|documentazione API]]. Esempio: [https://www.mediawiki.org/wiki/API#A_simple_example ottenere il contenuto della pagina principale]. Seleziona un'azione per vedere altri esempi.\n\nNota che, anche se questa è una pagina per le prove, le azioni che esegui qui potrebbero modificare il wiki.",
"apisandbox-submit": "Inoltra richiesta",
"apisandbox-reset": "Pulisci",
"apisandbox-results-error": "Si è verificato un errore durante il caricamento della risposta all'interrogazione API: $1",
"apisandbox-request-selectformat-label": "Mostra i dati richiesti come:",
"apisandbox-request-url-label": "URL di richiesta:",
+ "apisandbox-request-json-label": "Richiesta JSON:",
"apisandbox-request-time": "Tempo richiesto: {{PLURAL:$1|$1 ms}}",
"apisandbox-results-fixtoken": "Correggi token e reinvia",
"apisandbox-results-fixtoken-fail": "Impossibile recuperare il token \"$1\".",
"wlheader-enotif": "La notifica via email è attiva.",
"wlheader-showupdated": "Le pagine che sono state modificate dopo l'ultima visita sono evidenziate in '''grassetto'''.",
"wlnote": "Di seguito {{PLURAL:$1|è elencata la modifica più recente apportata|sono elencate le <strong>$1</strong> modifiche più recenti apportate}} {{PLURAL:$2|nella scorsa ora|nelle scorse <strong>$2</strong> ore}}; i dati sono aggiornati alle $4 del $3.",
- "wlshowlast": "Mostra le ultime $1 ore $2 giorni",
"watchlist-hide": "Nascondi",
"watchlist-submit": "Mostra",
"wlshowtime": "Periodo di tempo da visualizzare:",
"changecontentmodel": "Modifica il modello di contenuto di una pagina",
"changecontentmodel-legend": "Modifica il modello di contenuto",
"changecontentmodel-title-label": "Titolo della pagina",
+ "changecontentmodel-current-label": "Modello contenuto attuale:",
"changecontentmodel-model-label": "Nuovo modello di contenuto",
"changecontentmodel-reason-label": "Motivo:",
"changecontentmodel-submit": "Modifica",
"month": "Dal mese (e precedenti):",
"year": "Dall'anno (e precedenti):",
"date": "Dal giorno (e precedenti):",
- "sp-contributions-newbies": "Mostra solo i contributi dei nuovi utenti",
- "sp-contributions-newbies-sub": "Per i nuovi utenti",
- "sp-contributions-newbies-title": "Contributi dei nuovi utenti",
"sp-contributions-blocklog": "blocchi",
"sp-contributions-suppresslog": "contributi {{GENDER:$1|utente}} soppressi",
"sp-contributions-deleted": "contributi {{GENDER:$1|utente}} cancellati",
"newimages-legend": "Filtra",
"newimages-label": "Nome file (o una parte di esso):",
"newimages-user": "Indirizzo IP o nome utente",
- "newimages-newbies": "Mostra solo i contributi dei nuovi utenti",
"newimages-showbots": "Mostra caricamenti di bot",
"newimages-hidepatrolled": "Nascondi caricamenti verificati",
"newimages-mediatype": "Tipo di supporto:",
"img-lang-default": "(lingua predefinita)",
"img-lang-info": "Converti questa immagine in $1. $2",
"img-lang-go": "Vai",
- "ascending_abbrev": "cresc",
- "descending_abbrev": "decresc",
"table_pager_next": "Pagina successiva",
"table_pager_prev": "Pagina precedente",
"table_pager_first": "Prima pagina",
"apihelp-no-such-module": "モジュール「$1」が見つかりません。",
"apisandbox": "APIサンドボックス",
"apisandbox-jsonly": "API サンドボックスを利用するには JavaScript が必要です。",
- "apisandbox-api-disabled": "このウェブサイトでは、API は無効になっています。",
"apisandbox-intro": "このページでは、<strong>MediaWiki ウェブサービス API</strong> を試用できます。\nAPI の使用方法の詳細は[[mw:API:Main page|API のドキュメント]]をご覧ください。例: [https://www.mediawiki.org/wiki/API#A_simple_example Main Pageの内容を取得]。操作を選択すると他の例を閲覧できます。\n\nこれはサンドボックスですが、このページで実行した操作によってウィキが変更される場合があることにご注意ください。",
"apisandbox-submit": "リクエストする",
"apisandbox-reset": "消去",
"wlheader-enotif": "メール通知が有効になっています。",
"wlheader-showupdated": "最終訪問以降に変更されたページは、<strong>太字</strong>で表示されます。",
"wlnote": "$3 $4 までの{{PLURAL:$2|<strong>$2</strong>時間}}になされた{{PLURAL:$1|<strong>$1</strong>件の変更}}は以下の通りです。",
- "wlshowlast": "表示する期間: $1時間、$2日間",
"watchlist-hide": "非表示",
"watchlist-submit": "表示",
"wlshowtime": "表示範囲:",
"month": "この月以前:",
"year": "この年以前:",
"date": "この日以前:",
- "sp-contributions-newbies": "新規利用者の投稿のみ表示",
- "sp-contributions-newbies-sub": "新規利用者のみ",
- "sp-contributions-newbies-title": "新規利用者の投稿記録",
"sp-contributions-blocklog": "ブロック記録",
"sp-contributions-suppresslog": "{{GENDER:$1|利用者}}の秘匿された投稿",
"sp-contributions-deleted": "{{GENDER:$1|利用者}}の削除された投稿の一覧",
"newimages-legend": "絞り込み",
"newimages-label": "ファイル名 (またはその一部):",
"newimages-user": "IPアドレスまたは利用者名:",
- "newimages-newbies": "新規利用者の投稿のみ表示",
"newimages-showbots": "ボットによるアップロードを表示",
"newimages-hidepatrolled": "巡回済みのアップロードを隠す",
"newimages-mediatype": "メディアの種類:",
"img-lang-default": "(既定の言語)",
"img-lang-info": "この画像を $1 で描画する。$2",
"img-lang-go": "実行",
- "ascending_abbrev": "昇順",
- "descending_abbrev": "降順",
"table_pager_next": "次のページ",
"table_pager_prev": "前のページ",
"table_pager_first": "最初のページ",
"watchthispage": "Wach dis piej",
"unwatch": "Anwach",
"watchlist-details": "{{PLURAL:$1|$1 piej|$1 piej}} pahn yu wachlis, naa kount taak piej.",
- "wlshowlast": "Shuo laas $1 howa $2 die",
"watchlist-options": "Wachlis apshan",
"watching": "De wach ...",
"unwatching": "De anwach ...",
"uctop": "tap",
"month": "Frahn mont (ahn oerlia):",
"year": "Frahn ier (ahn oerlia):",
- "sp-contributions-newbies": "Shuo kanchribiushan fi onggl nyuu akount",
"sp-contributions-blocklog": "Blak lag",
"sp-contributions-search": "Saach fi kanchribiushan",
"sp-contributions-username": "IP ajres ar yuuzaniem",
"watchthispage": "Öwewåg siden",
"unwatch": "Fjän öwewågneng",
"watchlist-details": "Du har $1 {{PLURAL:$1|side|sider}} på din åvervågnengsliste (øn diskusjesider).",
- "wlshowlast": "Ves de seneste $1 têmer $2 dåg",
"watching": "Tilfye öwewågneng...",
"unwatching": "Fjäne öwewågneng...",
"deletepage": "Slett siid",
"uctop": "siensti",
"month": "Månj:",
"year": "Or:",
- "sp-contributions-newbies-sub": "Fra nyj konto",
"sp-contributions-blocklog": "blokiirengslogg",
"sp-contributions-deleted": "sletten brugebidraw",
"sp-contributions-talk": "diskusjon",
"apihelp-no-such-module": "Modhul \"$1\" ora katemu.",
"apisandbox": "Kothak wedhi API",
"apisandbox-jsonly": "JavaScript dibutuhaké saperlu nganggo bak wedhi API.",
- "apisandbox-api-disabled": "API dipatèni ing situs iki.",
"apisandbox-intro": "Anggo kaca iki kanggo njajal-njajal '''API layanan wèb MediaWiki'''.\nRujuk [https://www.mediawiki.org/wiki/API:Main_page the dhokumèntasi API] kanggo panganggoan API luwih rinci. Conto: [https://www.mediawiki.org/wiki/API#A_simple_example ngéntukaké kontèn Kaca Utama]. Pilih laku kanggo ndeleng conto luwih akèh.",
"apisandbox-submit": "Gawé panjalukan",
"apisandbox-reset": "Resiki",
"wlheader-enotif": "Wara-wara layang-èl diurubaké.",
"wlheader-showupdated": "Kaca kang wis owah kawit wektu pungkasan panjenengan priksa katuduhaké mawa <strong>hurup kandel</strong>.",
"wlnote": "Ing ngisor iki {{PLURAL:$1|owahan pungkasan|<strong>$1</strong> owahan pungkasan}} ing dalem {{PLURAL:$2|jam|<strong>$2</strong> jam}} pungkasan, rikala $3, $4.",
- "wlshowlast": "Tuduhaké $1 jam $2 dina pungkasan",
"watchlist-hide": "Dhelikaké",
"watchlist-submit": "Tuduhaké",
"wlshowtime": "Kala mangsa kanggo dituduhaké:",
"uctop": "saiki",
"month": "Saka wulan (lan sadurungé):",
"year": "Saka taun (lan sadurungé):",
- "sp-contributions-newbies": "Tuduhaké pasumbangé akun-akun anyar baé",
- "sp-contributions-newbies-sub": "Kanggo panganggo anyar",
- "sp-contributions-newbies-title": "Pasumbanging panganggo anyar",
"sp-contributions-blocklog": "log blokir",
"sp-contributions-deleted": "pasumbangé {{GENDER:$1|panganggo}} kang kabusek",
"sp-contributions-uploads": "unggahan",
"img-lang-default": "(basa gawan)",
"img-lang-info": "Olah gambar iki ing $1. $2",
"img-lang-go": "Mangkat",
- "ascending_abbrev": "unggah",
- "descending_abbrev": "mudhun",
"table_pager_next": "Kaca sabanjuré",
"table_pager_prev": "Kaca sadurungé",
"table_pager_first": "Kaca kapisan",
"apihelp-no-such-module": "მოდული „$1“ ვერ მოიძებნა.",
"apisandbox": "API-ის სავარჯიშო",
"apisandbox-jsonly": "API-ის სავარჯიშოს გამოსაყენებლად საჭიროა JavaScript.",
- "apisandbox-api-disabled": "API ამ საიტზე გამორთულია.",
"apisandbox-intro": "გამოიყენეთ ეს გვერდი, თუ გსურთ მოსინჯოთ <strong>MediaWiki web service API</strong>.\nიხილეთ [[mw:API:Main page|API დოკუმენტაცია]] სხვა დეტალებისათვის.\nმაგალითი: [https://www.mediawiki.org/wiki/API#A_simple_example მიიღეთ მთავარი გვერდის შინაარსი]. შეგიძლიათ ნახოთ სხვა მაგალითებიც.\n\nგაითვალისწინეთ, რომ თუმცა ეს სავარჯიშოა, თქვენმა მოქმედებამ შესაძლოა შეცვალოს ვიკის გვერდი.",
"apisandbox-submit": "მოთხოვნის გაკეთება",
"apisandbox-reset": "წაშლა",
"wlheader-enotif": "ელ.ფოსტით შეტყობინება ჩართულია.",
"wlheader-showupdated": "თქვენი ბოლო ვიზიტის შემდეგ შეცვლილი გვერდები, აღნიშნულია '''მუქად'''.",
"wlnote": "ქვემოთ {{PLURAL:$1|ნაჩვენებია ბოლო ცვლილება|ნაჩვენებია ბოლო '''$1''' ცვლილება}} უკანასკნელი {{PLURAL:$2|საათის|'''$2''' საათის}} მანძილზე, $3, $4 მდგომარეობით.",
- "wlshowlast": "ბოლო $1 საათის $2 დღის ჩვენება",
"watchlist-hide": "დამალვა",
"watchlist-submit": "ჩვენება",
"wlshowtime": "აჩვენე დროის პერიოდი:",
"month": "თვე:",
"year": "წელი:",
"date": "თარიღიდან (და უფრო ადრე):",
- "sp-contributions-newbies": "მხოლოდ ახალი მომხმარებლების წვლილის ჩვენება",
- "sp-contributions-newbies-sub": "ახალბედებისთვის",
- "sp-contributions-newbies-title": "ბოლოს დარეგისტრირებულ მომხმარებელთა წვლილი",
"sp-contributions-blocklog": "ბლოკირების ისტორია",
"sp-contributions-suppresslog": "{{GENDER:$1|მომხმარებლის}} წაშლილი წვლილი",
"sp-contributions-deleted": "{{GENDER:$1|მომხმარებლის}} წაშლილი შესწოებები",
"newimages-legend": "ფილტრი",
"newimages-label": "ფაილის (ან მისი სახელის) ნაწილი",
"newimages-user": "IP მისამართი ან მომხმარებლის სახელი",
- "newimages-newbies": "აჩვენე მხოლოდ ახალი მომხმარებლების წვლილი",
"newimages-showbots": "ბოტის ატვირთვების ჩვენება",
"newimages-hidepatrolled": "დამალე შემოწმებული ატვირთვები",
"newimages-mediatype": "მედიის ტიპი:",
"img-lang-default": "(საწყისი ენა)",
"img-lang-info": "აჩვენე ეს გამოსახულება : $1, $2-ში",
"img-lang-go": "წინ",
- "ascending_abbrev": "დაბრ",
- "descending_abbrev": "აღწერა",
"table_pager_next": "შემდეგი გვერდი",
"table_pager_prev": "წინა გვერდი",
"table_pager_first": "პირველი გვერდი",
"watchlist-details": "Baqlaw dizimin'izde (sa'wbet betlerin esapqa almag'anda) {{PLURAL:$1|1 bet|$1 bet}} bar.",
"wlheader-enotif": "E-mail arqalı eskertiw qosılg'an.",
"wlnote": "To'mende aqırg'ı {{PLURAL:$2|saattag'ı|'''$2''' saattag'ı}} {{PLURAL:$1|aqırg'ı o'zgeris bar|aqırg'ı '''$1''' o'zgeris bar}}.",
- "wlshowlast": "Aqırg'ı $1 saat, $2 ku'n, ko'rset",
"watchlist-options": "Baqlaw diziminin' sazlawları",
"watching": "Baqlaw...",
"unwatching": "Baqlamaw...",
"uctop": "joqarg'ı",
"month": "Aydag'ı (ha'm onnanda erterek):",
"year": "Jıldag'ı (ha'm onnanda erterek):",
- "sp-contributions-newbies": "Tek taza akkauntlar u'leslerin ko'rset",
- "sp-contributions-newbies-sub": "Taza akkauntlar ushın",
"sp-contributions-blocklog": "Bloklaw jurnalı",
"sp-contributions-userrights": "paydalanıwshı huqıqların basqarıw",
"sp-contributions-search": "U'lesi boyınsha izlew",
"imgmultipageprev": "← aldıng'ı bet",
"imgmultipagenext": "keyingi bet →",
"imgmultigo": "O'tin'!",
- "ascending_abbrev": "o's.",
- "descending_abbrev": "kem.",
"table_pager_next": "Keyingi bet",
"table_pager_prev": "Aldıng'ı bet",
"table_pager_first": "Birinshi bet",
"querypage-disabled": "Asebter uslig agi yensa , taɣzint : timellal is.",
"apihelp": "Tallelt n API",
"apihelp-no-such-module": "Azegrir\"$1\" ulac-it.",
- "apisandbox-api-disabled": "Asnas API ur yermid ara ɣef usmel-agi.",
"apisandbox-reset": "Sfeḍ",
"apisandbox-retry": "Ɛref̣ tikelt-nniḍen",
"apisandbox-helpurls": "Iseɣwan n tallelt",
"wlheader-enotif": "Talɣut s email yessermed.",
"wlheader-showupdated": "Isebtar ttubeddlen segwasmi tkecmeḍ tikelt taneggarut ttbanen-d s uḍris '''aberbuz'''.",
"wlnote": "Ddaw-a{{PLURAL:$1|ad twaliḍ abeddel aneggaru yettwagen|ad twaliḍ <strong>$1</strong> n ibeddilen ineggura yettwagen}} deg {{PLURAL:$2| usrag aneggaru|di <strong>$2</strong> n yisragen ineggura}}, arama d $3, $4.",
- "wlshowlast": "Sken wid n $1 n isragen ineggura, wid n $2 n wussan ineggura",
"watchlist-hide": "Ffer",
"watchlist-submit": "Sken",
"wlshowhideliu": "Iseqdacen yettwajerden",
"uctop": "amiran",
"month": "Seg uggur (d wid uqbel) :",
"year": "Seg useggwas (d wid uqbel) :",
- "sp-contributions-newbies": "Ssken tikkin n yimseqdacen imaynuten kan",
- "sp-contributions-newbies-sub": "I yisem yimseqdacen imaynuten",
- "sp-contributions-newbies-title": "Ittekkiyen n imseqdacen gar imiḍanen imaynuten",
"sp-contributions-blocklog": "Aɣmis n uɛeṭṭil",
"sp-contributions-suppresslog": "Attekki n {{GENDER:$1|useqdac|taseqdact}} yettwakkes",
"sp-contributions-deleted": "Attekki n {{GENDER:$1|useqdac|taseqdact}} yettwakkes",
"newimages-legend": "Tastayt",
"newimages-label": "Isem n ufaylu (naɣ aḥric ines) :",
"newimages-user": "Tansa IP neɣ isem n useqdac",
- "newimages-newbies": "Sken kan ittekkiyen n imiḍanen imaynuten",
"noimages": "Tugna ulac-itt.",
"ilsubmit": "Nadi",
"bydate": "s uzemz",
"img-lang-default": "(tutlayt s lexṣas)",
"img-lang-info": "Beqqeḍ tugna agi s $1 $2.",
"img-lang-go": "Ruḥ",
- "ascending_abbrev": "asawen",
- "descending_abbrev": "akessar",
"table_pager_next": "Asebtar ameḍfir",
"table_pager_prev": "Asebtar ssabeq",
"table_pager_first": "Asebtar amezwaru",
"watchthispage": "НапэкӀуэцӀым кӀэлъыплъын",
"unwatch": "КӀэлъымыплъын",
"watchlist-details": "Уи щӀэлъыплъыгъуэ тхылъым $1 {{PLURAL:$1|напэкӀуэцӀ|напэкӀуэцӀу}}, напэкӀуэцӀ тепсэлъыхьыгъуэхэр хэмыту",
- "wlshowlast": "Гъэлъэгъуэн кӀуа $1 сэхьэтым $2 махуэ",
"watchlist-options": "ЩӀэлъыплъыгъуэхэм я тхылъ зэгъэзэхуэгъуэ",
"watching": "СызыкӀэлъыплъ тхылъым хэлъхьэн...",
"unwatching": "СызыкӀэлъыплъ тхылъым хэхын",
"uctop": "яужырер",
"month": "Мазэм щыщIэдзауэ (икIи нэхъ пасэу):",
"year": "Мы илъэсым щыщIэдзауэ (е нэхъпасэжу):",
- "sp-contributions-newbies": "Аккаунт щӀэхэм я хэлъхьэгъуэ къуэдер гъэлъэгъуэн",
"sp-contributions-blocklog": "теубыдыныгъэхэр",
"sp-contributions-search": "Хэлъхьэгъуэм лъыхъуэн",
"sp-contributions-username": "IP-адрес иэ хэтым и цIэр:",
"watchthispage": "ھیہ صفحو تان نظرا لاکھے",
"unwatch": "زیرنظرمنسوخ",
"watchlist-details": "تہ زیرِنظرفہرستا {{PLURAL:$1|$1 صفحہ شیر|$1 صفحات شینی}}، ھیارا تبادلۂ خیالو صفحاتن تعداد شامل نیکی.",
- "wlshowlast": "پشاوے آخری $1 گھنٹو $2 آنوسو",
"watchlist-options": "واچ لسٹ آپشن",
"watching": "زیر نظر",
"unwatching": "منسوخ",
"uctop": "موجودہ نسخہ",
"month": "مس (وا ھیغاری پروشٹی):",
"year": "سال (وا ھیغاری پروشٹی):",
- "sp-contributions-newbies": "صرفی نوغ اکاونٹو مضمونن پشاوے",
- "sp-contributions-newbies-sub": "نوغ اکاونٹو بچے",
"sp-contributions-blocklog": "پاوبندی لیگیکو چٹ",
"sp-contributions-uploads": "اپلوڈ کاردو فایل",
"sp-contributions-logs": "لاگز",
"watchthispage": "Na pele de şêr ke",
"unwatch": "Şêr meke",
"watchlist-details": "Pelunê hurênaişi ra qêri {{PLURAL:$1|$1 pele lista şêrkerdişi dera|$1 peli lista şêrkerdişi derê}}.",
- "wlshowlast": "$1 saetunê $2 rozunê peyênu bıasne",
"watchlist-options": "Alternatifê lista şêrkerdene",
"watching": "Şêr ke…",
"unwatching": "Şêr meke…",
"uctop": "rocane",
"month": "Asme ra (u ravêr):",
"year": "Serre ra (u ravêr):",
- "sp-contributions-newbies": "Teyna iştırakunê neweqeydbiyaoğu basne",
"sp-contributions-blocklog": "qeydê engeli",
"sp-contributions-uploads": "barbiyaey",
"sp-contributions-logs": "qeydi",
"watchlist-details": "ၮ်ုခိုဝ်ယောဝ်ႋစ်ုရင့်ဖိုင် (အင်းကုံဆ်ုခၠါင် လိက်မေံၜၠါ်သယ်လ်ုဖး){{PLURAL:$1|လိက်မေံၜၠါ် $1 ၮါင်း|လိက်မေံၜၠါ် $1 ၮါင်းသယ်လ်ုဖး}} အှ်ဆေဝ်ႋလှ်။",
"wlheader-showupdated": "ၮ်ု အ်ုလါင်းခါင့်ထုက်ယောဝ်ႋဖှ်ေၯံင် အင်းလယ်သာလ်ုအ်ှ လိက်မေံသယ်လ်ုဖး <strong>လ်ုလိက်ဖၠုံးသုဲ့</strong> ၮ်ှ ၮဲဖှ်ေထဆေဝ်ႋလှ်",
"wlnote": "အ်ုဖံင့်လာ့သယ်ယိုဝ် $3၊ $4 အ်ုထံင် လါင်းခါင့် {{PLURAL:$2|နာႋဍီ|<strong>$2</strong> နာႋဍီ}}အ်ုဝှါန် {{PLURAL:$1|လါင်းခါင့်ဆ်ုအင်းလယ် လ်ုၮါင်း|လါင်းခါင့်ဆ်ုအင်းလယ် လ်ုၮါင်းလ်ုဖး <strong>$1</strong> ခု}} မွာဲဆေဝ်ႋလှ်။",
- "wlshowlast": "လါင်ခါင့်ထုက် $1 နာႋဍီ $2 သင့် အိုဝ်မ်ုၮဲ",
"watchlist-options": "ခီုဝ်ယောဝ်ႋစ်ုရင့်သယ်ၯင်း လုဲႋၮေဝ်ထလ်ုဖး",
"enotif_reset": "လိက်မေံၜၠါ်လုက်ဆိင့် ယောဝ်ႋၯံင်ဆ်ုပ်ုယှောဝ်ႋ မ်ုမါၮါင်း",
"deletepage": "မ်ုထုဂ်ဆိင့်လိက်မေံၜၠါ်",
"uctop": "လ်ုဏီမူႋအ်ုခါ့ယိုဝ်",
"month": "ၮိင်းအ်ုၮဝ့်ၯံင် ( ၮိင်းအှ်ၮှ်ၯံင်လါင်းခါင့်) :",
"year": "ၮိင်းအ်ုၮဝ့်ၯံင် ( ဝီးၮင် ၮိင်းအ်ုၮှ်) :",
- "sp-contributions-newbies": "က်ုဆာအ်ုၮါင်းသင့်သယ်လ်ုဖး ဆ်ုမာၜိုဝ်မာဆိုင်သယ် မ်ုၮဲဖှ်ေ",
"sp-contributions-blocklog": "ဆ်ုဍာ်အှ်ၯင်း လိက်မါၮါင်း",
"sp-contributions-uploads": "အးလုဂ်ထံင့်ဖှ်ေထး",
"sp-contributions-logs": "မာဏါင်းလ်ုဖး",
"wlheader-enotif": "ەسكەرتۋ حات جىبەرۋى قوسىلعان.",
"wlheader-showupdated": "سوڭعى كەلىپ-كەتۋىڭىزدەن بەرى وزگەرتىلگەن بەتتەردى '''جۋان''' قارىپىمەن كورسەت",
"wlnote": "تومەندە سوڭعى {{PLURAL:$2|ساعاتتا|'''$2''' ساعاتتا}} بولعان, {{PLURAL:$1|جۋىقتاعى وزگەرىس|جۋىقتاعى '''$1''' وزگەرىس}} كورسەتىلەدى.",
- "wlshowlast": "سوڭعى $1 ساعاتتاعى, $2 كۇندەگى, بولعان وزگەرىستى كورسەتۋ",
"watching": "باقىلاۋدا…",
"unwatching": "باقىلاماۋدا…",
"enotif_reset": "بارلىق بەت كەلىپ-كەتىلدى دەپ بەلگىلە",
"uctop": " ٴۇستى",
"month": "مىنا ايدان (جانە ەرتەرەكتەن):",
"year": "مىنا جىلدان (جانە ەرتەرەكتەن):",
- "sp-contributions-newbies": "تەك جاڭا تىركەلگىدەن جاساعان ۇلەستەردى كورسەت",
- "sp-contributions-newbies-sub": "جاڭادان تىركەلگى جاساعاندار ٴۇشىن",
"sp-contributions-blocklog": "بۇعاتتاۋ جۋرنالى",
"sp-contributions-deleted": "قاتىسۋشىنىڭ جويىلعان ۇلەسى",
"sp-contributions-talk": "تالقىلاۋى",
"imgmultipagenext": "كەلەسى بەتكە →",
"imgmultigo": "ٴوت!",
"imgmultigoto": "$1 بەتىنە ٴوتۋ",
- "ascending_abbrev": "ٴوسۋ",
- "descending_abbrev": "كەمۋ",
"table_pager_next": "كەلەسى بەتكە",
"table_pager_prev": "الدىڭعى بەتكە",
"table_pager_first": "العاشقى بەتكە",
"wlheader-enotif": "Ескерту хат жіберуі қосылған.",
"wlheader-showupdated": "Соңғы келіп-кетуіңізден бері өзгертілген беттер '''жуан''' қаріпімен көрсетіледі.",
"wlnote": "Төменде $3, $4 кезіне дейінгі соңғы {{PLURAL:$2|сағатта|<strong>$2</strong> сағатта}} болған, {{PLURAL:$1|жуықтағы өзгеріс|жуықтағы <strong>$1</strong> өзгеріс}} көрсетіледі.",
- "wlshowlast": "Соңғы $1 сағаттағы, $2 күндегіні көрсету",
"watchlist-hide": "Жасыру",
"watchlist-submit": "Көрсету",
"wlshowtime": "Соңғысын көрсету:",
"uctop": "соңғы",
"month": "Мына айдан (және ертеректен):",
"year": "Мына жылдан (және ертеректен):",
- "sp-contributions-newbies": "Тек жаңа тіркелгендер үлестерін көрсету",
- "sp-contributions-newbies-sub": "Жаңа тіркелгендер үшін",
- "sp-contributions-newbies-title": "Жаңа тіркелген қатысушылар үлесі",
"sp-contributions-blocklog": "бұғатталу журналы",
"sp-contributions-suppresslog": "жасырылған қатысушы үлестері",
"sp-contributions-deleted": "жойылған үлесі",
"img-lang-default": "(әдепкі тіл)",
"img-lang-info": "$1.$2 тілінде көрсету",
"img-lang-go": "Өту",
- "ascending_abbrev": "өсу",
- "descending_abbrev": "кему",
"table_pager_next": "Келесі бетке",
"table_pager_prev": "Алдыңғы бетке",
"table_pager_first": "Алғашқы бетке",
"wlheader-enotif": "Eskertw xat jiberwi qosılğan.",
"wlheader-showupdated": "Soñğı kelip-ketwiñizden beri özgertilgen betterdi '''jwan''' qaripimen körset",
"wlnote": "Tömende soñğı {{PLURAL:$2|sağatta|'''$2''' sağatta}} bolğan, {{PLURAL:$1|jwıqtağı özgeris|jwıqtağı '''$1''' özgeris}} körsetiledi.",
- "wlshowlast": "Soñğı $1 sağattağı, $2 kündegi, bolğan özgeristi körsetw",
"watching": "Baqılawda…",
"unwatching": "Baqılamawda…",
"enotif_reset": "Barlıq bet kelip-ketildi dep belgile",
"uctop": " üsti",
"month": "Mına aýdan (jäne erterekten):",
"year": "Mına jıldan (jäne erterekten):",
- "sp-contributions-newbies": "Tek jaña tirkelgiden jasağan ülesterdi körset",
- "sp-contributions-newbies-sub": "Jañadan tirkelgi jasağandar üşin",
"sp-contributions-blocklog": "Buğattaw jwrnalı",
"sp-contributions-deleted": "Qatıswşınıñ joýılğan ülesi",
"sp-contributions-talk": "Talqılawı",
"imgmultipagenext": "kelesi betke →",
"imgmultigo": "Öt!",
"imgmultigoto": "$1 betine ötw",
- "ascending_abbrev": "ösw",
- "descending_abbrev": "kemw",
"table_pager_next": "Kelesi betke",
"table_pager_prev": "Aldıñğı betke",
"table_pager_first": "Alğaşqı betke",
"wlheader-enotif": "បើកប្រើការផ្ដល់ដំណឹងតាមរយៈអ៊ីមែល។",
"wlheader-showupdated": "ទំព័រដែលត្រូវបានផ្លាស់ប្តូរតាំងពីពេលចូលមើលចុងក្រោយរបស់អ្នក ត្រូវបានបង្ហាញជា '''អក្សរដិត'''។",
"wlnote": "ខាងក្រោមនេះ {{PLURAL:$1|ជាបន្លាស់ប្ដូរចុងក្រោយ|ជាបន្លាស់ប្ដូរចុងក្រោយចំនួន <strong>$1</strong>}} នៅក្នុងរយៈពេល{{PLURAL:$2|១ម៉ោង|<strong>$2</strong> ម៉ោង}} គិតចាប់ពីម៉ោង $4 ថ្ងៃ $3។",
- "wlshowlast": "បង្ហាញ $1ម៉ោងចុងក្រោយ $2ថ្ងៃចុងក្រោយ",
"watchlist-hide": "លាក់",
"watchlist-submit": "បង្ហាញ",
"watchlist-options": "ជម្រើសនានាក្នុងបញ្ជីតាមដាន",
"month": "ខែ៖",
"year": "ឆ្នាំ៖",
"date": "មុនថ្ងៃ៖",
- "sp-contributions-newbies": "បង្ហាញតែការរួមចំណែករបស់អ្នកប្រើប្រាស់ថ្មីៗ",
- "sp-contributions-newbies-sub": "ចំពោះគណនីថ្មីៗ",
- "sp-contributions-newbies-title": "ការរួមចំណែករបស់អ្នកប្រើប្រាស់ចំពោះគណនីថ្មី",
"sp-contributions-blocklog": "កំណត់ហេតុនៃការហាមឃាត់",
"sp-contributions-deleted": "ការរួមចំណែករបស់{{GENDER:$1|អ្នកប្រើប្រាស់}}ដែលត្រូវបានលុបចោល",
"sp-contributions-uploads": "ឯកសារផ្ទុកឡើង",
"newimages-legend": "តម្រងការពារ",
"newimages-label": "ឈ្មោះរូបភាព៖",
"newimages-user": "អាសយដ្ឋានIP ឬ អត្តនាម",
- "newimages-newbies": "បង្ហាញតែការរួមចំណែករបស់អ្នកប្រើប្រាស់ថ្មីៗប៉ុណ្ណោះ",
"newimages-showbots": "បង្ហាញការផ្ទុកឡើងដោយរូបយន្ត",
"noimages": "គ្មានអ្វីសម្រាប់មើលទេ។",
"ilsubmit": "ស្វែងរក",
"img-lang-default": "(ភាសាតាមលំនាំដើម)",
"img-lang-info": "បង្ហាញរូបភាពនេះជា$1។ $2",
"img-lang-go": "ទៅ",
- "ascending_abbrev": "លំដាប់ឡើង",
- "descending_abbrev": "លំដាប់ចុះ",
"table_pager_next": "ទំព័របន្ទាប់",
"table_pager_prev": "ទំព័រមុន",
"table_pager_first": "ទំព័រដំបូង",
"watchlist-details": "ಚರ್ಚೆ ಪುಟಗಳನ್ನು ಹೊರತುಪಡಿಸಿ, ನಿಮ್ಮ ವೀಕ್ಷಣಾಪಟ್ಟಿಯಲ್ಲಿ {{PLURAL:$1|$1 ಪುಟ ಇದೆ|$1 ಪುಟಗಳು ಇವೆ}}.",
"wlheader-enotif": "ಮಿಂಚಂಚೆ ಸೂಚನೆಗಳನ್ನು ಸಕ್ರಿಯಗೊಳಿಸಲಾಗಿದೆ.",
"wlheader-showupdated": "ನೀವು ಕೊನೆಯ ಬಾರಿ ಭೇಟಿ ನೀಡಿದ ನಂತರ ಬದಲಾವಣೆಗಳು ಆಗಿರುವ ಪುಟಗಳು '''ದಪ್ಪ ಅಕ್ಷರಗಳಲ್ಲಿ''' ತೋರಿಸಲಾಗಿದೆ",
- "wlshowlast": "ಕೊನೆಯ $1 ಗಂಟೆ $2 ದಿನಗಳು ಅನ್ನು ತೋರಿಸು",
"watchlist-options": "ವೀಕ್ಷಣಾಪಟ್ಟಿ ಆಯ್ಕೆಗಳು",
"watching": "ವೀಕ್ಷಣೆಗೆ ಸೇರಿಸಲಾಗುತ್ತಿದೆ...",
"unwatching": "ವೀಕ್ಷಣೆಯಿಂದ ತೆಗೆಯಲಾಗುತ್ತಿದೆ...",
"uctop": "ಪ್ರಸಕ್ತ",
"month": "ಈ ತಿಂಗಳಿಂದ (ಮತ್ತು ಮುಂಚಿನ):",
"year": "ಈ ವರ್ಷದಿಂದ (ಮತ್ತು ಮುಂಚಿನ):",
- "sp-contributions-newbies": "ಹೊಸ ಖಾತೆಗಳ ಕಾಣಿಕೆಗಳನ್ನು ಮಾತ್ರ ತೋರಿಸು",
- "sp-contributions-newbies-sub": "ಹೊಸ ಖಾತೆಗಳಿಗೆ",
"sp-contributions-blocklog": "ತಡೆಹಿಡಿಯುವಿಕೆ ದಾಖಲೆ",
"sp-contributions-uploads": "ಅಪ್ಲೋಡುಗಳು",
"sp-contributions-logs": "ದಾಖಲೆಗಳು",
"imgmultipageprev": "← ಹಿಂದಿನ ಪುಟ",
"imgmultipagenext": "ಮುಂದಿನ ಪುಟ →",
"imgmultigo": "ಹೋಗು!",
- "ascending_abbrev": "ಏರು",
- "descending_abbrev": "ಇಳಿ",
"table_pager_next": "ಮುಂದಿನ ಪುಟ",
"table_pager_prev": "ಹಿಂದಿನ ಪುಟ",
"table_pager_first": "ಮೊದಲ ಪುಟ",
"apihelp-no-such-module": "\"$1\" 모듈을 찾을 수 없습니다.",
"apisandbox": "API 실험실",
"apisandbox-jsonly": "API 연습장을 이용하려면 자바스크립트가 필요합니다.",
- "apisandbox-api-disabled": "이 사이트에서는 API가 꺼져 있습니다.",
"apisandbox-intro": "<strong>미디어위키 웹 서비스 API</strong>를 시험해보려면 이 페이지를 이용해보세요. API 용법에 대해서는 [[mw:API:Main page|API 문서]]를 참고하십시오. 예: [https://www.mediawiki.org/wiki/API#A_simple_example 대문의 내용 요청하기]. 더 많은 예를 보려면 액션을 선택하세요.\n\n여기가 연습장이라도 이 페이지에서 실행하는 동작 때문에 위키를 변경할 수도 있다는 점에 유의하십시오.",
"apisandbox-submit": "요청하기",
"apisandbox-reset": "지우기",
"wlheader-enotif": "이메일 알림 기능이 활성화되었습니다.",
"wlheader-showupdated": "마지막으로 방문한 이후에 바뀐 문서는 '''굵은 글씨'''로 보입니다.",
"wlnote": "$3 $4 기준으로, 아래에 최근 {{PLURAL:$2|한 시간|<strong>$2</strong>시간}} 동안 {{PLURAL:$1|마지막 바뀜이|마지막 바뀜 <strong>$1</strong>개가}} 있습니다.",
- "wlshowlast": "최근 $1시간 $2일 동안의 바뀜 보기",
"watchlist-hide": "숨기기",
"watchlist-submit": "보기",
"wlshowtime": "표시할 기간:",
"sessionfailure": "로그인 세션에 문제가 발생한 것 같습니다.\n세션 하이재킹을 막기 위해 동작이 취소되었습니다.\n양식을 다시 제출해 주십시오.",
"changecontentmodel": "문서의 콘텐츠 모델을 변경",
"changecontentmodel-legend": "콘텐츠 모델 변경",
- "changecontentmodel-title-label": "문서 제목",
+ "changecontentmodel-title-label": "문서 제목:",
"changecontentmodel-current-label": "현재의 콘텐츠 모델:",
- "changecontentmodel-model-label": "새 콘텐츠 모델",
+ "changecontentmodel-model-label": "새 콘텐츠 모델:",
"changecontentmodel-reason-label": "이유:",
"changecontentmodel-submit": "바꾸기",
"changecontentmodel-success-title": "콘텐츠 모델이 변경되었습니다",
"month": "월:",
"year": "연도:",
"date": "날짜부터 (혹은 이전):",
- "sp-contributions-newbies": "새 사용자의 기여만 보기",
- "sp-contributions-newbies-sub": "새 사용자의 기여",
- "sp-contributions-newbies-title": "새 사용자의 기여",
"sp-contributions-blocklog": "차단 기록",
"sp-contributions-suppresslog": "숨겨진 {{GENDER:$1|사용자}} 기여",
"sp-contributions-deleted": "삭제된 {{GENDER:$1|사용자}} 기여",
"newimages-legend": "필터",
"newimages-label": "파일 이름 (또는 그 일부분):",
"newimages-user": "IP 주소 또는 사용자 이름",
- "newimages-newbies": "새 사용자의 기여만 보기",
"newimages-showbots": "봇이 올린 것 보기",
"newimages-hidepatrolled": "점검한 업로드 숨기기",
"newimages-mediatype": "미디어 유형:",
"img-lang-default": "(기본 언어)",
"img-lang-info": "이 그림을 $1로 렌더합니다. $2",
"img-lang-go": "보기",
- "ascending_abbrev": "오름차순",
- "descending_abbrev": "내림차순",
"table_pager_next": "다음 문서",
"table_pager_prev": "이전 문서",
"table_pager_first": "처음 문서",
"wlheader-enotif": "E-mail бла хапар бериу джандырылыбды.",
"wlheader-showupdated": "Ахыр кириуюгюзден сора бетни тюрлениулери '''къалын''' джазыу бла кёргюзюлгенди.",
"wlnote": "Тюбюндеди кёргюзюлгенди: ахыр '''$2''' сагъатха этилген ахыр '''$1''' тюрлениу, $3 $4 заманнга дери.",
- "wlshowlast": "Арт $1 сагъат $2 кюннге кёргюз",
"watchlist-options": "Кёзде тургъан тизмени джарашдырыулары",
"watching": "Кёзде тургъан тизмеге къошуу...",
"unwatching": "Кёзде тургъан тизмеден кетериу...",
"uctop": "бусагъатдагъы",
"month": "Айдан башлаб (эм алгъаракъ):",
"year": "Джылдан башлаб (эм алгъаракъ):",
- "sp-contributions-newbies": "Джангы тергеу джазыу (аккаунт) бла этилге къошакъны кёргюз",
- "sp-contributions-newbies-sub": "Джангы тергеу джазыуладан (аккаунтладан)",
- "sp-contributions-newbies-title": "Джангы тергеу джазыуладан этилген къошакъ",
"sp-contributions-blocklog": "Блок этиуню журналы",
"sp-contributions-suppresslog": "къошулуучуну кетерилген къошуму",
"sp-contributions-deleted": "къошулуучуну кетерилген тюрлендириулери",
"img-lang-default": "(тынгылау бла тил)",
"img-lang-info": "Бу суратны $1 тилде кёргюз. $2",
"img-lang-go": "Хайырландыр",
- "ascending_abbrev": "гитчеден уллугъа",
- "descending_abbrev": "азалгъан",
"table_pager_next": "Эндиги бет",
"table_pager_prev": "Аллындагъы бет",
"table_pager_first": "Биринчи бет",
"uctop": "nykyhini",
"month": "Kuukauši",
"year": "Vuosi",
- "sp-contributions-newbies": "Näytä uušien käyttäjien muutokšet",
"sp-contributions-blocklog": "šalpaušloki",
"sp-contributions-uploads": "Lataukšet",
"sp-contributions-logs": "lokit",
"apihelp-no-such-module": "Et Moduhl „$1“ wood nit jefonge.",
"apisandbox": "De <i lang=\"en\">API</i> ußprobeere",
"apisandbox-jsonly": "Der ohne JavaSkrepp kam_mer de <i lang=\"en\" xml:lang=\"en\" dir=\"ltr\" title=\"Application Programming Interface\">API</i> för zom erömprobehre nit bruche.",
- "apisandbox-api-disabled": "Dat <i lang=\"en\">API</i> es en heh dämm Wiki afjeschalldt.",
"apisandbox-intro": "Op heh dä Sigg kanns De met dä <strong><i lang=\"en\" xml:lang=\"en\" dir=\"ltr\" title=\"Application Programming Interface\">API</i> vum MehdijaWikki singem Wäbdehns</strong> eröm schpelle.\nBeloor Der de Einzelheijte, un wi di jebruch weed, op dä iere [[mw:API:Main_page Sigg met de Verklieronge]].\nE Beischpell: [https://www.mediawiki.org/wiki/API#A_simple_example De Houpsigg holle].\nSöhk ene {{int:Apisb-label-action}} uß, öm mih Beischpelle aanjezeisch ze krijje.\nOch wann dat heh nor zom Ußprobehre es, kann dat, wat De heh mähß, et Wikki veränndere.",
"apisandbox-submit": "Lohß jonn!",
"apisandbox-reset": "Läddesch maache",
"wlheader-enotif": "Et <i lang=\"en\">e-mail</i> Schecke es enjeschalt.",
"wlheader-showupdated": "Wann se Einer jeändert hätt, zickdäm De se et letzte Mol aanjeluurt häs, sin di Sigge <strong>extra markeet</strong>.",
"wlnote": "{{PLURAL:$1|Hee es de läzde Änderong uß|Hee sin de läzde <strong>$1</strong> Änderonge uß|Mer han kein Änderonge en}} de läzde {{PLURAL:$2|Stund|<strong>$2</strong> Stunde|<strong>noll</strong> Stunde}} zigg em $3 öm $4 Uhr.",
- "wlshowlast": "Zeisch de läzde $1 Schtunde, $2 Dähsch aan.",
"watchlist-hide": "Verschtisch",
"watchlist-submit": "Aanzeije!",
"wlshowtime": "De Aandeijl vun e Zigg zom Aanzeije:",
"uctop": "Neuste",
"month": "un Moohnt:",
"year": "Beß Johr:",
- "sp-contributions-newbies": "Nor neu Metmaacher ier Beidräg zeije",
- "sp-contributions-newbies-sub": "För neu Metmaacher",
- "sp-contributions-newbies-title": "Neu Metmaacher ier Beijdrähsch",
"sp-contributions-blocklog": "Logbohch met de Metmaacher ier Schpärre",
"sp-contributions-suppresslog": "verschtoche Beidrääch",
"sp-contributions-deleted": "Fottjeschmeße Beijdrähsch",
"img-lang-default": "(Schtandatt_Schprohch)",
"img-lang-info": "Zeisch heh dat Beld aan en $1. $2",
"img-lang-go": "Lohß Jonn!",
- "ascending_abbrev": "opwääts zoteet",
- "descending_abbrev": "raffkaz zoteet",
"table_pager_next": "De nächste Sigg",
"table_pager_prev": "De vörijje Sigg",
"table_pager_first": "De eetste Sigg",
"wlheader-enotif": "Agahdariya e-nameyan hate çalakkirin",
"wlheader-showupdated": "Ev rûpela hatî guhertin dema te lê meyzand bi <strong>nivîsa stûr</strong> tê xuyakirin.",
"wlnote": "Ji $3, $4 heta niha {{PLURAL:$1|guherandinê|<strong>$1</strong> guherandinên}} dawî yê {{PLURAL:$2|saetê|<strong>$2</strong> saetên}} dawî {{PLURAL:$1|tê|tên}} dîtin.",
- "wlshowlast": "Guhertinên berî $1 saetan, $2 rojan nîşan bide",
"watchlist-hide": "Veşêre",
"watchlist-submit": "Nîşan bide",
"wlshowhideminor": "guherandinên biçûk",
"uctop": "rojane",
"month": "Ji meha (û zûtir):",
"year": "Ji sala (û zûtir):",
- "sp-contributions-newbies": "Tenê beşdariyên bikarhênerên nû nîşan bide",
- "sp-contributions-newbies-sub": "Ji bikarhênerên nû re",
- "sp-contributions-newbies-title": "Tevkariyên bikarhêner ji bo hesabên nû",
"sp-contributions-blocklog": "astengkirina têketinê",
"sp-contributions-deleted": "beşdariyên bikarhêner yên jêbirî",
"sp-contributions-uploads": "yên barkirî",
"watchlist-details": "{{PLURAL:$1|$1 сагьифа}} сени тергев тизменгде (пикирлешив сагьифаланы санап).",
"wlheader-showupdated": "Сени ахырынчы геливюнгден сонг алышынгъан сагьифалар <strong>къалын</strong> шрифт булан гёрсетилген.",
"wlnote": "Тюбюндеги — {{PLURAL:$1|ахырынчы тюзлевюдюр|<strong>$1</strong> ахырынчы тюзлевлеридир}} алдагъы {{PLURAL:$2|сагьат аралыкъда|<strong>$2</strong> сагьат аралыкъда}} этилген, $3, $4 тархындан.",
- "wlshowlast": "Артдагъы $1 сагьат $2 гюннюкин гёрсетмек",
"watchlist-options": "Тергев тизмени кюйлевлери",
"enotif_reset": "Бары да сагьифаланы къаралгъандай белгилемек",
"dellogpage": "Тайдырыв гюнделиги",
"uctop": "гьалиги",
"month": "Бу айдан (ва дагъы алдан):",
"year": "Бу йылдан (ва дагъы алдын):",
- "sp-contributions-newbies": "Янгыз янгы гьисаплардан этилген ярдымны гёрсетмек",
"sp-contributions-blocklog": "къамав гюнделиги",
"sp-contributions-uploads": "юклевлер",
"sp-contributions-logs": "гюнделиклер",
"watchlist-details": "Yma {{PLURAL:$1|$1 folen}} war agas rol wolya, marnas folennow keskows.",
"wlheader-showupdated": "Yn '''tew''' y tiskwedhir folennow re beu chanjyes a-dhia agas vysytyans diwettha.",
"wlnote": "A-woles yma an {{PLURAL:$1|chanj diwettha|'''$1''' chanj diwettha}} y'n {{PLURAL:$2|our|'''$2''' our}} diwettha, a-dhia $3, $4.",
- "wlshowlast": "Diskwedhes an $1 our $2 dydh diwettha",
"watchlist-hide": "Kudha",
"watchlist-options": "Etholyow an rol wolya",
"watching": "Ow kolya...",
"uctop": "a-lemmyn",
"month": "Dhyworth an mis (ha moy a-varr):",
"year": "Dhyworth an vledhen (ha moy a-varr):",
- "sp-contributions-newbies": "Diskwedhes yn unnik kevrohow akontow nowyth",
"sp-contributions-blocklog": "kovnoten lettya",
"sp-contributions-uploads": "ughkargansow",
"sp-contributions-logs": "kovnotennow",
"watch": "Көзөмөлдөө",
"unwatch": "Көзөмөлдөбөө",
"watchlist-details": "Талкуу барактарын эсепке албаганда көзөмөл тизмеңизде {{PLURAL:$1|$1 барак|$1 барак}} бар.",
- "wlshowlast": "Соңку $1 саат $2 күн көрсөтүү.",
"watchlist-options": "Көзөмөл тизменин ырастоолору",
"created": "түзүлдү",
"changed": "өзгөртүлдү",
"uctop": "учурдагы",
"month": "Айынан (же андан мурдараак):",
"year": "Жылынан (же андан мурдараак):",
- "sp-contributions-newbies": "Жаңы эсептерден кылынган салымдарды көрсөтүү",
"sp-contributions-blocklog": "бөгөттөөлөр журналы",
"sp-contributions-uploads": "жүктөөлөр",
"sp-contributions-logs": "журналдар",
"imgmultipagenext": "кийинки барак →",
"imgmultigo": "Өтүү!",
"imgmultigoto": "$1 барагына өтүү",
- "ascending_abbrev": "өсүү",
- "descending_abbrev": "кемүү",
"table_pager_next": "Кийинки барак",
"table_pager_prev": "Мурунку барак",
"table_pager_first": "Биринчи барак",
"wlheader-enotif": "Mutationes si quae factae erunt, electronice tibi nuntiabuntur.",
"wlheader-showupdated": "Paginae nondum a te inspectae <strong>typis crassioribus</strong> ostenduntur.",
"wlnote": "{{PLURAL:$1|Indicatur mutatio novissima|Indicantur '''$1''' mutationes novissimae}} abhinc {{PLURAL:$2|superiorem horam|superiores '''$2''' horas}} (ab $3, $4) factae.",
- "wlshowlast": "Monstrare proximas $1 horas $2 dies",
"watchlist-hide": "Supprimere recensiones",
"watchlist-submit": "Ostendere",
"wlshowtime": "Index respiciat:",
"uctop": "vertex",
"month": "Ab mense (et prior):",
"year": "Ab anno (et prior):",
- "sp-contributions-newbies": "Nullas conlationes nisi a conlatoribus novis factis ostendere",
- "sp-contributions-newbies-sub": "a conlatoribus novis factae",
- "sp-contributions-newbies-title": "Conlationes a conlatoribus novis factae",
"sp-contributions-blocklog": "acta obstructionum",
"sp-contributions-deleted": "conlationes usoris deletae",
"sp-contributions-uploads": "Fasciculi impositi",
"imgmultipagenext": "pagina proxima →",
"imgmultigo": "I!",
"imgmultigoto": "Ire ad paginam $1",
- "ascending_abbrev": "asc",
- "descending_abbrev": "desc",
"table_pager_next": "Pagina proxima",
"table_pager_prev": "Pagina superior",
"table_pager_first": "Prima pagina",
"watchthispage": "Cudia esta hoja",
"unwatch": "dexa de cudiar",
"watchlist-details": "{{PLURAL:$1|$1 hoja|$1 hojas}} en tu lista de escogidas, sin contar las de la diskussión.",
- "wlshowlast": "Ver los trocamientos de las últimas $1 oras, $2 días",
"watchlist-options": "Opciones de la lista de escogidas",
"watching": "Cudiando...",
"unwatching": "Dexando de cudiar...",
"uctop": "korriente",
"month": "Desde el mes (i antes):",
"year": "Desde el anyo (i antes):",
- "sp-contributions-newbies": "Mostrar solo las ajustamientos de los usuarios nuevos",
"sp-contributions-blocklog": "registro de bloqueos",
"sp-contributions-uploads": "suvidas",
"sp-contributions-logs": "enrejistros",
"nocreate-loggedin": "Dir hutt keng Berechtigung fir nei Säiten unzeleeën.",
"sectioneditnotsupported-title": "Ännere vum Abschnitt gëtt net ënnerstëtzt",
"sectioneditnotsupported-text": "D'Ännere vun Abschnitte gëtt op dëser Ännerungssäit net ënnerstëtzt.",
+ "modeleditnotsupported-title": "Ännere gëtt net ënnerstëtzt",
"permissionserrors": "Net genuch Rechter",
"permissionserrorstext": "Dir hutt net genuch Rechter fir déi Aktioun auszeféieren. {{PLURAL:$1|Grond|Grënn}}:",
"permissionserrorstext-withaction": "Dir sidd, aus {{PLURAL:$1|folgendem Grond|folgende Grënn}}, net berechtegt $2 :",
"apihelp-no-such-module": "Modul \"$1\" net fonnt.",
"apisandbox": "API-Sandkëscht",
"apisandbox-jsonly": "Fir d'API-Sandkëscht ze benotze braucht Dir JavaScript.",
- "apisandbox-api-disabled": "API ass op dësem Site ausgeschalt.",
"apisandbox-submit": "Ufro maachen",
"apisandbox-reset": "Eidel maachen",
"apisandbox-retry": "Nach eng Kéier probéieren",
"wlheader-enotif": "E-Mail-Notifikatioun ass ageschalt.",
"wlheader-showupdated": "Säiten déi zanter Ärer leschter Visite geännert goufen, si '''fett''' geschriwwen",
"wlnote": "Hei {{PLURAL:$1|ass déi lescht Ännerung|sinn déi lescht <strong>$1</strong> Ännerunge}} vun {{PLURAL:$2|der leschter Stonn|de leschte(n) <strong>$2</strong> Stonnen}}, Stand: $3 ëm $4 Auer.",
- "wlshowlast": "Déi lescht $1 Stonnen $2 Deeg weisen",
"watchlist-hide": "Verstoppen",
"watchlist-submit": "Weisen",
"wlshowtime": "Zäitraum dee gewise gëtt:",
"sessionfailure": "Et schéngt e Problem mat Ärer Sessioun ze ginn;\nDës Aktioun gouf aus Sécherheetsgrënn ofgebrach, fir ze verhënneren datt Är Sessioun piratéiert ka ginn.\nSchéckt de Formulaire w.e.g. nach eng Kéier.",
"changecontentmodel": "De Modell vum Inhalt vun enger Säit änneren",
"changecontentmodel-legend": "Modell vun enger Säit mat Inhalt änneren",
- "changecontentmodel-title-label": "Titel vun der Säit",
- "changecontentmodel-model-label": "Neie Modell vun enger Säit mat Inhalt",
+ "changecontentmodel-title-label": "Titel vun der Säit:",
+ "changecontentmodel-model-label": "Neie Modell vun enger Säit mat Inhalt:",
"changecontentmodel-reason-label": "Grond:",
"changecontentmodel-submit": "Änneren",
"changecontentmodel-success-title": "De Modell vum Inhalt gouf geännert",
"month": "Vum Mount (a virdrun):",
"year": "Vum Joer (a virdrun):",
"date": "Vum Datum (a virdrun):",
- "sp-contributions-newbies": "Nëmme Kontributioune vun neie Mataarbechter weisen",
- "sp-contributions-newbies-sub": "Fir déi Nei",
- "sp-contributions-newbies-title": "Kontributioune vun neie Benotzer",
"sp-contributions-blocklog": "Spärlescht",
"sp-contributions-suppresslog": "geläscht {{GENDER:$1|Benotzerkontributiounen}}",
"sp-contributions-deleted": "geläscht {{GENDER:$1|Benotzerkontributiounen}}",
"immobile-target-namespace-iw": "En Interwiki-Link ass kee gëltegt Zil beim Réckele vun enger Säit.",
"immobile-source-page": "Dës Säit kann net geréckelt ginn.",
"immobile-target-page": "Kann net op de Bestëmmungs-titel geréckelt ginn.",
+ "movepage-invalid-target-title": "De gefroten Numm ass net valabel.",
"bad-target-model": "Déi gewënschten Zilsäit benotzt en anere Modell fir den Inhalt. Et kann net vun $1 op $2 ëmgewandelt ginn.",
"imagenocrossnamespace": "Fichiere kënnen net an aner Nummraim geréckelt ginn",
"nonfile-cannot-move-to-file": "\"Keng Fichiere\" kënnen net an den {{ns:file}}-Nummraum geréckelt ginn",
"img-lang-default": "(Standard-Sprooch)",
"img-lang-info": "Dëst Bild op $1 renderen. $2",
"img-lang-go": "Lass",
- "ascending_abbrev": "erop",
- "descending_abbrev": "erof",
"table_pager_next": "Nächst Säit",
"table_pager_prev": "Vireg Säit",
"table_pager_first": "Éischt Säit",
"watchthispage": "Гелкъуьн и хъувун",
"unwatch": "Вилив хуьмир",
"watchlist-details": "Куь вилив хуьнин сиягьда {{PLURAL:$1|1=$1 ччин|$1 ччин}} авайди я, веревирдрин ччинар квачиз.",
- "wlshowlast": "Эхиримжи $1 сят $2 югъ къалура",
"watchlist-options": "Вилив хуьнин сиягьдин низамарунар",
"watching": "Килигун...",
"unwatching": "Амма клигнай",
"uctop": "алай",
"month": " Вацралай (ва адалай вилик)",
"year": "Иисалай (ва адалай вилик):",
- "sp-contributions-newbies": "Анжах цlийи уртахрин кутур крар къалура",
"sp-contributions-blocklog": "Блокарунин журнал",
"sp-contributions-uploads": "ппарунар",
"sp-contributions-logs": "журналар",
"apihelp-no-such-module": "Modulo \"$1\" no ia es trovada.",
"apisandbox": "Caxa de arena API",
"apisandbox-jsonly": "JavaScript es nesesada per la usa de la caxa de arena.",
- "apisandbox-api-disabled": "La API es descomutada en esta pajeria.",
"apisandbox-intro": "Usa esta paje per esperimenta con la <strong>API MediaWiki per servis de ueb</strong>.\nConsulta [[mw:API:Main page|la documentos de API]] per plu detalias de la usa de la API. Esemplo: [https://www.mediawiki.org/wiki/API#A_simple_example retrae la contenida de un Paje Xef]. Eleje un ata per vide plu esemplos.\n\nNota ce, an si esta es un caxa de arena, atas cual tu fa en esta paje pote afeta la vici.",
"apisandbox-submit": "Fa solisita",
"apisandbox-reset": "Vacui",
"wlheader-enotif": "Avisas par eposta es comutada.",
"wlheader-showupdated": "Pajes cual on ia cambia pos tua visita la plu resente apare en leteras <strong>spesa</strong>.",
"wlnote": "A su es la {{PLURAL:$1|cambia|<strong>$1</strong> cambias}} en la {{PLURAL:$2|ora|<strong>$2</strong> oras}} la plu resente, a $3, $4.",
- "wlshowlast": "Mostra la $1 oras e $2 dias presedente",
"watchlist-hide": "Asconde",
"watchlist-submit": "Mostra",
"wlshowtime": "Periodo de tempo mostrada:",
"uctop": "aora",
"month": "De mense (e plu vea):",
"year": "De anio (e plu vea):",
- "sp-contributions-newbies": "Mostra sola contribuis de contas nova",
- "sp-contributions-newbies-sub": "Per contas nova",
- "sp-contributions-newbies-title": "Contribuis de usor per contas nova",
"sp-contributions-blocklog": "rejistra de impedis",
"sp-contributions-suppresslog": "contribuis supresada de {{GENDER:$1|usor}}",
"sp-contributions-deleted": "contribuis sutraeda de {{GENDER:$1|usor}}",
"newimages-legend": "Filtri",
"newimages-label": "Nom de fix (o un parte de lo):",
"newimages-user": "Adirije IP o nom de usor",
- "newimages-newbies": "Mostra contribuis sola de contas nova",
"newimages-showbots": "Mostra cargas par botes",
"newimages-hidepatrolled": "Asconde cargas patruliada",
"newimages-mediatype": "Tipo de media:",
"img-lang-default": "(lingua inisial)",
"img-lang-info": "Render esta imaje en $1. $2",
"img-lang-go": "Vade",
- "ascending_abbrev": "asen",
- "descending_abbrev": "desen",
"table_pager_next": "Paje seguente",
"table_pager_prev": "Paje presedente",
"table_pager_first": "Paje prima",
"watchthispage": "Goberera olupapula luno",
"unwatch": "Lekerawo okugoberera olupapula luno",
"watchlist-details": "Olina {{PLURAL:$1|olupapula $1|empapula $1}} z'ogoberera, nga tobalideko n'eza yogera-nange.",
- "wlshowlast": "Ndaga ez'omu ssaawa $1 n'ennaku $2 eziyise oba",
"watchlist-options": "Enteetakeeka y'endaga ya mpapula zengoberera",
"watching": "Kikolebwako...",
"unwatching": "Kikolebwako...",
"uctop": "enkyukakyuka esembye ku lupapula",
"month": "Mu mwezi (n'egyakulembera):",
"year": "Mu mwaka (n'egyakulembera):",
- "sp-contributions-newbies": "Ndaga ebikoledwa abaak'egata ku Wiki byokka",
"sp-contributions-blocklog": "Ebifa ku bagaanidwa",
"sp-contributions-talk": "yogera nange",
"sp-contributions-search": "Kebera bye bawaddeyo",
"apihelp-no-such-module": "Moduul \"$1\" neet gevonje.",
"apisandbox": "API-zandjbak",
"apisandbox-jsonly": "JavaScrip is vereisj veur de API-zandjbak te kónne broeke.",
- "apisandbox-api-disabled": "API is oetgesjakeld op deze site.",
"apisandbox-intro": "Gebroek dees pagina óm te experimentere mit de <strong>MediaWiki API</strong>.\nZuuch de [[mw:API:Main page|API-dokkemèntatie]] veur mier details euver 't gebroek van de API. Veurbeeld: [https://www.mediawiki.org/wiki/API#A_simple_example wie d'n inhawd van 'n houfpagina is op te haole]. Selecteer 'n hanjeling veur mieër veurbeelde te zeen.\n\nTródsdet dit 'n tesfunctie is kónne sommige hanjelinge toch verangeringe make in de wiki.",
"apisandbox-submit": "Verzeuk oetveure",
"apisandbox-reset": "Wusj",
"wlheader-enotif": "E-mailberichte zint aangezat.",
"wlheader-showupdated": "Pazjena's die verangerd zeen saers doe ze veur 't lètste bekeeks sjtaon '''vet'''",
"wlnote": "Hieónger {{PLURAL:$1|steit de lètste verangering|staon de lètste <strong>$1</strong> verangeringe}} van {{PLURAL:$2|'t lètste oer|de lètste <strong>$2</strong> oer}} óp $3 óm $4.",
- "wlshowlast": "Tuin lètste $1 oere $2 daag",
"watchlist-hide": "Versjtaek",
"watchlist-submit": "Tuine",
"wlshowtime": "Te tuinen tied:",
"uctop": "litste verangering",
"month": "Van maond (en ierder):",
"year": "Van jaor (en ierder):",
- "sp-contributions-newbies": "Tuin allein de biedrage van nuuj gebroekers",
- "sp-contributions-newbies-sub": "Veur nuujelinge",
- "sp-contributions-newbies-title": "Biedraag ven nuuj gebroekers",
"sp-contributions-blocklog": "Blokkeerlogbook",
"sp-contributions-suppresslog": "óngerdrökde {{GENDER:$1|gebroekersbiedrages}}",
"sp-contributions-deleted": "eweggesjafde {{GENDER:$1|gebroekersbiedrages}}",
"newimages-legend": "Bestandjsnaam",
"newimages-label": "Bestandjsnaam (of deel daarvan):",
"newimages-user": "IP-adres of gebroekersnaam",
- "newimages-newbies": "Tuin allein de biedrage van nuuj gebroekers",
"newimages-showbots": "Tuin botuploads",
"newimages-hidepatrolled": "Versjtaek gecontroleerde uploads",
"newimages-mediatype": "Mediaformaot:",
"img-lang-default": "(standerdspraok)",
"img-lang-info": "Gaef dit plaetje waor in de spraok $1. $2",
"img-lang-go": "Gank",
- "ascending_abbrev": "opl.",
- "descending_abbrev": "aaf.",
"table_pager_next": "Volgende pazjena",
"table_pager_prev": "Veurige pazjena",
"table_pager_first": "Ierste pazjena",
"apihelp-no-such-module": "Moddulo \"$1\" non trovou.",
"apisandbox": "Paggina de proeuva API",
"apisandbox-jsonly": "Pe doeuviâ a paggina de proeuva API ghe voeu o JavaScript.",
- "apisandbox-api-disabled": "E fonçionalitæ API son disabilitæ insce questo scito.",
"apisandbox-intro": "Doeuvia sta paggina pe fâ prattica co-e <strong>API web service MediaWiki</strong>.\nPe di urteioî detaggi de utilizzo de API, amia a [[mw:API:Main page|documentaçion API]]. Exempio: [https://www.mediawiki.org/wiki/API#A_simple_example ötegnî o contegnuo da paggina prinçipâ]. Seleçion-a un'açion pe vedde di atri exempi.\n\nNotta che, sciben che questa a segge 'na paggina pe-e proeuve, i açioin che ti esegui chì porieivan modificâ a wiki.",
"apisandbox-submit": "Inandia recesta",
"apisandbox-reset": "Nettezza",
"wlheader-enotif": "A notiffica via email a l'è attiva.",
"wlheader-showupdated": "E paggine che son stæte modificæ doppo l'urtima vixita son evidençiæ in '''grascetto'''.",
"wlnote": "De sotta {{PLURAL:$1|a l'è elencâ a modifica ciù reçente apportâ|son elencæ e <strong>$1</strong> modifiche ciù reçente apportæ}} {{PLURAL:$2|inte l'urtima oa|inti urtime <strong>$2</strong> oe}}; i dæti son aggiornæ a-e $4 do $3.",
- "wlshowlast": "Mostra i urtime $1 oe $2 giorni",
"watchlist-hide": "Ascondi",
"watchlist-submit": "Mostra",
"wlshowtime": "Periodo de tempo da vixualizzâ:",
"uctop": "atoâle",
"month": "Partindo da-o meize (e precedénti):",
"year": "Partindo da l'anno (e precedenti):",
- "sp-contributions-newbies": "Fanni védde sôlo e contribuçioìn di nêuvi utenti",
- "sp-contributions-newbies-sub": "Pe i nêuvi ûtenti",
- "sp-contributions-newbies-title": "Contribuçioin di noeuvi utenti",
"sp-contributions-blocklog": "blòcchi",
"sp-contributions-suppresslog": "contributi {{GENDER:$1|utente}} soppresci",
"sp-contributions-deleted": "contributi {{GENDER:$1|utente}} scassæ",
"newimages-legend": "Filtro",
"newimages-label": "Nomme do file (o una parte de questo):",
"newimages-user": "Adresso IP ò nomme utente",
- "newimages-newbies": "Fanni vedde solo e contribuçioin di noeuvi utenti",
"newimages-showbots": "Mostra i caregamenti fæti dai bot",
"newimages-hidepatrolled": "Ascondi i caregamenti controlæ",
"newimages-mediatype": "Tipo de suporto:",
"img-lang-default": "(lengua predefinia)",
"img-lang-info": "Converti questa immaggine in $1. $2",
"img-lang-go": "Vanni",
- "ascending_abbrev": "cresc",
- "descending_abbrev": "decresc",
"table_pager_next": "Pàgina sucesîva",
"table_pager_prev": "Pagina de primma",
"table_pager_first": "Primma pagina",
"watchthispage": "Vaņ iļ siedā līedpūoltõ",
"unwatch": "Lopta iļ-vaņtlimi",
"watchlist-details": " {{PLURAL:$1|$1 lēḑ|$1 līedtõ}} ātõ iļ-vaņtlimiz nimkēras, bäz luggõmõt nõvpidāmiz-līedidi.",
- "wlshowlast": "Nägţ perīzt $1 stuņdõ $2 päuvõ",
"watchlist-hide": "↓Vaŗț",
"watchlist-options": "Iļ-vaņtlimiz nimkēra pie-lēmizt",
"watching": "Vaņtlimi iļ sīe...",
"uctop": "tutkāms",
"month": " Kūstõ sōņist (un jo vārald)",
"year": "āigastõst",
- "sp-contributions-newbies": "Nägţ setku ūd kȭlbatijizt kubsõtīed",
"sp-contributions-blocklog": "blokīerimizt",
"sp-contributions-uploads": "ilzõ-lōţimizt",
"sp-contributions-logs": "logūd",
"wlheader-enotif": "ایمیلهای اعلان فعال است.",
"wlheader-showupdated": "صفحههایی که پس از آخرین بازدید شما تغییر کردهاند '''پررنگ''' نمایش داده شدهاند.",
"wlnote": "در زیر {{PLURAL:$1|تغییری|<strong>$1</strong> تغییری}} که در {{PLURAL:$2|ساعت|<strong>$2</strong> ساعت}} گذشته انجام شده موجود است، تاریخ آخرین بازیابی: $3، $4",
- "wlshowlast": "نمایش آخرین $1 ساعت $2 روز",
"watchlist-hide": "ئآشاردن-پنهان کردن",
"watchlist-submit": "نیشان دائن",
"wlshowtime": "دوره زمانی نمایش:",
"uctop": "نؤسخهٔ ایسه",
"month": ":)در این سال (و پیش از آن",
"year": ":)در این سال (و پیش از آن",
- "sp-contributions-newbies": "فقط مشارکتهای تازهکاران نمایش داده شود",
- "sp-contributions-newbies-sub": "برای تازهکاران",
- "sp-contributions-newbies-title": "مشارکتهای کاربری برای حسابهای تازهکار",
"sp-contributions-blocklog": "سیاههٔ بستهشدنها",
"sp-contributions-suppresslog": "کمکهای کاربر متوقف شده",
"sp-contributions-deleted": "مشارکتهای حذفشدهٔ کاربر",
"img-lang-default": "(زوون پئش فرض)",
"img-lang-info": "ارائه این تصویر در $1 . $2",
"img-lang-go": "بِچۆ",
- "ascending_abbrev": "ورِ بِڵِنگی/صعودی",
- "descending_abbrev": "ورِ هووار/نزولی",
"table_pager_next": "وەڵگە تِر(هەنی)",
"table_pager_prev": "وەڵگە دؤماێن",
"table_pager_first": "وةڵگة أؤةڵئن",
"unwatch": "Tegn pü d'ögg",
"unwatchthispage": "Desmèt de tègner d'öcc",
"watchlist-details": "{{PLURAL:$1|$1 pagina|$1 paginn}} tegnüü sot ögg, fö che i paginn de discüssión.",
- "wlshowlast": "Fa vidé i ültim $1 ur $2 dì",
"watchlist-options": "Upzión lista d'ussevazión",
"watching": "Giuntà ai pagin da ten d'ögg...",
"unwatching": "Eliminà dai pagin da ten d'ögg...",
"uctop": "ültima per la pagina",
"month": "A partì del mes (e quij inanz)",
"year": "A partì de l'ann (e quij inanz)",
- "sp-contributions-newbies": "Fà vidè dumà i cuntribüzión di dvurat növ",
"sp-contributions-blocklog": "Register di bloch",
"sp-contributions-deleted": "Cuntribüziun scancelaa",
"sp-contributions-talk": "ciciarada",
"watchthispage": "ຕິດຕາມໜ້ານີ້",
"unwatch": "ເຊົາຕິດຕາມ",
"wlheader-showupdated": "ບັນດາ ໜ້າ ທີ່ມີການປ່ຽນແປງ ຫຼັງຈາກທີ່ທ່ານ ເຂົ້າຊົມຫຼ້າສຸດ ຈະຖືກສະແດງເປັນ ໂຕໜັງສື '''ເຂັ້ມ'''",
- "wlshowlast": "ສະແດງ $1 ຊົ່ວໂມງຫຼ້າສຸດ $2 ມື້ຫຼ້າສຸດ",
"watching": "ພວມຕິດຕາມ...",
"unwatching": "ພວມເຊົາຕິດຕາມ...",
"enotif_lastvisited": "ເບິ່ງ $1 ເພື່ອ ທຸກໆການປ່ຽນແປງ ຕັ້ງແຕ່ເທື່ອສຸດທ້າຍ ທີ່ ທ່ານເຂົ້າຫາ.",
"uctop": "ເທິງສຸດ",
"month": "ແຕ່ເດືອນ (ແລະກ່ອນໜ້ານັ້ນ):",
"year": "ແຕ່ປີ (ແລະກ່ອນໜ້ານັ້ນ):",
- "sp-contributions-newbies": "ສະແດງສະເພາະ ການປະກອບສ່ວນ ໂດຍ ບັນຊີໃໝ່",
"sp-contributions-blocklog": "ບັນທຶກການຫ້າມ",
"sp-contributions-talk": "ສົນທະນາ",
"sp-contributions-search": "ຊອກຫາ ການປະກອບສ່ວນ",
"unwatchthispage": "Ngambu kentezi",
"notanarticle": "Ni di petulo infomelo",
"watchlist-details": "{{PLURAL:$1|$1 petulo|$1 petulo}} sa kentezi e no bulelezi.",
- "wlshowlast": "Kamukile lapu-lila $1 holani $2 dia",
"watching": "Kentezi...",
"unwatching": "Dikentezi...",
"enotif_impersonal_salutation": "{{SITENAME}} sebelu",
"uctop": "nca ng'i",
"month": "Di muna (previ):",
"year": "Dyanu (previ):",
- "sp-contributions-newbies": "Kamukile afina di sebelu nca",
- "sp-contributions-newbies-sub": "Di nca sebelu",
"sp-contributions-blocklog": "Desu di bolok",
"sp-contributions-deleted": "Afina di sebelu bye sa afi kulobala",
"sp-contributions-talk": "Bulelezi",
"imgmultipageprev": "← kona petulo",
"imgmultipagenext": "lila petulo →",
"imgmultigo": "Afi!",
- "ascending_abbrev": "asendin",
- "descending_abbrev": "disendin",
"table_pager_next": "Lila petulo",
"table_pager_prev": "Kona petulo",
"table_pager_limit": "Kamukile $1 hits di petulo",
"wlheader-enotif": "ڤارئسیاری أنجومانامە کونئشتکار بییە.",
"wlheader-showupdated": "بٱلگٱیایی کاٛ د آخری گلٛؽ کاْ شما ساٛیلٛشو کردؽتٱ د <strong>تۊپور</strong>نشوݩ داٛئٱ بۊئٱن",
"wlnote": "د هار {{PLURAL:$1|آلشت|<strong>$1</strong> آلشتؽ}} کاْ د {{PLURAL:$2|ساعت|<strong>$2</strong> ساعٱت}} دماتر ٱنجوم بیٱ هؽسش، ڤیرگار آخری ڤاجۊری ٱنجوم بیٱ هؽسش، ڤیرگار آخری ڤاجۊری: $3، $4",
- "wlshowlast": "آخری$1 ساعٱتؽا $2ۉ رۊزؽا نشوݩ باٛیٱ",
"wlshowtime": "نئشوٙ دأئن د آخأر",
"wlshowhideminor": "ڤیرایئشتیا فئرە کوچئک",
"wlshowhidebots": "بوتیا",
"uctop": "تازٱ بۊ",
"month": "د ما(یا زیتر)",
"year": "د سال",
- "sp-contributions-newbies": "فقٱت هومیارؽایؽ کاْ د هساو تازٱ بیٱ نشوݩ باٛیٱ",
- "sp-contributions-newbies-sub": "سی حساویا تازه",
- "sp-contributions-newbies-title": "هومیاریا کاریار سی حساویا تازه",
"sp-contributions-blocklog": "پهرستنومٱ قولف بیٱ",
"sp-contributions-suppresslog": "پاکساگری کردن هومیاریا کاریار",
"sp-contributions-deleted": "هومیاریا پاکسا بیه کاریار",
"img-lang-default": "(زون پیش زمینه)",
"img-lang-info": "اوردن ای عسگ د $1 . $2",
"img-lang-go": "رو",
- "ascending_abbrev": "ری وه وارو",
- "descending_abbrev": "ری وه هاری",
"table_pager_next": "بلگه نهایی",
"table_pager_prev": "بلگه دمايی",
"table_pager_first": "سرآسونه",
"apihelp": "API pagalba",
"apihelp-no-such-module": "Modulis „$1“ nerastas.",
"apisandbox": "API smėlio dėžės",
- "apisandbox-api-disabled": "API yra išjungtas šioje svetainėje.",
"apisandbox-intro": "Naudokite šį puslapį norėdami eksperimentuoti su '''MediaWiki API \"„.\n\tIeškokite [https://www.mediawiki.org/wiki/API:Main_page API dokumentacijoje] Išsamesnės informacijos apie API naudojimo.",
"apisandbox-submit": "Pateikti prašymą",
"apisandbox-reset": "Išvalyti",
"wlheader-enotif": "El. pašto pranešimai yra įjungti.",
"wlheader-showupdated": "Puslapiai pakeisti nuo tada, kai paskutinį kartą apsilankėte juose, yra <strong>paryškinti</strong>.",
"wlnote": "{{PLURAL:$1|Rodomas '''$1''' paskutinis pakeitimas, atliktas|Rodomi '''$1''' paskutiniai pakeitimai, atlikti|Rodoma '''$1''' paskutinių pakeitimų, atliktų}} per '''$2''' {{PLURAL:$2|paskutinę valandą|paskutines valandas|paskutinių valandų}}, nuo $3 $4.",
- "wlshowlast": "Rodyti paskutinių $1 valandų, $2 dienų",
"watchlist-hide": "Slėpti",
"watchlist-submit": "Rodyti",
"wlshowtime": "Laiko trukmė, kurią rodyti:",
"month": "Nuo mėnesio (ir anksčiau):",
"year": "Nuo metų (ir anksčiau):",
"date": "Nuo datos (ir anksčiau):",
- "sp-contributions-newbies": "Rodyti tik naujų paskyrų keitimus",
- "sp-contributions-newbies-sub": "Neseniai prisiregistravusieji",
- "sp-contributions-newbies-title": "Naujai užsiregistravusių naudotojų indėlis",
"sp-contributions-blocklog": "blokavimų sąrašas",
"sp-contributions-suppresslog": "ištrintas {{GENDER:$1|naudotojo|naudotojos}} indėlis",
"sp-contributions-deleted": "ištrintas {{GENDER:$1|naudotojo|naudotojos}} indėlis",
"img-lang-default": "(numatytoji kalba)",
"img-lang-info": "Rodyti šį vaizdą $1 kalba. $2",
"img-lang-go": "Eiti",
- "ascending_abbrev": "didėjanti tvarka",
- "descending_abbrev": "mažėjanti tvarka",
"table_pager_next": "Kitas puslapis",
"table_pager_prev": "Ankstesnis puslapis",
"table_pager_first": "Pirmas puslapis",
"watchthispage": "Puorraudzeit itū lopu",
"unwatch": "Vairs napuorraudzeit",
"watchlist-details": "(Tu puorraug $1 {{PLURAL:$1|lopu|lopys}}, naskaitūt sarunu lopys.)",
- "wlshowlast": "Paruodeit izmainis pādejūs $1 stuņžu laikā voi $2 dīnu laikā, voi ari",
"watchlist-options": "Puorraugamū rokstu saroksta īspiejis",
"watching": "Davīnoj puorraudzeišonai...",
"unwatching": "Atslādz puorraudzeišonu...",
"uctop": "pādejā pataise",
"month": "Nu mieneša (i vacuoki):",
"year": "Nu goda (i vacuoki):",
- "sp-contributions-newbies": "Ruodeit jaunūs lituotuoju īguļdejumu",
"sp-contributions-blocklog": "Blokiešonys registrs",
"sp-contributions-search": "Meklēt lītuotuoju izdareitūs lobuojumus",
"sp-contributions-username": "IP adress ci slāgvuords:",
"watchlist-details": "I ralvèn zing aţanga {{PLURAL:$1| phêk $1 |phêk $1}}, sawihona phêk chhiar lohvin.",
"wlheader-enotif": "*E-lehkha inhriattirna tihnun a ni.",
"wlheader-showupdated": "I tlawh hnuhnun ber hnua tihdanglam phêk te chu a '''thau'''va tihlan a ni.",
- "wlshowlast": "Darkar $1 kalta-a tihdanglam tilang rawh , ni $2 kalta-a tihdanglam tilang rawh, tilang rawh",
"watchlist-options": "Ralvèn duhdàn",
"enotif_reset": "Phêk zawng zawng tlawh tawh vek angin chhinchhiah rawh.",
"enotif_impersonal_salutation": "{{SITENAME}} hmangtu",
"uctop": "chung",
"month": "Thla (leh a hmalam):",
"year": "Kum (leh a hmalam):",
- "sp-contributions-newbies": "Siangchan tharte kut-thawhna chauh tilang rawh",
- "sp-contributions-newbies-sub": "Siangchan thar tán",
- "sp-contributions-newbies-title": "Siangchan thar tána hmangtu kutthawhnate",
"sp-contributions-blocklog": "danbeh chhinchhiahna",
"sp-contributions-uploads": "hlankaite",
"sp-contributions-logs": "chanchin-ziak",
"confirm-unwatch-button": "Aw le",
"imgmultigo": "Khai le!",
"imgmultigoto": "Phêk $1-ah kal rawh",
- "ascending_abbrev": "<<",
- "descending_abbrev": ">>",
"table_pager_next": "Phêk dawt",
"table_pager_prev": "Phêk hmasa",
"table_pager_first": "Phêk hmasa ber",
"Mjbmr",
"Hosseinblue",
"MtDu",
- "Shahriar dehghani"
+ "Shahriar dehghani",
+ "Shahriar.dehghani24"
]
},
"tog-underline": "لینکیا خط وه دومن",
"filehist-dimensions": "ابعاد",
"filehist-comment": "توٙضیح",
"imagelinks": "ئیستفادھ د فایل",
- "linkstoimage": "دوٙمین الذکر {{PLURAL:$1|لینکل بألگە|$1 لینک بألگل}} بە ئی فایل:",
+ "linkstoimage": "{{PLURAL:$1|صفحهٔ|صفحَلِ}} زِر و ای عکس پیوند دارہ :",
"nolinkstoimage": "بألگە یلی کە ڤە ئی فایل لینک دائنە نی.",
"sharedupload-desc-here": "ئی فایل ز $1 ئوٙمائە ڤ شاید د پۉرۉجە یل دیە مورد ئیستفادھ ڤابین.\nتوٙضیحتل ری [$2 بألگە تۉضیح فایل] دوٙمین نیشۉ ڤابیە .",
"upload-disallowed-here": "ئیشا نیتأریت ئی فایلنە بینڤیسیت",
"rcfilters-filter-major-description": "Labojumi, kas nav atzīmēti kā maznozīmīgi.",
"rcfilters-filtergroup-watchlist": "Uzraugāmie raksti",
"rcfilters-filter-watchlist-watchednew-description": "Izmaiņas uzraugāmajās lapās, kuras nav apmeklētas kopš izmaiņu veikšanas.",
+ "rcfilters-filter-watchlist-notwatched-label": "Nav uzraugāmo rakstu sarakstā",
"rcfilters-filter-watchlistactivity-unseen-label": "Neapskatītas izmaiņas",
"rcfilters-filter-watchlistactivity-unseen-description": "Izmaiņas lapās, kuras nav apmeklētas kopš izmaiņu veikšanas.",
"rcfilters-filter-watchlistactivity-seen-label": "Apskatītas izmaiņas",
"apihelp": "API palīdzība",
"apihelp-no-such-module": "Modulis \"$1\" nav atrasts.",
"apisandbox": "API smilškaste",
- "apisandbox-api-disabled": "API ir atspējots šajā tīmekļa vietnē.",
"apisandbox-submit": "Izveidot pieprasījumu",
"apisandbox-reset": "Notīrīt",
"apisandbox-retry": "Mēģināt vēlreiz",
"wlheader-enotif": "E-pasta paziņojumi ir ieslēgti.",
"wlheader-showupdated": "Lapas, kas ir tikušas izmainītas, kopš pēdējoreiz skatījies tās, tiek rādītas <strong>trekninātā</strong> rakstā.",
"wlnote": "Zemāk {{PLURAL:$1|redzamas <strong>$1</strong> izmaiņas|redzama <strong>$1</strong> izmaiņa|redzamas <strong>$1</strong> izmaiņas}} {{PLURAL:$2|pēdējās <strong>$2</strong> stundās|pēdējā <strong>$2</strong> stundā|pēdējās <strong>$2</strong> stundās}} uz $3 $4.",
- "wlshowlast": "Rādīt pēdējās $1 stundas $2 dienas",
"watchlist-hide": "Slēpt",
"watchlist-submit": "Rādīt",
"wlshowhideminor": "maznozīmīgos labojumus",
"month": "No mēneša (un senāki):",
"year": "No gada (un senāki):",
"date": "No datuma (un senāki):",
- "sp-contributions-newbies": "Rādīt jauno lietotāju devumu",
- "sp-contributions-newbies-sub": "Jaunie lietotāji",
- "sp-contributions-newbies-title": "Jauno dalībnieku devums",
"sp-contributions-blocklog": "bloķēšanas reģistrs",
"sp-contributions-suppresslog": "cenzēja {{GENDER:$1|dalībnieka|dalībnieces}} devumu",
"sp-contributions-deleted": "dzēstais {{GENDER:$1|dalībnieka|dalībnieces}} devums",
"newimages-legend": "Filtrs",
"newimages-label": "Faila nosaukums (vai tā daļa):",
"newimages-user": "IP adrese vai lietotājvārds",
- "newimages-newbies": "Rādīt tikai jaunu dalībnieku devumu",
"newimages-showbots": "Parādīt botu augšupielādētos failus",
"newimages-hidepatrolled": "Paslēpt pārbaudītās augšupielādes",
"newimages-mediatype": "Medija veids:",
"imgmultigoto": "Iet uz lapu $1",
"img-lang-default": "(noklusējuma valoda)",
"img-lang-go": "Aiziet",
- "ascending_abbrev": "pieaug.",
- "descending_abbrev": "dilst.",
"table_pager_next": "Nākamā lapa",
"table_pager_prev": "Iepriekšējā lapa",
"table_pager_first": "Pirmā lapa",
"wlheader-enotif": "*准報信。",
"wlheader-showupdated": "*易者'''粗體'''。",
"wlnote": "近<b>$2</b>時有$1者易。",
- "wlshowlast": "凡最近$1小時、$2日所更易皆示之",
"watchlist-options": "哨項",
"watching": "出陣…",
"unwatching": "收兵…",
"uctop": "至頂",
"month": "且不越",
"year": "年不越",
- "sp-contributions-newbies": "惟列新進",
- "sp-contributions-newbies-sub": "予新進",
- "sp-contributions-newbies-title": "新進之功績",
"sp-contributions-blocklog": "誌禁",
"sp-contributions-deleted": "已刪之積",
"sp-contributions-uploads": "貢",
"imgmultipagenext": "次頁→",
"imgmultigo": "往",
"imgmultigoto": "往頁$1",
- "ascending_abbrev": "升冪",
- "descending_abbrev": "降冪",
"table_pager_next": "次頁",
"table_pager_prev": "前頁",
"table_pager_first": "首頁",
"watchlist-details": "{{PLURAL:$1|$1 butʼkʼa|$1 butʼkʼa}}, skani gotxozu listʼes ren, ama oğarğaluşi butʼkʼapes va ren",
"wlheader-showupdated": "Sayfaları son ziyaretinizden beri değişen sayfalar '''kalın''' gösterilmiştir.",
"wlnote": "$3 saat $4 itibariyle son {{PLURAL:$2|bir saatte|'''$2''' saatte}} yapılan {{PLURAL:$1|son değişiklik|son '''$1''' değişiklik}} aşağıdadır.",
- "wlshowlast": "Son $1 saati $2 ndğa göster",
"watchlist-options": "Gotxozu listʼeşi tercihepe",
"watching": "i3ʼkʼedinen...",
"unwatching": "var i3ʼkʼedinen...",
"uctop": "dudi",
"month": "Tuta:",
"year": "3ʼana:",
- "sp-contributions-newbies": "Xvala ağani maxmarepeşi meşvelape ko3ʼiri",
"sp-contributions-blocklog": "Bloğiş kʼayitʼi",
"sp-contributions-uploads": "yüklenenler",
"sp-contributions-logs": "Kʼayitʼepe",
"wlheader-enotif": "ई-पत्र सूचना लागू अछि।",
"wlheader-showupdated": "पन्ना सभ जे अहाँक एतए अन्तिम बेर अएलाक बाद बदलल अछि तकर सूची देल अछि '''गाढ़''' मे",
"wlnote": "नीचाँ {{PLURAL:$1|is the last change|are the last '''$1''' changes}} अन्तिम {{PLURAL:$2|hour|'''$2''' hours}} $3, $4 जेना।",
- "wlshowlast": "देखाउ अन्तिम $1 घण्टा $2 दिन",
"watchlist-hide": "नुकाबी",
"watchlist-submit": "देखाबी",
"wlshowtime": "समय श्रेणी देखाबी:",
"month": "मास सँ (आ पहिने)",
"year": "ई साल (आ पहिने)",
"date": "माससँ (आ पहिने)",
- "sp-contributions-newbies": "मात्र नव खाताक योगदान देखाबी",
- "sp-contributions-newbies-sub": "नब प्रयोक्ताकऽ लेल",
- "sp-contributions-newbies-title": "नब प्रयोक्ताकऽ योगदान",
"sp-contributions-blocklog": "प्रतिबन्धित लौग",
"sp-contributions-suppresslog": "{{GENDER:$1|प्रयोगकर्ता}} योगदान दबाबी",
"sp-contributions-deleted": "{{GENDER:$1|प्रयोगकर्ता}}क मेटाएल योगदान",
"newimages-legend": "चलनी",
"newimages-label": "संचिका नाम (वा ओकर अंश):",
"newimages-user": "अनिकेत संकेत वा प्रयोक्तानाम:",
- "newimages-newbies": "मात्र नव खाताक योगदान देखाबी",
"newimages-showbots": "बोटद्वारा कएल गेल अपलोड देखाऊ",
"newimages-mediatype": "मीडिया प्रकार:",
"noimages": "किछु देखबा योग्य नै |",
"img-lang-default": "(डिफल्ट भाषा)",
"img-lang-info": "ई चित्र को $1. $2 में ढालु",
"img-lang-go": "जाए",
- "ascending_abbrev": "asc",
- "descending_abbrev": "जानकारी",
"table_pager_next": "अगला पृष्ठ",
"table_pager_prev": "पहिलुका पृष्ठ",
"table_pager_first": "पहिल पृष्ठ",
"watch": "Pantau",
"unwatch": "Batalna pantauan",
"watchlist-details": "Ana {{PLURAL:$1|$1 kaca|$1 kaca}} nang daftar pangawasané Rika, ora klebu kaca-kaca dhiskusiné.",
- "wlshowlast": "Tidokna $1 jam $2 dina pungkasan",
"watchlist-options": "Opsi daftar pangawasan",
"delete-confirm": "Busek \"$1\"",
"delete-legend": "Busek",
"uctop": "siki",
"month": "Sekang sasi (lan sadurungé):",
"year": "Sekang taun (lan sadurunge):",
- "sp-contributions-newbies": "Tidokna kontribusine panganggo anyar thok",
"sp-contributions-blocklog": "log pamblokiran",
"sp-contributions-uploads": "unggahan",
"sp-contributions-logs": "log",
"wlheader-enotif": "Электрононь сёрма вельде пачфнема нолдаф тевс.",
"wlheader-showupdated": "Лопат конань полафтозь тонь мекольце сувсемадот меле няфтевсть '''эчке тяшкса'''.",
"wlnote": "Ала {{PLURAL:$1|мекольце полафнема|'''$1''' мекольце полафнемат}} ётай {{PLURAL:$2| ойста (часста)|'''$2''' ойста (часста)}}.",
- "wlshowlast": "Няфтемс мекольце $1 ойхть (част) $2 шит",
"watchlist-options": "Мельгеваномать латцемасна",
"watching": "Ванома...",
"unwatching": "Аф ванома...",
"uctop": "прянь",
"month": "Ковста (ди сядынголе):",
"year": "Кизоста (ди сядынголе):",
- "sp-contributions-newbies": "Няфтемс аньцек од сёрматфтоматнень путкссна",
- "sp-contributions-newbies-sub": "Од сёрматфтомаста",
- "sp-contributions-newbies-title": "Тиить путксонза од сёрматфтоматненди",
"sp-contributions-blocklog": "Сёлгомань лувомась",
"sp-contributions-deleted": "нардаф тиинь путксонза",
"sp-contributions-uploads": "Тонгодемат",
"imgmultipagenext": "сай лопась →",
"imgmultigo": "Аре!",
"imgmultigoto": "Архт $1 лопас",
- "ascending_abbrev": "касом.",
- "descending_abbrev": "тум.",
"table_pager_next": "Сай лопа",
"table_pager_prev": "Сядынгольдень лопа",
"table_pager_first": "Васенце лопа",
"apihelp-no-such-module": "Tsy hita ny joro \"$1\".",
"apisandbox": "Kianjam-pasika API",
"apisandbox-jsonly": "Ilaina amin'ny fampiasana kianjam-pasika API ny JavaScript.",
- "apisandbox-api-disabled": "Tsy alefa amin'ity tranonkala ity ny API.",
"apisandbox-submit": "Hanao hataka",
"apisandbox-reset": "Diovina",
"apisandbox-retry": "Andramana indray",
"wlheader-enotif": "Alefa ny fampilazana amin'ny mailaka.",
"wlheader-showupdated": "Aseho '''sorabaventy''' ny pejy niova taorian'ny famangianao azy farany.",
"wlnote": "Eo ambany dia ahitana ny {{PLURAL:$1|fiovana farany indrindra|ny fiovana ''$1'' farany}} natao tanatin'ny adin'ny {{PLURAL:$2|iray|'''$2'''}}, nanomboka ny $3, $4.",
- "wlshowlast": "Haneho ny $1 ora farany, ny $2 andro farany na",
"watchlist-hide": "Afenina",
"watchlist-submit": "Aseho",
"wlshowtime": "Vanim-potoana aseho:",
"uctop": "ankehitriny",
"month": "Tamin'ny volana (sy teo aloha) :",
"year": "Tamin'ny taona (sy teo aloha) :",
- "sp-contributions-newbies": "Haneho ny fandraisan'anjaran'ireo mpikambana vaovao ihany",
- "sp-contributions-newbies-sub": "Ao amin'ny kaonty vaovao",
- "sp-contributions-newbies-title": "Fandraisan'anjara ao amin'ny kaonty vaovao",
"sp-contributions-blocklog": "Laogim-panakanana",
"sp-contributions-suppresslog": "Fandraisan'anjara voafafa",
"sp-contributions-deleted": "fandraisan'anjara voafafa",
"img-lang-default": "(fiteny tsipalotra)",
"img-lang-info": "Haneho ity sary ity ho $1. $2",
"img-lang-go": "Alefa",
- "ascending_abbrev": "mihak.",
- "descending_abbrev": "mihid.",
"table_pager_next": "Pejy manaraka",
"table_pager_prev": "Pejy nialoha",
"table_pager_first": "Pejy voalohany",
"unwatch": "Эскерыман огыл",
"unwatchthispage": "Эскерымым чараш",
"watchlist-details": "Эскерымаш лӱмерыштет $1 {{PLURAL:$1|лаштык}}, каҥашымаш лаштык-влакым шотлыде",
- "wlshowlast": "Пытартыш $1 шагат $2 кечылан ончыкташ",
"wlshowhidecategorization": "лаштык категоризацийым",
"watchlist-options": "Эскерыме лӱмерын келыштарымаш",
"watching": "Эскерымаш лӱмерыш ешарымаш...",
"uctop": "пытартыш",
"month": "Могай тылзе гыч тӱҥалаш?",
"year": "Могай ий гыч тӱҥалаш?",
- "sp-contributions-newbies": "У пайдалнышын гына пашам ончыкташ",
"sp-contributions-blocklog": "блокирований журнал",
"sp-contributions-uploads": "пуртымаш-влак",
"sp-contributions-logs": "Журнал-влак",
"NoiX180"
]
},
- "tog-underline": "Garisbawahi tautan:",
+ "tog-underline": "Garih bawah pautan:",
"tog-hideminor": "Suruakkan suntiangan ketek di parubahan baru",
"tog-hidepatrolled": "Suruakkan suntiangan nan lah dipatroli di parubahan tabaru",
"tog-newpageshidepatrolled": "Suruakkan laman nan lah dipatroli dari daftar laman baru",
"tog-hidecategorization": "Suruakkan pangkategorian laman",
"tog-extendwatchlist": "Kambangan daftar pantau untuak mancaliak kasado parubahan, bukan nan baru se",
- "tog-usenewrc": "Kalompokkan suntiangan di tampilan parubahan paliang baru jo daftar pantauan badasarkan halaman",
- "tog-numberheadings": "Agiah nomor judul sacaro otomatis",
+ "tog-usenewrc": "Kalompokkan badasarkan laman pado parubahan paliang baru jo daftar pantauan",
+ "tog-numberheadings": "Agiah nomor judul sacaro otomatih",
"tog-editondblclick": "Suntiang laman jo klik duo kali (paralu JavaScript)",
- "tog-editsectiononrightclick": "Aktifkan bagian panyuntiangan dengan caro mangklik kanan pado judul bagian",
- "tog-watchcreations": "Tambahan laman nan den buek jo gambar nan den unggah ka daftar pantau",
- "tog-watchdefault": "Tambahan laman jo gambar nan den suntiang ka daftar pantau",
- "tog-watchmoves": "Tambahan laman jo gambar nan den pindah ka daftar pantau",
+ "tog-editsectiononrightclick": "Aktipan bagian panyuntiangan jo mangklik kanan pado judul bagian",
+ "tog-watchcreations": "Tambahan laman nan den buek jo berkas nan den unggah ka daftar pantau",
+ "tog-watchdefault": "Tambahan laman jo berkas nan den suntiang ka daftar pantau",
+ "tog-watchmoves": "Tambahan laman jo berkas nan den pindah ka daftar pantau",
"tog-watchdeletion": "Tambahan laman jo gambar nan den hapuih ka daftar pantau",
"tog-watchuploads": "Tambahan bakeh baru nan ambo unggah ka daftar pantauan",
- "tog-watchrollback": "Tambahan halaman nan pernah ambo baliakan ke dalam daftar pantauan ambo",
+ "tog-watchrollback": "Tambahan laman nan pernah ambo baliakan ka dalam daftar pantauan ambo",
"tog-minordefault": "Tandoi kasado suntiangan sabagai suntiangan ketek sacaro baku",
- "tog-previewontop": "Tunjuakan pratonton sabalun kotak suntiang",
- "tog-previewonfirst": "Tunjuakan pratonton pado suntiangan patamo",
- "tog-enotifwatchlistpages": "Kiriman surel, kok laman atau gambar pado daftar pantau Ambo barubah",
+ "tog-previewontop": "Caliak pratinjau sabalun kotak suntiang",
+ "tog-previewonfirst": "Caliak pratinjau pado suntiangan patamo",
+ "tog-enotifwatchlistpages": "Kiriman surel bilo laman atau berkas pado daftar pantau Ambo barubah",
"tog-enotifusertalkpages": "Kiriman surel, koq laman maota Ambo barubah",
- "tog-enotifminoredits": "Kirimkan surel juo untuk saketek suntingan pado laman jo gambar",
+ "tog-enotifminoredits": "Kiriman surel untuak suntiangan ketek dari laman jo berkas",
"tog-enotifrevealaddr": "Tunjuakan alamaik surel ambo pado pambaritauan surel",
"tog-shownumberswatching": "Tunjuakan jumlah pamantau",
"tog-oldsig": "Tando tangan kini:",
- "tog-fancysig": "Jadikan tando tangan manjadi teks wiki (indak jo tautan otomatis)",
- "tog-uselivepreview": "Gunoan pratonton langsuang",
+ "tog-fancysig": "Jadikan tando tangan manjadi teks wiki (indak jo pautan otomatih)",
+ "tog-uselivepreview": "Gunoan pratinjau langsuang",
"tog-forceeditsummary": "Ingekan ambo bilo kotak ikhtisar suntiangan kosong",
"tog-watchlisthideown": "Suruakan suntiangan surang pado daftar pantau",
"tog-watchlisthidebots": "Suruakan suntiangan bot pado daftar pantau",
"tog-diffonly": "Jan tampilan isi laman di bawah pabedoan suntiangan",
"tog-showhiddencats": "Tunjuakan kategori tasuruak",
"tog-norollbackdiff": "Jan tampilan pabedoan sasudah malakukan pangambalian",
- "tog-useeditwarning": "Ingekan denai kok denai maninggakan laman suntiang sabalun manyimpan parubahan",
+ "tog-useeditwarning": "Ingekan denai jikok maninggakan laman suntiang sabalun manyimpan parubahan",
"tog-prefershttps": "Selalu gunokan koneksi aman katiko masuak log",
"underline-always": "Taruih",
"underline-never": "Indak pernah",
"listingcontinuesabbrev": "samb.",
"index-category": "Laman nan diindeks",
"noindex-category": "Laman nan indak diindeks",
- "broken-file-category": "Laman jo gamba rusak",
+ "broken-file-category": "Laman jo berkas rusak",
"about": "Perihal",
"article": "Artikel",
"newwindow": "(bukak di jandela baru)",
- "cancel": "Batalkan",
+ "cancel": "Batalan",
"moredotdotdot": "Lainnyo...",
"morenotlisted": "Daftar ko mungkin indak langkok.",
"mypage": "Laman",
"databaseerror": "Kasalahan basis data",
"databaseerror-function": "Fungsi: $1",
"databaseerror-error": "تېروتنه: $1",
- "transaction-duration-limit-exceeded": "Untuak mancagah panundoan replikasi yang tinggi, pangiriman ko dibatalan karano lamo panulihan $1 malabiahi bateh $2.\nJiko sanak nio maubah banyak hal dalam sakali ubah, cubo lakuan dalam operasi yang labiah ketek.",
+ "transaction-duration-limit-exceeded": "Untuak mancagah panundoan replikasi nan tinggi, pangiriman ko dibatalan karano lamo panulihan $1 malabiahi bateh $2.\nJiko sanak nio maubah banyak hal dalam sakali ubah, cubo lakuan dalam operasi nan labiah ketek.",
"laggedslavemode": "Paringatan: Laman mungkin indak barisi parubahan tabaru.",
"readonly": "Basis data dikunci",
"enterlockreason": "Masuakkan alasan panguncian, tamasuak pakiraan bilo kunci akan dibuka",
"missing-article": "Basisdata indak dapek manamukan teks dari laman nan saharuihnyo ado, yaitu \"$1\" $2.\n\nHal ko biasonyo disababkan dek pautan usang ka pabaikkan tadahulu laman nan alah dihapuih.\n\nJikok bukan ko panyababnyo, Sanak mungkin alah manamukan sabuah bug dalam pakakeh lunak.\nSilakan laporkan hal iko ka [[Special:ListUsers/sysop|pangurus]], sarato manyabuikkan alamaik URL nan dituju.",
"missingarticle-rev": "(revisi#: $1)",
"missingarticle-diff": "(Bedo: $1, $2)",
- "readonly_lag": "Basis data alah dikunci otomatis salagi basis data sakunder malakukan sinkronisasi jo basis data utamo",
+ "readonly_lag": "Basis data alah dikunci otomatih sangkek basis data sakunder malakukan sinkronisasi jo basis data utamo",
"nonwrite-api-promise-error": "Kapalo HTTP 'Promise-Non-Write-API-Action' alah dikirim tapi permintaan dibuek untuak model panulihan API.",
"internalerror": "Kasalahan internal",
"internalerror_info": "Kasalahan internal: $1",
"internalerror-fatal-exception": "Pangacualian fatal dalam mangetik \"$1\"",
"filecopyerror": "Indak dapek manyalin berkas \"$1\" ke \"$2\".",
"filerenameerror": "Indak dapek maubah namo berkas \"$1\" manjadi \"$2\".",
- "filedeleteerror": "Indak dapek mahapuih berkas \"$1\".",
+ "filedeleteerror": "Indak dapek mangapuih berkas \"$1\".",
"directorycreateerror": "Indak dapek mambuek direktori \"$1\".",
"directoryreadonlyerror": "Direktori \"$1\" hanyo-dibaco.",
"directorynotreadableerror": "Direktori \"$1\" indak bisa dibaco.",
"delete-hook-aborted": "Pengapusan batal jo hook.\nIndak ado keterangan.",
"badtitle": "Judul indak sah",
"badtitletext": "Pamintaan judul laman indak sah, kosong, atau antarbaso atau antarwiki nan salah sambuang. Mungkin juo ado kandungan karakter nan indak buliah digunoan untuak judul.",
- "title-invalid-empty": "Judul halaman yang dimintak kosong atau hanyo barisi namo sabuah ruang namo.",
- "title-invalid-utf8": "Judul halaman yang dimintak barisi rangkaian UTF-8 yang indak sah.",
- "title-invalid-interwiki": "Judul laman yang dimintak barisi pranala diantaro wiki yang indak bisa digunoan dalam judul.",
- "title-invalid-talk-namespace": "Judul laman yang dimintak marujuak ka halaman pambicaroan yang indak dapek tasadio.",
- "title-invalid-characters": "Judul laman yang dimintak barisi karakter yang indak sah:\"$1\".",
- "title-invalid-relative": "Judul manganduang alaman relatif. Halaman relatif (./, ../) indak sah, karano dapek mangalami kagagalan katiko ditangani dek paramban pangguno.",
- "title-invalid-magic-tilde": "Judul halaman manganduang rangkaian tilda yang indak sah (<nowiki>~~~</nowiki>).",
- "title-invalid-too-long": "Judul halaman panjang bana. Harusnyo indak buliah labiah dari $1 {{PLURAL:$1|byte|bytes}} di pangodean UTF-8.",
- "title-invalid-leading-colon": "Judul laman yang dimintak dimulai dek tando titiak duo tu indak sah.",
+ "title-invalid-empty": "Judul laman nan dimintak kosong atau hanyo barisi namo sabuah ruang namo.",
+ "title-invalid-utf8": "Judul laman nan dimintak barisi rangkaian UTF-8 nan indak sah.",
+ "title-invalid-interwiki": "Judul laman nan dimintak barisi pautan di antaro wiki nan indak bisa digunoan dalam judul.",
+ "title-invalid-talk-namespace": "Judul laman nan dimintak marujuak ka laman pambicaroan nan indak tasadio.",
+ "title-invalid-characters": "Judul laman nan dimintak barisi karakter nan indak sah:\"$1\".",
+ "title-invalid-relative": "Judul manganduang laman relatif. Laman relatif (./, ../) indak sah, karano dapek mangalami kagagalan samaso ditangani dek paramban pangguno.",
+ "title-invalid-magic-tilde": "Judul laman manganduang rangkaian tilda nan indak sah (<nowiki>~~~</nowiki>).",
+ "title-invalid-too-long": "Judul laman panjang bana. Harusnyo indak buliah labiah dari $1 {{PLURAL:$1|bita}} di pangodean UTF-8.",
+ "title-invalid-leading-colon": "Judul laman nan dimintak dimulai dek tando titiak duo tu indak sah.",
"perfcached": "Data barikuik ko diambiak dari singgahan dan mungkin indak data nan baru. Nan tabanyak dari {{PLURAL:$1|$1 hasilnyo}} ado di singgahan.",
"perfcachedts": "Data barikuik ko singgahan, dan tarakhia dipabarui tanggal $1. Nan tabanyak dari tanggal {{PLURAL:$1|$1}}, hasilnyo ado di singgahan.",
"querypage-no-updates": "Pamutakhiran dari laman ko sadang dimatian. Data nan ado di siko kini ko indak akan dimuaik ulang.",
"viewyourtext": "Sanak dapek mancaliak jo manyalin sumber <strong>suntiangan sanak</strong> pado laman ko",
"protectedinterface": "Laman ko baisi teks antarmuko untuak digunoan dek parangkaik lunak di wiki ko sajo, dan alah dikunci untuak maindaan kasalahan. \nUntuak manambah atau maubah tajamahan di kasado wiki, harap gunoan [https://translatewiki.net/ translatewiki.net], yaitu proyek palokalan MediaWiki.",
"editinginterface": "'''Paringatan:''' Sanak manyuntiang laman nan digunoan untuak manyadiokan teks antarmuko untuak parangkaik lunak.\nParubahan teks ko akan mampangaruhi tampilan pado antarmuko pangguno untuak pangguno lain.\nUntuak tajamahan, harap gunoan [https://translatewiki.net/wiki/Main_Page?setlang=min translatewiki.net], proyek palokalan MediaWiki.",
- "translateinterface": "Untuak manambah atau maubah sadolah wiki, mohon gunoan [https://translatewiki.net/ translatewiki.net], proyek palokalan MediaWiki.",
- "cascadeprotected": "Laman ko dilinduangi dari panyuntiangan karano ditransklusi pado {{PLURAL:$1|halaman nan}} dilinduangi dan opsi \"runtun\"-nyo diiduikan:\n$2",
+ "translateinterface": "Untuak manambah atau maubah kasado wiki, mohon gunoan [https://translatewiki.net/ translatewiki.net], proyek palokalan MediaWiki.",
+ "cascadeprotected": "Laman ko dilinduangi dari panyuntiangan karano ditransklusi pado {{PLURAL:$1|laman nan}} dilinduangi dan opsi \"runtun\"-nyo diiduikan:\n$2",
"namespaceprotected": "Sanak indak mampunyoi hak akses untuak manyuntiang laman di ruang namo '''$1'''.",
"customcssprotected": "Sanak indak mampunyoi izin untuak maubah laman CSS iko, karano manganduang pangaturan pribadi pangguno lain.",
"customjsonprotected": "Sanak indak mampunyoi izin untuak maubah laman JSON ko karano barisi pangaturan pribadi pangguno lain.",
"customjsprotected": "Sanak ndak mampunyo izin untuak maubah laman JavaScript iko, karano manganduang pangaturan pribadi pangguno lain.",
- "sitecssprotected": "Sanak indak mampunyoi izin untuak maubah halaman CSS ko karano bisa mampangaruhi sadolah pangunjuang.",
- "sitejsonprotected": "Sanak indak mampunyoi izin untuak maubah halaman JSON ko karano mampangaruhi sadolah pangunjuang.",
- "sitejsprotected": "Sanak indak mampunyoi izin untuak maubah halaman JavaScript karano mampangaruhi sadolah pangunjuang.",
- "mycustomcssprotected": "Sanak indak mampunyoi izin untuak maubah halaman CSS ko.",
- "mycustomjsonprotected": "Sanak indak mampunyoi izin untuak manyuntiang halaman JSON ko.",
- "mycustomjsprotected": "Sanak indak mampunyoi izin untuak manyuntiang halaman JavaScript ko.",
+ "sitecssprotected": "Sanak indak mampunyoi izin untuak maubah laman CSS ko karano bisa mampangaruhi kasado pangunjuang.",
+ "sitejsonprotected": "Sanak indak mampunyoi izin untuak maubah laman JSON ko karano mampangaruhi kasado pangunjuang.",
+ "sitejsprotected": "Sanak indak mampunyoi izin untuak maubah laman JavaScript karano mampangaruhi kasado pangunjuang.",
+ "mycustomcssprotected": "Sanak indak mampunyoi izin untuak maubah laman CSS ko.",
+ "mycustomjsonprotected": "Sanak indak mampunyoi izin untuak manyuntiang laman JSON ko.",
+ "mycustomjsprotected": "Sanak indak mampunyoi izin untuak manyuntiang laman JavaScript ko.",
"myprivateinfoprotected": "Sanak indak mampunyoi izin untuak manyuntiang informasi pribadi Sanak.",
"mypreferencesprotected": "Sanak indak mampunyoi izin untuak manyuntiang preferensi Sanak.",
"ns-specialprotected": "Laman istimewa indak dapek disuntiang.",
"invalidtitle-unknownnamespace": "Judul nan tak sah jo nomor ruang namo indak diketahui $1 dan teks \"$2\"",
"exception-nologin": "Indak masuak log",
"exception-nologin-text": "Untuak masuak ka dalam laman atau maambiak tindakan ko, mohon masuak log.",
- "exception-nologin-text-manual": "Silakan $1 untuak mangakses halaman atau tindakan ko.",
+ "exception-nologin-text-manual": "Silakan $1 untuak mangakses laman atau tindakan ko.",
"virus-badscanner": "Kasalahan konfigurasi: pamindai virus indak dikenal: ''$1''",
"virus-scanfailed": "Pamindaian gagal (kode $1)",
"virus-unknownscanner": "Antivirus indak dikenal:",
"userlogin-helplink2": "Bantuan masuak log",
"userlogin-loggedin": "Sanak alah masuak sabagai {{GENDER:$1|$1}}. Gunoan formulir di bawah untuak masuak sabagai pangguno lain.",
"userlogin-reauth": "Sanak harus masuak baliak untuk mambuktian Sanak adolah {{GENDER:$1|$1}}.",
- "userlogin-createanother": "Buek akun yang lain",
+ "userlogin-createanother": "Buek akun nan lain",
"createacct-emailrequired": "Alamaik surel",
"createacct-emailoptional": "Alamaik surel (opsional)",
"createacct-email-ph": "Masuakan alamaik surel Sanak",
"nocookiesnew": "Akun pangguno alah dibuek, tapi Sanak alun masuak log.\n{{SITENAME}} manggunokan cookies untuak log pangguno.\nPangaturan cookie Sanak nonaktif.\nAktifan dulu, sasudah tu baru masuak log jo namo pangguno dan kato sandi baru Sanak.",
"nocookieslogin": "{{SITENAME}} manggunokan cookies untuak log pangguno.\nPangaturan cookie paramban Sanak nonaktif.\nAktifan dulu dan cubo baliak.",
"nocookiesfornew": "Akun pangguno indak dibuek karano kami indak dapek mamastian sumbernyo.\nPastian Sanak alah mangaktifan cokies, lalu muek ulang laman ko dan cubo baliak.",
- "createacct-loginerror": "Akun alah salasai dibuek tapi Sanak indak dapek langsuang masuak sacaro otomatis. Mohon taruihan ka [[Special:UserLogin|manual login]].",
+ "createacct-loginerror": "Akun alah salasai dibuek tapi Sanak alun dapek langsuang masuak sacaro otomatih. Mohon manuju ka [[Special:UserLogin|manual login]].",
"noname": "Namo pangguno nan Sanak masuakan indak sah.",
"loginsuccesstitle": "Alah masuak log",
"loginsuccess": "'''Sanak kini lah masuak log di {{SITENAME}} sabagai \"$1\".'''",
"wrongpasswordempty": "Sanak indak mamasuakan kato sandi. Cubolah baliak.",
"passwordtooshort": "Kato sandi paliang indak harus tadiri dari {{PLURAL:$1|$1 karakter}}.",
"passwordtoolong": "Kato sandi indak buliah labiah dari {{PLURAL:$1|1 character|$1 characters}}.",
- "passwordtoopopular": "Kato sandi yang umum indak dapek digunoan. Mohon piliah kato sandi yang labiah sulik untuak ditakok.",
- "passwordinlargeblacklist": "Kato sandi yang dimasuakan adolah kato sandi yang umum. Mohon gunoan kato sandi yang labiah unik.",
+ "passwordtoopopular": "Kato sandi nan umum indak dapek digunoan. Mohon piliah kato sandi nan labiah sulik untuak ditakok.",
+ "passwordinlargeblacklist": "Kato sandi nan dimasuakan adolah kato sandi nan umum. Mohon gunoan kato sandi nan labiah unik.",
"password-name-match": "Kato sandi Sanak harus babedo dari namo pangguno Sanak.",
"password-login-forbidden": "Panggunoan namo pangguno dan sandi ko alah dilarang.",
"mailmypassword": "Atua kato sandi nan baru",
"passwordremindertitle": "Kato sandi samantaro untuak {{SITENAME}}",
- "passwordremindertext": "Urang lain (dari alamaik IP $1) mamintak kato sandi nan baru untuak {{SITENAME}} ($4). Kato sandi samantaro untuak pangguno \"$2\" alah dibuek dan diatua untuak \"$3\". Jikok iko kandak Sanak, mohon log masuak dan atua kato sandi nan baru kini. Kato sandi samantaro Sanak akan abih maso dalam wukatu {{PLURAL:$5|satu hari|$5 hari}}.\n\nKok urang lain nan mangajuan permintaan ko, atau kok Sanak taingek jo kato sandi nan lamo sainggo Sanak indak nio maubahnyo, padiakan sajo pasan ko dan taruihlah mamakai kato sandi nan lamo.",
+ "passwordremindertext": "Urang lain (dari alamaik IP $1) mamintak kato sandi nan baru untuak {{SITENAME}} ($4). Kato sandi samantaro untuak pangguno \"$2\" alah dibuek dan diatua untuak \"$3\". Jikok iko kandak Sanak, mohon log masuak dan atua kato sandi nan baru kini. Kato sandi samantaro Sanak akan abih maso dalam wukatu {{PLURAL:$5|$5 hari}}.\n\nKok urang lain nan mangajuan permintaan ko, atau kok Sanak taingek jo kato sandi nan lamo sainggo Sanak indak nio maubahnyo, padiakan sajo pasan ko dan taruihlah mamakai kato sandi nan lamo.",
"noemail": "Indak ado alamaik surel nan tacatat untuak pangguno \"$1\".",
"noemailcreate": "Sanak paralu manyadiokan alamaik surel nan sah",
"passwordsent": "Kato sandi baru alah dikiriman ka alamaik surel nan didaftakan untuak \"$1\".\nSilakan masuak log baliak sasudah manarimo surel tasabuik.",
"eauthentsent": "Surek elektronik untuak mangkonfirmasi alah dikirim ka alamaik ko. Sabalun surek-surek lain dikirim, mohon untuak maikuik'an patunjuak nan ado di surek tasabuik untuak mangkonfirmasi baso Sanaklah nan batua punyo akun tu.",
"throttled-mailpassword": "Suatu pangingek kato sandi alah dikiriman dalam {{PLURAL:$1|$1 jam}} tarakhia.\nUntuak manghindari panyalahgunoan, hanyo ciek kato sandi nan ka dikirim satiok {{PLURAL:$1|$1 jam}}.",
"mailerror": "Kasalahan dalam mangiriman surel: $1",
- "acct_creation_throttle_hit": "Ado pangunjuang wiki nan mamakai alamaik IP sanak ko nan alah mambuek {{PLURAL:$1|1 akun|banyak akun}} dalam $2 taakhia, bateh minimum untuak wukatu ko. Pangujuang nan mamakai alamaik IP ko indak bisa mambuek akun baru untuak wukatu ko.",
+ "acct_creation_throttle_hit": "Ado pangunjuang wiki nan mamakai alamaik IP sanak ko nan alah mambuek {{PLURAL:$1|1 akun|banyak akun}} dalam $2 taakhia, bateh minimum untuak wakatu ko. Pangujuang nan mamakai alamaik IP ko indak dapek mambuek akun baru samantaro.",
"emailauthenticated": "Alamaik surel Sanak alah dikonfirmasi pado $3, $2.",
"emailnotauthenticated": "Alamaik surel Sanak alun dikonfirmasi. Indak ado surel nan bisa dikirim untuak pakakeh ko.",
- "noemailprefs": "Sanak harus mamasuakan alamaik surel di pangaturan Sanak untuak dapek manggunoan fitur-fitur ko.",
+ "noemailprefs": "Sanak haruih mamasuakan alamaik surel di Pangaturan bia dapek manggunoan fitua-fitua ko.",
"emailconfirmlink": "Konfirmasi alamaik surel Sanak",
"invalidemailaddress": "Alamaik surel iko indak dapek ditarimo dek formatnyo indak sasuai.\nHarap masuakan alamaik surel dalam format nan bana atau kosoangan isian tasabuik.",
"cannotchangeemail": "Alamaik surel Sanak indak bisa diubah di wiki ko.",
"changepassword-throttled": "Sanak alah acok bana mancubo masuak log. Mohon tunggu $1 sabalun mancubo baliak.",
"botpasswords": "Kato sandi bot",
"botpasswords-disabled": "Kato sandi bot indak diaktifan.",
- "botpasswords-no-central-id": "Untuak manggunoan kato sandi bot, Sanak harus masuak log ka akun yang alah disentralisasi.",
+ "botpasswords-no-central-id": "Untuak manggunoan kato sandi bot, Sanak harus masuak log ka akun nan alah disentralisasi.",
"botpasswords-existing": "Kato sandi bot tasadio",
- "botpasswords-createnew": "Buek kato sandi bot yang baru",
- "botpasswords-editexisting": "Ubah kato sandi bot yang alah ado",
+ "botpasswords-createnew": "Buek kato sandi bot nan baru",
+ "botpasswords-editexisting": "Ubah kato sandi bot nan alah ado",
"botpasswords-label-needsreset": "(kato sandi paralu di atua ulang)",
"botpasswords-label-appid": "Namo bot:",
"botpasswords-label-create": "Buek",
"botpasswords-deleted-title": "Kato sandi bot dihapuih",
"botpasswords-deleted-body": "Kato sandi untuak bot \"$1\" dari {{GENDER:$2|user}} \"$2\" berhasil dihapuih.",
"botpasswords-restriction-failed": "Bateh dalam kato sandi mangahalangi masuak log ko.",
- "botpasswords-invalid-name": "Namo pangguno yang diaagiah indak manganduang pamisah kato sandi bot (\"$1\").",
+ "botpasswords-invalid-name": "Namo pangguno nan diagiah indak manganduang pamisah kato sandi bot (\"$1\").",
"botpasswords-not-exist": "Pangguno \"$1\" indak mampunyoi kato sandi bot banamo \"$2\".",
- "botpasswords-needs-reset": "Kato sandi untuak bot \"$2\" dari {{GENDER:$1|user}} \"$1\" harus di atur ulang.",
+ "botpasswords-needs-reset": "Kato sandi untuak bot \"$2\" dari {{GENDER:$1|user}} \"$1\" harus di atua ulang.",
"botpasswords-locked": "Sanak indak dapek masuak log jo kato sando bot karano akun Sanak dikunci.",
"resetpass_forbidden": "Kato sandi indak dapek dituka",
"resetpass_forbidden-reason": "Kato sandi indak dapek dituka:$1",
"resetpass-no-info": "Sanak harus masuak log untuak mangakses laman iko sacara langsuang.",
"resetpass-submit-loggedin": "Tuka kato sandi",
- "resetpass-submit-cancel": "Batalkan",
+ "resetpass-submit-cancel": "Batalan",
"resetpass-wrong-oldpass": "Kato sandi samantaro atau nan kini indak sah. Sanak mungkin alah mangganti kato sandi atau mamintak kato sandi samantaro.",
"resetpass-recycled": "Mohon ubah kato sandi Sanak jo nan lain dari kato sandi kini ko.",
- "resetpass-temp-emailed": "Sanak masuak log jo kode samantaro yang disurelan. Untuak manyalasaian masuak log, atur ulang kato sandi baru disiko:",
+ "resetpass-temp-emailed": "Sanak masuak log jo kode samantaro nan disurelkan. Untuak manyalasaian masuak log, atua ulang kato sandi baru di siko:",
"resetpass-temp-password": "Kato sandi samantaro:",
"resetpass-abort-generic": "Parubahan kato sandi alah dibatalan dek ekstensi.",
- "resetpass-expired": "Kato sandi sanak alah kadaluarsa. Mohon atur ulang kato sandi baru untuak masuak log.",
+ "resetpass-expired": "Kato sandi sanak alah kadaluarsa. Mohon atua ulang kato sandi baru untuak masuak log.",
"resetpass-expired-soft": "Kato sandi sanak alah kadaluarsa jo paralu diubah. Mohon piliah kato sandi baru, atau takan \"{{int:authprovider-resetpass-skip-label}}\" untuak maatur ulang di wakatu lain.",
"resetpass-validity": "Kato sandi Sanak indak sah:$1",
"resetpass-validity-soft": "Kato sandi sanak indak sah:$1\n\nMohon piliah kato sandi baru, atau takan \"{{int:authprovider-resetpass-skip-label}}\" untuak maubah di wakatu nan lain.",
"passwordreset-text-one": "Lengkapkan formulir ko untuak manuka baliak kato sandi Sanak.",
"passwordreset-text-many": "{{PLURAL:$1|Isi salah satu kotak di bawah ko untuak mandapekkan kato sandi samantaro malalui surel.}}",
"passwordreset-disabled": "Pangubahan kato sandi alah dimatian di wiki iko.",
- "passwordreset-emaildisabled": "Fitur surel alah dimatian pado wiki iko.",
+ "passwordreset-emaildisabled": "Fitua surel alah dimatian pado wiki ko.",
"passwordreset-username": "Namo pangguno:",
"passwordreset-domain": "Domain:",
"passwordreset-email": "Alamaik surel:",
"passwordreset-emailtext-user": "Sasaurang (mungkin Sanak, dari alamaik IP $1) mamintak parubahan kato sandi untuak {{SITENAME}} ($4).\n{{PLURAL:$3|Akun}} barikuik takaik jo alamaik surel ko:\n\n$2\n\n{{PLURAL:$3|Sandi samantaro}} barikuik akan habih masonyo dalam {{PLURAL:$5|$5 ari}}.\nSanak harus masuak dan mamiliah sandi baru. Jikok urang lain mambuek pamintaan ko atau jikok Sanak ingek sandi awal dan indak nio maubahnyo, Sanak dapek mangacuahkan pasan ko dan taruih manggunoan kato sandi lamo.",
"passwordreset-emailelement": "Namo pangguno: \n$1\n\nSandi samantaro: \n$2",
"passwordreset-emailsentemail": "Jiko alamaik surel ko bahubuangan jo akun Sanak, surel parubahan kato sandi akan dikirim.",
- "passwordreset-emailsentusername": "Jiko ado alamaik surel yang bahubuangan jo namo pangguno ko, surel untuak ma atur ulang kato sandi akan dikirim.",
+ "passwordreset-emailsentusername": "Jiko ado alamaik surel nan bahubuangan jo namo pangguno ko, surel untuak mangatua ulang kato sandi akan dikirim.",
"passwordreset-invalidemail": "Alamaik surel indak sah",
"passwordreset-nodata": "Namo pangguno ataupun alamai surel indak diaagiahan",
"changeemail": "Tuka atau hapuih alamaik surel.",
- "changeemail-header": "Langkoki formulir ko untuak maubah alamaik surel Sanak. Jiko nio mahapuih sadolah alamaik surel yang bahubuangan jo akun Sanak, kosongan alamaik surek katiko maisi formulir.",
+ "changeemail-header": "Langkoki formulir ko untuak maubah alamaik surel Sanak. Jiko nio mangapuih sado alah alamaik surel nan bahubuangan jo akun Sanak, kosongan alamaik surek samaso maisi formulir.",
"changeemail-no-info": "Sanak harus masuak log untuak mangakses laman ko.",
"changeemail-oldemail": "Alamat surel kini:",
"changeemail-newemail": "Alamat surel baru:",
- "changeemail-newemail-help": "Kolom ko harus dikosongan jiko Sanak nio mahapuih alamaik surel. Sanak indak dapek maatur ulang kato sandi yang talupo jo indak dapek manarimo surel dari wiki ko jiko alamaik surel dihapuih.",
+ "changeemail-newemail-help": "Kolom ko harus dikosongan jiko Sanak nio mangapuih alamaik surel. Sanak indak dapek maatua ulang kato sandi nan talupo jo indak dapek manarimo surel dari wiki ko jiko alamaik surel dihapuih.",
"changeemail-none": "(indak ado)",
"changeemail-password": "Sandi {{SITENAME}} Sanak:",
"changeemail-submit": "Ganti surel.",
"changeemail-throttled": "Sanak alah acok bana mancubo masuak log. Mohon tunggu $1 sabalun mancubo baliak.",
- "changeemail-nochange": "Mohon masuakan alamaik surel yang lain.",
+ "changeemail-nochange": "Mohon masuakan alamaik surel nan lain.",
"resettokens": "Ubah token",
"resettokens-token-label": "$1 (nilai saat ini:$2)",
"bold_sample": "Teks taba",
"bold_tip": "Teks taba",
"italic_sample": "Teks miriang",
"italic_tip": "Teks miriang",
- "link_sample": "Judua pautan",
+ "link_sample": "Judul pautan",
"link_tip": "Pautan dalam",
- "extlink_sample": "http://www.anyo-contoh.com judua pautan",
+ "extlink_sample": "http://www.hanyo-contoh.com judul pautan",
"extlink_tip": "Pautan lua (ingek awalannyo http://)",
"headline_sample": "Teks judul",
"headline_tip": "Tingkek 2 judul",
"watchthis": "Pantau laman ko",
"savearticle": "Simpan",
"savechanges": "Simpan parubahan",
- "publishpage": "Tabikan laman",
- "publishchanges": "Tabikan parubahan",
+ "publishpage": "Simpan laman",
+ "publishchanges": "Simpan parubahan",
"savearticle-start": "Simpan laman...",
"savechanges-start": "Simpan parubahan...",
- "publishpage-start": "Tabikan laman...",
- "publishchanges-start": "Tabikan parubahan...",
+ "publishpage-start": "Simpan laman...",
+ "publishchanges-start": "Simpan parubahan...",
"preview": "Caliak",
- "showpreview": "Pratonton",
+ "showpreview": "Caliak pratinjau",
"showdiff": "Parubahan",
- "blankarticle": "\"{{int:authprovider-resetpass-skip-label}}\"Paringatan:</strong> Laman yang Sanak buek kosong.\nJiko Sanak manakan \"$1\" baliak, laman tu akan dibuek tanpa ado isinyo.",
+ "blankarticle": "<strong>Paringatan:</strong> Laman nan Sanak buek kosong.\nJiko Sanak manakan \"$1\" baliak, laman tu akan dibuek tanpa ado isinyo.",
"anoneditwarning": "'''Ingek:''' Sanak alun masuak log.\nAlamat IP sanak tacatat pado riwayaik suntiangan laman ko. Kok Sanak <strong>[$1 log in]</strong> atau <strong>[$2 mambuek akun]</strong>, suantiang Sanak ka didistribusian kapado namo pangguno Sanak, sarato baragam kauntuangan lainnyo.",
"anonpreviewwarning": "''Sanak alun masuak log. Manyimpan laman akan manyababkan alamaik IP Sanak tacatat pado riwayat suntiangan laman iko.''",
- "missingsummary": "'''Paringatan:''' Sanak indak mamasuakan ringkasan panyuntiangan. Jikok Sanak baliak manakan tombol Simpan, suntiangan Sanak akan disimpan tanpa ringkasan panyuntiangan.",
- "selfredirect": "<strong>Paringatan:</strong> Sanak mangalihan halaman ko ka halaman samulo. Sanak bisa jadi maagiah tujuan pangalihan yang salah, atau manyuntiang halaman yang salah.\nJiko Sanak manakan \"$1\" baliak, halaman pangaliahan akan dibuek.",
+ "missingsummary": "<strong>Paringatan:</strong> Sanak indak mamasuakan ikhtisar panyuntiangan. Jikok Sanak baliak manakan $1, suntiangan Sanak akan disimpan tanpa ikhtisar.",
+ "selfredirect": "<strong>Paringatan:</strong> Sanak mangaliahan laman ko ka laman samulo. Sanak bisa jadi maagiah tujuan pangaliahan nan salah, atau manyuntiang laman nan salah.\nJiko Sanak manakan \"$1\" baliak, laman pangaliahan akan dibuek.",
"missingcommenttext": "Masuakan komentar Sanak.",
"missingcommentheader": "'''Paringatan:''' Sanak alun maagihan subjek atau judul untuak komenta Sanak. Jikok Sanak baliak manakan \"$1\", suntiangan Sanak akan disimpan tanpa komenta tasabuik.",
- "summary-preview": "Tinjauan awal untuak ringkasan suntiangan:",
- "subject-preview": "Tinjauan awal untuak subyek ko:",
- "previewerrortext": "Ado yang salah wakatu manunjuakan pratayang parubahan Sanak.",
+ "summary-preview": "Pratinjau ikhtisar suntiangan:",
+ "subject-preview": "Pratinjau subyek:",
+ "previewerrortext": "Ado nan salah wakatu manunjuakan pratinjau parubahan Sanak.",
"blockedtitle": "Pangguno diblokir",
- "blocked-email-user": "<strong>Namo pangguno Sanak diblokir untuak mangirim surel. Sanak masih bisa manyuntiang halaman lain di wiki ko. </strong> Sanak bisa mancaliak parincian pamblokiran pado [[Special:MyContributions|account contributions]].\n\nPamblokiran dilakuan dek $1.\n\nAlasannyo adolah <em>$2</em>.\n\n* Diblokir sajak: $8\n* Blokir kadaluarsa pado: $6\n* Sasaran pamblokiran: $7\n* ID pamblokiran #$5",
- "blockedtext": "'''Namo pangguno atau alamaik IP Sanak alah kanai sakek.'''\n\nSakek dibuek dek $1.\nAlasan nan diagiahan adolah ''$2''.\n\n* Kanai sakek sajak: $8\n* Maso sakek habih pado: $6\n* Sasaran nan disakek: $7\n\nSanak dapek maubungi $1 atau [[{{MediaWiki:Grouppage-sysop}}|panguruih lainnyo]] untuak marundiangan hal ko.\n\nSanak indak dapek manggunoan fitur 'Kirim surel ka pangguno ko' kacuali Sanak alah mamasuakan alamaik surel nan sah di [[Special:Preferences|pangaturan akun]] dan Sanak indak sadang disakek untuak manggunoannyo.\n\nAlamaik IP Sanak adolah $3, dan ID panyakek adolah $5.\nTolong saratoan informasi di ateh pado satiok patanyoan nan Sanak buek.",
- "autoblockedtext": "Alamaik IP Sanak alah kanai sakek sacaro otomatis dek dipakai jo pangguno lain, nan alah disakek dek $1. Alamaik ko disakek dek sebab:\n\n:<em>$2</em>\n\n* Kanai sakek sajak: $8\n* Maso sakek habih pado: $6\n* Sasaran nan disakek: $7\n\nSanak dapek maubuangi $1 atau [[{{MediaWiki:Grouppage-sysop}}|panguruih lainnya]] untuak marundiangan pakaro ko.\n\nSanak indak dapek manggunoan pakakeh \"{{int:emailuser}}\" kacuali Sanak alah mamasuakan alamaik surel nan sah pado [[Special:Preferences|pangaturan akun]] dan Sanak indak sadang disakek untuak manggunoannyo.\n\nAlamaik IP Sanak adolah $3, dan ID panyakekan adolah $5.\nTolong saratoan informasi di ateh pado satiok patanyaan nan Sanak buek.",
+ "blocked-email-user": "<strong>Namo pangguno Sanak diblokir untuak mangirim surel. Sanak masih bisa manyuntiang laman lain di wiki ko. </strong> Sanak bisa mancaliak parincian sakek pado [[Special:MyContributions|jariah pangguno]].\n\nSakek dilakuan dek $1.\n\nAlasannyo adolah <em>$2</em>.\n\n* Disakek sajak: $8\n* Sakek kadaluarsa pado: $6\n* Sasaran panyakek: $7\n* ID sakek #$5",
+ "blockedtext": "'''Namo pangguno atau alamaik IP Sanak alah kanai sakek.'''\n\nSakek dibuek dek $1.\nAlasan nan diagiahan adolah ''$2''.\n\n* Kanai sakek sajak: $8\n* Maso sakek habih pado: $6\n* Sasaran nan disakek: $7\n\nSanak dapek maubungi $1 atau [[{{MediaWiki:Grouppage-sysop}}|panguruih lainnyo]] untuak marundiangan hal ko.\n\nSanak indak dapek manggunoan fitua 'Kirim surel ka pangguno ko' kacuali Sanak alah mamasuakan alamaik surel nan sah di [[Special:Preferences|pangaturan akun]] dan Sanak indak sadang disakek untuak manggunoannyo.\n\nAlamaik IP Sanak adolah $3, dan ID panyakek adolah $5.\nTolong saratoan informasi di ateh pado satiok patanyoan nan Sanak buek.",
+ "autoblockedtext": "Alamaik IP Sanak alah kanai sakek sacaro otomatih dek dipakai jo pangguno lain, nan alah disakek dek $1. Alasannyo dek:\n\n:<em>$2</em>\n\n* Kanai sakek sajak: $8\n* Maso sakek habih pado: $6\n* Sasaran nan disakek: $7\n\nSanak dapek maubuangi $1 atau [[{{MediaWiki:Grouppage-sysop}}|panguruih lainnya]] untuak marundiangan pakaro ko.\n\nSanak indak dapek manggunoan pakakeh \"{{int:emailuser}}\" kacuali Sanak alah mamasuakan alamaik surel nan sah pado [[Special:Preferences|pangaturan akun]] dan Sanak indak sadang disakek untuak manggunoannyo.\n\nAlamaik IP Sanak adolah $3, dan ID panyakekan adolah $5.\nTolong saratoan informasi di ateh pado satiok patanyaan nan Sanak buek.",
"blockednoreason": "indak ado alasan nan diagiah.",
"whitelistedittext": "Sanak musti $1 untuak manyuntiang laman.",
"confirmedittext": "Sanak musti mangkonfirmasian alamaik surel sabalun manyuntiang laman.\nMasuakan dan validasian alamaik surel Sanak pado [[Special:Preferences|pangaturan pangguno]] Sanak.",
"missing-revision": "Revisi $1 di laman nan banamo \"{{FULLPAGENAME}}\" ko indak ado.\n\nHal iko biasonyo disababkan dek pautan sijarah nan alah kadaluarsa ka laman nan alah diapuih.\nRinciannyo dapek dicaliak di [{{fullurl:{{#Special:Log}}/delete|page={{FULLPAGENAMEE}}}} log pangapuihan].",
"userpage-userdoesnotexist": "Akun pangguno \"$1\" indak tadaftar.\nCubo pareso jikok nio mambuek/suntiang laman ko.",
"userpage-userdoesnotexist-view": "Pangguno \"$1\" indak tadaftar.",
- "blocked-notice-logextract": "Pangguno ko tangah diblokir.\nEntri log pamblokiran tabaru disadioan di bawah ko untuak referensi:",
+ "blocked-notice-logextract": "Pangguno ko tangah disakek.\nEntri log panyakekan tabaru disadioan di bawah ko untuak referensi:",
"clearyourcache": "<strong>Catatan:</strong> Sasudah manyimpan, Sanak mungkin harus meminteh singgahan paramban Sanak untuak maliek parubahan.\n* <strong>Firefox / Safari:</strong> Tahan <em>Shift</em> sambia mangklik <em>Reload</em>, atau takan <em>Ctrl-F5</em> atau <em>Ctrl-R</em> (<em>⌘-R</em> di Mac)\n* <strong>Google Chrome:</strong> Takan <em>Ctrl-Shift-R</em> (<em>⌘-Shift-R</em> di Mac)\n* <strong>Internet Explorer:</strong> Tahan <em>Ctrl</em> sambia mangklik <em>Refresh</em>, atau takan <em>Ctrl-F5</em>\n* <strong>Opera:</strong> Pai ka <em>Menu → Settings </em> (<em>Opera → Preferences</em> di Mac) lalu ka <em>Privacy & security → Clear browsing data → Cached images and files</em>.",
"usercssyoucanpreview": "'''Tips:''' Gunoan tombol \"{{int:showpreview}}\" untuak mauji CSS baharu Sanak sabalun manyimpannyo.",
"userjsonyoucanpreview": "<strong>Tip:</strong> Gunoan tombol \"{{int:showpreview}}\" untuak mauji JSON baharu Sanak sabalun manyimpannyo.",
"userjsyoucanpreview": "'''Tips:''' Gunoan tombol \"{{int:showpreview}}\" untuak mauji JS baharu Sanak sabalun manyimpannyo.",
- "usercsspreview": "'''Ingeklah bahawa Sanak sadang manampilan pratayang dari CSS Sanak.\nPratayang iko alun disimpan!'''",
- "userjspreview": "'''Ingeklah bahawa nan Sanak liek hanyolah pratayang JavaScript Sanak, dan bahawa pratayang tasabuik alun disimpan!'''",
- "sitecsspreview": "'''Ingeklah bahawa Sanak hanyo manampilan pratayang dari CSS iko.'''\n'''Parubahan alun disimpan!'''",
- "sitejsonpreview": "<strong>Ingeklah bahwa Sanak hanyo manampilan pratonton konfigurasi JSON ko. Parubahan alun basimpan!</strong>",
- "sitejspreview": "<strong>Ingek! Sanak hanyo manampilan pratonton kode JavaScript ko. Parubahan alun basimpan!</strong>",
- "userinvalidconfigtitle": "<strong>Paringatan:</strong> Kulik \"$1\" indak ado. \n\nMohon diingek baso laman .css, .json, jo .js manggunoan huruf nan ketek; cando {{ns:user}}:Foo/vector.css bukannyo {{ns:user}}:Foo/Vector.css.",
+ "usercsspreview": "<strong>Ingeklah bahawa Sanak sadang manampilan pratinjau dari CSS Sanak.\nPratinjau ko alun disimpan!</strong>",
+ "userjspreview": "<strong>Ingeklah bahawa nan Sanak liek hanyolah pratinjau JavaScript Sanak, dan pratinjau tasabuik alun disimpan!</strong>",
+ "sitecsspreview": "<strong>Ingeklah Sanak hanyo manampilan pratinjau dari CSS ko. Parubahan alun disimpan!</strong>",
+ "sitejsonpreview": "<strong>Ingeklah bahwa Sanak hanyo manampilan pratinjau konfigurasi JSON ko. Parubahan alun basimpan!</strong>",
+ "sitejspreview": "<strong>Ingek! Sanak hanyo manampilan pratinjau kode JavaScript ko. Parubahan alun basimpan!</strong>",
+ "userinvalidconfigtitle": "<strong>Paringatan:</strong> Kulik \"$1\" indak ado. \n\nMohon diingek baso laman .css, .json, jo .js manggunoan huruf ketek; cando {{ns:user}}:Foo/vector.css bukannyo {{ns:user}}:Foo/Vector.css.",
"updated": "(Dipabaharui)",
"note": "'''Catatan:'''",
- "previewnote": "'''Ingek iko hanyo pratonton'''\nParubahan Sanak alun disimpan!",
+ "previewnote": "<strong>Ingek iko hanyo pratinjau.</strong>\nParubahan Sanak alun disimpan!",
"continue-editing": "Pai ka kotak panyuntiangan",
- "previewconflict": "Pratayang iko mancaminan teks pado bagian ateh kotak suntiangan teks sabagaimano akan taliek bilo Sanak manyimpannyo.",
+ "previewconflict": "Pratinjau ko mancaminan teks pado bagian ateh kotak suntiangan sabagaimano akan taliek bilo Sanak manyimpannyo.",
"session_fail_preview": "Maaf, kami indak bisa mamproses suntiangan Sanak dek ilangnyo data sesi. \n\nSanak mungkin lah takalua dari log. <strong>Mohon pastikan baso Sanak masih masuak log. Cubo sajo sakali lai.</strong>.\nKok masih indak bisa, cubo [[Special:UserLogout|kalua]] dan masuak log sakali lai, dan pareso kok panjalajah web sanak mambuliahan panyimpanan ''cookies'' dari laman web ko.",
"session_fail_preview_html": "Maaf, kami indak bisa mamproses suntiangan sanak dek ilangnyo data sesi. \n\n<em> Dek sebab teks HTML mantah pado {{SITENAME}} alah diaktifkan, pratinjau ko disuruakkan untuak mancagah sarangan JavaScript.</em>\n\n<strong>Kok iko satu pacuboan suntiangan nan sah, mohon cubo liak.</strong>\nKok indak juo bisa, cubo [[Special:UserLogout|kalua log]] dan masuak lai. Pareso kalau panjalajah web Sanak mampabuliahan cookie dari laman ko.",
"token_suffix_mismatch": "'''Suntiangan Sanak ditolak karano aplikasi klien Sanak maubah karakter tando baco pado suntiangan.'''\nSuntiangan tasabuik ditolak untuak mancegah kasalahan pado teks laman.\nHal iko kadang tajadi jikok Sanak manggunokan layanan proxy anonim babasis web nan bamasalah.",
"editingold": "'''Paringatan:\nSanak manyuntiang revisi lamo suatu laman.\nJikok Sanak manyimpannyo, parubahan-parubahan nan dibuek sajak revisi ko akan hilang.'''",
"yourdiff": "Pambedoan",
"copyrightwarning": "Untuak diingek bahaso apo nan disumbang kapado {{SITENAME}} dianggap lah dilapeh di bawah $2 (caliak $1 untuak langkoknyo).\nJikok awak indak ingin apo nan ditulih tu disuntiang dan disebaran, jan dikirim tulisan tu ka siko.<br />\nAwak musti bajanji juo bahaso iko adolah asia karya awak surang, atau disalin dari sumber miliak basamo atau sumber bebas lainnyo.\n'''Jan dikirim karya bahak cipta nan indak baizin!'''",
- "copyrightwarning2": "Parhatikan bahawa sadoalah kontribusi terhadap {{SITENAME}} dapek disuntiang, diubah, atau dihapuih oleh panyumbang lainnyo. Jikok Sanak indak ingin tulisan Sanak disuntiang urang lain, jan kiriman ka siko.<br />Sanak jua bajanji bahawa iko adolah hasil karyo Sanak surang, atau disalin dari sumber miliak umum atau sumber bebas nan lain (liek $1 untuak informasi labiah lanjuik). '''JAN KIRIMAN KARYO NAN DILINDUNGI HAK CIPTA TANPA IJIN!'''",
+ "copyrightwarning2": "Parhatikan sadoalah jariah tahadok {{SITENAME}} dapek disuntiang, diubah, atau dihapuih dek panyumbang lainnyo. Jikok Sanak indak ingin tulisan Sanak disuntiang urang lain, jan kiriman ka siko.<br />Sanak juo bajanji iko adolah hasil karya Sanak surang, atau disalin dari sumber miliak umum atau sumber bebas nan lain (liek $1 untuak informasi labiah lanjuik). '''JAN KIRIMAN KARYA NAN DILINDUNGI HAK CIPTA TANPA IJIN!'''",
"editpage-cannot-use-custom-model": "Model konten ko indak dapek diubah.",
"longpageerror": "'''Kasalahan: Teks nan Sanak kiriman sagadang {{PLURAL:$1|$1 kilobita}}, barati labiah gadang dari jumlah maksimum {{PLURAL:$2|$2 kilobita}}. Teks indak dapek disimpan.'''",
- "readonlywarning": "<strong>Paringatan: Basis data ko dikunci untuak karajo pambarasiahan. Sanak indak bisa manyimpan suntiangan kini ko.</strong>\nSanak disarankan untuak manyalin jo manyimpan suntiangan sanak ka file teks untuak diunggah kudian.\n\nManuruik panguruih sistem nan mangunci: $1",
+ "readonlywarning": "<strong>Paringatan: Basis data ko dikunci untuak karajo pambarasiahan. Sanak indak dapek manyimpan suntiangan kini ko.</strong>\nSanak disarankan untuak manyalin jo manyimpan suntiangan sanak ka file teks untuak diunggah kudian.\n\nManuruik panguruih sistem nan mangunci: $1",
"protectedpagewarning": "'''Paringatan: Laman iko sadang dilinduangi sahinggo hanyo pangguno jo hak akses pangurus nan dapek manyuntiangnyo.'''\nEntri catatan tarakhir disadioan di bawah untuak referensi:",
- "semiprotectedpagewarning": "<strong>Catatan:</strong> Laman ko alah dilinduangi, hanyo pangguno nan alah takonfirmasi sacaro otomatis nan bisa manyuntiang.\nLog nan paliang akhia:",
+ "semiprotectedpagewarning": "<strong>Catatan:</strong> Laman ko alah dilinduangi, hanyo pangguno nan alah takonfirmasi sacaro otomatih nan dapek manyuntiang.\nLog nan paliang akhia:",
"cascadeprotectedwarning": "<strong>Paringatan:</strong> Laman ko alah dilinduangi. Hanyo pangguno nan [[Special:ListGroupRights|punyo hak nan tatantu]] buliah untuak manyuntiang, dek karano laman ko ditransklusi pado {{PLURAL:$1|laman nan dilinduangi ko}}:",
"titleprotectedwarning": "'''Paringatan: Laman iko alah dilinduangi sahinggo diparaluan [[Special:ListGroupRights|hak khusus]] untuak mambueknyo.'''\nEntri catatan tarakhir disadioan di bawah untuak referensi:",
"templatesused": "{{PLURAL:$1|Templat}} nan digunoan di laman ko:",
- "templatesusedpreview": "{{PLURAL:$1|Templat}} nan digunoan dalam pratonton ko:",
+ "templatesusedpreview": "{{PLURAL:$1|Templat}} nan digunoan dalam pratinjau ko:",
"templatesusedsection": "{{PLURAL:$1|Templat}} nan digunoan di bagian ko:",
"template-protected": "(dilinduangi)",
"template-semiprotected": "(palinduangan semi)",
"contentmodelediterror": "Sanak indak dapek manyuntiang revisi ko karano isi model <code>$1</code>, beda dari isi model laman kini <code>$2</code>.",
"recreate-moveddeleted-warn": "'''Ingek: Sanak mambuek ulang suatu laman nan alah dihapuih.'''\n\nArok dipatimbangkan lai rancak malanjuikan suntiangan Sanak.\nBarikuik ko log pangapuihan jo pamindahan dari laman ko:",
"moveddeleted-notice": "Laman ko alah dihapuih.\nSabagai referensi, barikuik adolah log pangapuihan jo pamindahannyo.",
- "moveddeleted-notice-recent": "Maaf, halaman ko baru sajo dihapuih (dalam rantang wakatu 24 jam). Log panghapuiah, palinduangan, jo pamindahan halaman tu tasadio di bawah sabagai referensi.",
+ "moveddeleted-notice-recent": "Maaf, laman ko baru sajo dihapuih (dalam rantang wakatu 24 jam). Log panghapuiah, palinduangan, jo pamindahan laman tu tasadio di bawah sabagai referensi.",
"log-fulllog": "Liek saluruah log",
"edit-hook-aborted": "Suntiangan dibatalan samo kait parser\ntanpa ado katarangan.",
"edit-gone-missing": "Indak dapek mampabarui laman.\nMungkin alah dihapuih.",
- "edit-conflict": "Konflik suntingan.",
+ "edit-conflict": "Konflik panyuntiangan.",
"edit-no-change": "Suntiangan sanak ditulak, karano indak ado parubahan nan tajadi ka teks.",
"edit-slots-cannot-add": "{{PLURAL:$1|slot is|slots are}} barikuik indak didukuang disiko: $2.",
"edit-slots-cannot-remove": "{{PLURAL:$1|slot is|slots are}} wajib dan indak buliah dihapuih: $2.",
- "postedit-confirmation-created": "Halaman alah dibuek.",
- "postedit-confirmation-restored": "Halaman alah dipulihan.",
+ "postedit-confirmation-created": "Laman alah dibuek.",
+ "postedit-confirmation-restored": "Laman alah dipuliahan.",
"postedit-confirmation-saved": "Suntiangan Sanak alah tasimpan.",
"postedit-confirmation-published": "Suntiangan Sanak alah ditabikan.",
- "edit-already-exists": "Indak dapek mambuek aman baru.\nNyo alah ado.",
+ "edit-already-exists": "Indak dapek mambuek laman baru.\nNyo alah ado.",
"defaultmessagetext": "Teks baku.",
"content-failed-to-parse": "Gagal manjabarkan konten $2 untuak model $1: $3",
"invalid-content-data": "Data kanduangan indak valid.",
- "content-not-allowed-here": "Isi \"$1\" indak diizinkan pado laman [[:$2]] di slot \"$3\"",
- "editwarning-warning": "Maninggakan laman ko dapek maakibaikan parubahan nan dibuek hilang. Jikok Sanak lah masuak log, dapek mamatian pasan ko malalui bagian \"Panyuntiangan\" pado laman pangaturan.",
+ "content-not-allowed-here": "Isi \"$1\" indak diizinkan di laman [[:$2]] pado slot \"$3\"",
+ "editwarning-warning": "Maninggakan laman ko dapek maakibaikan parubahan nan dibuek hilang. Jikok Sanak lah masuak log, dapek mamatian pasan ko malalui bagian \"{{int:prefs-editing}}\" pado laman Pangaturan.",
"slot-name-main": "Utamo",
"content-model-wikitext": "Teks wiki",
"content-model-text": "Teks kosong",
"content-model-css": "CSS",
"content-json-empty-object": "Objek kosong",
"content-json-empty-array": "Lariak kosong",
- "deprecated-self-close-category": "Halaman yang menggunoan tag HTML tatutuik-surang indak sah",
+ "deprecated-self-close-category": "Laman nan menggunoan tag HTML tatutuik-surang indak sah",
"expensive-parserfunction-warning": "'''Paringatan:''' Laman ko manganduang talalu banyak panggilan fungsi parser.\n\nSeharusnyo kurang dari $2 {{PLURAL:$2|panggilan}}, tapi {{PLURAL:$1|kini ado $1 panggilan}}.",
"expensive-parserfunction-category": "Laman nan talalu banyak panggilan fungsi parser",
"post-expand-template-inclusion-warning": "'''Peringatan:''' Ukuran templat talalu gadang.\nBabarapo templat akan diabaikan.",
"post-expand-template-argument-warning": "Paringatan: Laman ko barisi satidaknyo ciek uraian templat na ukuran ekspansinyo talalu gadang. \nUraian-uraian tu alah diabaikan.",
"post-expand-template-argument-category": "Laman nan barisi uraian templat nan diabaikan",
"parser-template-loop-warning": "Hubungan barulang templat tadeteksi: [[$1]]",
- "template-loop-category": "Halaman dengan templat barulang",
+ "template-loop-category": "Laman jo templat barulang",
"parser-template-recursion-depth-warning": "Limit kadalaman hubungan barulang templat lah talampau ($1)",
"language-converter-depth-warning": "Bateh kadalaman pangonversi bahaso lah talampau ($1)",
"node-count-exceeded-category": "Laman dimano hitungan-node talampaui",
- "node-count-exceeded-warning": "Laman hitungan-node lah talampau",
+ "node-count-exceeded-warning": "Laman nan labiah jumlah node",
"expansion-depth-exceeded-category": "Laman dima kadalaman ekspansi lah talampau",
"expansion-depth-exceeded-warning": "Laman kadalaman ekspansi lah talampau",
"parser-unstrip-loop-warning": "Unstrip loop detected",
"page_last": "akhia",
"histlegend": "Bandiangan piliahan: Tandoi revisi untuak mambandiangan dan takan enter atau tombol di bawah.<br />\nContoh: '''({{int:cur}})''' = bedo jo versi tarakhia, '''({{int:last}})''' = bedo jo versi sabalunnyo, '''{{int:minoreditletter}}''' = suntiangan ketek.",
"history-fieldset-title": "Sariang riwayaik",
- "history-show-deleted": "Hanyo nan dihapuih",
+ "history-show-deleted": "Hanyo revisi nan dihapuih",
"histfirst": "Nan paliang lamo",
"histlast": "Nan paliang baru",
"historysize": "({{PLURAL:$1|$1 bita}})",
- "historyempty": "(kosong)",
+ "historyempty": "kosong",
"history-feed-title": "Riwayat revisi",
"history-feed-description": "Riwayaik revisi laman ko di wiki",
"history-feed-item-nocomment": "$1 pado $2",
"history-feed-empty": "Laman nan dicari indak ado.\nMungkin alah dihapuih dari wiki, atau diagiah namo baru.\nCuba [[Special:Search|cari dulu]] untuak laman lain nan relevan.",
- "rev-deleted-comment": "(ringkasan suntiangan dihapuih)",
+ "rev-deleted-comment": "(ikhtisar suntiangan dihapuih)",
"rev-deleted-user": "(namo pangguno dihapuih)",
- "rev-deleted-event": "(isi dihapuih)",
+ "rev-deleted-event": "(rincian log dihapuih)",
"rev-deleted-user-contribs": "[namo pangguno atau alamaik IP dihapuih - suntiangan disuruakan dari daftar jariah]",
"rev-deleted-text-permission": "Revisi laman ko alah '''dihapuih'''.\nRinciannyo mungkin ado di [{{fullurl:{{#Special:Log}}/delete|page={{FULLPAGENAMEE}}}} log pangapuihan]",
"rev-deleted-text-unhide": "Revisi laman ko alah '''dihapuih'''.\nRinciannyo mungkin ado di [{{fullurl:{{#Special:Log}}/delete|page={{FULLPAGENAMEE}}}} log pangapuihan].\nSanak masih dapek [$1 mancaliak revisi ko] ko' amuah.",
"revdelete-show-file-submit": "Yo",
"logdelete-selected": "{{PLURAL:$1|Log piliahan}}:",
"revdelete-confirm": "Tolong konfirmasi baso Sanak samemang bamakasuik malakuan iko, mamahami konsekuensinyo, dan baso Sanak malakuannyo sasuai jo [[{{MediaWiki:Policy-url}}|kabijakan]].",
- "revdelete-suppress-text": "Panyambunyian revisi '''hanyo''' buliah digunoan untuak kasus-kasus barikuik:\n* Informasi paribadi nan indak patuik\n*: ''alamaik rumah jo nomor telepon, nomor kartu identitas, dll.''",
+ "revdelete-suppress-text": "Panyambunyian revisi <strong>hanyo</strong> buliah digunoan untuak kasus-kasus barikuik:\n* Informasi bapotensi pancemaran namo baiak\n* Informasi paribadi nan indak patuik\n*: <em>alamaik rumah jo nomor telepon, nomor kartu identitas, dll.</em>",
"revdelete-legend": "Pangaturan bateh",
- "revdelete-hide-text": "Suruakan teks revisi",
+ "revdelete-hide-text": "Teks revisi",
"revdelete-hide-image": "Suruakan isi berkas",
- "revdelete-hide-name": "Suruakan tindakan jo target",
- "revdelete-hide-comment": "Suruakan ikhtisar suntiangan",
- "revdelete-hide-user": "Suruakan namo pangguno/IP panyuntiang",
+ "revdelete-hide-name": "Suruakan parameter jo target",
+ "revdelete-hide-comment": "Suntiang ikhtisar",
+ "revdelete-hide-user": "Namo pangguno editor/alamaik IP",
"revdelete-hide-restricted": "Suruakan juo data dari panguruih",
"revdelete-radio-same": "(jan diubah)",
- "revdelete-radio-set": "Yo",
- "revdelete-radio-unset": "Indak",
+ "revdelete-radio-set": "Suruakan",
+ "revdelete-radio-unset": "Nampak",
"revdelete-suppress": "Suruakan juo data dari panguruih",
"revdelete-unsuppress": "Hapuih batehan pado revisi nan dikambalian",
"revdelete-log": "Alasan:",
"revdelete-submit": "Terapkan pado {{PLURAL:$1|revisi}} tapiliah",
- "revdelete-success": "'''Revisi barasil dipabarui.'''",
+ "revdelete-success": "Revisi nan tampak dipabarui.",
"revdelete-failure": "'''Revisi indak dapek dipabarui:'''\n$1",
- "logdelete-success": "'''Log data barasil dipabarui.'''",
+ "logdelete-success": "Log nan tampak diatua.",
"logdelete-failure": "'''Log data indak dapek dipabarui:'''\n$1",
"revdel-restore": "ganti tampilan",
"pagehist": "Riwayaik laman",
"revdelete-modify-missing": "Gagal maubah parubahan ID $1: parubahan ko indak ado di basis data!",
"revdelete-no-change": "<strong>Paringatan:</strong>Parubahan tanggal $2, $1 alah punyo aturan panyambunyian.",
"revdelete-concurrent-change": "Gagal maubah parubahan tanggal $2, $1: statusnyo mungkin alah diubah pangguno lain basamoan jo Sanak.\nCubo pareso catatan log.",
- "revdelete-only-restricted": "Ado yang salah wakatu manyambunyian item tanggal $2, $1: Sanak indak dapek manyambunyiannyo dari panguruih tanpa mamiliah salah satu opsi panyambunyian lainnyo.",
+ "revdelete-only-restricted": "Ado nan salah wakatu manyambunyian item tanggal $2, $1: Sanak indak dapek manyambunyiannyo dari panguruih tanpa mamiliah salah satu opsi panyambunyian lainnyo.",
"revdelete-reason-dropdown": "*Alasan pangapuihan umum\n** Palanggaran hak cipta\n** Komentar atau informasi paribadi nan indak patuik\n** Namo pangguno nan indak patuik\n** Bapotensi mancemarkan namo baiak",
"revdelete-otherreason": "Alasan lain/tambahan:",
"revdelete-reasonotherlist": "Alasan lain",
"revdelete-edit-reasonlist": "Alasan mangapuih laman",
"revdelete-offender": "Pambuek reviri:",
"suppressionlog": "Log pambanaman",
- "suppressionlogtext": "Dibawah ko adolah daftar panghapuihan jo pamblokiran, tamasuak isi yang disambunyian dari panguruih.\nCaliak [[Special:BlockList|block list]] untuak daftar yang paliang baru.",
- "mergehistory": "Riwayaik panggabuangan sajarah halaman",
- "mergehistory-box": "Gabuang parubahan-parubahan dari duo halaman:",
- "mergehistory-from": "Halaman sumber:",
- "mergehistory-into": "Halaman tujuan:",
- "mergehistory-go": "Tampilan suntiangan yang dapek digabuang",
+ "suppressionlogtext": "Di bawah ko adolah daftar panghapuihan jo panyakekan, tamasuak isi nan disambunyian dari panguruih.\nCaliak [[Special:BlockList|daftar sakek]] untuak daftar nan paliang baru.",
+ "mergehistory": "Gabuangan sijarah laman",
+ "mergehistory-box": "Gabuang parubahan-parubahan dari duo laman:",
+ "mergehistory-from": "Laman sumber:",
+ "mergehistory-into": "Laman tujuan:",
+ "mergehistory-go": "Tampilan suntiangan nan dapek digabuang",
"mergehistory-submit": "Gabuang revisi",
- "mergehistory-empty": "Indak ado parubahan yang dapek digabuang.",
+ "mergehistory-empty": "Indak ado parubahan nan dapek digabuang.",
"mergehistory-done": "$3 {{PLURAL:$3|revision|revisions}} dari $1 {{PLURAL:$3|was|were}} berhasil digabuangan ka [[:$2]].",
- "mergehistory-fail": "Indak dapek digabuang, mohon pareso baliak halaman jo parameter waktu.",
- "mergehistory-fail-invalid-source": "Halaman asal indak sah.",
- "mergehistory-fail-invalid-dest": "Halaman tujuan indak sah.",
- "mergehistory-fail-self-merge": "Halaman sumber jo tujuannyo samo.",
+ "mergehistory-fail": "Indak dapek digabuang, mohon pareso baliak laman jo parameter wakatu.",
+ "mergehistory-fail-invalid-source": "Laman asal indak sah.",
+ "mergehistory-fail-invalid-dest": "Laman tujuan indak sah.",
+ "mergehistory-fail-self-merge": "Laman sumber jo tujuannyo samo.",
"mergehistory-reason": "Alasan:",
"mergelog": "Log panggabuangan",
"revertmerge": "Batal gabuang",
"diff-multi-sameuser": "({{PLURAL:$1|Ciek parubahan antaro|$1 parubahan antaro}} dek pangguno nan samo indak ditampilkan)",
"diff-multi-otherusers": "({{PLURAL:$1|Ciek parubahan antaro|$1 parubahan antaro}} dek {{PLURAL:$2|ciek pangguno lain|$2 pangguno}} indak ditampilkan)",
"searchresults": "Hasil pancarian",
+ "search-filter-title-prefix-reset": "Cari kasado laman",
"searchresults-title": "Hasil pancarian untuak \"$1\"",
"titlematches": "Judul laman pas",
"textmatches": "Teks laman pas",
"notextmatches": "Indak ado judul nan pas",
"prevn": "{{PLURAL:$1|$1}} sabalunnyo",
"nextn": "{{PLURAL:$1|$1}} barikuiknyo",
+ "prev-page": "laman sabalunnyo",
+ "next-page": "laman salanjuiknyo",
"prevn-title": "$1 {{PLURAL:$1|hasil}} sabalunnyo",
"nextn-title": "$1 {{PLURAL:$1|hasil}} barikuiknyo",
"shown-title": "Tampilkan $1 {{PLURAL:$1|hasil}} per laman",
"search-result-category-size": "{{PLURAL:$1|$1 anggota}} ({{PLURAL:$2|$2 subkategori}}, {{PLURAL:$3|$3 berkas}})",
"search-redirect": "(dialiahan dari $1)",
"search-section": "(bagian $1)",
+ "search-category": "(kategori $1)",
"search-file-match": "(isi berkas nan sasuai)",
"search-suggest": "Mungkin makasuiknyo: $1",
- "search-interwiki-caption": "Proyek badunsanak",
- "search-interwiki-default": "Hasil $1:",
+ "search-interwiki-caption": "Hasil dari proyek lain",
+ "search-interwiki-default": "Hasil dari $1:",
"search-interwiki-more": "(salanjuiknyo)",
+ "search-interwiki-more-results": "hasil lainnyo",
"search-relatedarticle": "Bakaitan",
"searchrelated": "bakaitan",
- "searchall": "sado",
+ "searchall": "sadonyo",
"showingresults": "Di bawah ko dikaluaan sampai {{PLURAL:$1|'''$1''' hasil}}, dimulai dari #'''$2'''.",
+ "showingresultsinrange": "Manampilkan {{PLURAL:$1|<strong>$1</strong> hasil}} dalam rantang #<strong>$2</strong> sampai #<strong>$3</strong>.",
"search-showingresults": "{{PLURAL:$4|Hasia <strong>$1</strong> dari <strong>$3</strong>|Hasia <strong>$1 - $2</strong> dari <strong>$3</strong>}}",
"search-nonefound": "Indak ado hasil nan sasuai jo pamintaan",
"powersearch-legend": "Pencarian lanjut",
"prefs-personal": "Profil pangguno",
"prefs-rc": "Parubahan baru",
"prefs-watchlist": "Daftar pantau",
+ "prefs-editwatchlist": "Suntiang daftar pantauan",
+ "prefs-editwatchlist-label": "Suntiang entri daftar pantauan Sanak:",
"prefs-watchlist-days": "Jumlah hari dalam daftar pantau:",
"prefs-watchlist-days-max": "Maksimum $1 {{PLURAL:$1|hari}}",
- "prefs-watchlist-edits": "Jumlah suntiangan nan ditunjuakan pado daftar pantau:",
+ "prefs-watchlist-edits": "Jumlah parubahan tabanyak nan ditunjuakan pado daftar pantau:",
"prefs-watchlist-edits-max": "Nilai maksimum: 1000",
"prefs-watchlist-token": "Token pantauan:",
"prefs-misc": "Lain-lain",
"prefs-resetpass": "Tuka kato sandi",
- "prefs-changeemail": "Tuka alamaik surel",
+ "prefs-changeemail": "Tuka atau hapuih alamaik surel",
"prefs-setemail": "Atua alamaik surel",
"prefs-email": "Piliahan surel",
"prefs-rendering": "Tampilan",
"saveprefs": "Simpan",
- "restoreprefs": "Baliakan ka setelan awal",
+ "restoreprefs": "Baliakan ka setelan awal (kasado bagian)",
"prefs-editing": "Panyuntiangan",
"searchresultshead": "Cari",
- "stub-threshold": "Ambang bateh untuak format <a href=\"#\" class=\"stub\">pautan rancangan</a>:",
+ "stub-threshold": "Ambang bateh untuak format pautan rancangan $1:",
+ "stub-threshold-sample-link": "contoh",
"stub-threshold-disabled": "Nonaktifkan",
"recentchangesdays": "Jumlah hari nan ditunjuakan di parubahan baru:",
"recentchangesdays-max": "Maksimum $1 {{PLURAL:$1|hari}}",
- "recentchangescount": "Jumlah suntiangan nan ditunjuakan:",
- "prefs-help-recentchangescount": "Iko untuak parubahan tabaru, riwayaik laman nan lalu, sarato log.",
+ "recentchangescount": "Jumlah suntiangan nan ditunjuakan dalam parubahan baru, riwayaik laman, dan dalam log, sacaro baku:",
+ "prefs-help-recentchangescount": "Nilai maksimum: 1000",
"savedprefs": "Pangaturan lah tasimpan",
"timezonelegend": "Zona wakatu:",
"localtime": "Wakatu satampaik:",
"timezoneregion-indian": "Samudera Hindia",
"timezoneregion-pacific": "Samudera Pasifik",
"allowemail": "Izinkan pangguno lain mangirim surel",
+ "email-allow-new-users-label": "Izinkan surel dari pangguno baru",
+ "email-blacklist-label": "Panggono ko indak dapek kirim surel ka Ambo:",
"prefs-searchoptions": "Cari",
"prefs-namespaces": "Ruangnamo",
"default": "baku",
"prefs-files": "Berkas",
- "prefs-custom-css": "CSS paribadi",
- "prefs-custom-js": "JS paribadi",
- "prefs-common-config": "CSS/JS untuak kasado kulik:",
+ "prefs-custom-css": "CSS surang",
+ "prefs-custom-js": "JS surang",
+ "prefs-common-config": "CSS/JS babagi untuak kasado kulik:",
"prefs-reset-intro": "Angku dapek manggunokan laman ko untuak mangambalikan pangaturan ka setelan baku situs ko.\nPangambalian pangaturan indak dapek dibatalan.",
"prefs-emailconfirm-label": "Surel konfirmasi:",
"youremail": "Surel:",
"username": "{{GENDER:$1|Namo pangguno}}:",
"prefs-memberingroups": "{{GENDER:$2|Anggota}} {{PLURAL:$1|kalompok}}:",
+ "group-membership-link-with-expiry": "$1 (sampai $2)",
"prefs-registration": "Wakatu pandaftaran:",
"yourrealname": "Namo asli:",
"yourlanguage": "Bahaso",
"prefs-help-signature": "Komen pado laman rundiang paralu ditandotangani jo \"<nowiki>~~~~</nowiki>\" nan ka diubah manjadi tando tangan Sanak sarato wakatu kini ko.",
"badsig": "Tando tangan mantah indak sah; pariso tag HTML.",
"badsiglength": "Tando tangan Sanak panjang bana.\nJan labiah dari $1 {{PLURAL:$1|karakter}}.",
- "yourgender": "Jinih kalamin:",
+ "yourgender": "Ba'a Sanak labiah suko digambarkan?",
"gender-unknown": "Indak ditanyo",
"gender-male": "Laki-laki",
"gender-female": "Padusi",
"prefs-signature": "Tando tangan",
"prefs-dateformat": "Format tanggal",
"prefs-timeoffset": "Format wakatu",
- "prefs-advancedediting": "Umum",
+ "prefs-advancedediting": "Piliahan umum",
+ "prefs-developertools": "Alaik Pangambang",
+ "prefs-editor": "Editor",
+ "prefs-preview": "Pratinjau",
"prefs-advancedrc": "Piliahan lanjuik",
"prefs-advancedrendering": "Piliahan lanjuik",
"prefs-advancedsearchoptions": "Piliahan lanjuik",
"prefs-advancedwatchlist": "Piliahan lanjuik",
"prefs-displayrc": "Piliahan tampilan",
"prefs-displaywatchlist": "Piliahan tampilan",
+ "prefs-changesrc": "Parubahan ditampilkan",
+ "prefs-tokenwatchlist": "Token",
"prefs-diffs": "Pabedoan",
- "userrights": "Manajemen hak pangguno",
- "userrights-lookup-user": "Mangatua kalompok pangguno",
+ "userrights": "Hak pangguno",
+ "userrights-lookup-user": "Piliah pangguno",
"userrights-user-editname": "Masuakan namo pangguno:",
- "editusergroup": "Suntiang kalompok pangguno",
- "editinguser": "Mangganti hak akses pangguno '''[[User:$1|$1]]''' $2",
- "userrights-editusergroup": "Suntiang kalompok pangguno",
- "saveusergroups": "Simpan kalompok pangguno",
+ "editusergroup": "Muek kalompok pangguno",
+ "editinguser": "Mangganti hak pangguno untuak {{GENDER:$1|pangguno}} <strong>[[User:$1|$1]]</strong> $2",
+ "userrights-editusergroup": "Suntiang kalompok {{GENDER:$1|pangguno}}",
+ "userrights-viewusergroup": "Caliak kalompok {{GENDER:$1|pangguno}}",
+ "saveusergroups": "Simpan kalompok {{GENDER:$1|pangguno}}",
"userrights-groupsmember": "Anggota dari:",
"userrights-groupsmember-auto": "Anggota implisit dari:",
- "userrights-groups-help": "Sanak dapek mangubah kalompok pangguno ko:\n* Kotak jo tando centang marupoan kalompok pangguno tasabuik\n* Kotak indak ado tando centang bararti pangguno ko bukan anggota kalompok tasabuik\n* Tando * manandoan Sanak indak dapek mambatalan kalompok tasabuik bilo Sanak alah manambahannyo, ataupun sabaliaknyo.",
+ "userrights-groups-help": "Sanak dapek mangubah kalompok pangguno ko:\n* Kotak jo tando centang marupoan kalompok pangguno tasabuik\n* Kotak indak ado tando centang bararti pangguno ko bukan anggota kalompok tasabuik\n* Tando * manandoan Sanak indak dapek mambatalan kalompok tasabuik bilo Sanak alah manambahannyo, ataupun sabaliaknyo.\n* Tando # manandoan Sanak hanyo dapek mangambalikan wakatu usang kaanggotaan kalompok ko; Sanak indak dapek mamajukannyo.",
"userrights-reason": "Alasan:",
"userrights-no-interwiki": "Sanak indak bahak untuak mangubah hak pangguno di wiki lain.",
"userrights-nodatabase": "Basis data $1 indak ado atau bukan disiko.",
"userrights-changeable-col": "Kalompok nan dapek Sanak ubah",
"userrights-unchangeable-col": "Kalompok nan indak dapek Sanak ubah",
+ "userrights-expiry-current": "Usang $1",
+ "userrights-expiry-none": "Indak usang",
+ "userrights-expiry": "Usang:",
+ "userrights-expiry-existing": "Wakatu usang kini ko: $3, $2",
+ "userrights-expiry-othertime": "Wakatu lain:",
+ "userrights-expiry-options": "1 hari:1 hari,1 minggu:1 minggu,1 bulan:1 bulan,3 bulan:3 bulan,6 bulan:6bulan,1 taun:1 taun",
+ "userrights-invalid-expiry": "Wakatu usang untuak kalompok \"$1\" indak sah.",
+ "userrights-expiry-in-past": "Wakatu usang untuak kalompok \"$1\" alah balalu.",
"group": "Kalompok:",
"group-user": "Pangguno",
- "group-autoconfirmed": "Pangguno takonfirmasi otomatis",
+ "group-autoconfirmed": "Pangguno takonfirmasi otomatih",
"group-bot": "Bot",
"group-sysop": "Panguruih",
+ "group-interface-admin": "Panguruih antarmuko",
"group-bureaucrat": "Birokrat",
- "group-suppress": "Pangawas",
+ "group-suppress": "Pamberedel",
"group-all": "(sadonyo)",
"group-user-member": "{{GENDER:$1|pangguno}}",
- "group-autoconfirmed-member": "{{GENDER:$1|pangguno takonfirmasi otomatis}}",
+ "group-autoconfirmed-member": "{{GENDER:$1|pangguno takonfirmasi otomatih}}",
"group-bot-member": "{{GENDER:$1|bot}}",
"group-sysop-member": "{{GENDER:$1|panguruih}}",
+ "group-interface-admin-member": "{{GENDER:$1|panguruih antarmuko}}",
"group-bureaucrat-member": "{{GENDER:$1|birokrat}}",
- "group-suppress-member": "{{GENDER:$1|pangawas}}",
+ "group-suppress-member": "{{GENDER:$1|pamberedel}}",
"grouppage-user": "{{ns:project}}:Pangguno",
- "grouppage-autoconfirmed": "{{ns:project}}:Pangguno takonfirmasi otomatis",
+ "grouppage-autoconfirmed": "{{ns:project}}:Pangguno takonfirmasi otomatih",
"grouppage-bot": "{{ns:project}}:Bot",
"grouppage-sysop": "{{ns:project}}:Panguruih",
+ "grouppage-interface-admin": "{{ns:project}}:Panguruih antarmuko",
"grouppage-bureaucrat": "{{ns:project}}:Birokrat",
- "grouppage-suppress": "{{ns:project}}:Pangawas",
+ "grouppage-suppress": "{{ns:project}}:Pamberedel",
"right-read": "Mambaco laman",
- "right-edit": "Manyuntiang laman",
+ "right-edit": "Suntiang laman",
"right-createpage": "Mambuek laman baru (nan bukan laman diskusi)",
"right-createtalk": "Mambuek laman diskusi",
"right-createaccount": "Mambuek akun baru",
"right-upload": "Mamuek berkas",
"right-reupload": "Manimpo berkas lamo",
"right-reupload-own": "Manimpo berkas nan dimuek surang",
- "right-purge": "Mangapuih singgahan laman tanpa laman konfirmasi",
- "right-autoconfirmed": "Manyuntiang laman palinduangan semi",
- "right-bot": "Dipalakuan sabagai proses otomatis",
+ "right-purge": "Mangapuih singgahan laman untuak laman",
+ "right-autoconfirmed": "Indak dipangaruahi bateh limik babasis IP",
+ "right-bot": "Dipalakuan sabagai proses otomatih",
"right-nominornewtalk": "Indak ado tando suntiangan ketek di laman rundiang mamicu pasan baru",
"right-apihighlimits": "Manggunoan bateh labiah tinggi dalam kueri API",
"right-writeapi": "Manggunoan panulisan API",
"right-delete": "Mangapuih laman",
"right-suppressionlog": "Mancaliak log privat",
- "right-unblockself": "Malapehan sakek diri surang",
+ "right-unblockself": "Malapehan sakek surang",
"right-editinterface": "Manyuntiang antarmuko pangguno",
"right-editusercss": "Manyuntiang berkas CSS pangguno lain",
"right-edituserjson": "Manyuntiang berkas JSON pangguno lain",
"right-noratelimit": "Indak dipangaruahi jo pambatehan jumlah suntiangan",
"right-import": "Mangimpor laman dari wiki lain",
"right-importupload": "Mangimpor laman dari berkas nan dimuek",
- "right-autopatrol": "Suntiangan surang sacaro otomatis ditandoi tapantau",
+ "right-autopatrol": "Suntiangan surang sacaro otomatih ditandoi tapantau",
+ "grant-group-email": "Kirim surel",
+ "grant-createaccount": "Buek akun",
+ "grant-createeditmovepage": "Buek, suntiang, dan pindahkan laman",
+ "grant-delete": "Hapuih laman, revisi, dan log entri",
+ "grant-basic": "Akses dasar",
"newuserlogpage": "Log pangguno baru",
"newuserlogpagetext": "Di bawah ko log pandaftaran pangguno baru",
"rightslog": "Log parubahan hak akses",
"rightslogtext": "Di bawah ko daftar log parubahan pado hak-hak pangguno.",
"action-read": "baco laman ko",
"action-edit": "suntiang laman ko",
- "action-createpage": "buek laman",
- "action-createtalk": "buek laman diskusi",
+ "action-createpage": "buek laman ko",
+ "action-createtalk": "buek laman rundiang ko",
"action-createaccount": "buek akun pangguno ko",
"action-minoredit": "tandoi sabagai suntiangan ketek",
"action-move": "pindahan laman ko",
"action-upload": "muek berkas ko",
"action-reupload": "timpo berkas lamo",
"action-writeapi": "manggunoan panulisan API",
- "action-import": "impor laman ko dari wiki lain",
+ "action-import": "impor laman dari wiki lain",
"nchanges": "$1 {{PLURAL:$1|parubahan}}",
"enhancedrc-history": "riwayaik",
"recentchanges": "Parubahan baru",
"recentchanges-legend": "Piliahan parubahan baru",
- "recentchanges-summary": "Caliak parubahan tabaru pado wiki di laman ko.<br />\n;Patunjuak:(<span style=\"color:blue;\">bedo</span>) parubahan, (<span style=\"color:blue;\">sijarah</span>) riwayaik parubahan, '''B''' laman baru, '''b''' suntiangan bot, '''k''' suntiangan ketek, <span class=\"unpatrolled\">!</span> parubahan alun dipatroli,<br /><span style=\"color:green;\">'''(+ ''bita'')'''</span> isi laman batambah, <span style=\"color:red;\">(- ''bita'')</span> isi laman bakurang, (← Ikhtisar otomatih), (→ <span style=\"color:grey;\">Suntiangan bagian</span>)",
+ "recentchanges-summary": "Caliak parubahan baru di wiki pado laman ko.<br />\n;Patunjuak:(<span style=\"color:blue;\">bedo</span>) parubahan, (<span style=\"color:blue;\">sijarah</span>) riwayaik parubahan, '''B''' laman baru, '''b''' suntiangan bot, '''k''' suntiangan ketek, <span class=\"unpatrolled\">!</span> parubahan alun dipatroli,<br /><span style=\"color:green;\">'''(+ ''bita'')'''</span> isi laman batambah, <span style=\"color:red;\">(- ''bita'')</span> isi laman bakurang, (← Ikhtisar otomatih), (→ <span style=\"color:grey;\">Suntiangan bagian</span>)",
"recentchanges-noresult": "Indak ado parubahan dalam rantang wakatu ko nan sasuai jo kriteria.",
"recentchanges-feed-description": "Tamuan parubahan baru dalam umpan wiki ko",
"recentchanges-label-newpage": "Suntiangan ko mambuek laman baru",
"recentchanges-label-plusminus": "Parubahan ukuran laman dalam bita",
"recentchanges-legend-heading": "<strong>Katarangan:</strong>",
"recentchanges-legend-newpage": "{{int:recentchanges-label-newpage}} (caliak pulo [[Special:NewPages|daftar laman nan baru]])",
+ "rcfilters-other-review-tools": "Pakakeh paninjauan lainnyo",
+ "rcfilters-group-results-by-page": "Kalompokan hasil manuruik laman",
+ "rcfilters-activefilters": "Panyariang aktip",
+ "rcfilters-activefilters-hide": "Suruakan",
+ "rcfilters-activefilters-show": "Tunjuakan",
+ "rcfilters-advancedfilters": "Panyariang lanjutan",
+ "rcfilters-limit-title": "Hasil untuak ditampilkan",
+ "rcfilters-limit-and-date-label": "$1 {{PLURAL:$1|parubahan}}, $2",
+ "rcfilters-date-popup-title": "Rantang wakatu untuak dicari",
+ "rcfilters-days-title": "Hari-hari tarakhia",
+ "rcfilters-hours-title": "Jam-jam tarakhia",
+ "rcfilters-days-show-days": "$1 {{PLURAL:$1|hari}}",
+ "rcfilters-days-show-hours": "$1 {{PLURAL:$1|jam}}",
+ "rcfilters-highlighted-filters-list": "Disorot: $1",
+ "rcfilters-quickfilters": "Panyariang tasimpan",
+ "rcfilters-quickfilters-placeholder-title": "Indak ado panyariang nan disimpan",
+ "rcfilters-quickfilters-placeholder-description": "Untuak manyimpan pangaturan panyariang jo manggunoannyo baliak, klik ikon panando laman di area Panyariang Aktip, di bawah.",
+ "rcfilters-savedqueries-defaultlabel": "Panyariang tasimpan",
+ "rcfilters-savedqueries-rename": "Ganti namo",
+ "rcfilters-savedqueries-setdefault": "Atua jadi baku",
+ "rcfilters-savedqueries-unsetdefault": "Hapuih dari baku",
+ "rcfilters-savedqueries-remove": "Hapuih",
+ "rcfilters-savedqueries-new-name-label": "Namo",
+ "rcfilters-savedqueries-apply-label": "Buek panyariang",
+ "rcfilters-savedqueries-apply-and-setdefault-label": "Buek panyariang baku",
+ "rcfilters-savedqueries-cancel-label": "Batalan",
+ "rcfilters-savedqueries-add-new-title": "Simpan pangaturan panyariang ko",
+ "rcfilters-savedqueries-already-saved": "Panyariang ko alah tasimpan. Ubah pangaturan Sanak untuak manyimpan panyariang baru.",
+ "rcfilters-show-new-changes": "Tunjuakan parubahan baru dari $1",
+ "rcfilters-search-placeholder": "Panyariang parubahan (gunokan menu atau cari namo panyariang)",
+ "rcfilters-search-placeholder-mobile": "Panyariang",
+ "rcfilters-filterlist-title": "Panyariang",
+ "rcfilters-filterlist-noresults": "Indak ado panyariang ditamukan",
+ "rcfilters-filter-editsbyself-label": "Suntiangan Sanak",
+ "rcfilters-filter-editsbyother-label": "Suntiangan urang lain",
+ "rcfilters-filter-user-experience-level-registered-label": "Tadaftar",
+ "rcfilters-filter-user-experience-level-unregistered-label": "Indak tadaftar",
+ "rcfilters-filter-user-experience-level-newcomer-label": "Pandatang baru",
+ "rcfilters-filter-bots-label": "Bot",
+ "rcfilters-filter-humans-label": "Manusio (bukan bot)",
+ "rcfilters-filter-reviewstatus-unpatrolled-label": "Alun dipatroli",
+ "rcfilters-filter-minor-label": "Suntiangan ketek",
+ "rcfilters-filter-major-label": "Nan indak suntiangan ketek",
+ "rcfilters-filter-pageedits-label": "Suntiangan laman",
+ "rcfilters-filter-newpages-label": "Laman baru",
+ "rcfilters-filter-categorization-label": "Parubahan kategori",
+ "rcfilters-filter-logactions-label": "Tindakan tacataik",
+ "rcfilters-view-tags": "Suntiangan ditandoi",
+ "rcfilters-liveupdates-button": "Parubahan langsuang",
+ "rcfilters-liveupdates-button-title-on": "Matian parubahan langsuang",
"rcnotefrom": "Di bawah iko adolah {{PLURAL:$5|parubahan|babagai parubahan}} sajak <strong>$3, $4</strong> (ditampilkan sampai <strong>$1</strong> parubahan).",
"rclistfrom": "Tunjuakan parubahan baru mulai dari tanggal $3 $2",
"rcshowhideminor": "$1 suntiangan ketek",
"rcshowhidemine-show": "Tunjuakan",
"rcshowhidemine-hide": "Suruakan",
"rclinks": "Tunjuakkan $1 parubahan tabaru dalam $2 hari nan tarakhia",
- "diff": "beda",
+ "diff": "bedo",
"hist": "sijarah",
"hide": "Suruakan",
"show": "Tunjuakan",
"minoreditletter": "k",
"newpageletter": "B",
"boteditletter": "b",
- "rc-change-size-new": "$1 {{PLURAL:$1|byte|bita}} salapeh parubahan",
- "rc-enhanced-expand": "Tampilkan rincian (paralu JavaScript)",
+ "rc-change-size-new": "$1 {{PLURAL:$1|bita}} salapeh parubahan",
+ "rc-enhanced-expand": "Caliak rincian",
"rc-enhanced-hide": "Suruakkan rincian",
- "rc-old-title": "awanyo dibuek jo judua \"$1\"",
+ "rc-old-title": "awalnyo dibuek jo judul \"$1\"",
"recentchangeslinked": "Parubahan takaik",
"recentchangeslinked-feed": "Parubahan takaik",
"recentchangeslinked-toolbox": "Parubahan takaik",
"upload_directory_read_only": "Direktori pamuatan ($1) indak dapek ditulih jo server web.",
"uploaderror": "Kasalahan pamuatan",
"upload-recreate-warning": "'''Paringatan: Berkas jo namo tu alah dihapuih atau dipindahan.'''\n\nLog pangapuihan dan pamindahan laman ko adolah sabagai barikuik:",
- "uploadtext": "Gunoan formulir di bawah ko untuak mangunggah berkas.\nUntuak manampilan atau mancari berkas nan sabalumnyo dimuek, gunoan [[Special:FileList|daftar berkas]]. Pangunggahan (ulang) tacatat dalam [[Special:Log/upload|log pangunggahan]], samantaro pangapuihan tacatat dalam [[Special:Log/delete|log pangapuihan]].\n\nUntuak manampilkan berkas pado suatu laman, gunoan salah satu format di bawah ko:\n* '''<code><nowiki>[[</nowiki>{{ns:file}}<nowiki>:Berkas.jpg]]</nowiki></code>''' untuak manampilan berkas dalam ukuran aslinyo\n* '''<code><nowiki>[[</nowiki>{{ns:file}}<nowiki>:Berkas.png|200px|thumb|left|teks alternatif]]</nowiki></code>''' untuak manampilan berkas jo leba 200px dalam sabuah kotak di kiri laman jo 'teks alternatif' sabagai katarangan gambar\n* '''<code><nowiki>[[</nowiki>{{ns:media}}<nowiki>:Berkas.ogg]]</nowiki></code>''' sabagai pautan langsuang ka berkas media nan dimakasuik tanpa manampilan berkas tarsabuik di laman wiki",
- "upload-permitted": "Jenis berkas nan dipabuliahan: $1.",
- "upload-preferred": "Jenis berkas nan disaranan: $1.",
- "upload-prohibited": "Jenis berkas nan dilarang: $1.",
+ "uploadtext": "Gunoan formulir di bawah ko untuak mangunggah berkas.\nUntuak manampilan atau mancari berkas nan sabalumnyo dimuek, gunoan [[Special:FileList|daftar berkas]]. Pangunggahan (ulang) tacatat dalam [[Special:Log/upload|log pangunggahan]], samantaro pangapuihan tacatat dalam [[Special:Log/delete|log pangapuihan]].\n\nUntuak manampilkan berkas pado suatu laman, gunoan salah satu format di bawah ko:\n* <strong><code><nowiki>[[</nowiki>{{ns:file}}<nowiki>:Berkas.jpg]]</nowiki></code></strong> untuak manampilan berkas dalam ukuran aslinyo\n* <strong><code><nowiki>[[</nowiki>{{ns:file}}<nowiki>:Berkas.png|200px|thumb|left|teks alternatif]]</nowiki></code></strong> untuak manampilan berkas jo leba 200px dalam sabuah kotak di kiri laman jo 'teks alternatif' sabagai katarangan gambar\n* <strong><code><nowiki>[[</nowiki>{{ns:media}}<nowiki>:Berkas.ogg]]</nowiki></code></strong> sabagai pautan langsuang ka berkas media nan dimakasuik tanpa manampilan berkas tasabuik di laman wiki",
+ "upload-permitted": "{{PLURAL:$2|Tipe}} berkas nan dipabuliahan: $1.",
+ "upload-preferred": "{{PLURAL:$2|Tipe}} berkas nan disaranan: $1.",
+ "upload-prohibited": "{{PLURAL:$2|Tipe}} berkas nan dilarang: $1.",
"uploadlogpage": "Log muek",
"uploadlogpagetext": "Barikuik ko adolah daftar pangunggahan berkas tabaru. \nCaliak [[Special:NewFiles|galeri berkas baru]] untuak tampilan visual.",
"filename": "Namo berkas",
"license": "Lisensi:",
"license-header": "Lisensi",
"nolicense": "Indak ado nan dipiliah",
- "license-nopreview": "(Pratonton indak tasadio)",
- "upload_source_url": " (suatu URL sah nan dapek diakses publik)",
- "upload_source_file": " (berkas nan di komputer Sanak)",
- "listfiles-summary": "Laman istimewa ko manampilan kasado berkas nan alah diunggah.\nKatiko disariang dek pangguno, hanyo versi berkas tabaru dari berkas nan diunggah nan tampil.",
+ "license-nopreview": "(Pratinjau indak tasadio)",
+ "upload_source_url": "(Sanak piliah berkas dari URL valid nan dapek diakses publik)",
+ "upload_source_file": "(Sanak piliah berkas dari komputer Sanak)",
+ "listfiles-summary": "Laman istimewa barikuik manunjuakan sado berkas nan dimuek.",
"listfiles_search_for": "Cari namo berkas:",
"imgfile": "berkas",
"listfiles": "Daftar berkas",
"filehist-filesize": "Ukuaran berkas",
"filehist-comment": "Komen",
"imagelinks": "Panggunoan berkas",
- "linkstoimage": "{{PLURAL:$1|Halaman|$1 halaman}} nan iko manggunoan berkas nan iko:",
+ "linkstoimage": "{{PLURAL:$1|Laman|$1 laman}} barikuik manggunoan berkas ko:",
"linkstoimage-more": "Labiah dari $1 {{PLURAL:$1|laman}} ado pautan ka berkas ko.\nDaftar barikuik manunjuakan {{PLURAL:$1|$1 laman jo pautan langsuang}} ka berkas ko.\nAdo juo tasadio [[Special:WhatLinksHere/$2|daftar langkoknyo]].",
"nolinkstoimage": "Indak ado laman nan manggunokan berkas ko.",
"morelinkstoimage": "Caliak [[Special:WhatLinksHere/$1|pautan baliak]] ka berkas ko.",
"filerevert-badversion": "Indak ado versi lokal tadahulu dari berkas ko pado wakatu nan dituju.",
"filedelete": "Hapuih $1",
"filedelete-legend": "Hapuih berkas",
+ "filedelete-success": "'''$1''' alah dihapuih.",
"mimesearch": "Pancarian MIME",
"unwatchedpages": "Laman nan indak tapantau",
"listredirects": "Daftar pangaliahan",
"pageswithprop-text": "Laman ko barisi daftar laman nan manggunoan properti laman tatantu.",
"pageswithprop-prop": "Namo properti:",
"pageswithprop-submit": "Lanjuik",
- "doubleredirects": "Pangaliahan gando",
+ "doubleredirects": "Pangaliahan ganda",
"doubleredirectstext": "Laman ko mamuek daftar laman nan dialiahkan ka laman pangaliahan nan lain.\nSatiok barih mamuek pautan ka pangaliahan partamo dan pangaliahan kadua sarato target dari pangaliahan kadua nan umumnyo adolah laman nan \"sabananyo\". Laman pangaliahan partamo saharuihnyo dialiahkan ka laman nan bukan marupoan laman pangaliahan.\nJudul laman nan <del>dicoret</del> bararti alah dipelokan.",
"double-redirect-fixer": "Revisi pangaliahan",
"brokenredirects": "Pangaliahan rusak",
"wantedtemplates": "Templat nan diinginan",
"mostlinked": "Laman nan acok dituju",
"mostlinkedcategories": "Kategori nan acok digunoan",
- "mostlinkedtemplates": "Templat nan acok dituju",
+ "mostlinkedtemplates": "Templat nan acok ditransklusi",
"mostcategories": "Laman jo kategori tabanyak",
"mostimages": "Berkas nan paliang acok digunoan",
"mostinterwikis": "Laman jo interwiki paliang banyak",
"booksources-search-legend": "Cari di sumber buku",
"booksources-search": "Cari",
"specialloguserlabel": "Pangguno:",
- "speciallogtitlelabel": "Target (judua atau {{ns:pangguno}}:namo pangguno untuak pangguno):",
+ "speciallogtitlelabel": "Target (judul atau {{ns:user}}:namo pangguno untuak pangguno):",
"log": "Log",
"all-logs-page": "Sado log publik",
"alllogstext": "Gabuangan kasado log nan ado di {{SITENAME}}.\nSanak dapek mamiliah jinih log nan ado, namo pangguno (bedoan hurup ketek/gadang), atau judul laman (bedaan hurup ketek/gadang).",
"logempty": "Indak basobok entri log nan sasuai.",
"log-title-wildcard": "Cari judul nan diawali jo teks ko",
"showhideselectedlogentries": "Tunjuakan/Suruakan entri log tapiliah",
+ "checkbox-select": "Piliah: $1",
+ "checkbox-all": "Sadonyo",
+ "checkbox-none": "Kosong",
+ "checkbox-invert": "Baliakan",
"allpages": "Kasado laman",
"nextpage": "Laman salanjuiknyo ($1)",
"prevpage": "Laman sabalunnyo ($1)",
"allpages-hide-redirects": "Suruakan pangaliahan",
"cachedspecial-refresh-now": "Caliak versi baru.",
"categories": "Kategori",
- "categoriespagetext": "{{PLURAL:$1|Isi kategori}} ko ado laman atau media.\n[[Special:UnusedCategories|Kategori nan indak tapakai]] indak nampak di siko.\nLihek pulo [[Special:WantedCategories|kategori nan diinginan]].",
+ "categoriespagetext": "{{PLURAL:$1|Kategori barikuik}} ado di Wiki, dan mungkin digunoan atau indak.\nCaliak pulo [[Special:WantedCategories|kategori nan diinginkan]].",
"categoriesfrom": "Tunjuakan kategori mulai jo:",
"deletedcontributions": "Jariah nan dihapuih",
"deletedcontributions-title": "Jariah nan dihapuih",
"activeusers-noresult": "Pangguno indak basobok",
"listgrouprights": "Daftar kalompok pangguno",
"listgrouprights-summary": "Barikuik ko adolah daftar kalompok pangguno nan ado di wiki ko, jo daftar hak aksesnyo masiang-masiang. Informasi labih lanjuik masalah hak masiang-masiang dapek dijumpoi di [[{{MediaWiki:Listgrouprights-helppage}}|laman bantuan hak pangguno]].",
- "listgrouprights-key": "* <span class=\"listgrouprights-granted\">Hak nan balaku</span>\n* <span class=\"listgrouprights-revoked\">Hak nan dicabuik</span>",
+ "listgrouprights-key": "Legenda:\n* <span class=\"listgrouprights-granted\">Hak nan balaku</span>\n* <span class=\"listgrouprights-revoked\">Hak nan dicabuik</span>",
"listgrouprights-group": "Kalompok",
"listgrouprights-rights": "Hak",
"listgrouprights-helppage": "Help:Hak akses",
"watchlist": "Pantauan",
"mywatchlist": "Pantauan",
"watchlistfor2": "Untuak $1 $2",
- "addedwatchtext": "Laman \"[[:$1]]\" lah ditambahan ka [[Special:Watchlist|Pantauan]] Sanak.\nParubahan laman ko tamasuak laman rundiangnyo akan ditampilan disinan.",
+ "addedwatchtext": "\"[[:$1]]\" jo laman rundiangnyo lah ditambahan ka [[Special:Watchlist|Pantauan]] Sanak.",
"removewatch": "Hapuih dari daftar pantau",
- "removedwatchtext": "Laman \"[[:$1]]\" lah dihapuih dari [[Special:Watchlist|daftar pantau Sanak]].",
+ "removedwatchtext": "\"[[:$1]]\" jo laman rundiangnyo lah dihapuih dari [[Special:Watchlist|daftar pantau Sanak]].",
"watch": "Pantau",
"watchthispage": "Pantau laman ko",
"unwatch": "Batal pantau",
"watchlist-details": "Ado {{PLURAL:$1|$1 laman}} dalam daftar pantau Sanak (tamasuak laman rundiangnyo).",
"wlheader-showupdated": "Laman nan alah barubah sajak kunjuangan tarakhia Sanak ditunjuakan jo <strong>hurup taba</strong>",
"wlnote": "Di bawah ko ado $1 {{PLURAL:$1|parubahan}} dalam {{PLURAL:$2|'''$2''' jam}} iko, sampai tanggal $3, pukua $4.",
- "wlshowlast": "Tunjuakan $1 jam parubahan dalam $2 hari tarakhia",
"watchlist-options": "Piliahan daftar pantau",
"watching": "Mamantau...",
"unwatching": "indak dipantau le...",
"deletepage": "Hapuih laman",
"confirm": "Konfirmasi",
"excontent": "isi sabalunnyo: \"$1\"",
- "excontentauthor": "isinyo: \"$1\" (dan dibuek dek \"[[Special:Contributions/$2|$2]]\")",
+ "excontentauthor": "isinyo: \"$1\", dan dibuek dek \"[[Special:Contributions/$2|$2]]\" ([[User talk:$2|maota]])",
"exbeforeblank": "isi sabalun dikosongan: \"$1\"",
"delete-confirm": "Hapuih \"$1\"",
"delete-legend": "Hapuih",
- "historywarning": "'''Paringatan:''' Laman nan ka dihapuih ado riwayaik jo $1 {{PLURAL:$1|revisi}}:",
- "confirmdeletetext": "Awak akan mahapuih laman atau berkas basamo riwayatnyo.\nPastikan awak mainginkannyo, dan awak lah tahu sagalo akibatnyo dan sasuai jo [[{{MediaWiki:Policy-url}}|kebijakan]] yang balaku.",
+ "historywarning": "<strong>Paringatan:</strong> Laman nan ka dihapuih ado riwayaik jo $1 {{PLURAL:$1|revisi}}:",
+ "confirmdeletetext": "Sanak akan mangapuih laman atau berkas jo riwayaiknyo.\nPastikan Sanak mainginkannyo, dan lah tahu sagalo akibatnyo dan sasuai jo [[{{MediaWiki:Policy-url}}|kabijakan]] nan balaku.",
"actioncomplete": "Proses salasai",
"actionfailed": "Proses gagal",
"deletedtext": "\"$1\" lah dihapuih.\nCaliak $2 untuak rakam jajak laman nan lah dihapuih.",
"protect_expiry_old": "Maso kadaluwarsa adolah pado maso lampau",
"protect-text": "Sanak buliah malihek jo mangganti tingkek palinduangan untuak laman '''$1'''.",
"protect-locked-access": "Akun Sanak indak bahak untuak maubah tingkek palinduangan laman ko.\nBarikuik ko pangaturan nan balaku untuak laman '''$1''':",
- "protect-cascadeon": "Laman ko sedang dilindungi karano tamasuak dalam {{PLURAL:$1|laman|laman}} aktif perlindungan batingkek.\nAwak dapek maubah tingkek perlindungannyo, walaupun indak pangaruah pado perlindungan batingkeknyo.",
+ "protect-cascadeon": "Laman ko sedang dilindungi karano tamasuak dalam {{PLURAL:$1|laman}} aktif palinduangan batingkek.\nParubahan tingkek palinduangannyo indak mampangaruahi palinduangan batingkeknyo.",
"protect-default": "Kasado pangguno diizinan",
"protect-fallback": "Untuak pangguno jo izin \"$1\" sajo",
- "protect-level-autoconfirmed": "Untuak pangguno takonfirmasi otomatis sajo",
+ "protect-level-autoconfirmed": "Untuak pangguno takonfirmasi otomatih sajo",
"protect-level-sysop": "Untuak panguruih sajo",
"protect-summary-cascade": "batingkek",
"protect-expiring": "sampai $1 (UTC)",
"restriction-move": "Pindah",
"restriction-create": "Buek",
"restriction-upload": "Muek",
- "restriction-level-sysop": "palinduangan panuah",
- "restriction-level-autoconfirmed": "palinduangan semi",
- "restriction-level-all": "sado tingkek",
+ "restriction-level-sysop": "Palinduangan panuah",
+ "restriction-level-autoconfirmed": "Palinduangan semi",
+ "restriction-level-all": "Sado tingkek",
"undelete": "Caliak laman nan dihapuih",
"undeletepage": "Caliak dan baliakan laman tahapuih",
"undeletepagetitle": "'''Iko daftar revisi nan dihapuih dari [[:$1|$1]]'''.",
"undelete-cleanup-error": "Kasalahan sawaktu mangapuih arsip berkas \"$1\" nan indak digunoan.",
"namespace": "Ruangnamo:",
"invert": "Baliakkan piliahan",
- "tooltip-invert": "Buek centang pado kotak ko untuak manyuruakkan parubahan pado halaman nan tagolong pado ruang namo nan dipiliah (dan ruang namo nan takaik jikok tacentang)",
+ "tooltip-invert": "Buek centang pado kotak ko untuak manyuruakkan parubahan pado laman nan tagolong pado ruang namo nan dipiliah (dan ruang namo nan takaik jikok tacentang)",
"namespace_association": "Ruangnamo takaik",
- "tooltip-namespace_association": "Centang halaman ko untuak mamasuakkan ruang namo rundiang atau topik nan takaik jo ruang namo nan dipiliah",
+ "tooltip-namespace_association": "Centang laman ko untuak mamasuakkan ruang namo rundiang atau topik nan takaik jo ruang namo nan dipiliah",
"blanknamespace": "(Utamo)",
"contributions": "Jariah {{GENDER:$1|pangguno}}",
"contributions-title": "Jariah pangguno untuak $1",
"uctop": "kini",
"month": "Dari bulan (dan sabalunnyo):",
"year": "Dari taun (dan sabalunnyo):",
- "sp-contributions-newbies": "Tunjuakan jariah pangguno baru sajo",
- "sp-contributions-newbies-sub": "Untuak pangguno baru",
- "sp-contributions-newbies-title": "Jariah pangguno baru",
"sp-contributions-blocklog": "log sakek",
- "sp-contributions-deleted": "jariah pangguno nan lah dihapuih",
+ "sp-contributions-deleted": "jariah {{GENDER:$1|pangguno}} nan lah dihapuih",
"sp-contributions-uploads": "muek",
"sp-contributions-logs": "log",
"sp-contributions-talk": "maota",
- "sp-contributions-userrights": "pangalolaan hak pangguno",
- "sp-contributions-blocked-notice": "Pangguno ko sadang kanai sakek. log pamblokiran tarakhia ditunjuakan disiko untuak referensi:",
+ "sp-contributions-userrights": "pangalolaan hak {{GENDER:$1|pangguno}}",
+ "sp-contributions-blocked-notice": "Pangguno ko sadang kanai sakek. log panyakekan tarakhia ditunjuakan disiko untuak referensi:",
"sp-contributions-blocked-notice-anon": "Alamaik IP ko tangah kanai sakek.\nEntri log sakek tabaru ado di bawah ko untuak referensi:",
"sp-contributions-search": "Cari jariah",
"sp-contributions-username": "Alamaik IP atau namo pangguno:",
"whatlinkshere-title": "Laman nan takaik ka \"$1\"",
"whatlinkshere-page": "Laman:",
"linkshere": "Laman-laman ko bakaik ka '''$2''':",
- "nolinkshere": "Indak ado laman nan punyo tautan ka '''$2'''.",
+ "nolinkshere": "Indak ado laman nan ado pautan ka <strong>$2</strong>.",
"nolinkshere-ns": "Indak ado pautan laman ka '''$2''' pado ruang namo nan dipiliah.",
"isredirect": "laman pangaliahan",
"istemplate": "transklusi",
"autoblockid": "Sakek otomatih #$1",
"block": "Sakek pangguno",
"unblock": "Lapeh sakek",
- "blockip": "Sakek pangguno",
- "blockiptext": "Gunoan formulir di bawah ko untuak manyakek akses dari sabuah alamaik IP atau pangguno.\nIko hanyo buliah dilakuan untuak mancagah vandal, dan sajalan jo [[{{MediaWiki:Policy-url}}|kabijakan]].\nMasuakan alasan sakek di bawah (contoh, mambuek karusakan atau vandal).",
+ "blockip": "Sakek {{GENDER:$1|pangguno}}",
+ "blockiptext": "Gunoan formulir di bawah ko untuak manyakek akses dari sabuah alamaik IP atau pangguno.\nIko hanyo buliah dilakuan untuak mancagah vandal, dan sajalan jo [[{{MediaWiki:Policy-url}}|kabijakan]].\nMasuakan alasan sakek di bawah (contoh, mambuek karusakan atau vandal). Sanak dapek manyakek rantang IP manggunoan [https://en.wikipedia.org/wiki/Classless_Inter-Domain_Routing CIDR]; rantang tagadang nan dibuliahkan adolah /$1 untuak IPv4 dan /$2 untuak IPv6.",
"ipaddressorusername": "Alamaik IP atau namo pangguno:",
"ipbreason": "Alasan:",
"ipbreason-dropdown": "*Alasan umum sakek\n** Marusak (vandal)\n** Mangagiah informasi palsu\n** Mangilangkan isi laman\n** Spam pautan ka situs lua\n** Mambuek ota gadang di laman\n** Babuek intimidasi/palecehan\n** Manyalahgunoan babarapo akun\n** Namo pangguno talarang\n** Bot alun ado bot flag",
"ipb-hardblock": "Halang pangguno tadaftar untuak manyuntiang dari alamaik IP ko",
- "ipbcreateaccount": "Halang mambuek akun",
- "ipbemailban": "Halang pangguno mangirim surel",
+ "ipbcreateaccount": "Pambuek akun",
+ "ipbemailban": "Kirim surel",
"ipbenableautoblock": "Otomatih sakek alamaik IP tarakhia nan digunoan pangguno ko, jo sado alamaik IP takaik nan mancubo manyuntiang.",
"ipbsubmit": "Sakek pangguno ko",
"ipbother": "Salamo:",
"ipboptions": "2 jam:2 hours,1 ari:1 day,3 ari:3 days,1 pakan:1 week,2 pakan:2 weeks,1 bulan:1 month,3 bulan:3 months,6 bulan:6 months,1 taun:1 year,salamonyo:infinite",
"ipbhidename": "Suruakan namo pangguno dari daftar jo suntiangan",
"ipbwatchuser": "Pantau laman pangguno ko jo laman rundiangnyo",
- "ipb-disableusertalk": "Halang pangguno ko manyuntiang laman diskusinyo wakatu disakek",
+ "ipb-disableusertalk": "Manyuntiang laman rundiangnyo surang",
"ipb-change-block": "Sakek baliak pangguno jo setelan ko",
"ipb-confirm": "Konfirmasi sakek",
"badipaddress": "Alamaik IP salah",
"ipb-unblock-addr": "Lapeh sakek $1",
"ipb-unblock": "Lapeh sakek pangguno atau alamaik IP",
"ipb-blocklist": "Caliak nan disakek",
- "ipb-blocklist-contribs": "Jariah untuak $1",
+ "ipb-blocklist-contribs": "Jariah untuak {{GENDER:$1|$1}}",
"block-expiry": "Sampai:",
"unblockip": "Lapeh sakek",
"unblockiptext": "Gunoan formulir ko untuak mangambalian hak akses alamaik IP atau pangguno nan kanai sakek",
"emailblock": "surel disakek",
"blocklist-nousertalk": "indak dapek manyuntiang laman maota surang",
"ipblocklist-empty": "Daftar sakek ko kosong.",
- "ipblocklist-no-results": "Alamaik IP atau pangguno nan dimintak indak disakek.",
+ "ipblocklist-no-results": "Indak ado sakek untuak alamat IP atau nama pangguno nan dituju.",
"blocklink": "sakek",
"unblocklink": "lapeh sakek",
"change-blocklink": "ubah sakek",
"contribslink": "jariah",
"emaillink": "kirim surel",
- "autoblocker": "Sakek otomatih dek alamaik IP lah digunoan jo \"[[User:$1|$1]]\".\nAlasan disakek untuak $1 adolah \"''$2''\"",
+ "autoblocker": "Sakek otomatih dek alamaik IP lah digunoan jo \"[[User:$1|$1]]\".\nAlasan disakek untuak $1 adolah \"$2\"",
"blocklogpage": "Log sakek",
"blocklogentry": "manyakek [[$1]] dalam maso $2 $3",
"reblock-logentry": "maubah panyakekan [[$1]] jo maso abih $2 $3",
"lockedbyandtime": "(dek {{GENDER:$1|$1}} pado $2 pukua $3)",
"move-page": "Pindahan $1",
"move-page-legend": "Pindahkan laman",
- "movepagetext": "Formulir di bawah ko digunoan untuak maubah namo suatu laman dan mamindahan kasado data riwayaiknyo ka namo baru. \nJudua lamo tu ka manjadi laman pangaliahan manuju judua nan baru. \nSanak dapek mampabarui pangaliahan-pangaliahan nan manuju ka judua lamo sacaro otomatih.\nKok indak dipabarui sacaro otomatih, pastikan lah dipareso laman ko dari [[Special:DoubleRedirects|pangaliahan ganda]] atau [[Special:BrokenRedirects|pangaliahan rusak]]. Sanak batangguang jawek untuak mamastian baso pautan tu taruih manyambuang ka laman nan saharuihnyo.\n\nIngek baso laman ko '''indak''' ka bapindah apobilo lah ado laman nan manggunoan judua nan baru, kacuali bilo laman tu kosong atau marupoan laman pangaliahan dan indak adoi riwayaik suntiangan. Aratinyo Sanak dapek maubah baliak namo laman tu ka namo lamo apobilo ado kasalahan, dan baso awak indak dapek maimpok laman nan alah ado.\n\n'''Paringatan!''' \nIko dapek maakibaikan parubahan nan indak dipakiroan pado laman nan populer; jadi pastian Sanak paham bana akibaik dari tindakan ko sabalun malanjuikannyo.",
- "movepagetext-noredirectfixer": "Formulir di bawah ko digunoan untuak maubah namo suatu laman dan mamindahan sado data riwayaiknyo ka namo baru. \nJudul lamo tu ka manjadi laman paraliahan manuju judul nan baru. \nSanak dapek mampabarui paraliahan-paraliahan nan manuju ka judul lamo sacaro otomatih.\nKok indak dipabarui sacaro otomatih, pastikan lah dipareso laman ko dari [[Special:DoubleRedirects|paraliahan ganda]] atau [[Special:BrokenRedirects|paralihan rusak]]. Sanak batangguang-jawek untuak mamastian pautan tu taruih manyambuang ka laman nan saaruihnyo.\n\nIngeklah bahaso laman ko '''indak''' ka bapindah apobilo lah ado laman nan manggunoan judul nan baru tu, kacuali bilo laman tu kosong atau marupoan laman paraliahan dan indak punyo riwayaik suntiangan. Aratinyo Sanak dapek maubah baliak namo laman ka namo samulo apobilo ado kasalahan, dan Sanak indak dapek manimpo laman nan lah ado.\n\n'''Paringatan!''' \nIko dapek maakibaikan parubahan nan indak dipakiroan pado laman nan populer; jadi pastikan Sanak paham akibaik tindakan ko sabalun malanjuikannyo.",
- "movepagetalktext": "Laman rundiang nan takaik akan dipindahan sacaro otomatih '''kacuali bilo:'''\n\n*Laman rundiang nan indak kosong lah ado pado judul baru, atau\n*Sanak indak mangagiah tando pado kotak di bawah.\n\nDalam kasus tu, kok amuah Sanak dapek mamindahan ataupun manggabuangan laman sacaro manual.",
+ "movepagetext": "Formulir di bawah ko digunoan untuak maubah namo suatu laman dan mamindahan kasado data riwayaiknyo ka namo baru. \nJudua lamo tu ka manjadi laman pangaliahan manuju judua nan baru. \nSanak dapek mampabarui pangaliahan-pangaliahan nan manuju ka judua lamo sacaro otomatih.\nKok indak dipabarui sacaro otomatih, pastikan lah dipareso laman ko dari [[Special:DoubleRedirects|pangaliahan ganda]] atau [[Special:BrokenRedirects|pangaliahan rusak]]. Sanak batangguang jawek untuak mamastian baso pautan tu taruih manyambuang ka laman nan saharuihnyo.\n\nIngek baso laman ko '''indak''' ka bapindah apobilo lah ado laman nan manggunoan judua nan baru, kacuali bilo laman tu kosong atau marupoan laman pangaliahan dan indak adoi riwayaik suntiangan. Aratinyo Sanak dapek maubah baliak namo laman tu ka namo lamo apobilo ado kasalahan, dan baso awak indak dapek maimpok laman nan alah ado.\n\n<strong>Paringatan!</strong> \nIko dapek maakibaikan parubahan nan indak dipakiroan pado laman nan populer; jadi pastian Sanak paham bana akibaik dari tindakan ko sabalun malanjuikannyo.",
+ "movepagetext-noredirectfixer": "Formulir di bawah ko digunoan untuak maubah namo suatu laman dan mamindahan sado data riwayaiknyo ka namo baru. \nJudul lamo tu ka manjadi laman paraliahan manuju judul nan baru. \nSanak dapek mampabarui paraliahan-paraliahan nan manuju ka judul lamo sacaro otomatih.\nKok indak dipabarui sacaro otomatih, pastikan lah dipareso laman ko dari [[Special:DoubleRedirects|paraliahan ganda]] atau [[Special:BrokenRedirects|paralihan rusak]]. Sanak batangguang-jawek untuak mamastian pautan tu taruih manyambuang ka laman nan saaruihnyo.\n\nIngeklah bahaso laman ko '''indak''' ka bapindah apobilo lah ado laman nan manggunoan judul nan baru tu, kacuali bilo laman tu kosong atau marupoan laman paraliahan dan indak punyo riwayaik suntiangan. Aratinyo Sanak dapek maubah baliak namo laman ka namo samulo apobilo ado kasalahan, dan Sanak indak dapek manimpo laman nan lah ado.\n\n<strong>Paringatan!</strong> \nIko dapek maakibaikan parubahan nan indak dipakiroan pado laman nan populer; jadi pastikan Sanak paham akibaik tindakan ko sabalun malanjuikannyo.",
+ "movepagetalktext": "Jikok Sanak mancentang kotak ko, laman rundiang nan takaik akan dipindahkan sacaro otomatih ka judul baru, kacuali laman rundiangnyo indak kosong.\n\nJikok saroman tu, Sanak tapaso mamindahkan atau manggabuangkan laman sacaro manual.",
"moveuserpage-warning": "'''Paringatan:''' Sanak tangah mamindahan laman pangguno. Paralu dikatahui bahwa hanyo laman nan ka bapindah namun pangguno ''indak akan'' baganti namo.",
"movenologintext": "Sanak musti pangguno tadaftar dan [[Special:UserLogin|masuak log]] untuak mamindahan laman.",
"movenotallowed": "Sanak indak ado izin untuak mamindahan laman.",
"movenotallowedfile": "Sanak indak ado izin untuak mamindahan berkas.",
"cant-move-user-page": "Sanak indak ado izin untuak mamindahan laman pangguno (bagian dari sublaman).",
"cant-move-to-user-page": "Sanak indak ado izin untuak mamindahan laman ka laman pangguno (salain ka sublaman pangguno).",
- "newtitle": "Ka judul baru:",
+ "newtitle": "Judul baru:",
"move-watch": "Pantau laman ko",
"movepagebtn": "Pindahkan laman",
"pagemovedsub": "Pamindahan barasil",
"thumbnail_error": "Gagal mambuek miniatua: $1",
"import": "Impor laman",
"importstart": "Mangimpor laman...",
- "importnosources": "Indak ado sumber impor transwiki nan lah dibuek dan pamuatan riwayaik sacaro langsuang alah dinon-aktipan.",
+ "importnosources": "Indak ado sumber impor transwiki nan lah dibuek dan pamuatan riwayaik sacaro langsuang indak aktip.",
"importlogpage": "Log impor",
"importlogpagetext": "Administrasi laman impor jo riwayaik panyuntiangannyo dari wiki lain.",
"tooltip-pt-userpage": "Laman {{GENDER:|pangguno Sanak}}",
"tooltip-pt-anonuserpage": "Laman pangguno IP Sanak",
"tooltip-pt-mytalk": "Laman rundiang {{GENDER:|Sanak}}",
"tooltip-pt-anontalk": "Parundiangan tantang suntiangan dari IP ko",
- "tooltip-pt-preferences": "Piliahan {{GENDER:|Sanak}}",
+ "tooltip-pt-preferences": "Pangaturan {{GENDER:|Sanak}}",
"tooltip-pt-watchlist": "Daftar laman nan dipantau.",
"tooltip-pt-mycontris": "Daftar jariah {{GENDER:|Sanak}}",
"tooltip-pt-login": "Sanak disaranan untuak masuak log; walaupun indak wajib",
"tooltip-t-recentchangeslinked": "Parubahan baru laman nan bakaik jo laman ko",
"tooltip-feed-rss": "Umpan RSS untuak laman ko",
"tooltip-feed-atom": "Umpan Atom untuak laman ko",
- "tooltip-t-contributions": "Daftar kontribusi {{GENDER:$1|pangguno iko}}",
+ "tooltip-t-contributions": "Daftar jariah {{GENDER:$1|pangguno ko}}",
"tooltip-t-emailuser": "Kirimkan surel pado {{GENDER:$1|pangguno ko}}",
"tooltip-t-upload": "Muek berkas",
"tooltip-t-specialpages": "Daftar kasado laman istimewa",
"tooltip-ca-nstab-category": "Caliak laman kategori",
"tooltip-minoredit": "Tandoi iko sabagai suntiangan ketek",
"tooltip-save": "Simpan nan diubah",
+ "tooltip-publish": "Simpan parubahan Sanak",
"tooltip-preview": "Caliak lu nan diubah, gunoan ko sabalun manyimpan",
"tooltip-diff": "Caliak parubahan nan lah dibuek",
"tooltip-compareselectedversions": "Caliak pabedaan antaro duo revisi piliahan laman ko",
"tooltip-recreate": "Buek baliak laman walaupun sabananyo pernah dihapuih",
"tooltip-upload": "Mulai mamuek",
"tooltip-rollback": "\"Baliakkan\" uruangan suntiang laman ko pado jariah tarakhir dalam sakali klik",
- "tooltip-undo": "\"Batalan\" uruangkan panyuntiangan iko jo mambukak bantuak suntiang dalam bantuak pratonton. Hal ko mamungkinkan manambahkan alasan pado kotak ringkasan.",
+ "tooltip-undo": "\"Batalan\" uruangkan panyuntiangan ko jo mambukak bantuak suntiang dalam bantuak pratinjau. Hal iko mamungkinkan manambah alasan pado kotak ikhtisar .",
"tooltip-preferences-save": "Simpan preferensi",
- "tooltip-summary": "Buek ringkasan pendek",
+ "tooltip-summary": "Buek ikhtisar pendek",
"print.css": "/* CSS placed here will affect the print output */",
"anonymous": "{{PLURAL:$1|Pangguno}} anonim {{SITENAME}}",
"siteuser": "pangguno {{SITENAME}} $1",
"anonuser": "pangguno anonim {{SITENAME}} $1",
"others": "lainnyo",
- "siteusers": "{{PLURAL:$2|pangguno}} {{SITENAME}} $1",
+ "siteusers": "{{PLURAL:$2|Pangguno}} {{SITENAME}} $1",
"anonusers": "{{PLURAL:$2|pangguno}} anonim {{SITENAME}} $1",
"creditspage": "Panghargaan laman",
"spam_blanking": "Sado revisi nan ado pautan ka $1, kosong",
"patrol-log-header": "Iko daftar log revisi nan alah dipatroli.",
"previousdiff": "← Revisi sabalunnyo",
"nextdiff": "Revisi salanjuiknyo →",
- "imagemaxsize": "Bateh ukuran gambar:<br />''(untuak laman katarangan berkas)''",
+ "imagemaxsize": "Bateh ukuran gambar pado laman katarangan berkas:",
"thumbsize": "Ukuran miniatua:",
"widthheight": "$1 × $2",
"widthheightpage": "$1 × $2, $3 {{PLURAL:$3|laman}}",
"svg-long-desc-animated": "Berkas animasi SVG, $1 × $2 piksel, ukuran berkas: $3",
"svg-long-error": "Berkas SVG indak sah: $1",
"show-big-image": "Ukuran nan asali",
- "show-big-image-preview": "Ukuran pratonton ko: $1",
+ "show-big-image-preview": "Ukuran pratinjau ko: $1",
"show-big-image-other": "{{PLURAL:$2|Resolusi}} lainnyo: $1.",
"show-big-image-size": "$1 × $2 piksel",
"file-info-gif-looped": "ulang",
"metadata-help": "Berkas ko ado informasi tambahan nan mungkin ditambahan dek kamera digital atau pamindai nan digunoan untuak mambuek atau mandigitalisasi berkas ko. Jikok berkas ko lah mangalami parubahan, rincian nan ado mungkin indak sacaro jaleh mancaminan parubahan dari berkas tu.",
"metadata-expand": "Tunjuakan rincian tambahan",
"metadata-collapse": "Suruakan rincian tambahan",
- "metadata-fields": "Tapak metadata gambar nan didata dalam pasan ko ka dimasuakan pado tampilan laman gambar katiko tabel metadata disuruakan. \nNan lainnyo ka tasuruak sacaro baku.\n* make\n* model\n* datetimeoriginal\n* exposuretime\n* fnumber\n* isospeedratings\n* focallength\n* artist\n* copyright\n* imagedescription\n* gpslatitude\n* gpslongitude\n* gpsaltitude",
- "namespacesall": "sadonyo",
+ "metadata-fields": "Tapak metadata gambar nan didata dalam pasan ko ka dimasuakan pado tampilan laman gambar sangkek tabel metadata disuruakan. \nNan lainnyo ka tasuruak sacaro baku.\n* make\n* model\n* datetimeoriginal\n* exposuretime\n* fnumber\n* isospeedratings\n* focallength\n* artist\n* copyright\n* imagedescription\n* gpslatitude\n* gpslongitude\n* gpsaltitude",
+ "namespacesall": "Sadonyo",
"monthsall": "sadonyo",
"imgmultipagenext": "Laman salanjuiknyo →",
"imgmultigo": "Cari!",
"duplicate-defaultsort": "'''Peringatan:''' Kunci panguruitan default \"$2\" sabalunnyo mangabaikan kunci panguruitan default \"$1\".",
"version": "Versi",
"version-extensions": "Ekstensi tarinstal",
- "version-skins": "Kulik",
+ "version-skins": "Kulik tarinstal",
"version-specialpages": "Laman istimewa",
"version-parserhooks": "Kaik parser",
"version-variables": "Variabel",
"version-antispam": "Pancagahan spam",
"version-other": "Lain-lain",
"version-version": "($1)",
- "version-license": "Lisensi",
+ "version-license": "Lisensi MediaWiki",
"version-poweredby-credits": "Wiki ko didukuang jo '''[https://www.mediawiki.org/ MediaWiki]''', hak cipta © 2001-$1 $2.",
"version-poweredby-others": "lainnyo",
"version-credits-summary": "Kami nio mangakui urang-urang ko ateh kontribusinyo pado [[Special:Version|MediaWiki]].",
- "version-license-info": "MediaWiki adolah parangkaik lunak bebas; Sanak dapek mandistribusian dan/atau mamodfikasinyo jo syaraik Lisensi Publik Umum GNU nan dikaluaan dek Free Software Foundation; versi 2 atau nan tabaru.\n\nMediaWiki didistribusian jo harapan dapek digunoan, tapi INDAK JO JAMINAN APO PUN; indak ado jaminan PADAGANGAN atau KACOCOKAN UNTUAK TUJUAN TATANTU. Caliak Lisensi Publik Umum GNU untuak informasi lebiah lanjuik.\n\nSanak mustilah alah manarimo [{{SERVER}}{{SCRIPTPATH}}/COPYING salinan Lisensi Publik Umum GNU] basamo jo program iko; jikok indak, kiriman suraik ka Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA atau [//www.gnu.org/licenses/old-licenses/gpl-2.0.html baco sacaro online].",
+ "version-license-info": "MediaWiki adolah parangkaik lunak bebas; Sanak dapek mandistribusian dan/atau mamodfikasinyo jo syaraik Lisensi Publik Umum GNU nan dikaluaan dek Free Software Foundation; versi 2 atau nan tabaru.\n\nMediaWiki didistribusian jo harapan dapek digunoan, tapi <em>INDAK ADO JAMINAN APOPUN</em>; indak ado jaminan <strong>PADAGANGAN</strong> atau <strong>KACOCOKAN UNTUAK TUJUAN TATANTU</strong>. Caliak Lisensi Publik Umum GNU untuak informasi lebiah lanjuik.\n\nSanak mustilah alah manarimo [{{SERVER}}{{SCRIPTPATH}}/COPYING salinan Lisensi Publik Umum GNU] basamo jo program iko; jikok indak, kiriman suraik ka Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA atau [//www.gnu.org/licenses/old-licenses/gpl-2.0.html baco sacaro online].",
"version-software": "Parangkaik lunak tapasang",
"version-software-product": "Produk",
"version-software-version": "Versi",
"fileduplicatesearch-result-n": "Berkas \"$1\" ado {{PLURAL:$2|$2 duplikat nan samo}}.",
"fileduplicatesearch-noresults": "Indak basobok berkas banamo \"$1\".",
"specialpages": "Laman istimewa",
- "specialpages-note-restricted": "* Laman istimewa normal.\n* <span class=\"mw-specialpagerestricted\">Laman istimewa talarang.</span>\n* <span class=\"mw-specialpagecached\">Laman istimewa tasinggah (mungkin usang).</span>",
+ "specialpages-note-restricted": "* Laman istimewa biaso.\n* <span class=\"mw-specialpagerestricted\">Laman istimewa talarang.</span>",
"specialpages-group-maintenance": "Laporan pamaliharoan",
"specialpages-group-other": "Lain-lain",
"specialpages-group-login": "Masuak log / mandaftar",
"specialpages-group-spam": "Pakakeh panangka spam",
"blankpage": "Laman kosong",
"intentionallyblankpage": "Laman ko sangajo dikosoangkan.",
- "external_image_whitelist": "#Bia se barih ko apo adonyo<pre>\n#Latakan fragmen tando regular (hanyo bagian antaro //) di bawah ko\n#Iko akan dicocokan jo URL gambar dari lua (tahubuang langsuang)\n#Nan mano nan cocok ditampilkan sabagai gambar, sisonyo hanyo sabagai tautan sajo\n#Barih nan dimulai jo # dianggap sabagai komentar\n#Iko indak mambedoan huruf gadang jo ketek\n\n#Latakan sado fragmen regex di bawah barih ko. Bia se barih ko apo adonyo</pre>",
+ "external_image_whitelist": "#Bia barih ko apo adonyo<pre>\n#Latakan fragmen tando regular (hanyo bagian antaro //) di bawah ko\n#Iko akan dicocokan jo URL gambar dari lua (tahubuang langsuang)\n#Nan mano nan cocok ditampilkan sabagai gambar, sisonyo hanyo sabagai pautan sajo\n#Barih nan dimulai jo # dianggap sabagai komentar\n#Iko indak mambedoan huruf gadang jo ketek\n\n#Latakan sado fragmen regex di bawah barih ko. Bia barih ko apo adonyo</pre>",
"tags": "Tag parubahan nan sah",
"tag-filter": "[[Special:Tags|Tag]] sariang:",
"tag-filter-submit": "Sariang",
"tag-list-wrapper": "[[Special:Tags|{{PLURAL:$1|Tag}}]]: $2",
+ "tag-mw-contentmodelchange": "Parubahan mode konten",
+ "tag-mw-removed-redirect": "Mangapuih pangaliahan",
+ "tag-mw-blank": "Pangosongan",
+ "tag-mw-replace": "Panggantian",
+ "tag-mw-rollback": "Pangambalian",
+ "tag-mw-undo": "Pambatalan",
"tags-title": "Tag",
"tags-intro": "Laman ko barisi daftar tag nan dapek ditandoi dek parangkaik lunak jo suntiangan dan maknanyo.",
"tags-tag": "Namo tag",
"compare-revision-not-exists": "Revisi nan dituju indak basobok.",
"dberr-problems": "Maaf! Situs ko mangalami masalah teknis.",
"htmlform-required": "Nilai ko diparaluan",
+ "htmlform-cloner-create": "Tambahkan labiah banyak",
+ "htmlform-date-placeholder": "HH-BB-TTTT",
"logentry-delete-delete": "$1 {{GENDER:$2|maapuih}} laman $3",
"logentry-delete-restore": "$1 {{GENDER:$2|mangambalian}} laman $3 ($4)",
"logentry-delete-revision": "$1 {{GENDER:$2|mangubah}} tampilan dari {{PLURAL:$5|revisi|$5 revisi}} di laman $3: $4",
"logentry-move-move_redir": "$1 {{GENDER:$2|mamindahan}} laman $3 ka $4 maimpok pangaliahan lamo",
"logentry-move-move_redir-noredirect": "$1 {{GENDER:$2|mamindahan}} laman $3 ka $4 maimpok pangaliahan lamo tanpa mambuek pangaliahan",
"logentry-patrol-patrol": "$1 {{GENDER:$2|manandoi}} revisi $4 dari laman $3 tapatroli",
- "logentry-patrol-patrol-auto": "$1 otomatis {{GENDER:$2|manandoi}} revisi $4 dari laman $3 tapatroli",
+ "logentry-patrol-patrol-auto": "$1 otomatih {{GENDER:$2|manandoi}} revisi $4 dari laman $3 tapatroli",
"logentry-newusers-newusers": "Akun pangguno $1 alah {{GENDER:$2|dibuek}}",
"logentry-newusers-create": "Akun pangguno $1 alah {{GENDER:$2|dibuek}}",
"logentry-newusers-create2": "Akun pangguno $3 alah {{GENDER:$2|dibuek}} dek $1",
"logentry-newusers-byemail": "Akun pangguno $3 alah {{GENDER:$2|dibuek}} dek $1 dan kato sandi alah dikirim jo surel",
- "logentry-newusers-autocreate": "Akun pangguno $1 alah {{GENDER:$2|dibuek}} sacaro otomatis",
- "logentry-rights-rights": "$1 {{GENDER:$2|maubah}} kaanggotaan kalompok $3 dari $4 manjadi $5",
+ "logentry-newusers-autocreate": "Akun pangguno $1 alah {{GENDER:$2|dibuek}} sacaro otomatih",
+ "logentry-rights-rights": "$1 {{GENDER:$2|maubah}} kaanggotaan kalompok {{GENDER:$6|$3}} dari $4 manjadi $5",
"logentry-rights-rights-legacy": "$1 {{GENDER:$2|maubah}} kaanggotaan kalompok $3",
"logentry-upload-upload": "$1 {{GENDER:$2|mangunggah}} $3",
"logentry-upload-overwrite": "$1 {{GENDER:$2|maunggah}} versi baru dari $3",
"expand_templates_xml_output": "Hasil XML",
"expand_templates_ok": "OK",
"expand_templates_remove_comments": "Hapuih komentar",
- "expand_templates_preview": "Pratonton",
+ "expand_templates_preview": "Pratinjau",
"special-characters-group-latin": "Latin",
"special-characters-group-latinextended": "Latin tambahan",
"special-characters-group-ipa": "IPA",
"special-characters-title-emdash": "em dash",
"special-characters-title-minus": "tando kurang",
"mw-widgets-abandonedit": "Apo Sanak yakin nio baliak ka mode baco sabalun manyimpan?",
- "randomrootpage": "Laman dasa sambarang"
+ "mw-widgets-dateinput-no-date": "Tanggal indak ado nan tapiliah",
+ "mw-widgets-usersmultiselect-placeholder": "Tambahkan labiah banyak...",
+ "mw-widgets-titlesmultiselect-placeholder": "Tambahkan labiah banyak...",
+ "randomrootpage": "Laman dasa sambarang",
+ "userlogout-continue": "Apo Sanak nio kalua log?"
}
"nocreate-loggedin": "Немате дозвола да создавате нови страници.",
"sectioneditnotsupported-title": "Уредувањето на заглавија не е поддржано",
"sectioneditnotsupported-text": "Уредувањето на заглавија не е поддржано на оваа страница.",
+ "modeleditnotsupported-title": "Уредувањето не е поддржано",
+ "modeleditnotsupported-text": "Уредувањето не е поддржано за содржинскиот модел $1.",
"permissionserrors": "Грешка со дозволата",
"permissionserrorstext": "Немате дозвола да го направите тоа, од {{PLURAL:$1|следнава причина|следниве причини}}:",
"permissionserrorstext-withaction": "Немате дозвола за $2, од {{PLURAL:$1|следнава причина|следниве причини}}:",
"content-model-css": "CSS",
"content-json-empty-object": "Празен објект",
"content-json-empty-array": "Празна низа",
+ "unsupported-content-model": "<strong>Предупредување:</strong> Содржинскиот модел $1 не е поддржан на ова вики.",
+ "unsupported-content-diff": "Разликите не се поддржани за содржинскиот модел $1.",
+ "unsupported-content-diff2": "Разликите помеѓу содржинските модели $1 и $2 не се поддржани на ова вики.",
"deprecated-self-close-category": "Страници со неважечки самозатворени HTML-ознаки",
"deprecated-self-close-category-desc": "Страницата содржи неважечки самозатворени HTML-ознаки, како што се <code><b/></code> или <code><span/></code>. Нивното поведение наскоро ќе биде сменето, за да бидат во склад со определбите на HTML5. Ова значи дека се застарени и не треба да се употребуваат во викитекст.",
"duplicate-args-warning": "<strong>Предупредување:</strong> [[:$1]] го повикува [[:$2]] со повеќе од една вредност за параметарот „$3“. Ќе се употреби само последната вредност.",
"apihelp-no-such-module": "Модулот „$1“ не е пронајден.",
"apisandbox": "Извршнички песочник",
"apisandbox-jsonly": "Употребата на овој извршнички песочник бара JavaScript.",
- "apisandbox-api-disabled": "Извршникот е оневозможен на ова мрежно место.",
"apisandbox-intro": "Страницава служи за вршење проби со <strong>Извршник на МедијаВики</strong>.\n\nПовеќе за употребата на овој извршник ќе најдете во [[mw:API:Main page|неговата документација]]. Пример: [https://www.mediawiki.org/wiki/API#A_simple_example преземање на содржината на Главната страница]. Одберете дејство за да видите повеќе примери.\n\nИмајте предвид дека она шо го правите на страницава може да се одрази врз викито, иако ова е песочник.",
"apisandbox-submit": "Постави барање",
"apisandbox-reset": "Исчисти",
"wlheader-enotif": "Известувањето по е-пошта е овозможено.",
"wlheader-showupdated": "Страниците кои се променети од вашата последна посета се прикажани со <strong>задебелени</strong> букви.",
"wlnote": "Подолу {{PLURAL:$1|е прикажана последната промена|се прикажани последните <strong>$1</strong> промени}} во {{PLURAL:$2|последниов час|последниве <strong>$2</strong> часа}}, заклучно со $3, $4 ч.",
- "wlshowlast": "Прикажи ги последните $1 часа, $2 дена",
"watchlist-hide": "Скриј",
"watchlist-submit": "Прикажи",
"wlshowtime": "Период за приказ:",
"month": "Од месец (и порано):",
"year": "Од година (и порано):",
"date": "Од датумот (и порано):",
- "sp-contributions-newbies": "Прикажи само придонеси на нови корисници",
- "sp-contributions-newbies-sub": "За нови кориснички сметки",
- "sp-contributions-newbies-title": "Придонеси на нови корисници",
"sp-contributions-blocklog": "Дневник на блокирања",
"sp-contributions-suppresslog": "притаени придонесите на {{GENDER:$1|корисникот|корисничката}}",
"sp-contributions-deleted": "избришани придонеси на {{GENDER:$1|корисникот}}",
"newimages-legend": "Филтрирај",
"newimages-label": "Име на податотека (или дел од името):",
"newimages-user": "IP-адреса или корисничко име",
- "newimages-newbies": "Прикажи само придонеси на нови корисници",
"newimages-showbots": "Прикажувај подигања од ботови",
"newimages-hidepatrolled": "Скриј испатролриани подигања",
"newimages-mediatype": "Тип на медиум:",
"img-lang-default": "(стандарден јазик)",
"img-lang-info": "Испиши ја сликата на $1. $2",
"img-lang-go": "Прикажи",
- "ascending_abbrev": "раст",
- "descending_abbrev": "опаѓ",
"table_pager_next": "Следна страница",
"table_pager_prev": "Претходна страница",
"table_pager_first": "Прва страница",
"autoblockedtext": "താങ്കളുടെ ഐ.പി. വിലാസം സ്വയം തടയപ്പെട്ടിരിക്കുന്നു, മറ്റൊരു ഉപയോക്താവ് ഉപയോഗിച്ച കാരണത്താൽ $1 എന്ന കാര്യനിർവാഹകനാണ് തടഞ്ഞുവെച്ചത്.\nഇതിനു കാരണമായി നൽകിയിട്ടുള്ളത്:\n\n:<em>$2</em>\n\n* തടയൽ തുടങ്ങിയത്: $8\n* തടയൽ അവസാനിക്കുന്നത്: $6\n* തടയാൻ ഉദ്ദേശിച്ചത്: $7\n\nഈ തടയലിനെ കുറിച്ച് ചർച്ച ചെയ്യാൻ താങ്കൾക്കു $1 എന്ന കാര്യനിവാഹകനേയോ മറ്റു [[{{MediaWiki:Grouppage-sysop}}|കാര്യനിർവാഹകരെയോ]] ബന്ധപ്പെടാവുന്നതാണ്.\n\nശ്രദ്ധിക്കുക [[Special:Preferences|താങ്കളുടെ ക്രമീകരണങ്ങളിൽ]] സാധുവായ ഇമെയിൽ വിലാസം രേഖപ്പെടുത്താതിരിക്കുകയോ, അത് ഉപയോഗിക്കുന്നതിൽ നിന്ന് താങ്കളെ തടയുകയോ ചെയ്തിട്ടുണ്ടെങ്കിൽ \"{{int:emailuser}}\" എന്ന സംവിധാനം പ്രവർത്തന രഹിതമായിരിക്കും.\n\nതാങ്കളുടെ നിലവിലുള്ള ഐ.പി. വിലാസം $3 ആണ്, താങ്കളുടെ തടയലിന്റെ ഐ.ഡി. #$5 ആകുന്നു.\nദയവായി മുകളിൽ കൊടുത്തിരിക്കുന്ന വിവരങ്ങളെല്ലാം താങ്കൾ നടത്തുന്ന അന്വേഷണങ്ങളിൽ ഉൾപ്പെടുത്തുവാൻ ശ്രദ്ധിക്കുക.",
"systemblockedtext": "താങ്കളുടെ ഉപയോക്തൃനാമം അല്ലെങ്കിൽ ഐ.പി. വിലാസം മീഡിയവിക്കി സ്വയം തടഞ്ഞിരിക്കുന്നു.\nതടയാനുള്ള കാരണം:\n\n:<em>$2</em>\n\n* തടയൽ തുടങ്ങിയത്: $8\n* തടയൽ കാലഹരണപ്പെടുന്നത്: $6\n* തടയാനുദ്ദേശിച്ചയാൾ: $7\n\nതാങ്കളുടെ നിലവിലെ ഐ.പി. വിലാസം $3 ആണ്.\nതാങ്കൾക്കെന്തെങ്കിലും ചോദ്യങ്ങളുണ്ടെങ്കിൽ മുകളിലെ എല്ലാ വിവരങ്ങളും ഉൾപ്പെടുത്തുക.",
"blockednoreason": "കാരണമൊന്നും സൂചിപ്പിച്ചിട്ടില്ല",
+ "blockedtext-composite": "<strong>താങ്കളുടെ ഉപയോക്തൃനാമം അല്ലെങ്കിൽ ഐ.പി. വിലാസം തടയപ്പെട്ടിരിക്കുന്നു.</strong>\n\nനൽകിയിരിക്കുന്ന കാരനം:\n\n:<em>$2</em>.\n\n* തടയൽ തുടങ്ങിയത്: $8\n* ഏറ്റവും ദൈർഘ്യമുള്ള തടയൽ കാലഹരണപ്പെടുന്നത്: $6\n\n* $5\n\nതാങ്കളുടെ നിലവിലെ ഐ.പി. വിലാസം $3 ആണ്.\nതാങ്കൾക്കെന്തെങ്കിലും ചോദ്യങ്ങളുണ്ടെങ്കിൽ മുകളിലെ എല്ലാ വിവരങ്ങളും ഉൾപ്പെടുത്തുക.",
+ "blockedtext-composite-ids": "ബന്ധപ്പെട്ട തടയൽ ഐ.ഡി.കൾ: $1 (താങ്കളുടെ ഐ.പി. വിലാസം കരിമ്പട്ടികയിൽ പെടുത്തിയിട്ടുമുണ്ടാകാം)",
"blockedtext-composite-no-ids": "താങ്കളുടെ ഐ.പി. വിലാസം വിവിധ കരിമ്പട്ടികകളിൽ ഉൾപ്പെട്ടിരിക്കുന്നു",
"blockedtext-composite-reason": "താങ്കളുടെ അംഗത്വത്തിന് അല്ലെങ്കിൽ ഐ.പി. വിലാസത്തിന് വിവിധ തടയലുകൾ നിലവിലുണ്ട്.",
"whitelistedittext": "താളുകൾ തിരുത്താൻ താങ്കൾ $1 ചെയ്യേണ്ടതാണ്",
"apihelp": "എ.പി.ഐ. സഹായം",
"apihelp-no-such-module": "ഘടകം \"$1\" കണ്ടെത്താനായില്ല.",
"apisandbox": "എ.പി.ഐ. എഴുത്തുകളരി",
- "apisandbox-api-disabled": "ഈ സൈറ്റിൽ എ.പി.ഐ. പ്രവർത്തനരഹിതമാക്കിയിരിക്കുന്നു.",
"apisandbox-intro": "<strong>മീഡിയവിക്കി വെബ് സെർവീസ് എ.പി.ഐ.</strong>യിൽ പരീക്ഷണങ്ങൾ നടത്താൻ ഈ താൾ ഉപയോഗിക്കുക.\nഎ.പി.ഐ.യുടെ ഉപയോഗത്തെക്കുറിച്ചുള്ള കൂടുതൽ വിവരങ്ങൾക്കായി [[mw:API:Main page|എ.പി.ഐ. സഹായം]] പരിശോധിക്കുക. ഉദാഹരണം: [https://www.mediawiki.org/wiki/API#A_simple_example പ്രധാന താളിന്റെ ഉള്ളടക്കം എടുക്കുക]. കൂടുതൽ ഉദാഹരണങ്ങൾക്കായി പ്രവൃത്തി തിരഞ്ഞെടുക്കുക.\n\nഇതൊരു പരീക്ഷണകളരിയാണെങ്കിലും ഇവിടെ ചെയ്യുന്നവ വിക്കിയിൽ മാറ്റങ്ങൾ വരുത്തിയേക്കാമെന്ന് ഓർക്കുക.",
"apisandbox-submit": "അഭ്യർത്ഥിക്കുക",
"apisandbox-reset": "ശൂന്യമാക്കുക",
"wlheader-enotif": "ഇമെയിൽ അറിയിപ്പുകൾ സജ്ജമാക്കിയിരിക്കുന്നു.",
"wlheader-showupdated": "താങ്കളുടെ അവസാന സന്ദർശനത്തിനു ശേഷം മാറ്റം വന്ന താളുകൾ '''കടുപ്പിച്ച്''' കാണിച്ചിരിക്കുന്നു",
"wlnote": "$3, $4-നു കഴിഞ്ഞ {{PLURAL:$2|മണിക്കൂറിൽ|<strong>$2</strong> മണിക്കൂറിൽ}} നടന്ന {{PLURAL:$1|ഒരു പുതിയ മാറ്റം|<strong>$1</strong> പുതിയ മാറ്റങ്ങൾ}} താഴെ പ്രദർശിപ്പിച്ചിരിക്കുന്നു.",
- "wlshowlast": "ഒടുവിലത്തെ $1 മണിക്കൂറുകൾ $2 ദിനങ്ങൾ പ്രദർശിപ്പിക്കുക",
"watchlist-hide": "മറയ്ക്കുക",
"watchlist-submit": "പ്രദർശിപ്പിക്കുക",
"wlshowtime": "പ്രദർശിപ്പിക്കേണ്ട കാലാവധി:",
"month": "മാസം:",
"year": "വർഷം:",
"date": "തുടങ്ങേണ്ട തീയതി (അതിന് മുമ്പുള്ളവയും):",
- "sp-contributions-newbies": "പുതിയ അംഗങ്ങൾ നടത്തിയ തിരുത്തുകൾ മാത്രം",
- "sp-contributions-newbies-sub": "പുതിയ ഉപയോക്താക്കൾ ചെയ്തവ",
- "sp-contributions-newbies-title": "പുതിയ അംഗത്വമെടുത്ത ഉപയോക്താക്കളുടെ സേവനങ്ങൾ",
"sp-contributions-blocklog": "തടയൽ രേഖ",
"sp-contributions-suppresslog": "ഒതുക്കപ്പെട്ട {{GENDER:$1|ഉപയോക്തൃ}}സംഭാവനകൾ",
"sp-contributions-deleted": "മായ്ക്കപ്പെട്ട {{GENDER:$1|ഉപയോക്തൃ}}സംഭാവനകൾ",
"newimages-legend": "അരിപ്പ",
"newimages-label": "പ്രമാണത്തിന്റെ പേര് (അഥവാ പേരിന്റെ ഭാഗം)",
"newimages-user": "ഐ.പി. വിലാസം അഥവാ ഉപയോക്തൃനാമം",
- "newimages-newbies": "പുതിയ അംഗങ്ങൾ നടത്തിയ തിരുത്തുകൾ മാത്രം കാണിക്കുക",
"newimages-showbots": "യന്ത്രങ്ങൾ ചെയ്ത അപ്ലോഡുകൾ പ്രദർശിപ്പിക്കുക",
"newimages-hidepatrolled": "റോന്തുചുറ്റപ്പെട്ട അപ്ലോഡുകൾ മറയ്ക്കുക",
"newimages-mediatype": "മീഡിയ തരം:",
"img-lang-default": "(സ്വതേയുള്ള ഭാഷ)",
"img-lang-info": "ഈ ചിത്രം ഈ ഭാഷയിൽ കാണിക്കുക: $1. $2",
"img-lang-go": "പോകൂ",
- "ascending_abbrev": "ആരോഹണം",
- "descending_abbrev": "അവരോഹണം",
"table_pager_next": "അടുത്ത താൾ",
"table_pager_prev": "മുൻപത്തെ താൾ",
"table_pager_first": "ആദ്യതാൾ",
"permanentlink": "സ്ഥിരംകണ്ണി",
"permanentlink-revid": "നാൾപ്പതിപ്പ് ഐ.ഡി.",
"permanentlink-submit": "നാൾപ്പതിപ്പിലേക്ക് പോവുക",
+ "newsection": "പുതിയ വിഭാഗം",
+ "newsection-page": "ലക്ഷ്യ താൾ",
+ "newsection-submit": "താളിലേക്ക് പോകുക",
"dberr-problems": "ക്ഷമിക്കണം! ഈ സൈറ്റിൽ സാങ്കേതിക തകരാറുകൾ അനുഭവപ്പെടുന്നുണ്ട്.",
"dberr-again": "കുറച്ച് മിനിട്ടുകൾ കാത്തിരുന്ന് വീണ്ടും തുറക്കുവാൻ ശ്രമിക്കുക.",
"dberr-info": "(വിവരശേഖരം എടുക്കാൻ പറ്റിയില്ല: $1)",
"log-action-filter-upload-upload": "പുതിയ അപ്ലോഡ്",
"log-action-filter-upload-overwrite": "പുനർ അപ്ലോഡ്",
"log-action-filter-upload-revert": "തിരിച്ചാക്കൽ",
+ "authmanager-authn-autocreate-failed": "പ്രാദേശിക അംഗത്വം യാന്ത്രികമായി സൃഷ്ടിക്കൽ പരാജയപ്പെട്ടു: $1",
"authmanager-create-disabled": "അംഗത്വസൃഷ്ടി പ്രവർത്തനരഹിതമാക്കിയിരിക്കുന്നു.",
"authmanager-create-from-login": "താങ്കളുടെ അംഗത്വം സൃഷ്ടിക്കാൻ, ദയവായി കളങ്ങൾ പൂരിപ്പിക്കുക.",
"authmanager-create-not-in-progress": "സെഷൻ ഡേറ്റ നഷ്ടപ്പെട്ടതിനാൽ അംഗത്വസൃഷ്ടിയുടെ പുരോഗതി നഷ്ടമായിരിക്കുന്നു. ദയവായി ആദ്യം മുതൽ വീണ്ടും തുടങ്ങുക.",
"authmanager-create-no-primary": "അംഗത്വസൃഷ്ടിക്ക് നൽകിയിരിക്കുന്ന വിവരങ്ങൾ ഉപയോഗിക്കാനാവില്ല.",
"authmanager-link-no-primary": "അംഗത്വം ബന്ധിപ്പിക്കാൻ നൽകിയിരിക്കുന്ന വിവരങ്ങൾ ഉപയോഗിക്കാനാവില്ല.",
"authmanager-link-not-in-progress": "സെഷൻ ഡേറ്റ നഷ്ടപ്പെട്ടതിനാൽ അംഗത്വം ബന്ധിപ്പിക്കലിന്റെ പുരോഗതി നഷ്ടമായിരിക്കുന്നു. ദയവായി ആദ്യം മുതൽ വീണ്ടും തുടങ്ങുക.",
+ "authmanager-autocreate-noperm": "യാന്ത്രികമായ അംഗത്വസൃഷ്ടി അനുവദിച്ചിട്ടില്ല.",
+ "authmanager-autocreate-exception": "മുമ്പുണ്ടായ പിഴവുകളെത്തുടർന്ന് യാന്ത്രികമായ അംഗത്വസൃഷ്ടി താത്കാലികമായി പ്രവർത്തനരഹിതമാക്കിയിരിക്കുന്നു.",
"authmanager-userdoesnotexist": "\"$1\" എന്ന ഉപയോക്തൃ അംഗത്വം നിലവിലില്ല.",
"authmanager-userlogin-remembermypassword-help": "രഹസ്യവാക്ക് സെഷൻ കാലയളവിലധികം ഓർത്തുവെക്കണോ.",
"authmanager-username-help": "രഹസ്യവാക്ക് ഉപയോഗിച്ചുള്ള സാധൂകരണം.",
"specialmute": "നിശബ്ദമാക്കുക",
"specialmute-submit": "സ്ഥിരീകരിക്കുക",
"specialmute-label-mute-email": "ഈ ഉപയോക്താവിൽ നിന്നുമുള്ള ഇമെയിലുകൾ നിശബ്ദമാക്കുക",
+ "specialmute-error-invalid-user": "ആവശ്യപ്പെട്ട ഉപയോക്തൃനാമം കണ്ടെത്താനായില്ല.",
"specialmute-login-required": "താങ്കളുടെ നിശബ്ദമാക്കൽ ഐച്ഛികങ്ങൾ മാറ്റുന്നതിനായി ദയവായി പ്രവേശിക്കുക.",
"mute-preferences": "നിശബ്ദമാക്കൽ ഐച്ഛികങ്ങൾ",
"revid": "നാൾപ്പതിപ്പ് $1",
"wlheader-enotif": "И-мэйл мэдэгдэл хүчинтэй боллоо.",
"wlheader-showupdated": "Таны хамгийн сүүлд айлчилснаас хойш өөрчлөгдсөн хуудсууд '''тодоор''' бичигдсэн байгаа",
"wlnote": "Энд нь {{PLURAL:$2|цагийн|'''$2''' цагийн}} өмнө хамгийн сүүлд хийсэн {{PLURAL:$1|өөрчлөлт| '''$1''' өөрчлөлтүүд}} байна.",
- "wlshowlast": "Сүүлийн $1 цагийн $2 өдрийн -г харуул",
"watchlist-options": "Хянаж буй хуудсуудын жагсаалтны сонголтууд",
"watching": "Хянаж байна...",
"unwatching": "Хянахаа больж байна...",
"uctop": "одоох",
"month": "Дараах сараас урагш:",
"year": "Арын он:",
- "sp-contributions-newbies": "Зөвхөн шинэ бүртгэлүүдийн хувь нэмрийг харуулах",
- "sp-contributions-newbies-sub": "Шинээр бүртгүүлсэн хэрэглэгчид",
- "sp-contributions-newbies-title": "Шинэ бүртгэлүүдийн хувь нэмэр",
"sp-contributions-blocklog": "Түгжээний лог",
"sp-contributions-suppresslog": "Хориглосон хэрэглэгчийн оролцоо",
"sp-contributions-deleted": "устгагдсан хэрэглэгчийн хувь нэмэр",
"imgmultipagenext": "дараагийн хуудас →",
"imgmultigo": "Явах",
"imgmultigoto": "$1 хуудас руу явах",
- "ascending_abbrev": "өгсөх",
- "descending_abbrev": "буурах",
"table_pager_next": "Дараагийн хуудас",
"table_pager_prev": "Өмнөх хуудас",
"table_pager_first": "Эхний хуудас",
"watch": "ꯌꯦꯡꯕꯥ",
"unwatch": "ꯌꯦꯡꯗꯕ",
"watchlist-details": "{{PLURAL:$1|$1 page is|$1 pages are}} ꯗ ꯅꯪꯅ ꯌꯦꯡꯂꯤꯕ ꯄꯥꯔꯦꯡꯁꯤꯡ(plus talk pages).",
- "wlshowlast": "$1 ꯄꯨꯪ ꯱ $2 ꯅꯨꯃꯤꯠꯁꯤꯡ ꯑꯔꯣꯏꯕꯗꯨ ꯎꯨꯠꯂꯨ",
"watchlist-options": "ꯌꯦꯡꯂꯤꯕ ꯄꯔꯦꯡ ꯑꯄꯥꯝꯕ ꯈꯟꯅꯕ",
"enotif_reset": "ꯂꯥꯃꯥꯏꯁꯤꯡ ꯁꯤ ꯂꯣꯏꯅ ꯊꯨꯪꯈꯔꯦ ꯍꯥꯏꯅ ꯍꯧ ꯎ",
"dellogpage": "ꯀꯛꯊꯠꯄꯥꯒꯤ ꯂꯣꯒ",
"uctop": "ꯍꯧꯖꯤꯛ",
"month": "ꯃꯗꯨꯒꯤ ꯊꯥꯗꯒꯤ (ꯑꯃꯗꯤ ꯅꯧꯔꯤꯕꯥ)",
"year": "ꯃꯗꯨꯒꯤ ꯆꯥꯍꯤꯗꯒꯤ (ꯑꯃꯗꯤ ꯅꯧꯔꯤꯕꯥ)",
- "sp-contributions-newbies": "ꯑꯅꯧꯕ ꯑꯦꯀꯥꯎꯟꯅꯥ ꯈꯣꯝꯒꯠꯂꯛꯄꯁꯤꯡꯗꯨ ꯈꯛꯇꯃꯛ ꯎꯨꯠꯂꯨ",
"sp-contributions-blocklog": "ꯆꯪꯁꯤꯟꯕꯥ ꯊꯤꯡꯕꯥ",
"sp-contributions-uploads": "ꯊꯥꯒꯠꯄꯁꯤꯡ",
"sp-contributions-logs": "ꯆꯪꯕꯁꯤꯟꯕ ꯃꯌꯥꯝ",
"watchlist-details": "{{PLURAL:$1|$1 မုက်လိက်ဂှ် နွံ|$1 မုက်လိက်တအ်ဂှ် နွံ}} ပ္ဍဲ စရင်မမင်မဲ မၞး (သီုကဵု မုက်လိက် ဓရီုကျာဂမၠိုင်).",
"wlheader-showupdated": "မုက်လိက် မပြံင်လှာဲလဝ် ကြဴနူ မၞးမလုပ်ဝေင်လဝ်တုဲတအ်ဂှ် ထ္ၜးလဝ် နကဵု <strong>အက္ခရ်တီုတီု</strong>.",
"wlnote": "ဗွဲသၟဝ်ဝွံ {{PLURAL:$1|ဒှ် အရာ မပြံင်လှာဲလဝ် လက္ကရဴအိုတ်ရ၊၊| ဒှ် အရာ မပြံင်လှာဲလဝ် လက္ကရဴအိုတ်ဂမၠိုင်ရ၊၊ <strong>$1</strong> အပြံင်အလှာဲ}} ပ္ဍဲအခိင် မအောန် နူ {{PLURAL:$2|နာဍဳ|<strong>$2</strong> နာဍဳ}}, ကု $3, $4.",
- "wlshowlast": "လက္ကရဴအိုတ် $1 နာဍဳ $2 တ္ၚဲ ဂှ် ထ္ၜးညိ",
"watchlist-hide": "ဗဒန်",
"watchlist-submit": "ထ္ၜး",
"wlshowhideminor": "မပလေဝ်ဒါန်လဝ် ညိည",
"uctop": "လၟုဟ်",
"month": "နူ ဂိတု (ကေုာံ ပြဟ်နူ)",
"year": "နူ သၞာံ (ကေုာံ ပြဟ်နူ):",
- "sp-contributions-newbies": "ထ္ၜး အရာမကၠောန်ခၞံ နူကဵု အကံက်တၟိ ဟေင်",
- "sp-contributions-newbies-sub": "သွက် အကံက် တၟိဂမၠိုၚ်",
- "sp-contributions-newbies-title": "ညးလွပ် ရီုဗၚ် သွက် အကံက် တၟိဂမၠိုၚ်",
"sp-contributions-blocklog": "စၟတ်သမ္တီ အရာမကၟာတ်ဗလံက်လဝ်",
"sp-contributions-uploads": "ပတိုန်ပၠောပ်",
"sp-contributions-logs": "တင်စၟတ်သမ္တီဂမၠိုင်",
"show-big-image-size": "$1 × $2 pixels",
"newimages-legend": "ဖဍိုဟ်",
"newimages-user": "IP address ဟွံသေင်မ္ဂး ယၟုမညးလွပ်",
- "newimages-newbies": "ထ္ၜး အရာမကၠောန်ခၞံ နူကဵု အကံက်တၟိ ဟေင်",
"newimages-showbots": "ထ္ၜး ပတိုန်နူ ရုပ်စက်တအ်",
"ilsubmit": "ဂၠာဲ",
"bydate": "နကဵု စၟတ်တ္ၚဲ",
"apihelp-no-such-module": "मॉड्यूल \"$1\" सापडत नाही.",
"apisandbox": "एपीआय(API) धूळपाटी",
"apisandbox-jsonly": "ही एपीआय धूळपाटी वापरण्यास जावास्क्रिप्ट आवश्यक आहे.",
- "apisandbox-api-disabled": "या संकेतस्थळावर हा एपीआय अक्षम केला आहे.",
"apisandbox-intro": "<strong>मिडियाविकि वेब सर्व्हीस एपीआय</strong> वर प्रयोग करण्यासाठी या पानाचा वापर करा. एपीआय वापरण्याच्या अधिक तपशिलासाठी [[mw:API:Main page| एपीआय दस्ताऐवजीकरण]] हे पान बघा. उदाहरणार्थ:[https://www.mediawiki.org/wiki/API#A_simple_example मुख्य पानाचा आशय मिळवा]. अधिक उदाहरणे बघण्यास एखादी क्रिया निवडा.\n\nयाची नोंद घ्या कि ही धूळपाटी असली तरी, या पानावर आपण केलेल्या क्रियांद्वारे विकिवर फेरफार होऊ शकतो.",
"apisandbox-submit": "विनंती करा",
"apisandbox-reset": "हटवा",
"wlheader-enotif": "विपत्र अधिसूचना सुविधा शक्य केली.",
"wlheader-showupdated": "ती पाने, जी आपण दिलेल्या शेवटच्या भेटीनंतर बदललेली आहेत, '''ठळक''' दाखवली आहेत.",
"wlnote": "खाली $3, $4 चे गेल्या {{PLURAL:$2|तासातील|<strong>$2</strong> तासांतील}} {{PLURAL:$1|शेवटचा बदल दिला आहे|शेवटाचे<strong>$1</strong>बदल दिले आहेत}}.",
- "wlshowlast": "मागील $1 तास $2 दिवस दाखवा",
"watchlist-hide": "लपवा",
"watchlist-submit": "दर्शवा",
"wlshowtime": "दर्शविण्याचा कालावधी:",
"month": "या महिन्यापासून (आणि पूर्वीचे):",
"year": "या वर्षापासून (आणि पूर्वीचे):",
"date": "दिनांकापासून (अथवा पूर्वीचे):",
- "sp-contributions-newbies": "केवळ नवीन सदस्य खात्यांचे योगदान दाखवा",
- "sp-contributions-newbies-sub": "नवशिक्यांसाठी",
- "sp-contributions-newbies-title": "नवीन खात्यांसाठी सदस्य योगदान",
"sp-contributions-blocklog": "रोध नोंदी",
"sp-contributions-suppresslog": "{{GENDER:$1|सदस्य}} योगदानाचे दमन केले",
"sp-contributions-deleted": "वगळलेली {{GENDER:$1|सदस्य}} संपादने",
"newimages-legend": "गाळक",
"newimages-label": "संचिकानाम (किंवा त्याचा भाग):",
"newimages-user": "अंकपत्ता अथवा सदस्यनाम",
- "newimages-newbies": "फक्त नवीन खात्यांचीच योगदाने दाखवा",
"newimages-showbots": "सांगकाम्याद्वारे केलेली अपभारणे दाखवा",
"newimages-hidepatrolled": "गस्त घातलेली अपभारणे लपवा",
"noimages": "बघण्यासारखे येथे काही नाही.",
"imgmultigoto": "$1 पानावर जा",
"img-lang-default": "(अविचल भाषा)",
"img-lang-go": "जा",
- "ascending_abbrev": "चढ",
- "descending_abbrev": "उतर",
"table_pager_next": "पुढील पान",
"table_pager_prev": "मागील पान",
"table_pager_first": "पहिले पान",
"apihelp-no-such-module": "Modul \"$1\" tidak dijumpai.",
"apisandbox": "Kotak pasir API",
"apisandbox-jsonly": "JavaScript diperlukan untuk menggunakan kotak pasir API.",
- "apisandbox-api-disabled": "API dimatikan di tapak web ini.",
"apisandbox-intro": "Gunakan laman ini untuk bereksperimen dengan '''API perkhidmatan sesawang MediaWiki'''.\nRujuk [https://www.mediawiki.org/wiki/API:Main_page dokumentasi API] untuk keterangan lanjut tentang penggunaan API.\nContoh: [https://www.mediawiki.org/wiki/API#A_simple_example dapatkan kandungan Laman Utama]. Pilih satu tindakan untuk melihat banyak lagi contoh.",
"apisandbox-submit": "Buat permintaan",
"apisandbox-reset": "Padamkan",
"wlheader-enotif": "Pemberitahuan melalui e-mel dibolehkan.",
"wlheader-showupdated": "Laman-laman yang telah diubah sejak kunjungan terakhir anda dipaparkan dalam '''teks tebal'''.",
"wlnote": "Yang berikut ialah <strong>$1</strong> perubahan terakhir sejak $2 jam yang lalu, sehingga $3, $4.",
- "wlshowlast": "Tunjukkan $2 hari $1 jam yang lalu",
"watchlist-hide": "Sorok",
"wlshowtime": "Tempoh masa untuk dipaparkan:",
"wlshowhideminor": "suntingan kecil",
"uctop": "terkini",
"month": "Sebelum bulan:",
"year": "Sejak tahun (dan sebelumnya):",
- "sp-contributions-newbies": "Tunjukkan sumbangan daripada akaun baru sahaja",
- "sp-contributions-newbies-sub": "Bagi akaun-akaun baru",
- "sp-contributions-newbies-title": "Sumbangan oleh pengguna baru",
"sp-contributions-blocklog": "log sekatan",
"sp-contributions-suppresslog": "sumbangan pengguna tersembunyi",
"sp-contributions-deleted": "sumbangan dihapuskan",
"img-lang-default": "(bahasa azali)",
"img-lang-info": "Paparkan gambar ini dalam $1. $2",
"img-lang-go": "Jalan",
- "ascending_abbrev": "menaik",
- "descending_abbrev": "menurun",
"table_pager_next": "Muka berikutnya",
"table_pager_prev": "Muka sebelumnya",
"table_pager_first": "Muka pertama",
"apihelp": "Għajnuna fuq l-API",
"apihelp-no-such-module": "Il-modulu \"$1\" ma nstabx.",
"apisandbox": "Paġna tal-provi tal-API",
- "apisandbox-api-disabled": "L-API hija diżattivata fuq dan is-sit.",
"apisandbox-intro": "Uża din il-paġna sabiex tesperimenta mal-'''MediaWiki web service API'''.\nŻur id-[https://www.mediawiki.org/wiki/API:Main_page dokumentazzjoni tal-API] għal aktar dettalji dwar l-użu tal-API. Eżempju: [https://www.mediawiki.org/wiki/API#A_simple_example ikseb il-kontenut tal-paġna prinċipali]. Agħżel azzjoni sabiex tara aktar eżempji.",
"apisandbox-submit": "Agħmel rikjesta",
"apisandbox-reset": "Ħassar",
"wlheader-enotif": "In-notifikazzjoni bl-użu tal-posta elettronika hija attivata.",
"wlheader-showupdated": "Il-paġni li ġew editjati wara l-aħħar żjara tiegħek qed jiġu murija b'tipa '''ħoxna'''",
"wlnote": "Hawn taħt hawn {{PLURAL:$1|l-aħħar modifika|l-aħħar '''$1''' modifiki}} fl-aħħar {{PLURAL:$2|siegħa|'''$2''' siegħat}}, sal-$3, fil-$4.",
- "wlshowlast": "Uri l-aħħar $1 siegħat $2 ġranet",
"watchlist-options": "Opzjonijiet tal-lista ta' osservazzjoni",
"watching": "Imsegwi...",
"unwatching": "Mhux osservat aktar...",
"uctop": "attwali",
"month": "Mix-xahar (u qabel):",
"year": "Mis-sena (u qabel):",
- "sp-contributions-newbies": "Uri biss il-kontribuzzjonijiet tal-utenti l-ġodda",
- "sp-contributions-newbies-sub": "Għall-utenti l-ġodda",
- "sp-contributions-newbies-title": "Kontribuzzjonijiet ta' utenti ġodda",
"sp-contributions-blocklog": "blokki",
"sp-contributions-suppresslog": "kontribuzzjonijiet tal-utenti mħassra",
"sp-contributions-deleted": "kontribuzzjonijiet imħassra tal-utent",
"img-lang-default": "(lingwa awtomatika)",
"img-lang-info": "Aqleb din l-istampa f'$1. $2",
"img-lang-go": "Mur",
- "ascending_abbrev": "axx",
- "descending_abbrev": "dixx",
"table_pager_next": "Il-paġna li jmiss",
"table_pager_prev": "Il-paġna ta' qabel",
"table_pager_first": "L-ewwel paġna",
"wlheader-enotif": "La notificaçon por correio eiletrónico stá atiba.",
"wlheader-showupdated": "Las páiginas altaradas zde la redadeira beç que las besitou aparecen çtacadas an <strong>negrito</strong>.",
"wlnote": "A seguir {{PLURAL:$1|stá la redadeira altaraçon ocorrida|stan las redadeiras <strong>$1</strong> altaraçones ocorridas}} {{PLURAL:$2|na redadeira hora|nas redadeiras<strong>$2</strong> horas}}, anté $3, $4.",
- "wlshowlast": "Ber redadeiras $1 horas $2 dies",
"watchlist-submit": "Amostrar",
"watchlist-options": "Oupçones de la lhista de páiginas begiadas",
"watching": "A begiar...",
"uctop": "rebison atual",
"month": "De l més (i atrasados):",
"year": "De l anho (i atrasados):",
- "sp-contributions-newbies": "Amostrar solo las cuntrebuiçones de cuontas recientes",
- "sp-contributions-newbies-sub": "Pa cuontas nuobas",
- "sp-contributions-newbies-title": "Cuntrebuiçones de cuontas nuobas",
"sp-contributions-blocklog": "registro de bloqueios",
"sp-contributions-uploads": "cargaduras",
"sp-contributions-logs": "registros",
"imgmultipagenext": "páigina seguinte →",
"imgmultigo": "Bota!",
"imgmultigoto": "Ir pa páigina $1",
- "ascending_abbrev": "chubir",
- "descending_abbrev": "decer",
"table_pager_next": "Páigina seguinte",
"table_pager_prev": "Páigina atrasada",
"table_pager_first": "Purmeira páigina",
"wlheader-enotif": "အီးမေးလ် အသိပေးချက်ကို ဖွင့်ထားသည်။",
"wlheader-showupdated": "သင် နောက်ဆုံးကြည့်ရှုခဲ့ပြီးနောက် ပြောင်းလဲမှုရှိခဲ့သော စာမျက်နှာများကို <strong>စာလုံးမဲ</strong> ဖြင့် ပြသထားသည်",
"wlnote": "အောက်ပါတို့သည် $3၊ $4 အထိ နောက်ဆုံး {{PLURAL:$2|နာရီ|<strong>$2</strong> နာရီ}}အတွင်း {{PLURAL:$1|နောက်ဆုံးပြောင်းလဲချက် တစ်ခု|နောက်ဆုံးပြောင်းလဲချက်များ <strong>$1</strong> ခု}} ဖြစ်သည်။",
- "wlshowlast": "နောက်ဆုံး $1 နာရီ $2 ရက် ကိုပြရန်",
"watchlist-hide": "ဝှက်",
"watchlist-submit": "ပြသရန်",
"wlshowtime": "ပြသပေးရမည့် အချိန်ကာလ:",
"month": "အဆိုပါ လမှစ၍ ( အဆိုပါလထက်လည်း စောသော) :",
"year": "အဆိုပါ နှစ်မှစ၍ (အဆိုပါနှစ်ထက်လည်း စောသော):",
"date": "အဆိုပါရက်စွဲမှစ၍ (ယင်းထက်လည်း စောသော):",
- "sp-contributions-newbies": "အကောင့်အသစ်များ၏ ပံ့ပိုးမှုများကိုသာ ပြရန်",
- "sp-contributions-newbies-sub": "အကောင့်အသစ်များအတွက်",
- "sp-contributions-newbies-title": "အကောင့်သစ်များအတွက် အသုံးပြုသူပံ့ပိုးမှုများ",
"sp-contributions-blocklog": "ပိတ်ပင်တားဆီးမှု မှတ်တမ်း",
"sp-contributions-deleted": "ဖျက်ခံထားရသည့် {{GENDER:$1|အသုံးပြုသူ}} ဆောင်ရွက်ချက်များ",
"sp-contributions-uploads": "အပ်လုပ်တင်ထားသည်များ",
"newimages-legend": "စိစစ်မှု",
"newimages-label": "ဖိုင်အမည် (သို့ ယင်း၏အစိတ်အပိုင်း) -",
"newimages-user": "အိုင်ပီလိပ်စာ သို့ အသုံးပြုသူအမည်",
- "newimages-newbies": "အကောင့်အသစ်များ၏ ပံ့ပိုးမှုများကိုသာ ပြရန်",
"newimages-showbots": "ဘော့များ တင်ထားသည်ကို ပြရန်",
"newimages-mediatype": "မီဒီယာ အမျိုးအစား:",
"noimages": "ကြည့်စရာဘာမှ မရှိပါ။",
"imgmultigoto": "စာမျက်နှာ $1 ကို သွားရန်",
"img-lang-default": "(ပင်မ ဘာသာစကား)",
"img-lang-go": "သွားပါ",
- "ascending_abbrev": "ငယ်စဉ်ကြီးလိုက်",
- "descending_abbrev": "ကြီးစဉ်ငယ်လိုက်",
"table_pager_next": "နောက်စာမျက်နှာ",
"table_pager_prev": "ပြီးခဲ့သော စာမျက်နှာ",
"table_pager_first": "ပထမဆုံး စာမျက်နှာ",
"unwatchthispage": "Лоткамс ванстомадонзо",
"notvisiblerev": "Лиякстомтомась нардазь",
"watchlist-details": "Ванома лемрисьмесэть (кортнема лопатнесэяк) {{PLURAL:$1|$1 лопа|$1 лопат}}.",
- "wlshowlast": "Невтемс меельце $1 цяст $2 чить",
"wlshowhideanons": "лемтеме теицят",
"watchlist-options": "Ванома потмонь аравтнемат",
"watching": "Ванома...",
"uctop": "течеме чинь",
"month": "Ковстонть (ды седе икеле):",
"year": "Иестэнть (ды седе икеле):",
- "sp-contributions-newbies": "Невтемс ансяк од теицятнень путовксост",
- "sp-contributions-newbies-sub": "Од акаунтс",
"sp-contributions-blocklog": "Пекстамонь журналось",
"sp-contributions-uploads": "Ёвкстамот",
"sp-contributions-logs": "журналт",
"uctop": "سر",
"month": "این ماه (و پیش از اون) دله:",
"year": "این سال (و پیش از اون) دله:",
- "sp-contributions-newbies": "نـه وا بـأیـه ئـهکـانـتئون دأچـیـهنئون ره نـهشـون هـاده",
"sp-contributions-talk": "گپ",
"sp-contributions-username": "IP نـهشـونـی یا کـارورینوم",
"sp-contributions-submit": "چرخهتو",
"watchthispage": "Tictlachiyāz inīn zāzanilli",
"unwatch": "Ahmo titlachiyaz",
"watchlist-details": "Oncah {{PLURAL:$1|$1 tlahcuilolamatl|$1 tlahcuilolamameh}} ipan motlachiyaliz (oc tlahcuilolamatl iteixnamiquiliz).",
- "wlshowlast": "Tiquittaz itlapatlaliz itech $1 horas, $2 tonaltin",
"watchlist-submit": "Monextiz",
"watching": "Tlachiyacah...",
"unwatching": "Ahtlachiyacah...",
"uctop": "axcan tlapatlaliztli",
"month": "Metzpan (auh yeppa):",
"year": "Xiuhpan (auh yeppa):",
- "sp-contributions-newbies": "Tiquimittaz zan yancuic tequitiuhqui intlapatlaliz",
- "sp-contributions-newbies-sub": "Ic yancuīc",
- "sp-contributions-newbies-title": "Yancuīc tlatequitiltilīlli ītlahcuilōl",
"sp-contributions-blocklog": "Tlatzacuiliztli tlahcuilōlloh",
"sp-contributions-uploads": "tlahcuilolquetzaliztli",
"sp-contributions-talk": "teixnamiquiliztli",
"imgmultipagenext": "niman tlahcuilolamatl →",
"imgmultigo": "¡Ma xiyauh!",
"imgmultigoto": "Yaliztica ihuicpa tlahtolamatl $1",
- "ascending_abbrev": "quetza",
- "descending_abbrev": "temoa",
"table_pager_next": "Niman tlahcuilolamatl",
"table_pager_prev": "Achto tlahcuilolamatl",
"table_pager_first": "Achtopa tlahcuilolamatl",
"unwatchthispage": "Mài koh kàm-sī",
"watchlist-details": "Kàm-sī-toaⁿ ū {{PLURAL:$1|$1 ia̍h|$1 ia̍h}}, thó-lūn-ia̍h bô sǹg chāi-lāi.",
"wlnote": "$3 $4: Ē-kha sī <strong>$2</strong> tiám-cheng í-lāi siōng sin ê <strong>$1</strong> ê kái-piàn.",
- "wlshowlast": "Hián-sī chêng $1 tiám-cheng $2 ji̍t",
"deletepage": "Thâi ia̍h",
"confirm": "Khak-tēng",
"excontent": "lōe-iông sī: '$1'",
"uctop": "siōng téng ê",
"month": "Kàu tó 1 kó͘ goe̍h ûi-chí:",
"year": "Kàu tó 1 nî ûi-chí:",
- "sp-contributions-newbies": "Kan-taⁿ hián-sī sin kháu-chō ê kòng-kiàn",
- "sp-contributions-newbies-sub": "Sin lâi--ê",
"sp-contributions-blocklog": "Hong-só ji̍t-chì",
"sp-contributions-deleted": "{{GENDER:$1|iōng-chiá}} hō͘ lâng thâi tiāu ê kòng-hiàn",
"sp-contributions-uploads": "ap-ló͘",
"viewsource-title": "Vere surgente 'e $1",
"actionthrottled": "Azione ritardata",
"actionthrottledtext": "Comme mesùra anti-abuse, site lemmetato 'a ffà st'azione troppe vote dint'a nu curto spazio 'e tiempo, e mo stu lèmmeto l'avite superato.\nPe piacere pruvate n'ata vota dint'a quacche minuto.",
- "protectedpagetext": "Sta paggena s'è prutetta pe' ne bloccà 'a mudifeca o n'ata azione.",
+ "protectedpagetext": "Sta paggena s'è prutetta pe ne ntuppà 'o càgno o quacche ata azione.",
"viewsourcetext": "Putite vedé e copià 'o codece surgiva 'e sta paggena.",
"viewyourtext": "Putite vedé e copià 'o codice surgiva d' 'e <strong>cagnamiénte vuoste</strong> a sta paggena.",
"protectedinterface": "Sta paggena nce appruviggióna 'e n'interfaccia testo p' 'o software dint'a sta wiki, e s'è prutetta pe' nce scanzà 'e cocch'abbuso.\nSi se buò azzeccà o cagnà traduzzione ncopp'a tutte 'e wiki, pe piacere ausate [https://translatewiki.net/ translatewiki.net], 'o pruggetto Mediawiki p'a localizzaziona dint'a l'ate llengue",
"logout": "Jèsce",
"userlogout": "Jèsce",
"notloggedin": "Acciesso nun affettuato",
- "userlogin-noaccount": "Nun tenite ancora n'acciesso?",
+ "userlogin-noaccount": "Nun tenite perzine n'acciesso?",
"userlogin-joinproject": "Facite 'o riggistro ncopp'a {{SITENAME}}",
"createaccount": "Crèa nu cunto nuovo",
"userlogin-resetpassword-link": "Te sì scurdat' 'a password?",
"usercssyoucanpreview": "'''Cunziglio:''' spremme 'o buttone 'Vide anteprimma' pe' pruvà 'o CSS nuovo apprimma d' 'o sarvà.",
"userjsonyoucanpreview": "<strong>Cunziglio:</strong> premme 'o buttone \"{{int:showpreview}}\" pe' pruvà 'o JSON nuovo apprimma d' 'o sarvà.",
"userjsyoucanpreview": "'''Cunziglio:''' spremme 'o buttone 'Vide anteprimma' pe' pruvà 'o JavaScript nuovo apprimma d' 'o sarvà.",
- "usercsspreview": "'''Arricuordate ca chest'è sulamente n'anteprimma p' 'o CSS perzunale. 'E cagnamiente nun so' state ancora sarvate!'''",
+ "usercsspreview": "'''Arricuordate ca chest'è sulamente n'anteprimma p' 'o CSS perzunale. 'E cagnamiente nun so' state sarvate perzì!'''",
"userjsonpreview": "<strong>Arricuordate ca chest'è sulamente n'anteprimma p' 'o JSON perzunale. 'E cagnamiente nun so' state ancora sarvate!</strong>",
- "userjspreview": "'''Arricuordate ca chest'è sulamente n'anteprimma p' 'o JavaScript perzunale. 'E cagnamiente nun so' state ancora sarvate!'''",
- "sitecsspreview": "'''Arricuordate ca chest'è sulamente n'anteprimma p' 'o CSS. 'E cagnamiente nun so' state ancora sarvate!'''",
+ "userjspreview": "'''Arricuordate ca chest'è sulamente n'anteprimma p' 'o JavaScript perzunale. 'E cagnamiente nun so' state sarvate perzì!'''",
+ "sitecsspreview": "'''Arricuordate ca chest'è sulamente n'anteprimma p' 'o CSS. 'E cagnamiente nun so' state sarvate perzì!'''",
"sitejsonpreview": "<strong>Arricuordate ca chest'è sulamente n'anteprimma d' 'a configurazzione d' 'o JSON. 'E cagnamiente nun so' state ancora sarvate!</strong>",
- "sitejspreview": "'''Arricuordate ca chest'è sulamente n'anteprimma p' 'o codece JavaScript. 'E cagnamiente nun so' state ancora sarvate!'''",
+ "sitejspreview": "'''Arricuordate ca chest'è sulamente n'anteprimma p' 'o codece JavaScript. 'E cagnamiente nun so' state sarvate perzì!'''",
"userinvalidconfigtitle": "<strong>Attenziò:</strong> Nun esiste nisciuna skin c' 'o nomme \"$1\". Vide ch' 'e paggene .css e .js personalezzate teneno nu titolo ca minuscola, p'esempio {{ns:user}}:Esempio/vector.css (e no {{ns:user}}:Esempio/Vector.css).",
"updated": "(Agghiurnato)",
"note": "'''Nota:'''",
- "previewnote": "'''Chesta è sola n'anteprimma; 'e cagnamiénte â paggena nun songo ancora sarvate!'''",
+ "previewnote": "'''Chesta è sola n'anteprimma; 'e cagnamiénte â paggena nun so' state sarvate perzì!'''",
"continue-editing": "Trasite int'a l'area 'e modifica",
"previewconflict": "L'anteprimma currisponne a 'o testo presente dint'a cascia 'e modifica ccà ncoppa e rappresentasse 'a paggena comme cumpare si sciglite 'e Sarvà ind'a stu mumento.",
- "session_fail_preview": "Scusate! nun è possibbile prucessà 'o cagnamiento pecché se so' sperdut' 'e date d' 'a sessione.\n\nPuò darse ca d' 'a parta vosta nun eravate trasute.<strong>Pe' piacere cuntrullate ca site ancora dinto e tentate n'ata vota</strong>.\nSi chesto nun funziunasse ancora, tentate a ve [[Special:UserLogout|n'ascì]] e a trasì n'ata vota, e cuntrullate si 'o navigatóre vuosto tenisse 'e cookies appicciàte.",
+ "session_fail_preview": "Scusate! nun è possibbile prucessà 'o cagnamiento pecché se so' sperdut' 'e date d' 'a sessione.\n\nPuò essere ca d' 'a parta vosta nun stavate trasute.<strong>Pe piacere cuntrullate ca state ancora dinto e pruate n'ata vota</strong>.\nSi cchesto nun funziunasse porzì, pruate a ve [[Special:UserLogout|n'ascì]] e a trasì n'ata vota, e cuntrullate si 'o navigatóre vuosto tenisse 'e cookies appicciàte.",
"session_fail_preview_html": "Scusate! Nun è possibbile prucessà 'o cagnamiento pecché se so' sperdut' 'e date d' 'a sessione.\nProva n'ata vota.\n\n<em>Siccome dint' 'o {{SITENAME}} è abilitato l'uso 'e l'HTML cruro, 'o buttone d'anteprimma nun è abbiàto comme misura 'e sicurezza annanza cocch'attacco JavaScript</em>\n\n<strong>Si chest'era nu tentativo legittimo 'e cagnamiento, tentate n'ata vota.</strong>\nSi nun funziunass'ancora, putite pruvà a ve [[Special:UserLogout|n'ascì]] e a trasì n'ata vota, e cuntrullate si 'o navigatóre vuosto premmettesse 'e cookies ca veneno 'a stu sito.",
"token_suffix_mismatch": "'''Stu cagnamiento nun è stato sarvato pecché 'o client ave mmustato nu sbaglio dint'o scrivere d' 'e carattere d' 'a punteggiatura token. Pe luvà na possibbile corruzione d' 'o testo dint'a paggena, s'è rifiutat' 'a modifeca.\n\nSta situazione se può truvà, quanno staje ausanno nu servizio 'e proxy anonime via web cu d' 'e bug.'''",
"edit_form_incomplete": "'''Cocche parte d' 'o modulo 'e cagnamiento nun ha arrivato a 'o server; cuntrolla ch' 'e cagnamiente songo intatte e prova n'ata vota.'''",
"last": "prec",
"page_first": "primma",
"page_last": "úrdema",
- "histlegend": "Confronto nfra verziune: sciglite 'e casciulelle c'attoccassero a 'e verziune che vulite cunfruntà e spremmite Invio o pure 'o buttóne ccà abbascio.\n\nLiggenda: '''({{int:cur}})''' = differenze c' 'a verzione 'e mmò, '''({{int:last}})''' = differenze c' 'a verzione 'e primma, '''{{int:minoreditletter}}''' = cagnamiento minore",
- "history-fieldset-title": "Circa pe' verziune",
+ "histlegend": "Confronto nfra verziune: sciglite 'e casciulelle c'attoccassero a 'e verziune che vulite cunfruntà e spremmite Invio o pure 'o buttóne ccà abbascio.\n\nLiggenda: '''({{int:cur}})''' = differenze c’'a verzione 'e mmò, '''({{int:last}})''' = differenze c’'a verzione 'e primma, '''{{int:minoreditletter}}''' = cagnamiénto piccerillo",
+ "history-fieldset-title": "Truova pe verzione",
"history-show-deleted": "Sulo 'e verziune scancellate",
"histfirst": "primma",
"histlast": "urdema",
"revdelete-text-text": "'E verziune scancellate cumpareno ancora dint' 'a cronologgia d' 'a paggena, ma na parte d' 'o cuntenuto lloro nun sarrà a disposizione a 'o pubbreco.",
"revdelete-text-file": "'E verziune 'e file scancellate cumpareno ancora dint' 'a cronologgia d' 'o file, ma parte d' 'o cuntenuto lloro nun sarrà a disposizione a 'o pubbreco.",
"logdelete-text": "'E fatte 'e riggistro scancellate cumpareno ancora dint' 'a cronologgia 'e riggistro, ma na parte d' 'o cuntenuto lloro nun sarrà a disposizione a 'o pubbreco.",
- "revdelete-text-others": "Ll'at'ammenistrature puterranno ancora trasì e arrepiglià 'e cuntenute annascunnute, si nun so' state mpustate cchiù restrizziune.",
+ "revdelete-text-others": "Ll'at'ammenistrature putarranno trasì perzì e arrepiglià 'e cuntenute annascunnute, si nun so' state mpustate ate restrizziune.",
"revdelete-confirm": "Pe ppiacere cunfermate ca overo vulite ffà chisto, ca cunuscite 'e cunseguenze, e ca state facenno chisto rispettanno 'e [[{{MediaWiki:Policy-url}}|linee guida]].",
"revdelete-suppress-text": "Sti luvamiente hana essere fatte '''unicamente''' dint' 'e situaziune ccà abbascio:\n* nfurmaziune potenzialmente diffamatorie\n* date perzunale inopportune\n*: ''indirizze, nummeri 'e telefono, codece fiscale, ecc.''",
"revdelete-legend": "Miette 'e limmete 'e visibilità",
"filerevert-identical": "'A verziona 'e mo d' 'o file è già eguale eguale a chella scigliuta.",
"filedelete": "Scancella $1",
"filedelete-legend": "Scancella 'o file",
- "filedelete-intro": "State pe' scancellà 'o file '''[[Media:$1|$1]]''' cu tutta 'a cronologgia 'e chisto.",
+ "filedelete-intro": "State pe scancellà 'o file '''[[Media:$1|$1]]''' cu tutta 'a cronologgia soia.",
"filedelete-intro-old": "State a scancellà 'a verziona 'e '''[[Media:$1|$1]]''' d' 'o [$4 $3, $2].",
"filedelete-comment": "Mutivo:",
"filedelete-submit": "Scancèlla",
"unusedtemplates": "Template ca nun se song'ausate",
"unusedtemplatestext": "Sta paggena alenca tutt' 'e paggene int'a 'o namespace {{ns:template}} ca nun se songo nzertàte dint'a n'ata paggena.\nArricuòrdete 'e cuntrullà l'ati cullegamiente a 'e template apprimm' 'e scancellà.",
"unusedtemplateswlh": "ati cullegamiente",
- "randompage": "Na paggena qualsiase",
+ "randompage": "Na paggena qualonca",
"randompage-nopages": "Nun gè song paggene {{PLURAL:$2|dint'ô seguente namespace|dint'ê seguenti namespace}}: $1.",
"randomincategory": "Paggena a uocchio dint' 'a categurìa",
"randomincategory-invalidcategory": "\"$1\" nun è nu nomme 'e categurìa bbuono.",
"statistics-pages-desc": "Tutt' 'e paggene dint'a wiki, mettenno 'e chiacchieriate, redirezionamiente, ecc.",
"statistics-files": "File carrecate",
"statistics-edits": "Cagnamiente d' 'e paggene 'a che {{SITENAME}} s'è accumminciata",
- "statistics-edits-average": "Cagnamiente medie pe' paggena",
+ "statistics-edits-average": "Cagni medie pe paggena",
"statistics-users": "Utente riggistrate",
"statistics-users-active": "Utente attive",
"statistics-users-active-desc": "Utente c'hanno fatto coccosa dint' 'a {{PLURAL:$1|l'urdemo juorno|l'urdeme $1 juorne}}",
"move": "Mòve",
"movethispage": "Mòve sta paggena",
"unusedimagestext": "'E file ccà abbascio esisteno, ma nun songo appennute dint' 'a nisciuna paggena.\nPe' piacere vedite ca n'ati site ncopp' 'a ll'Internet putessero cullegà cu nu file direttamente cu l'URL, picciò vedite ca putessero stà dint'a sta lista ancora tenenno nu cullegamiento diretto.",
- "unusedcategoriestext": "'E categurìe ccà abbascio esisteno, ancora ch' 'e categurìe o l'ati paggene nun l'aùsano.",
+ "unusedcategoriestext": "'E categurìe ccà abbascio esisteno, simbè ca nun nce stanne categurìe o ati paggene ca l'aùsano.",
"notargettitle": "Nisciuna destinazione",
"notargettext": "Nun avete specificato na paggena o n'utente 'e destinazione pe' putè fa sta operazione.",
"nopagetitle": "Nisciuna paggena 'e destinazione",
"apihelp-no-such-module": "'O modulo \"$1\" nun se trova.",
"apisandbox": "Casciulella 'e pprove API",
"apisandbox-jsonly": "'O JavaScript è necessario pe' puté ausà 'a casciulella 'e pprove 'e ll'API.",
- "apisandbox-api-disabled": "Ll'API è stutata ind'a stu sito.",
"apisandbox-intro": "Aùsa sta paggena pe' puté ffà prove c' 'o <strong>servizio web 'e ll'API MediaWiki</strong>.\nVedite e ve piglià riferimento ncopp' 'a [[mw:API:Main page|documentazione 'e ll'API]] pe' n'avé cchiù dettaglie 'e comm'ausà n'API. Esempio: [https://www.mediawiki.org/wiki/API#A_simple_example piglia 'e ccuntenute 'e na Paggena Prencepale]. Sceglie n'aziona pe' n'avé cchiù dettaglie.\n\nTenite a mmente ca, pure si chest'è na casciulella 'e pprove, ll'aziune ca vuje facite putessero cagnà sta wiki.",
"apisandbox-submit": "Fà 'na richiesta",
"apisandbox-reset": "Pulezza",
"wlheader-enotif": "'A funzione 'e notifiche e-mail è appicciata.",
"wlheader-showupdated": "* 'E paggene cca so' state cagnate a l'urdema visita avevano so' nzignate ccà 'n '''grassetto'''.",
"wlnote": "Ccà abbascio {{PLURAL:$1|è elencato 'o cagnamiento cchiù ricente|songo elencate 'e <strong>$1</strong> cagnamiente cchiù recente}} {{PLURAL:$2|int'a ll'urdema ora|int' 'e ll'urdeme <strong>$2</strong> ore}}; 'e date songo agghiurnate 'o $3, $4.",
- "wlshowlast": "Mmusta ll'urdeme $1 ore $2 ghiuorne",
"watchlist-hide": "Annascunne",
"watchlist-submit": "Faje vedé",
"wlshowtime": "Periodo 'e tiempo a mmustà:",
"exbeforeblank": "'O cuntenuto apprimm' 'a ll'arrevacamento era: '$1'",
"delete-confirm": "Scancella \"$1\"",
"delete-legend": "Scancella",
- "historywarning": "'''Attenzione:''' 'A paggena ca state pe' scancellà tene na cronologgia cu $1 {{PLURAL:$1|verzione|verziune}}:",
+ "historywarning": "'''Attenzione:''' 'A paggena ca state pe scancellà tene na cronologgia cu $1 {{PLURAL:$1|verzione|verziune}}:",
"historyaction-submit": "Faje vedé",
- "confirmdeletetext": "Vedite bbuono, vedite ca state a scancellà na paggena nziem' 'a tutt' 'a cronologgia.\nPe' piacere cunfermate si overo vulite fà cchesto, ca ve site fatto/a capace 'e l'effette 'e st'azione e ca chest'azione rispetta 'e [[{{MediaWiki:Policy-url}}|reole 'e scancellamiento]].",
+ "confirmdeletetext": "Vedite bbuono, vedite ca state a scancellà na paggena nziem' 'a tutt' 'a cronologgia soia.\nPe piacere cunfermate si overo vulite fà cchesto, ca ve site fatto/a capace 'e l'effette 'e st'azione e ca chest'azione rispetta 'e [[{{MediaWiki:Policy-url}}|reole 'e scancellamiento]].",
"actioncomplete": "Azzione fernuta",
"actionfailed": "Aziona sfalluta",
"deletedtext": "Qauccheruno ha scancellata 'a paggena \"$1\". Addumannà 'o $2 pe na lista d\"e ppaggene scancellate urdemamente.",
"delete-toobig": "Sta paggena tene na storia 'e cagnamiente troppo longa, ncopp'a $1 {{PLURAL:$1|verzione|verziune}}.\n'O scancellamiento 'e chiste paggene è stato ristretto pe nce 'e putè astipà si ce sta cocche probblema dint' 'o database 'e {{SITENAME}}.",
"delete-warning-toobig": "Sta paggena tene na cronologgia troppo longa, ncopp'a $1 {{PLURAL:$1|verzione|verziune}}.\nScancellannole se putesse crià troppo burdello ncopp' 'e operaziune 'e database dint'a {{SITENAME}};\niate cuoncio cuoncio.",
"deleteprotected": "Nun putite scancellà sta paggena pecché è stata prutetta.",
- "deleting-backlinks-warning": "<strong>Attenzione:</strong>\n[[Special:WhatLinksHere/{{FULLPAGENAME}}|ati paggene]] cunteneno cullegamiente o paggene appennute â n'ata paggena ca state pe' scancellà.",
+ "deleting-backlinks-warning": "<strong>Attenzione:</strong>\n[[Special:WhatLinksHere/{{FULLPAGENAME}}|ati paggene]] cunteneno cullegamiente o paggene appennute â n'ata paggena ca state pe scancellà.",
"deleting-subpages-warning": "<strong>Accuorto:</strong> 'A paggena ca staie pe scancellà tene [[Special:PrefixIndex/{{FULLPAGENAME}}/|{{PLURAL:$1|na sottopaggena|$1 sottopaggene|51=cchiù 'e 50 sottopaggene}}]].",
"rollback": "Ausa na revizione 'e primma",
"rollback-confirmation-yes": "Sfàjere",
"revertpage-nouser": "Annullate 'e cagnamiente 'e n'utente annascunnuto, è stata ripigliata ll'urdema verzione 'e {{GENDER:$1|[[User:$1|$1]]}}",
"rollback-success": "Cagnamiente annullate 'a {{GENDER:$3|$1}};\ns'è turnato arreto a l'urdema verzione 'e {{GENDER:$4|$2}}.",
"sessionfailure-title": "Sessione fallita",
- "sessionfailure": "Pare ca stanno probbleme cu 'a sessiona toja;\nst'azione è stata fermata pe' precauzione annanz' 'e cavall' 'e troia;\nPe' piacere turnate arreto, carrecate n'ata vota 'a paggena pe pruvate n'ata vota.",
+ "sessionfailure": "Pare ca stanno probbleme cu 'a sessiona toja;\nst'azione è stata fremmata pe precauzione annanz' 'e cavall' 'e troia;\nPe piacere mannate n'ata vota 'o modulo.",
"changecontentmodel": "Cagna 'o mudello 'e cuntenute 'e na paggena",
"changecontentmodel-legend": "Cagna 'o mudello 'e cuntenute",
"changecontentmodel-title-label": "Titulo d\"a paggena",
"month": "D' 'o mese (e pure cchiù primma):",
"year": "'E ll'anno (e primma):",
"date": "'A data (e tanno)",
- "sp-contributions-newbies": "Mosta solo 'e contribbute dde nove utente",
- "sp-contributions-newbies-sub": "Pe' l'utente nuove",
- "sp-contributions-newbies-title": "Contribbute 'a l'utente nuove",
"sp-contributions-blocklog": "blocche",
"sp-contributions-suppresslog": "contribbute utente scancellate",
"sp-contributions-deleted": "contribbute 'e l'{{GENDER:$1|utente}} scancellate",
"img-lang-default": "(lengua predefinita)",
"img-lang-info": "Fà addeventà sta paggena comm'a $1. $2",
"img-lang-go": "Vaje",
- "ascending_abbrev": "crisc",
- "descending_abbrev": "dicrisc",
"table_pager_next": "Paggena successiva",
"table_pager_prev": "Paggena 'e primma",
"table_pager_first": "Primma paggena",
"tags-create-warnings-above": "{{PLURAL:$2|Chist'avviso s'è truvato|Chist'avvise se so' truvate}} pe' tramente ca se steva a crià 'o tag \"$1\":",
"tags-create-warnings-below": "Vulite cuntinuà a crià 'o tag?",
"tags-delete-title": "Scancella tag",
- "tags-delete-explanation-initial": "State pe' scancellà 'o tag \"$1\" d' 'o database.",
+ "tags-delete-explanation-initial": "State pe scancellà 'o tag \"$1\" d' 'o database.",
"tags-delete-explanation-in-use": "Sarrà luvato d' 'o {{PLURAL:$2|$2 verziona o d' 'o riggistro|tutt' 'e verziune $2 e/o 'e nutarelle int' 'o riggistro}} addò stesse azzeccato.",
"tags-delete-explanation-warning": "St'aziona è <strong>irreversibbele</strong> e <strong>nun se pò turnà arreto</strong>, pure 'a ll'ammenistrature d' 'o database. Faciteve capace ca stu tag è chillu ca vulite scancellà.",
"tags-delete-explanation-active": "<strong>'O tag \"$1\" è ancora attivo, e sarrà apprecato int' 'o futuro.</strong> Pe' fernì cu st'attività, jate, a lloco addò 'o tag s'è apprecato, e stutate llànno.",
"tags-delete-not-found": "'O tag $1 nun esiste.",
"tags-delete-too-many-uses": "'O tag \"$1\" è apprecato a cchiù 'e $2 {{PLURAL:$2|verziona|verziune}}, cosa ca vulesse dicere ca nun se ò scancellà.",
"tags-delete-warnings-after-delete": "'O tag \"$1\" s'è scancellato, ma {{PLURAL:$2|s'è ncuntrato ll'avviso|se songhe ncuntrate ll'avise}} ccà:",
- "tags-delete-no-permission": "Nun tenite 'o permesso pe' scancellà 'e tag 'e cagnamiente.",
+ "tags-delete-no-permission": "Nun tenite 'o permesso 'e scancellà 'e ttag 'e cagnamiento.",
"tags-activate-title": "Appiccia 'o tag",
"tags-activate-question": "Vuje state p'appiccià 'o tag \"$1\".",
"tags-activate-reason": "Mutivo:",
"apihelp-no-such-module": "Modulen «$1» ikke funnet.",
"apisandbox": "API-sandkasse",
"apisandbox-jsonly": "JavaScript kreves for å bruke API-sandkassa.",
- "apisandbox-api-disabled": "API er deaktivert på dette nettstedet.",
"apisandbox-intro": "Bruk denne siden for å eksperimentere med <strong>webtjenesteprogrammeringsgrensesnittet til MediaWiki</strong>.\nSe [[mw:API:Main page|API-dokumentasjonen]] for mer informasjon om bruk. Eksempel: [https://www.mediawiki.org/wiki/API#A_simple_example hente innholdet til en hovedside]. Velg en handling for å se flere eksempler.\n\nMerk at selv om dette er en sandkasse så kan du utføre handlinger her som fører til endringer på wikien.",
"apisandbox-submit": "Foreta en forespørsel",
"apisandbox-reset": "Tilbakestill",
"wlheader-enotif": "E-postvarsling er slått på.",
"wlheader-showupdated": "Sider som har blitt endret siden du besøkte dem sist vises med '''fet skrift'''.",
"wlnote": "Nedenfor er {{PLURAL:$1|den siste endringen|de siste <strong>$1</strong> endringene}} {{PLURAL:$2|den siste timen|de siste <strong>$2</strong> timene}}, per $3 kl. $4",
- "wlshowlast": "Vis siste $1 timer $2 dager",
"watchlist-hide": "Skjul",
"watchlist-submit": "Vis",
"wlshowtime": "Tidsperiode som skal vises:",
"month": "Fra måned (og tidligere):",
"year": "Fra år (og tidligere):",
"date": "Fra dato (og tidligere):",
- "sp-contributions-newbies": "Vis kun bidrag fra nye kontoer",
- "sp-contributions-newbies-sub": "For nybegynnere",
- "sp-contributions-newbies-title": "Bidrag av nye kontoer",
"sp-contributions-blocklog": "blokkeringslogg",
"sp-contributions-suppresslog": "undertrykte {{GENDER:$1|brukerbidrag}}",
"sp-contributions-deleted": "slettede {{GENDER:$1|brukerbidrag}}",
"newimages-legend": "Filnavn",
"newimages-label": "Filnavn (helt eller delvis):",
"newimages-user": "IP-adresse eller brukernavn",
- "newimages-newbies": "Vis kun bidrag fra nye kontoer",
"newimages-showbots": "Vis opplastinger av botter",
"newimages-hidepatrolled": "Skjul patruljerte opplastinger",
"newimages-mediatype": "Medietype:",
"img-lang-default": "(standardspråk)",
"img-lang-info": "Vis dette bildet i $1.$2",
"img-lang-go": "Start",
- "ascending_abbrev": "stig.",
- "descending_abbrev": "synk.",
"table_pager_next": "Neste side",
"table_pager_prev": "Forrige side",
"table_pager_first": "Første side",
"monday": "måndag",
"tuesday": "dinsdag",
"wednesday": "woonsdag",
- "thursday": "donderdag",
+ "thursday": "dunnerdag",
"friday": "vrydag",
"saturday": "såterdag",
- "sun": "zun",
- "mon": "mao",
- "tue": "die",
+ "sun": "sün",
+ "mon": "mån",
+ "tue": "din",
"wed": "woo",
- "thu": "don",
- "fri": "vrie",
- "sat": "zao",
+ "thu": "dun",
+ "fri": "vry",
+ "sat": "såt",
"january": "januåri",
"february": "februåri",
"march": "määrt",
"november": "november",
"december": "december",
"january-gen": "jannewaori",
- "february-gen": "febrewaori",
+ "february-gen": "februåri",
"march-gen": "meert",
"april-gen": "april",
"may-gen": "mei",
"october-date": "$1 oktober",
"november-date": "$1 november",
"december-date": "$1 desember",
- "pagecategories": "{{PLURAL:$1|Kategorie|Kategorieën}}",
+ "pagecategories": "{{PLURAL:$1|Kategory|Kategoryen}}",
"category_header": "Artikels in kategorie $1",
"subcategories": "Subkategorieën",
"category-media-header": "Media in kategorie \"$1\"",
"category-empty": "''In disse kategoria staon op t moment nog gien artikels of media.''",
- "hidden-categories": "Verbörgen {{PLURAL:$1|kategorie|kategorieën}}",
+ "hidden-categories": "Verbörgen {{PLURAL:$1|kategory|kategoryen}}",
"hidden-category-category": "Verbörgen kategorieën",
"category-subcat-count": "{{PLURAL:$2|Disse kategorie hef de volgende subkategorie.|Disse kategorie hef de volgende {{PLURAL:$1|subkategorie|$1 subkategorieën}}, van in totaal $2.}}",
"category-subcat-count-limited": "Disse kategorie hef de volgende {{PLURAL:$1|subkategorie|$1 subkategorieën}}.",
"mypage": "Gebrukerszied",
"mytalk": "Myn oaverleg",
"anontalk": "Oaverleg",
- "navigation": "Navigasie",
+ "navigation": "Navigaty",
"and": " en",
"faq": "Vragen die vake esteld wörden",
"actions": "Haandeling",
- "namespaces": "Naamrüümdes",
- "variants": "Variaanten",
- "navigation-heading": "Navigasiemenu",
+ "namespaces": "Naamruumdes",
+ "variants": "Varianten",
+ "navigation-heading": "Navigatymenu",
"errorpagetitle": "Foutmelding",
"returnto": "Weerumme naor $1.",
"tagline": "Van {{SITENAME}}",
- "help": "Hulpe",
- "search": "Zeuken",
- "searchbutton": "Zeuken",
+ "help": "Hülpe",
+ "search": "Söken",
+ "searchbutton": "Söken",
"go": "Artikel",
"searcharticle": "Artikel",
"history": "Geschiedenisse",
- "history_short": "Geschiedenisse",
+ "history_short": "Geskydenisse",
"updatedmarker": "bie-ewörken sinds mien leste bezeuk",
- "printableversion": "Afdrukbåre versy",
+ "printableversion": "Afdrükbåre versy",
"permalink": "Vaste verwysing",
"print": "Aofdrokken",
"view": "Leasen",
"specialpage": "Speciale syde",
"personaltools": "Persoonlike instellingen",
"talk": "Oaverleg",
- "views": "Weergaven",
+ "views": "Weadergåven",
"toolbox": "Hülpmiddels",
"tool-link-userrights": "{{GENDER:$1|Gebrukersgruppen}} wysigen",
"tool-link-emailuser": "Disse {{GENDER:$1|gebruker}} een bericht stüren",
"viewhelppage": "Hulpzied bekieken",
"categorypage": "Kategoriezied bekieken",
"viewtalkpage": "Bekiek overlegzied",
- "otherlanguages": "Andere talen",
- "redirectedfrom": "(deurestuurd vanaof \"$1\")",
+ "otherlanguages": "Andere språken",
+ "redirectedfrom": "(döärstüürd vanaf \"$1\")",
"redirectpagesub": "Deurverwieszied",
"redirectto": "Deurverwiezen naor:",
- "lastmodifiedat": "Disse zied is t lest ewiezigd op $1 um $2.",
+ "lastmodifiedat": "Disse syde is et lätst wysigd up $1 üm $2.",
"viewcount": "Disse zied is $1 {{PLURAL:$1|keer|keer}} bekeken.",
"protectedpage": "Beveiligden zied",
- "jumpto": "Gao naor:",
- "jumptonavigation": "navigasie",
- "jumptosearch": "zeuk",
+ "jumpto": "Gå nå:",
+ "jumptonavigation": "navigaty",
+ "jumptosearch": "söök",
"view-pool-error": "De servers bin op heden overbelast.\nTe veule gebrukers proberen disse zied te bekieken.\nWacht effen veurda'j opniej toegang proberen te kriegen tot disse zied.\n\n$1",
"generic-pool-error": "De servers bin op heden overbelast.\nTe veule gebrukers proberen disse zied te bekieken.\nWacht effen veurda'j opniej toegang proberen te kriegen tot disse zied.",
"pool-timeout": "De maximumwachttied veur databankvergrendeling is verleupen.",
"pool-queuefull": "De wachtrie van de poel is vol",
"pool-errorunknown": "Onbekende fout",
"pool-servererror": "De dienst \"pool counter\" is niet beschikbaor ($1).",
- "aboutsite": "Over {{SITENAME}}",
+ "aboutsite": "Oaver {{SITENAME}}",
"aboutpage": "Project:Info",
"copyright": "De inhoud is beschikbaor onder de $1 as der niks aanders an-egeven is.",
"copyrightpage": "{{ns:project}}:Auteursrechten",
- "currentevents": "In t niejs",
- "currentevents-url": "Project:In t niejs",
- "disclaimers": "Veurbehold",
- "disclaimerpage": "Project:Veurbehoud",
+ "currentevents": "In et nys",
+ "currentevents-url": "Project:In et nys",
+ "disclaimers": "Vöärbehold",
+ "disclaimerpage": "Project:Vöärbehold",
"edithelp": "Hulpe mit bewarken",
"helppage-top-gethelp": "Hulpe",
"mainpage": "Vöärblad",
"mainpage-description": "Vöärblad",
"policy-url": "Project:Beleid",
- "portal": "Gebrukersportål",
- "portal-url": "Project:Gebrukersportaol",
- "privacy": "Gegevensbeleid",
- "privacypage": "Project:Gegevensbeleid",
+ "portal": "Gemeynskapsportaal",
+ "portal-url": "Project:Gemeynskapsportaal",
+ "privacy": "Gegeavensbeleid",
+ "privacypage": "Project:Gegeavensbeleid",
"badaccess": "Gien toestemming",
"badaccess-group0": "Je hebben gien toestemming um disse aksie uut te voeren.",
"badaccess-groups": "Disse aksie kan allinnig uutevoerd wörden deur gebrukers uut {{PLURAL:$2|de groep|één van de groepen}}: $1.",
"editold": "bewark",
"viewsourceold": "brontekste bekyken",
"editlink": "bewark",
- "viewsourcelink": "brontekste bekyken",
+ "viewsourcelink": "brontekst bekyken",
"editsectionhint": "Bewarkingsveld: $1",
"toc": "Inhold",
"showtoc": "Bekieken",
"site-atom-feed": "$1 Atom-voer",
"page-rss-feed": "\"$1\" RSS-voer",
"page-atom-feed": "\"$1\" Atom-voer",
- "red-link-title": "$1 (zied besteet nog niet)",
+ "red-link-title": "$1 (syde besteyt noch neet)",
"sort-descending": "Aoflopend sorteren",
"sort-ascending": "Oplopend sorteren",
"nstab-main": "Artikel",
"nohistory": "Der bin gien eerdere versies van disse zied.",
"currentrev": "Leste versie",
"currentrev-asof": "Leste versie van $1",
- "revisionasof": "Versie op $1",
+ "revisionasof": "Versy up $1",
"revision-info": "Versie op $1 van {{GENDER:$6|$2}}$7",
- "previousrevision": "← eerdere versie",
+ "previousrevision": "← eyrere versy",
"nextrevision": "niejere versie →",
"currentrevisionlink": "versie zo as t noen is",
"cur": "noen",
"lineno": "Regel $1:",
"compareselectedversions": "Vergeliek de ekeuzen versies",
"showhideselectedversions": "Ekeuzen versies bekieken/verbargen",
- "editundo": "weerummedreien",
+ "editundo": "weaderümmedraien",
"diff-empty": "(Gien verschil)",
"diff-multi-sameuser": "({{PLURAL:$1|n Tussenliggende versie|$1 tussenliggende versies}} deur de zelfde gebruker is verbörgen)",
"diff-multi-manyusers": "($1 tussenliggende {{PLURAL:$1|versie|versies}} deur meer as $2 {{PLURAL:$2|gebruker|gebrukers}} niet weeregeven)",
"difference-missing-revision": "{{PLURAL:$2|Eén versie|$2 versies}} van disse verschillen ($1) {{PLURAL:$2|is|bin}} niet evunnen.\n\nDit kömp meestentieds deur t volgen van n verouwerde verwiezing naor n zied die vortedaon is.\nWaorschienlik ku'j der meer gegevens over vienen in t [{{fullurl:{{#Special:Log}}/delete|page={{FULLPAGENAMEE}}}} vortdologboek].",
- "searchresults": "Zeukresultaoten",
- "searchresults-title": "Zeukresultaoten veur \"$1\"",
+ "searchresults": "Söökresultaten",
+ "searchresults-title": "Söökresultaten vöär \"$1\"",
"titlematches": "Overeenkomst mit t onderwarp",
"textmatches": "Overeenkomst mit teksten",
"notextmatches": "Gien overeenstemming",
"nextn": "volgende {{PLURAL:$1|$1}}",
"prevn-title": "{{PLURAL:$1|Veurig resultaot|Veurige $1 resultaoten}}",
"nextn-title": "{{PLURAL:$1|Volgend resultaot|Volgende $1 resultaoten}}",
- "shown-title": "Laot $1 {{PLURAL:$1|resultaot|resultaoten}} per zied zien",
+ "shown-title": "Låt $1 {{PLURAL:$1|resultaat|resultaten}} per syde seen",
"viewprevnext": "($1 {{int:pipe-separator}} $2) ($3)",
"searchmenu-exists": "'''Der is n zied mit de naam \"[[:$1]]\" op disse wiki.'''",
"searchmenu-new": "<strong>De zied \"[[:$1]]\" op disse wiki anmaken!</strong> \n{{PLURAL:$2|0=|Zie oek de zied mit joew zeukresultaoten.|Zie oek de lieste mit evunnen zeukresultaoten.}}",
"searchprofile-articles": "Artikels",
"searchprofile-images": "Multimedia",
"searchprofile-everything": "Alles",
- "searchprofile-advanced": "Uutgebreid",
- "searchprofile-articles-tooltip": "Zeuken in $1",
- "searchprofile-images-tooltip": "Zeuken naor bestaanden",
- "searchprofile-everything-tooltip": "Alle inhoud deurzeuken (oek overlegziejen)",
- "searchprofile-advanced-tooltip": "Zeuken in de an-egeven naamruumtes",
+ "searchprofile-advanced": "Uutwyded",
+ "searchprofile-articles-tooltip": "Söken in $1",
+ "searchprofile-images-tooltip": "Söken nå bestanden",
+ "searchprofile-everything-tooltip": "Alle inhold döärsöken (ouk oaverlegsyden)",
+ "searchprofile-advanced-tooltip": "Söken in de angeaven naamruumden",
"search-result-size": "$1 ({{PLURAL:$2|1 woord|$2 woorden}})",
"search-result-category-size": "{{PLURAL:$1|1 kategorielid|$1 kategorielejen}} ({{PLURAL:$2|1 onderkategorie|$2 onderkategorieën}}, {{PLURAL:$3|1 bestaand|$3 bestaanden}})",
"search-redirect": "(deurverwiezing vanaof $1)",
"right-siteadmin": "De databanke blokkeren en weer vriegeven",
"right-override-export-depth": "Ziejen exporteren, oek de ziejen waor naor verwezen wördt, tot n diepte van 5",
"right-sendemail": "Bericht versturen naor aandere gebrukers",
- "newuserlogpage": "Logboek mit anwas",
+ "newuserlogpage": "Logbook van nye brukers",
"newuserlogpagetext": "Hieronder staon de niej in-eschreven gebrukers",
"rightslog": "Gebrukersrechtenlogboek",
"rightslogtext": "Dit is n logboek mit veraanderingen van gebrukersrechten",
"recentchanges-summary": "Up disse syde kün jy de lätste wysigingen van disse wiki bekyken.",
"recentchanges-noresult": "Der waren in disse periode gien wiezigingen die an de kriteria voldoon.",
"recentchanges-feed-description": "Zeuk naor de alderleste wiezingen op disse wiki in disse voer.",
- "recentchanges-label-newpage": "Mid disse bewarking is een nye syde emaked",
+ "recentchanges-label-newpage": "Mid disse bewarking is een nye syde maked",
"recentchanges-label-minor": "Dit is een kleine wysiging",
- "recentchanges-label-bot": "Disse bewarking is üütevoord döär een bot",
- "recentchanges-label-unpatrolled": "Disse bewarking is noch neet nå-ekeaken",
- "recentchanges-label-plusminus": "Disse sydgroutte is mid dit antal bytes ewysigd",
+ "recentchanges-label-bot": "Disse bewarking is uutvoord döär een bot",
+ "recentchanges-label-unpatrolled": "Disse bewarking is noch neet nåkeaken",
+ "recentchanges-label-plusminus": "Disse sydgroutte is mid dit antal bytes wysigd",
"recentchanges-legend-heading": "<strong>Legenda:</strong>",
"recentchanges-legend-newpage": "{{int:recentchanges-label-newpage}}<br />(see ouk de [[Special:NewPages|lyste mid nye syden]])",
"recentchanges-submit": "Bekiek",
"rcfilters-filter-user-experience-level-experienced-label": "Ervåren gebrukers",
"rcfilters-filter-user-experience-level-experienced-description": "An-emelde bewarkers mid meyr as 500 bewarkingen en 30 dagen van aktiviteit.",
"rcfilters-filter-bots-label": "Bot",
- "rcfilters-filter-humans-label": "Meanskelik (geen bot)",
+ "rcfilters-filter-humans-label": "Menskelik (geen bot)",
"rcfilters-filter-humans-description": "Bewarkingen döär meanskelike bewarkers.",
"rcfilters-filtergroup-reviewstatus": "Beoordelingsstaotus",
"rcfilters-filter-reviewstatus-unpatrolled-label": "Niet nao-ekeken",
"newpageletter": "N",
"boteditletter": "B",
"unpatrolledletter": "!",
- "rc-change-size-new": "$1 {{PLURAL:$1|byte|bytes}} nao de wieziging",
+ "rc-change-size-new": "$1 {{PLURAL:$1|byte|bytes}} nå de wysiging",
"newsectionsummary": "Ny underwarp: /* $1 */",
"rc-enhanced-expand": "Details bekieken",
"rc-enhanced-hide": "Details verbargen",
"recentchanges-page-removed-from-category": "[[:$1]] is vortedaon uut kategorie",
"recentchanges-page-removed-from-category-bundled": "[[:$1]] vortedaon uut kategorie, [[Special:WhatLinksHere/$1|disse zied zit in aandere ziejen in-esleuten]]",
"autochange-username": "Automatiese wieziging van MediaWiki",
- "upload": "Holder upladen",
+ "upload": "Bestand upladen",
"uploadbtn": "Holder upladen",
"reuploaddesc": "Weerumme naor de opstuurzied",
"upload-tryagain": "Bestaandsbeschrieving biewarken",
"listfiles-latestversion": "Aktuele versie",
"listfiles-latestversion-yes": "Ja",
"listfiles-latestversion-no": "Nee",
- "file-anchor-link": "Bestaand",
- "filehist": "Bestaandsgeschiedenisse",
- "filehist-help": "Klik op n daotum/tied um t bestaand te zien zo as t to was.",
+ "file-anchor-link": "Bestand",
+ "filehist": "Bestandsgeskydenisse",
+ "filehist-help": "Klik up een dåtum/tyd üm et bestand te seen so as et destyds was.",
"filehist-deleteall": "alles vortdoon",
"filehist-deleteone": "disse vortdoon",
"filehist-revert": "weerummedreien",
- "filehist-current": "zo as t noen is",
- "filehist-datetime": "Daotum/tied",
- "filehist-thumb": "Miniatuuraofbeelding",
- "filehist-thumbtext": "Miniatuuraofbeelding veur versie van $1",
+ "filehist-current": "aktueel",
+ "filehist-datetime": "Dåtum/tyd",
+ "filehist-thumb": "Miniatuurafbealding",
+ "filehist-thumbtext": "Miniatuurafbealding vöär versy van $1",
"filehist-nothumb": "Gien miniatuuraofbeelding",
- "filehist-user": "Gebruker",
- "filehist-dimensions": "Grootte",
+ "filehist-user": "Bruker",
+ "filehist-dimensions": "Groutde",
"filehist-filesize": "Bestaandsgrootte",
- "filehist-comment": "Opmarkingen",
- "imagelinks": "Bestaandsgebruuk",
+ "filehist-comment": "Kommentaar",
+ "imagelinks": "Bestandsbruuk",
"linkstoimage": "Disse holder wördt up de volgende {{PLURAL:$1|syde|$1 syden}} gebrüked:",
"linkstoimage-more": "Der {{PLURAL:$2|is|bin}} meer as $1 {{PLURAL:$1|verwiezing|verwiezingen}} naor dit bestaand.\nDe volgende lieste gif allinnig de eerste {{PLURAL:$1|verwiezing|$1 verwiezingen}} naor dit bestaand weer.\nDe [[Special:WhatLinksHere/$2|hele lieste]] is oek beschikbaor.",
"nolinkstoimage": "Geen enkelde syde gebrüükt disse holder.",
"duplicatesoffile": "{{PLURAL:$1|t Volgende bestaand is|De volgende $1 bestaanden bin}} gelieke an dit bestaand ([[Special:FileDuplicateSearch/$2|meer informasie]]):",
"sharedupload": "Dit is n edeeld bestaand op $1 en ku'j oek gebruken veur aandere projekten.",
"sharedupload-desc-there": "Dit is n edeeld bestaand op $1 en ku'j oek gebruken veur aandere projekten. Bekiek de [$2 beschrieving van t bestaand] veur meer informasie.",
- "sharedupload-desc-here": "Dit is n edeeld bestaand op $1 en ku'j oek gebruken veur aandere projekten. De [$2 beschrieving van t bestaand] dergindse, steet hieronder.",
+ "sharedupload-desc-here": "Dit bestand kümt van $1 en kan ouk in andere projekten bruked weasen. De [$2 syde mid de beskryving van et bestand] steyt hyrunder.",
"sharedupload-desc-edit": "Dit besatand kömp van $1 en kan oek in aandere projekten gebruukt wörden.\nJe kunnen de [$2 zied mit de bestaandsbeschrieving] daor bewarken.",
"sharedupload-desc-create": "Dit besatand kömp van $1 en kan oek in aandere projekten gebruukt wörden.\nJe kunnen de [$2 zied mit de bestaandsbeschrieving] daor bewarken.",
"filepage-nofile": "Der besteet gien bestaand mit disse naam.",
"allpagesto": "Laot ziejen zien tot:",
"allarticles": "Alle artikels",
"allinnamespace": "Alle ziejen (naamruumte $1)",
- "allpagessubmit": "Zeuk",
+ "allpagessubmit": "Söken",
"allpagesprefix": "Ziejen bekieken die beginnen mit:",
"allpagesbadtitle": "De op-egeven ziednaam is ongeldig of der steet n interwikiveurvoegsel in. Meugelikerwieze staon der karakters in de naam die niet gebruukt maggen wörden in ziednamen.",
"allpages-bad-ns": "{{SITENAME}} hef gien \"$1\"-naamruumte.",
"wlheader-enotif": "Je kriegen bericht per netpost",
"wlheader-showupdated": "Ziejen die sinds joew leste bezeuk bie-ewörken bin staon '''vet'''.",
"wlnote": "Hieronder {{PLURAL:$1|steet de leste wieziging|staon de leste $1 wiezigingen}} in {{PLURAL:$2|t aofgeleupen ure|de leste $2 uren}} vanaof $3 um $4.",
- "wlshowlast": "Laot de veurbieje $1 uur $2 dagen zien",
"watchlist-submit": "Bekiek",
"wlshowhideminor": "kleine bewarkingen",
"watchlist-options": "Opsies veur de volglieste",
"confirm": "Bevestigen",
"excontent": "De tekste was: '$1'",
"excontentauthor": "De tekste was: '$1' (zied an-emaakt deur: [[Special:Contributions/$2|$2]])",
- "exbeforeblank": "veurdat disse zied leegemaakt wörden stung hier: '$1'",
+ "exbeforeblank": "vöärdat disse syde leadigmaked wördde stünd hyr: '$1'",
"delete-confirm": "\"$1\" vortdoon",
"delete-legend": "Vortdoon",
"historywarning": "'''Waorschuwing''': de zied die'j vortdoon willen, hef $1 {{PLURAL:$1|versie|versies}}:",
"delete-warning-toobig": "Disse zied hef n lange bewarkingsgeschiedenisse, meer as $1 {{PLURAL:$1|versie|versies}}.\nWoart je: t vortdoon van disse zied kan de warking van de databanke van {{SITENAME}} versteuren.\nWees veurzichtig",
"deleting-backlinks-warning": "<strong>Waorschuwing:</strong> [[Special:WhatLinksHere/{{FULLPAGENAME}}|aandere ziejen]] gebruken of verwiezen naor de zied die'j vortdoon willen.",
"rollback": "Wiezigingen herstellen",
- "rollbacklink": "weerummedreien",
+ "rollbacklink": "weaderümmedraien",
"rollbacklinkcount": "{{PLURAL:$1|één bewarking|$1 bewarkingen}} weerummedreien",
"rollbacklinkcount-morethan": "Meer as {{PLURAL:$1|één bewarking|$1 bewarkingen}} weerummedreien",
"rollbackfailed": "Wieziging herstellen is mislokt",
"undelete-error-long": "Fouten bie t herstellen van t bestaand:\n\n$1",
"undelete-show-file-confirm": "Bi'j der wisse van da'j n vortedaone versie van t bestaand \"<nowiki>$1</nowiki>\" van $2 um $3 bekieken willen?",
"undelete-show-file-submit": "Ja",
- "namespace": "Naamrüümde:",
- "invert": "Seleksie ummekeren",
+ "namespace": "Naamruumde:",
+ "invert": "Selekty ümmekeyren",
"tooltip-invert": "Vink dit vakjen an um wiezigingen an ziejen binnen de ekeuzen naamruumte te verbargen (en de biebeheurende naamruumte as dat an-evinkt is)",
"namespace_association": "Naamruumte die hieran ekoppeld is",
"tooltip-namespace_association": "Vink dit vakjen an um oek de overlegnaamruumte, of in t ummekeren geval de naamruumte zelf, derbie te doon die bie disse naamruumte heurt.",
- "blanknamespace": "(Heufdnaamruumte)",
+ "blanknamespace": "(Höyvdnaamruumde)",
"contributions": "{{GENDER:$1|Gebrukersbydragen}}",
"contributions-title": "Biedragen van $1",
"mycontris": "Myn bydragen",
"uctop": "leste wieziging",
"month": "Maond:",
"year": "Jaor:",
- "sp-contributions-newbies": "Allinnig biedragen van anwas bekieken",
- "sp-contributions-newbies-sub": "Veur anwas",
- "sp-contributions-newbies-title": "Biedragen van anwas",
"sp-contributions-blocklog": "blokkeerlogboek",
"sp-contributions-deleted": "vortedaone gebrukersbiedragen",
"sp-contributions-uploads": "nieje bestaanden",
"allmessages-prefix": "Filtreer op veurvoegsel:",
"allmessages-language": "Taal:",
"allmessages-filter-submit": "zeuk",
- "thumbnail-more": "vergroten",
+ "thumbnail-more": "vergrouten",
"filemissing": "Bestaand ontbrik",
"thumbnail_error": "Fout bie t laojen van de miniatuuraofbeelding: $1",
"thumbnail_error_remote": "Foutmelding van $1:\n$2",
"tooltip-pt-preferences": "{{GENDER:|Miene}} vuurkeuren",
"tooltip-pt-watchlist": "Lieste van zieden die op miene volglieste stoan",
"tooltip-pt-mycontris": "Oaverzicht van {{GENDER:|oew}} biejdreagen",
- "tooltip-pt-login": "Iej wördt van harte oetneugd um oe an te melden as gebroeker, mer t is nich verplicht",
+ "tooltip-pt-login": "Jy wördt van harte uutnöygd üm ju an te melden as bruker, mar et is neet verplicht",
"tooltip-pt-logout": "Ofmaelden",
- "tooltip-pt-createaccount": "Schrief je eigen veural in en meld je an, mer t is niet verplicht.",
- "tooltip-ca-talk": "Loat n oaverlegtekst oaver disse ziede zeen",
- "tooltip-ca-edit": "Beweark disse ziede",
+ "tooltip-pt-createaccount": "Skryv juw eigen vöäral in en meld juw eigen an. Dit is lykewels neet verplicht.",
+ "tooltip-ca-talk": "Låt een oaverlegtekst oaver disse syde seen",
+ "tooltip-ca-edit": "Bewark disse syde",
"tooltip-ca-addsection": "Niej oonderwaerp tovogen",
"tooltip-ca-viewsource": "Disse ziede is beveiligd taegen veraanderen. Iej könt wal kieken noar de ziede",
- "tooltip-ca-history": "Oaldere versies van disse ziede",
+ "tooltip-ca-history": "Oldere versys van disse syde",
"tooltip-ca-protect": "Beveilig disse ziede taegen veraanderen",
"tooltip-ca-unprotect": "De beveiliging vuur disse ziede wiezigen",
"tooltip-ca-delete": "Smiet disse ziede vort",
"tooltip-ca-undelete": "Haal n inhoald van disse ziede oet n emmer",
"tooltip-ca-move": "Gef disse ziede nen aanderen titel",
- "tooltip-ca-watch": "Voog disse ziede to an oewe volglieste",
+ "tooltip-ca-watch": "Voog disse syde to an juw volglyste",
"tooltip-ca-unwatch": "Smiet disse ziede van oewe voalglieste",
- "tooltip-search": "{{SITENAME}} duurzeuken",
- "tooltip-search-go": "Noar n ziede mit disse naam goan as t besteet",
- "tooltip-search-fulltext": "Zeuk noar zieden woar disse tekst in steet",
- "tooltip-p-logo": "Goa noar t vuurblad",
- "tooltip-n-mainpage": "Goa noar t vuurblad",
- "tooltip-n-mainpage-description": "Goa noar t vuurblad",
- "tooltip-n-portal": "Informoasie oaver t projekt: wel, wat, ho en woarum",
- "tooltip-n-currentevents": "Achtergroondinformoasie oaver dinge in t niejs",
- "tooltip-n-recentchanges": "Lieste van pas verrichte veraanderingen",
- "tooltip-n-randompage": "Loat ne willekeurige ziede zeen",
- "tooltip-n-help": "Hölpinformoasie oaver {{SITENAME}}",
- "tooltip-t-whatlinkshere": "Lieste van alle zieden die hiernoar verwiezen",
- "tooltip-t-recentchangeslinked": "Pas verrichte veraanderingen die noar disse ziede verwiezen",
+ "tooltip-search": "{{SITENAME}} döärsöken",
+ "tooltip-search-go": "Gå nå een syde mid eksakt disse name as et besteyt",
+ "tooltip-search-fulltext": "Söök nå syden wår disse tekst in steyt",
+ "tooltip-p-logo": "Gå nå et vöärblad",
+ "tooltip-n-mainpage": "Gå nå et vöärblad",
+ "tooltip-n-mainpage-description": "Gå nå et vöärblad",
+ "tooltip-n-portal": "Informaty oaver et projekt: wee, wat, ho en wårümme",
+ "tooltip-n-currentevents": "Achtergrundinformaty oaver dingen in et nys",
+ "tooltip-n-recentchanges": "Lyste van pas verrichte veranderingen",
+ "tooltip-n-randompage": "Låt ne willeköärige syde seen",
+ "tooltip-n-help": "Hülpinformaty oaver {{SITENAME}}",
+ "tooltip-t-whatlinkshere": "Lyste van alle syden dee når disse syde verwysen",
+ "tooltip-t-recentchangeslinked": "Pas verrichte veranderingen dee nå disse syde verwyset",
"tooltip-feed-rss": "RSS-voer vuur disse ziede",
"tooltip-feed-atom": "Atom-voer vuur disse ziede",
"tooltip-t-contributions": "Lieste met biejdreagen van {{GENDER:$1|disse gebroeker}}",
"tooltip-t-emailuser": "Stüür disse {{GENDER:$1|gebruker}} een netpostbericht",
"tooltip-t-info": "Meer informasie over disse zied",
- "tooltip-t-upload": "Laad ofbeeldingen en/of geluudsmateriaal",
- "tooltip-t-specialpages": "Lieste van alle biejzeundere zieden",
- "tooltip-t-print": "De ofdrukboare versie van disse ziede",
- "tooltip-t-permalink": "Verbeending vuur altied noar de versie van disse ziede van vandaag-an-n-dag",
- "tooltip-ca-nstab-main": "Loat n tekst van t artikel zeen",
+ "tooltip-t-upload": "Laad afbealdingen en/of gelüüdsmateriaal",
+ "tooltip-t-specialpages": "Lyste van alle bysündere syden",
+ "tooltip-t-print": "De afdrükbåre versy van disse syde",
+ "tooltip-t-permalink": "Permanente verwysing nå disse versy van de syde",
+ "tooltip-ca-nstab-main": "Låt een tekst van et artikel seen",
"tooltip-ca-nstab-user": "Loat de gebroekersbladziede zeen",
"tooltip-ca-nstab-media": "Loat n mediatekst zeen",
- "tooltip-ca-nstab-special": "Dit is ne biejzeundere ziede die'j nich könt veraanderen",
+ "tooltip-ca-nstab-special": "Dit is een bysündere syde dee jy neet veranderen künt",
"tooltip-ca-nstab-project": "Loat de projektbladziede zeen",
- "tooltip-ca-nstab-image": "Loat de bestaandsbladziede zeen",
+ "tooltip-ca-nstab-image": "Låt de bestandssyde seen",
"tooltip-ca-nstab-mediawiki": "Loat de systeemtekstbladziede zeen",
"tooltip-ca-nstab-template": "Loat de malbladziede zeen",
"tooltip-ca-nstab-help": "Loat de hölpbladziede zeen",
"tooltip-watchlistedit-raw-submit": "Volglieste biewarken",
"tooltip-recreate": "Disse ziede opniej anmaken, ondanks t feit dat t vortdoan is.",
"tooltip-upload": "Bestaanden opsturen",
- "tooltip-rollback": "Mit \"weerummedreien\" kö'j mit één klik de bewaerking(en) van n leste gebroeker dee disse ziede bewaerkt hef terugdraeien.",
+ "tooltip-rollback": "\"Weaderümmedraien\" drait mid eyn klik de bewarking(en) van de lätste bruker up disse syde terügge.",
"tooltip-undo": "A'j op \"weerummedreien\" klikken geet t bewaerkingsvaenster lös en kö'j ne vurige versie terugzetten.\nIej könt in de bewaerkingssamenvatting n reden opgeven.",
"tooltip-preferences-save": "Vuurkeuren opsloan",
"tooltip-summary": "Voer ne korte samenvatting in",
"anonymous": "Anonieme {{PLURAL:$1|gebruker|gebrukers}} van {{SITENAME}}",
"siteuser": "{{SITENAME}}-gebruker $1",
"anonuser": "Anonieme {{SITENAME}}-gebruker $1",
- "lastmodifiedatby": "Disse zied is t lest ewiezigd op $2, $1 deur $3.",
+ "lastmodifiedatby": "Disse syde is et lätst ewysigd up $1 üm $2 döär $3.",
"othercontribs": "Ebaseerd op wark van $1.",
"others": "aandere",
"siteusers": "{{SITENAME}}-{{PLURAL:$2|gebruker|gebrukers}} $1",
"show-big-image": "Oorspronkelik bestaand",
"show-big-image-preview": "Grootte van disse weergave: $1.",
"show-big-image-other": "Aandere {{PLURAL:$2|resolusie|resolusies}}: $1.",
- "show-big-image-size": "$1 × $2 beeldpunten",
+ "show-big-image-size": "$1 × $2 bealdpunten",
"file-info-gif-looped": "herhaolend",
"file-info-gif-frames": "$1 {{PLURAL:$1|beeld|beelden}}",
"file-info-png-looped": "herhaolend",
"metadata-help": "In dit bestaand zit metadata mit EXIF-informasie, die deur n fotokamera, inleesapparaot of fotobewarkingsprogramma op-estuurd kan ween.",
"metadata-expand": "Bekiek uutebreiden gegevens",
"metadata-collapse": "Verbarg uutebreiden gegevens",
- "metadata-fields": "De aofbeeldingsmetadatavelden in dit bericht staon oek op n aofbeeldingszied as de metadatatabel in-eklapt is.\nAandere velden wörden verbörgen.\n* make\n* model\n* datetimeoriginal\n* exposuretime\n* fnumber\n* isospeedratings\n* focallength\n* artist\n* copyright\n* imagedescription\n* gpslatitude\n* gpslongitude\n* gpsaltitude",
+ "metadata-fields": "De afbealdingsmetadatavelden in dit bericht ståt ouk up een afbealdingssyde as de metadatatabel inklapped is.\nAndere velden wördet verbörgen.\n* make\n* model\n* datetimeoriginal\n* exposuretime\n* fnumber\n* isospeedratings\n* focallength\n* artist\n* copyright\n* imagedescription\n* gpslatitude\n* gpslongitude\n* gpsaltitude",
"namespacesall": "alles",
"monthsall": "alles",
"confirmemail": "Bevestig netpostadres",
"imgmultipagenext": "volgende →",
"imgmultigo": "Oké",
"imgmultigoto": "Gao naor de zied $1",
- "ascending_abbrev": "opl.",
- "descending_abbrev": "aofl.",
"table_pager_next": "Volgende",
"table_pager_prev": "Veurige",
"table_pager_first": "Eerste zied",
"table_pager_limit_label": "Zaken per zied:",
"table_pager_limit_submit": "Zeuk",
"table_pager_empty": "Gien resultaoten",
- "autosumm-blank": "Zied leegemaakt",
+ "autosumm-blank": "Syde leadigmaked",
"autosumm-replace": "Tekste vervöngen deur '$1'",
"autoredircomment": "döärverwysing når [[$1]]",
"autosumm-changed-redirect-target": "Döärverwysingsdool ewysigd van [[$1]] når [[$2]]",
"tag-mw-new-redirect": "Nye döärverwysing",
"tag-mw-removed-redirect": "Döärverwysing vordedån",
"tag-mw-changed-redirect-target": "Döärverwysingsdool ewysigd",
+ "tag-mw-blank": "Leadigmaked",
"tags-title": "Etiket",
"tags-intro": "Op disse zied staon de etiketten waormee de programmatuur elke bewarking kan markeren, en de betekenisse dervan.",
"tags-tag": "Etiketnaam",
"logentry-patrol-patrol": "$1 hef versie $4 van de zied $3 op {{GENDER:$2|nao-ekeken}} ezet",
"logentry-patrol-patrol-auto": "$1 hef versie $4 van de zied $3 automaties op {{GENDER:$2|nao-ekeken}} ezet",
"logentry-newusers-newusers": "Gebruker $1 is {{GENDER:$2|an-emaakt}}",
- "logentry-newusers-create": "Gebruker $1 is {{GENDER:$2|an-emaakt}}",
+ "logentry-newusers-create": "Brukerskonto $1 is {{GENDER:$2|anmaked}}",
"logentry-newusers-create2": "Gebruker $3 is {{GENDER:$2|an-emaakt}} an-emaakt deur $1",
"logentry-newusers-byemail": "Gebruker $3 {{GENDER:$2|is}} an-emaakt deur $1 en t wachtwoord is per netpost verstuurd",
"logentry-newusers-autocreate": "De gebruker $1 is automaties {{GENDER:$2|an-emaakt}}",
"wlheader-enotif": "Benarichtigen per E-Mail is anstellt.",
"wlheader-showupdated": "Sieden, de siet dien letzten Besöök ännert worrn sünd, warrt '''fett''' wiest.",
"wlnote": "Ünnen {{PLURAL:$1|steiht de letzte Ännern|staht de letzten $1 Ännern}} vun de {{PLURAL:$2|letzte Stünn|letzten '''$2''' Stünnen}}.",
- "wlshowlast": "Wies de letzten $1 Stünnen $2 Daag",
"watchlist-hide": "Versteken",
"watchlist-options": "Optionen för de Oppasslist",
"watching": "warrt op de Oppasslist ropsett...",
"uctop": " aktuell",
"month": "bet Maand:",
"year": "Bet Johr:",
- "sp-contributions-newbies": "Wies blot Bidrääg vun ne’e Brukers",
- "sp-contributions-newbies-sub": "För ne’e Kontos",
- "sp-contributions-newbies-title": "Brukerbidrääg vun ne’e Brukers",
"sp-contributions-blocklog": "Sparr-Logbook",
"sp-contributions-deleted": "Wegsmetene Bidrääg vun’n Bruker",
"sp-contributions-uploads": "hooglaadt Datein",
"imgmultipagenext": "nächste Siet →",
"imgmultigo": "Los!",
"imgmultigoto": "Gah na de Siet $1",
- "ascending_abbrev": "op",
- "descending_abbrev": "dal",
"table_pager_next": "Nächste Siet",
"table_pager_prev": "Vörige Siet",
"table_pager_first": "Eerste Siet",
"invalidtitle": "अमान्य शीर्षक",
"invalidtitle-knownnamespace": "नेमस्पेस \"$2\" तथा अक्षर \"$3\" सहितको अवैश शिर्षक",
"invalidtitle-unknownnamespace": "अज्ञात नेमस्पेस अंक $1 तथा अक्षर \"$2\" भएको अवैध शिर्षक",
- "exception-nologin": "प्रवेश (लग ईन) नगरिएको",
+ "exception-nologin": "प्रवेश नगरिएको",
"exception-nologin-text": "यस पृष्ठमा जान वा कुनै कार्य गर्नको लागि कृपया प्रवेश (लग इन) गर्नुहोस् ।",
"exception-nologin-text-manual": "यस पृष्ठमा प्रवेश गर्न वा कुनै कार्य गर्नको लागि कृपया $1 गर्नु होस् ।",
"virus-badscanner": "खराव मिलान: अज्ञात भाइरस स्क्यानर :''$1''",
"nav-login-createaccount": "प्रवेश गर्ने/नयाँ खाता बनाउने",
"logout": "निर्गमन",
"userlogout": "निर्गमन (लग आउट)",
- "notloggedin": "प्रवेश (लग ईन) नगरिएको",
+ "notloggedin": "प्रवेश नगरिएको",
"userlogin-noaccount": "के खाता छैन ?",
"userlogin-joinproject": "{{SITENAME}} मा खाता खोल्नुहोस् ।",
"createaccount": "खाता खोल्नुहोस्",
"loginlanguagelabel": "भाषा: $1",
"suspicious-userlogout": "तपाईंको निर्गमन अनुरोध अस्विकार गरिन्छ किन कि यो खराब ब्राउजर वा क्यासिङ प्रोक्सिले पठाएको जस्तो देखिन्छ।",
"createacct-another-realname-tip": "वास्तविक नाम ऐच्छिक हो ।\nतपाईंले यो खुलाउनु भएको खण्डमा तपाईंको काममा प्रयोगकर्ता श्रेय दिनको लागि यसको प्रयोग गरिने छ ।",
- "pt-login": "प्रवेश (लग ईन)",
+ "pt-login": "प्रवेश",
"pt-login-button": "प्रवेश",
"pt-login-continue-button": "प्रवेस जारी राख्नुहोस् ।",
"pt-createaccount": "खाता खोल्नुहोस्",
"nosuchsectiontitle": "सेक्सन फेला परेन",
"nosuchsectiontext": "तपाईँले त्यस्तो खण्डको सम्पादन गर्ने प्रयास गर्नुभयो जुन छैन।\nजब तपाईं यस पृष्ठलाई हेर्नुहुँदैथियो, यो सारिएको अथवा मेटाइएको हुनुपर्छ।",
"loginreqtitle": "प्रवेशगर्नु जरुरी छ।",
- "loginreqlink": "प्रवेश (लग ईन)",
+ "loginreqlink": "प्रवेश",
"loginreqpagetext": "अरु पृष्ठ हेर्न तपाईंले $1 गर्नुपर्छ ।",
"accmailtitle": "पासवर्ड पठाइयो",
"accmailtext": "जथाभावीरूपमा सृजना गरिएको प्रवेशशब्द प्रयोगकर्ता [[User talk:$1|$1]] को $2 मा पठाइएको छ।\n\nयो नयाँ खाताको प्रवेशशब्द ''[[Special:ChangePassword|change password]]'' मा प्रवेश गरेर परिवर्तन गर्न सकिन्छ ।",
"prefs-pageswatchlist": "हेरिएका पृष्ठहरू",
"prefs-tokenwatchlist": "टोकन",
"prefs-diffs": "diffs(भिन्नता)",
- "prefs-help-prefershttps": "यà¥\8b à¤\85à¤à¤¿à¤°à¥\82à¤\9aà¥\80 तपाà¤\88à¤\82à¤\95à¥\8b à¤\85रà¥\8dà¤\95à¥\8b पà¥\8dरवà¥\87श (लà¤\97 à¤\87न) बाà¤\9f लाà¤\97à¥\81 हà¥\81नà¥\87à¤\9b ।",
+ "prefs-help-prefershttps": "यà¥\8b à¤\85à¤à¤¿à¤°à¥\82à¤\9aà¥\80 तपाà¤\88à¤\95à¥\8b à¤\85रà¥\8dà¤\95à¥\8b पà¥\8dरवà¥\87शबाà¤\9f लाà¤\97à¥\82 हà¥\81नà¥\87à¤\9b।",
"prefswarning-warning": "तपाईंले आफ्नो अभिरूचीमा गर्नुभएको परिवर्तन अहिले सम्म सङ्ग्रह गरिएको छैन। यदि तपाईं \"$1\" मा क्लिक नगरी यस पृष्ठबाट बाहिर जानुभयो भने तपाईंको अभिरूची अपडेट गर्न सकिदैन।",
"prefs-tabs-navigation-hint": "सुझाव: तपाईं ट्याबसहरूमा ट्याबसको बीच आवागमन गर्नका लागि देब्रे वा दाहिने तीर साँचोको प्रयोग गर्न सक्नुहुन्छ।",
"userrights": "प्रयोगकर्ता अधिकारहरू",
"uploadbtn": "फाइलहरू उर्ध्वभरण गर्ने",
"reuploaddesc": "उर्ध्वभरण रद्द गर्ने र उर्ध्वभरण फारमतिर जाने",
"upload-tryagain": "संशोधित फाइल विवरण बुझाउने",
- "uploadnologin": "प्रवेश (लग ईन) नगरिएको",
+ "uploadnologin": "प्रवेश नगरिएको",
"uploadnologintext": "फाइल उर्ध्वभरण गर्न तपाईंले $1 गर्नुपर्छ।",
"upload_directory_missing": "उर्ध्वभरण डाइरेक्टरी ($1) हराइरहेको छ र वेवसर्भरले नयाँ डाइरेक्टरी निर्माणगर्न असमर्थ भयो ।",
"upload_directory_read_only": "उर्ध्व भरण डाइरेक्टरी ($1) वेवसर्भर द्वारा लेख्य छैन ।",
"watchlistfor2": "$1को $2",
"nowatchlist": "तपाईंको अवलोकन सूचीमा कुनै पनि सामाग्री छैन।",
"watchlistanontext": "कृपया तपाईंको निगरानी सूची हेर्न या सम्पादन गर्न लगइन गर्नुहोस्।",
- "watchnologin": "प्रवेश (लग ईन) नगरिएको",
+ "watchnologin": "प्रवेश नगरिएको",
"addwatch": "निगरानी सुचीमा थप्ने",
"addedwatchtext": "\"[[:$1]]\" पृष्ठ [[Special:Watchlist|अवलोकनसूची]]मा थपियो\nयो पृष्ठ र यससित सम्बद्ध वार्तालाप पृष्ठमा भविष्यमा हुने परिवर्तन सूचिबद्ध गरिनेछ।",
"addedwatchtext-short": "\"$1\" पृष्ठ तपाईंको अवलोकन सूचीमा थप भएको छ ।",
"wlheader-enotif": "इमेल जानकारी सक्रिय गरियो ।",
"wlheader-showupdated": "तपाईंले पछिल्लो पल्ट भ्रमण गरेपछि परिवर्तन भएका पृष्ठहरूलाई <strong>गाढा<strong> गरेर देखाइएको छ ।",
"wlnote": "$3 र $4 अनुसार विगत {{PLURAL:$2|घण्टामा|'''$2''' घण्टाहरूमा}} {{PLURAL:$1|गरिएको अन्तिम परिवर्तन तल दिइएकोछ|गरिएका अन्तिम '''$1''' परिवर्तनहरू तल दिइएका छन्}}।",
- "wlshowlast": "पछिल्ला $2 दिनहरू $1 घण्टाहरू देखाउनुहोस्",
"watchlist-hide": "लुकाउनुहोस्",
"watchlist-submit": "देखाउनुहोस्",
"wlshowhideminor": "सामान्य सम्पादनहरू",
"uctop": "वर्तमान",
"month": "महिना देखि (र पहिले):",
"year": "वर्ष देखि( र पहिले):",
- "sp-contributions-newbies": "नयाँ खाताको योगदानहरू मात्र देखाउने",
- "sp-contributions-newbies-sub": "नयाँ खाताहरूको लागि",
- "sp-contributions-newbies-title": "नयाँ खाताहरूको लागि प्रयोगकर्ताका योगदानहरू",
"sp-contributions-blocklog": "रोकावट लग",
"sp-contributions-suppresslog": "प्रयोगकर्ताको योगदानहरू दबाइएको छ ।",
"sp-contributions-deleted": "प्रयोगकर्ताका योगदानहरू मेटाइयो",
"newimages-summary": "यस विशेष पृष्ठले अन्तिम उर्ध्वभरण गरिएका फाइलहरू देखाउँछ ।",
"newimages-legend": "फिल्टर",
"newimages-label": "फाइल अथवा (यसको एउटा अंश)को नाम:",
- "newimages-newbies": "नयाँ खाताको योगदानहरू मात्र देखाउने",
"newimages-showbots": "बोटहरूद्वारा गरिएको अपलोड देखाउने",
"noimages": "हेर्नको लागि केही छैन.",
"ilsubmit": "खोज्नुहोस्",
"img-lang-default": "(पूर्वनिर्धारित भाषा)",
"img-lang-info": "यस चित्रलाई $1 मा प्रस्तुत गर्ने । $2",
"img-lang-go": "जाउ",
- "ascending_abbrev": "वर्णानुक्रम",
- "descending_abbrev": "धट्दोक्रम",
"table_pager_next": "पछिको पृष्ठ",
"table_pager_prev": "अगाडिको पृष्ठ",
"table_pager_first": "प्रथम पृष्ठ",
"KlaasZ4usV",
"Elroy",
"PiefPafPier",
- "Ecthelion3"
+ "Ecthelion3",
+ "RadioAzureus"
]
},
"tog-underline": "Verwijzingen onderstrepen:",
"rcfilters-filter-showlinkedto-label": "Toon wijzigingen op pagina's gekoppeld naar",
"rcfilters-filter-showlinkedto-option-label": "<strong>Pagina's gekoppeld naar</strong> de geselecteerde pagina",
"rcfilters-target-page-placeholder": "Voer een paginanaam (of categorie) in",
- "rcfilters-allcontents-label": "Alle inhoud",
- "rcfilters-alldiscussions-label": "Al het overleg",
+ "rcfilters-allcontents-label": "Volledige inhoud",
+ "rcfilters-alldiscussions-label": "Volledig overleg",
"rcnotefrom": "Wijzigingen sinds <strong>$3 om $4</strong> (maximaal <strong>$1</strong> {{PLURAL:$1|wijziging|wijzigingen}}).",
"rclistfromreset": "Datum selectie opnieuw instellen",
"rclistfrom": "Wijzigingen bekijken vanaf $3 $2",
"apihelp-no-such-module": "Module \"$1\" niet gevonden.",
"apisandbox": "API-zandbak",
"apisandbox-jsonly": "JavaScript is vereist om de API-zandbak te kunnen gebruiken.",
- "apisandbox-api-disabled": "De API is uitgeschakeld op deze site.",
"apisandbox-intro": "Gebruik deze pagina om te experimenteren met de <strong>MediaWiki-API</strong>.\nZie de [[mw:API:Main page|API-documentatie]] voor verdere details over het gebruik van de API. Voorbeeld: [https://www.mediawiki.org/wiki/API#A_simple_example hoe de inhoud van een Hoofdpagina ophalen]. Selecteer een handeling om meer voorbeelden te zien.\n\nHoewel dit een testfunctie is, kunnen sommige handelingen toch wijzigingen in de wiki maken.",
"apisandbox-submit": "Verzoek uitvoeren",
"apisandbox-reset": "Wissen",
"wlheader-enotif": "U wordt per e-mail gewaarschuwd.",
"wlheader-showupdated": "Pagina's die zijn bewerkt sinds uw laatste bezoek worden '''vet''' weergegeven.",
"wlnote": "Hieronder {{PLURAL:$1|staat de laaste wijziging|staan de laatste $1 wijzigingen}} in {{PLURAL:$2|het laatste uur|de laatste $2 uur}} per $3 om $4.",
- "wlshowlast": "Laatste $1 uur, $2 dagen bekijken",
"watchlist-hide": "Verbergen",
"watchlist-submit": "Weergeven",
"wlshowtime": "Weer te geven periode:",
"month": "Van maand (en eerder):",
"year": "Van jaar (en eerder):",
"date": "Op deze datum (en eerder):",
- "sp-contributions-newbies": "Alleen bijdragen van nieuwe accounts bekijken",
- "sp-contributions-newbies-sub": "Voor nieuwelingen",
- "sp-contributions-newbies-title": "Gebruikersbijdragen van nieuwe accounts",
"sp-contributions-blocklog": "blokkeerlogboek",
"sp-contributions-suppresslog": "onderdrukte {{GENDER:$1|gebruikersbijdragen}}",
"sp-contributions-deleted": "verwijderde {{GENDER:$1|gebruiker}}sbijdragen",
"immobile-target-namespace-iw": "Een interwikikoppeling is geen geldige bestemming voor het hernoemen van een pagina.",
"immobile-source-page": "Deze pagina kan niet hernoemd worden.",
"immobile-target-page": "Het is niet mogelijk te hernoemen naar die paginanaam.",
- "movepage-invalid-target-title": "De opgevraagde naam is ongeldig.",
+ "movepage-invalid-target-title": "De gevraagde naam is ongeldig.",
"bad-target-model": "De gewenste bestemming gebruikt een ander inhoudsmodel. Het is niet mogelijk om te zetten van $1 naar $2.",
"imagenocrossnamespace": "Een mediabestand kan niet naar een andere naamruimte verplaatst worden",
"nonfile-cannot-move-to-file": "Het is niet mogelijk te hernoemen van en naar de bestandsnaamruimte",
"newimages-legend": "Bestandsnaam",
"newimages-label": "Bestandsnaam (of deel daarvan):",
"newimages-user": "IP-adres of gebruikersnaam",
- "newimages-newbies": "Alleen bijdragen van nieuwe accounts bekijken",
"newimages-showbots": "Uploads door bots weergeven",
"newimages-hidepatrolled": "Gecontroleerde uploads verbergen",
"newimages-mediatype": "Mediatype:",
"img-lang-default": "(standaard taal)",
"img-lang-info": "Deze afbeeldingen renderen in de taal $1. $2",
"img-lang-go": "OK",
- "ascending_abbrev": "opl.",
- "descending_abbrev": "afl.",
"table_pager_next": "Volgende pagina",
"table_pager_prev": "Vorige pagina",
"table_pager_first": "Eerste pagina",
"suppress": "Historikkfjerning",
"querypage-disabled": "Spesialsida er slegen av for skuld yting.",
"apisandbox": "API-sandkasse",
- "apisandbox-api-disabled": "API er slege av på nettstaden.",
"apisandbox-intro": "Nytt sida til å røyna ut '''MediaWiki web service API''-en.\nSjå [https://www.mediawiki.org/wiki/API:Main_page API-dokumentasjonen] for meir informasjon om bruk av API-en. Døme: [https://www.mediawiki.org/wiki/API#A_simple_example hent innhaldet til ei hovudside].\nVel ei handling for å sjå fleire døme.",
"apisandbox-submit": "Gjer førespurnad",
"apisandbox-reset": "Tøm",
"wlheader-enotif": "Funksjonen for endringsmeldingar per e-post er på.",
"wlheader-showupdated": "Sider som har vorte endra sidan du sist såg på dei er <strong>utheva</strong>",
"wlnote": "Nedanfor er {{PLURAL:$1|den siste endringa|dei siste <strong>$1</strong> endringane}} {{PLURAL:$2|den siste timen|dei siste <strong>$2</strong> timane}}, for $3, kl. $4.",
- "wlshowlast": "Vis siste $1 timane $2 dagane",
"watchlist-hide": "Gøym",
"wlshowtime": "Vis siste:",
"wlshowhideminor": "småplukk",
"month": "Månad:",
"year": "År:",
"date": "Frå dato (og tidlegare):",
- "sp-contributions-newbies": "Vis berre bidrag frå nye brukarar",
- "sp-contributions-newbies-sub": "Frå nye brukarkontoar",
- "sp-contributions-newbies-title": "Brukarbidrag av nye brukarar",
"sp-contributions-blocklog": "blokkeringslogg",
"sp-contributions-deleted": "sletta brukarbidrag",
"sp-contributions-uploads": "opplastingar",
"newimages-legend": "Filnamn",
"newimages-label": "Filnamn (eller ein del av det):",
"newimages-user": "IP-adresse eller brukarnamn",
- "newimages-newbies": "Berre vis opplastingar frå nye kontoar",
"newimages-showbots": "Vis opplastingar av robotar",
"newimages-hidepatrolled": "Gøym patruljerte opplastingar",
"noimages": "Her er ingen filer som kan visast.",
"img-lang-default": "(standardspråk)",
"img-lang-info": "Teikn biletet på $1. $2",
"img-lang-go": "Gjer det",
- "ascending_abbrev": "stigande",
- "descending_abbrev": "synkande",
"table_pager_next": "Neste side",
"table_pager_prev": "Førre sida",
"table_pager_first": "Fyrste sida",
"rev-showdeleted": "ߦߌ߬ߘߊ߬ߟߌ",
"revisiondelete": "ߛߌ߰ߘߊ ߖߏ߬ߛߌ߬/ߖߏ߬ߛߌ߬ߣߍ߲ ߓߐ߫",
"revdelete-nooldid-title": "ߞߏ߲߭ ߟߢߊ߬ߟߌ ߓߍ߲߬ߓߊߟߌ",
+ "revdelete-no-file": "ߞߐߕߐ߮ ߝߊߛߌߣߌ߲ ߕߴߦߋ߲߬.",
+ "revdelete-show-file-confirm": "ߌ ߟߊ߫ ߣߴߊ߬ ߟߊ߫ ߝߋߎ߫ ߞߴߌ ߦߴߊ߬ ߝߍ߬ ߞߊ߬ ߟߢߊ߬ߟߌ ߖߏ߬ߛߌ߬ߣߍ߲ ߠߎ߬ ߦߋ߫ ߞߐߕߐ߮ ߟߎ߬ ߘߐ߫ <nowiki>$1</nowiki> ߞߵߊ߬ ߕߊ߬ $3 ߡߊ߬ $2 ߟߊ߫؟",
"revdelete-show-file-submit": "ߐ߲߬ߐ߲߬ߐ߲߫",
+ "revdelete-selected-text": "{{PLURAL:$1|ߟߢߊ߬ߟߌ߬ ߓߊߕߐ߬ߡߐ߲߬ߣߍ߲|ߟߢߊ߬ߟߌ߬ ߓߊߕߐ߬ߡߐ߲߬ߣߍ߲ ߠߎ߬}} ߞߊ߬ ߝߘߊ߫ [[:$2]]",
+ "revdelete-selected-file": "{{PLURAL:$1|ߞߐߕߐ߯ ߓߊߕߐ߬ߡߐ߲߬ߣߍ߲ ߦߌߟߡߊ|ߞߐߕߐ߯ ߓߊߕߐ߬ߡߐ߲߬ߣߍ߲ ߠߎ߬ ߦߌߟߡߊ}} ߞߊ߬ ߝߘߊ߫ [[:$2]]",
"revdelete-legend": "ߦߋߟߌ ߟߊ߬ߘߐ߰ߦߊ߬ߟߌ ߟߊߘߏ߲߬",
"revdelete-hide-text": "ߛߓߍߟߌ ߟߊߢߊ߬",
"revdelete-hide-image": "ߞߐߕߐ߮ ߞߣߐߘߐ ߢߡߊߘߏ߲߰",
"powersearch-togglelabel": "ߝߛߍ߬ߝߛߍ߬ߟߌ",
"powersearch-toggleall": "ߊ߬ ߓߍ߯",
"powersearch-togglenone": "ߝߏߦߌ߬",
+ "powersearch-remember": "ߢߌߣߌ߲ߠߌ߲ ߣߊ߬ߕߐ ߓߊߕߐߡߐ߲ߠߌ߲ ߠߎ߬ ߟߊߓߊ߬ߕߏ߬.",
"search-external": "ߞߐߞߊ߲߫ ߢߌߣߌ߲ߠߌ߲",
+ "searchdisabled": "{{SITENAME}} ߢߌߣߌ߲ߠߌ߲ ߓߘߊ߫ ߓߴߊ߬ ߟߊ߫. \nߌ ߘߌ߫ ߛߋ߫ ߢߌߣߌ߲ߠߌ߲ ߞߍ߫ ߟߊ߫ ߜ߭ߎߜ߭ߑߟߎ ߞߊ߲߬ ߥߛߎ߬ߣߍ߲߬ ߞߘߐ߫.\nߕߎ߬ߡߊ߬ߘߐ߫ ߊ߬ߟߎ߬ ߟߊ߫ ߛߌߝߊߟߌ ߞߊ߬ ߟߐ߬ {{SITENAME}} ߡߊ߬߸ ߏ߬ ߞߣߐߘߐ ߟߋ߬ ߕߍ߫ ߕߎ߬ߡߊ߬ߘߊ ߟߊ߫.",
"search-error": "ߝߎ߬ߕߎ߲߬ߕߌ ߘߏ߫ ߓߘߴߊ߬ ߞߎ߲߬ߓߐ߫ ߞߵߌ ߕߏ߫ $1 ߢߌߣߌ߲ ߠߊ߫",
"search-warning": "ߖߊ߬ߛߙߋ߬ߡߊ߬ߟߊ ߘߏ߫ ߓߘߴߊ߬ ߞߎ߲߬ߓߐ߫ ߞߵߌ ߕߏ߫ $1 ߢߌߣߌ߲ ߠߊ߫",
"preferences": "ߟߊ߬ߝߌ߬ߛߦߊ߬ߟߌ",
"prefs-email": "ߢߎߡߍߙߋ߲ ߞߏ߲ߘߏ ߛߎߥߊ߲ߘߟߌ",
"prefs-rendering": "ߟߊ߲ߞߣߍߡߊ",
"saveprefs": "ߊ߬ ߟߊߞߎ߲߬ߘߎ߬",
+ "restoreprefs": "ߘߊ߲ߛߎ߲ ߟߊ߬ߓߍ߲߬ߢߐ߲߰ߡߊ ߓߍ߯ ߟߊߞߎߣߎ߲߫ (ߕߍߕߎ߲߮ ߓߍ߯ ߘߐ߫)",
"prefs-editing": "ߡߊ߬ߦߟߍ߬ߡߊ߲߬ߠߌ߲ ߦߴߌ ߘߐ߫",
"searchresultshead": "ߢߌߣߌ߲ߠߌ߲",
"stub-threshold-sample-link": "ߣߐ߰ߡߊ߲",
"rcfilters-liveupdates-button-title-off": "ߡߝߊ߬ߟߋ߲߬ߠߌ߲߬ ߞߎߘߊ߫ ߞߎߘߊ߫ ߟߊߓߊ߯ߙߊ߫ ߊ߬ߟߎ߬ ߞߍߢߊ ߡߊ߬",
"rcfilters-watchlist-markseen-button": "ߡߊ߬ߦߟߍ߬ߡߊ߲߬ߠߌ߲ ߓߍ߯ ߣߐ߬ߣߐ߬ ߦߋߣߍ߲ ߘߌ߫",
"rcfilters-watchlist-edit-watchlist-button": "ߌ ߟߊ߫ ߞߐߜߍ߫ ߡߊߝߟߍߣߍ߲ ߠߎ߬ ߛߙߍߘߍ ߡߊߦߟߍ߬ߡߊ߲߫",
+ "rcfilters-filter-showlinkedfrom-label": "ߡߊ߬ߦߟߍ߬ߡߊ߲߬ߠߌ߲ ߠߎ߬ ߦߌ߬ߘߊ߬ ߞߐߜߍ ߟߎ߬ ߘߐ߫ ߡߍ߲ ߠߎ߬ ߜߋ߲߬ߞߘߎ߬ߢߐ߲߰ߦߊ ߝߘߊߣߍ߲߫",
+ "rcfilters-filter-showlinkedfrom-option-label": "<strong>ߞߐߜߍ ߡߍ߲ ߠߎ߬ ߛߘߌ߬ߜߋ߲ ߝߘߊߣߍ߲߫</strong> ߞߐߜߍ߫ ߓߊߕߐ߬ߡߐ߲߬ߣߍ߲ ߠߎ߬ ߟߊ߫.",
+ "rcfilters-filter-showlinkedto-label": "ߡߊ߬ߦߟߍ߬ߡߊ߲߬ߠߌ߲ ߠߎ߬ ߦߌ߬ߘߊ߬ ߞߐߜߍ ߘߐ߫ ߡߍ߲ ߠߎ߬ ߛߘߌ߬ߜߋ߲ ߦߋ߫",
"rcfilters-target-page-placeholder": "ߞߐߜߍ ߕߐ߮ ߟߊߘߏ߲߬ (ߥߟߊ߫ ߦߌߟߡߊ)",
"rcfilters-allcontents-label": "ߞߣߐߘߐ ߟߎ߬ ߓߍ߯",
"rcfilters-alldiscussions-label": "ߘߊߘߐߖߊߥߏ ߟߎ߬ ߓߍ߯",
"lockmanager-notlocked": "ߊ߬ ߕߍ߫ ߣߊ߬ ߛߐ߲߬ ߠߊ߫ \"$1\" ߟߊߞߊ߬ ߟߊ߫߸ ߊ߬ ߛߐ߰ߣߍ߲߬ ߕߍ߫.",
"lockmanager-fail-closelock": "ߊ߬ ߕߍ߫ ߣߊ߬ ߛߋ߫ ߟߊ߫ \"$1\" ߞߐߕߐ߮ ߛߐ߰ߣߍ߲ ߘߊߕߎ߲߯ ߠߊ߫.",
"lockmanager-fail-deletelock": "ߊ߬ ߕߍ߫ ߣߊ߬ ߛߋ߫ ߟߊ߫ \"$1\" ߞߐߕߐ߯ ߛߐ߰ߣߍ߲ ߖߏ߰ߛߌ߬ ߟߊ߫.",
+ "lockmanager-fail-releaselock": "ߌ ߕߍ߫ ߣߊ߬ ߛߋ߫ ߟߊ߫ ߛߐ߰ߟߌ ߓߐ߫ ߟߊ߫ \"$1\" ߞߊ߲߬.",
+ "lockmanager-fail-db-release": "ߌ ߕߍ߫ ߣߊ߬ ߛߋ߫ ߟߊ߫ ߛߐ߰ߟߌ ߓߐ߫ ߟߊ߫ ߓߟߏߡߟߊߝߊ߲ $1 ߞߊ߲߬.",
+ "lockmanager-fail-svr-release": "ߌ ߕߍ߫ ߣߊ߬ ߛߋ߫ ߟߊ߫ ߛߐ߰ߟߌ ߓߐ߫ ߟߊ߫ ߡߊ߬ߛߐ߬ߟߊ $1 ߞߊ߲߬.",
+ "zip-file-open-error": "ߝߎ߬ߕߎ߲߬ߕߌ ߘߏ߫ ߕߎ߲߬ ߓߘߴߊ߬ ߞߎ߲߬ߓߐ߫ ߞߵߌ ߕߏ߫ ߞߐߕߐ߮ ߘߟߊߞߊ߭ ߟߊ߫ ZIP ߝߛߍ߬ߝߛߍ߬ߟߌ߬ ߞߊ߲ߡߊ߬.",
+ "zip-wrong-format": "ߞߐߕߐ߯ ߡߊߕߍ߰ߣߍ߲ ߕߎ߲߬ ߕߍ߫ ZIP ߞߐߕߐ߯ ߘߌ߫.",
"uploadstash": "ߥߊ߬ߣߊߙߌ ߟߊߦߟߍ߬",
"uploadstash-clear": "ߞߐߕߐ߮ ߥߣߊ߬ߙߌ߬ߣߍ߲ ߠߎ߬ ߖߏ߬ߛߌ߬",
"uploadstash-nofiles": "ߞߐߕߐ߮ ߥߣߊ߬߬ߙߌ߬ߣߍ߲߬ ߕߴߌ ߓߟߏ߫.",
"uploadstash-file-not-found": "ߟߊߘߏ߲߬ߣߍ߲ \"$1\" ߕߍ߫ ߥߊ߬ߣߊߙߌ ߟߎ߬ ߘߐ߫.",
"uploadstash-file-not-found-no-thumb": "ߞߝߊ߬ߟߋ߲ߛߋ߲ ߕߍ߫ ߣߊ߬ ߟߊߛߐ߬ߘߐ߲߬ ߠߊ߫.",
"uploadstash-file-not-found-missing-content-type": "ߞߣߐߘߐ ߛߎ߯ߦߊ ߞߎ߲߬ߕߐ߮ ߞߐߢߌ߬ߣߊ߬ߣߍ߲߫.",
+ "uploadstash-file-not-found-not-exists": "ߌ ߕߴߛߋ߫ ߞߐߕߐ߮ ߝߊ߲߭ ߘߏ߫ ߛߐ߬ߘߐ߲߬ ߠߊ߫߸ ߥߟߴߊ߬ ߘߝߊߣߍ߲.",
+ "uploadstash-file-too-large": "ߊ߬ ߕߴߛߋ߫ ߞߐߕߐ߯ ߡߊߛߐ߫ ߟߊ߫ ߡߍ߲ ߢߊ߲ߞߊ߲ ߓߏ߲߬ߓߊ߫ ߖߌ߬ߦߊ߬ߘߊ߲ߕߊ $1 ߘߌ߫.",
+ "uploadstash-not-logged-in": "ߟߊ߬ߓߊ߰ߙߊ߬ߟߊ߫ ߜߊ߲߬ߞߎ߲߬ߣߍ߲߬ ߕߍ߫߸ ߡߍ߲ ߕߊ߫ ߦߋ߫ ߞߐߕߐ߮ ߘߌ߫.",
+ "uploadstash-wrong-owner": "ߕߋ߲߭ߕߋ߲߭ ߟߊ߬ߓߊ߰ߙߊ߬ߟߊ ߕߊ߫ ߕߍ߫ ߞߐߕߐ߮ ($1) ߘߌ߫.",
+ "uploadstash-no-such-key": "ߒ߬ߒ߫ ߞߣߐߘߐ߫ ߛߎ߮ ߣߌ߲߬ ($1) ߕߴߛߋ߫ ߛߋ߲߬ߓߐ߫ ߟߊ߫.",
"uploadstash-no-extension": "ߘߐ߬ߥߙߊ߬ߟߌ ߦߋ߫ ߝߏߦߊ߲ ߠߋ߬ ߘߌ߫.",
"uploadstash-zero-length": "ߞߐߕߐ߮ ߦߋ߫ ߥߊ߲߬ߥߊ߲߬ ߘߐߞߏߟߏ߲ ߠߋ߬ ߘߌ߫.",
+ "img-auth-accessdenied": "ߓߊ߲߬ ߞߍߣߍ߲ ߠߋ߬ ߦߴߊ߬ ߟߊߛߐ߬ߘߐ߲߬ ߞߏ ߡߊ߬.",
+ "img-auth-badtitle": "ߞߎ߲߬ߕߐ߮ ߓߍ߲߬ߣߍ߲ ߕߴߛߋ߫ ߘߐߓߍ߲߬ ߠߊ߫ ߞߊ߬ ߝߘߊ߫ \"$1\".",
"img-auth-nofile": "ߞߐߕߐ߮ \"$1\" ߕߍ߫ ߦߋ߲߬.",
+ "img-auth-isdir": "ߌ ߦߴߌ ߞߊߘߊ߲ ߞߊ߲߬ ߞߊ߬ ߦߌ߬ߘߊ߬ߥߟߊ ߟߊߛߐ߬ߘߐ߲߬ \"$1\" ߞߐߕߐ߮ ߟߎ߬ ߟߊߛߐ߬ߘߐ߲ ߘߐߙߐ߲߫ ߠߋ߬ ߟߊߘߌ߬ߢߍ߬ ߣߍ߲߬.",
+ "img-auth-streaming": "ߞߟߋߞߟߋ \"$1\".",
"img-auth-noread": "ߟߊ߬ߛߐ߬ߘߐ߲߬ߠߌ߲ ߝߙߍ߫ ߕߍ߫ ߟߊ߬ߓߊ߰ߙߊ߬ߟߊ ߦߋ߫ ߞߊ߬ \"$1\" ߘߐߞߊ߬ߙߊ߲߬.",
"http-invalid-url": "URL: $1 ߓߍ߲߬ߓߊߟߌ",
"http-request-error": "HTTP ߡߊ߬ߢߌ߬ߣߌ߲߬ߠߌ߲ ߓߘߊ߫ ߗߌߙߏ߲߫ ߝߎ߬ߕߎ߲߬ߕߌ߬ ߡߊߟߐ߲ߓߊߟߌ ߘߏ߫ ߞߏߛߐ߲߬.",
"mostinterwikis": "ߞߐߜߍ ߡߍ߲ ߠߎ߬ ߦߋ߫ ߥߞߌ ߣߌ߫ ߢߐ߲ߕߍ ߝߊ߲߬ߓߊ ߘߐ߫",
"mostrevisions": "ߟߢߊ߬ߟߌ߬ ߦߙߌߞߊ߫ ߦߋ߫ ߞߐߜߍ ߡߍ߲ ߠߎ߬ ߘߐ߫",
"prefixindex": "ߞߐߜߍ ߡߍ߲ ߠߎ߬ ߓߍ߯ ߟߊߝߟߐߣߍ߲߫",
+ "prefixindex-namespace": "ߢߍߣߙߊ ߦߋ߫ ߞߐߜߍ ߡߍ߲ ߓߍ߯ ߟߊ߫ ($1 ߕߐ߯ߛߓߍ ߞߣߍ)",
"prefixindex-submit": "ߊ߬ ߦߌ߬ߘߊ߬",
+ "prefixindex-strip": "ߢߍߣߙߊ ߟߎ߬ ߢߡߊߘߏ߲߰ ߞߐߝߟߌ ߟߎ߬ ߘߐ߫.",
"shortpages": "ߞߐߜߍ߫ ߛߎߘߎ߲ ߠߎ߬",
"longpages": "ߞߐߜߍ߫ ߖߊ߲ ߠߎ߬",
+ "deadendpages": "ߞߐߜߍ߫ ߘߏ߲߬ߘߊ߬ߒߕߊ߲ ߠߎ߬",
"deadendpagestext": "ߓߌ߬ߟߊ߬ߢߐ߲߰ߡߊ߬ ߕߍ߫ ߞߐߜߍ ߢߌ߲߬ ߠߎ߬ ߣߌ߫ ߞߐߜߍ ߕߐ߭ ߟߎ߬ ߕߍ߫ {{SITENAME}} ߘߐ߫.",
"protectedpages": "ߞߐߜߍ߫ ߟߊߞߊ߲ߘߊߣߍ߲ ߠߎ߬",
"protectedpages-filters": "ߛߍ߲ߛߍ߲ߟߊ߲ ߠߎ߬:",
+ "protectedpages-indef": "ߟߊ߬ߞߊ߲߬ߘߊ߬ߟߌ ߘߊ߲߬ߠߊߕߍ߰ߓߊߟߌ ߘߐߙߐ߲߫",
+ "protectedpages-noredirect": "ߟߊ߬ߞߎ߲߬ߛߌ߲߬ߠߌ߲ ߢߡߊߘߏ߲߰",
"protectedpages-timestamp": "ߕߎ߬ߡߊ ߓߊ߬ߘߌ߬ߟߊ߲",
"protectedpages-page": "ߞߐߜߍ",
"protectedpages-expiry": "ߊ߬ ߛߕߊ ߓߘߊ߫ ߝߊ߫",
"apihelp": "API ߘߍ߬ߡߍ߲߬ߠߌ߲",
"apisandbox": "API ߕߌ߬ߢߍ߬ߞߏ߲ߘߏ",
"apisandbox-jsonly": "ߡߊ߬ߞߏ ߦߋ߫ JavaScript ߟߊ߫ ߞߊ߬ API ߕߌ߬ߢߍ߬ߞߏ߲ߘߏ ߟߊߓߊ߯ߙߊ߫",
- "apisandbox-api-disabled": "API ߓߐߣߍ߲߫ ߦߋ߫ ߞߍߦߙߐ ߟߊ߫.",
"apisandbox-submit": "ߡߊ߬ߢߌ߬ߣߌ߲߬ߞߊ߬ߟߌ ߘߏ߫ ߞߍ߫",
"apisandbox-reset": "ߊ߬ ߖߏ߰ߛߌ߬",
"apisandbox-retry": "ߊ߬ ߡߊߝߍߣߍ߲߫ ߕߎ߲߯",
"wlheader-enotif": "ߢߎߡߍߙߋ߲ߞߏ߲ߘߏ ߟߊ߫ ߡߙߌߣߊ߲߫ ߦߌߘߊ ߓߘߊ߫ ߓߌ߬ߟߵߊ߬ ߟߊ߫.",
"wlheader-showupdated": "ߞߐߜߍ ߡߍ߲ ߠߎ߬ ߡߊߦߟߍ߬ߡߊ߲߬ߣߍ߲߬ ߌ ߟߊ߫ ߡߊ߬ߝߍ߬ߣߍ߲߬ߠߌ߲ ߞߐ߫߸ ߏ߬ ߟߎ߫ ߟߋ߬ ߦߌ߬ߘߊ߬ߣߍ߲߫ <strong>ߛߓߍߘߋ߲߫ ߞߎ߲ߓߊ</strong> ߘߐ߫.",
"wlnote": "ߘߎ߰ߟߊ ߘߐ߫ {{PLURAL:$1|is the last change|are the last <strong>$1</strong> changes}} ߞߐ߯ߟߕߊ ߘߐ߫ {{PLURAL:$2|hour|<strong>$2</strong> hours}}, as of $3, $4.",
- "wlshowlast": "ߕߎ߬ߡߊ߬ߙߋ߲ $1 ߞߐߟߕߊ $2 ߕߋ߬ߟߋ ߟߎ߬ ߦߌ߬ߘߊ߬",
"watchlist-hide": "ߊ߬ ߢߡߊߘߏ߲߰",
"watchlist-submit": "ߊ߬ ߦߌ߬ߘߊ߬",
"wlshowtime": "ߊ߬ ߞߊߞߊ߲߫ ߞߊ߬ ߟߊߓߊ߯ߙߊ߫ ߥߎ߬ߛߎ ߡߍ߲ ߞߘߐ߫",
"month": "ߞߵߊ߬ ߕߊ߬ ߞߊߙߏ ߡߊ߬ (ߊ߬ ߣߌ߫ ߞߊߙߏ ߞߎ߲߬ߝߟߐ ߘߐ߫):",
"year": "ߞߵߊ߬ ߕߊ߬ ߞߊߙߏ ߡߊ߬ (ߊ߬ ߣߌ߫ ߞߊߙߏ ߞߎ߲߬ߝߟߐ ߡߊ߬):",
"date": "ߞߵߊ߬ ߕߊ߬ ߕߎ߬ߡߊ߬ߘߊ ߡߊ߬ (ߊ߬ ߣߌ߫ ߖߏߣߊ߫)",
- "sp-contributions-newbies": "ߖߊ߬ߕߋ߬ߘߊ߬ ߞߎߘߊ ߟߎ߫ ߘߐߙߐ߲߫ ߠߊ߫ ߓߟߏߓߌߟߊߢߐ߲߯ߞߊ߲ ߦߌ߬ߘߊ߫ ߕߋ߲߬",
- "sp-contributions-newbies-sub": "ߖߊ߬ߕߋ߬ߘߊ߬ ߞߎߘߊ ߟߎ߬ ߦߋ߫",
- "sp-contributions-newbies-title": "ߟߊ߬ߓߊ߰ߙߊ߬ߟߊ ߟߊ߫ ߓߟߏߡߊߜߍ߲ ߖߊ߬ߕߋ߬ߘߊ߬ ߞߎߘߊ ߟߎ߬ ߦߋ߫",
"sp-contributions-blocklog": "ߜߊ߲߬ߞߎ߲߬ߠߌ߲ ߓߊ߬ߟߊ߲߬",
"sp-contributions-suppresslog": "{{GENDER:$1|ߟߊ߬ߓߊ߰ߙߊ߬ߟߊ}} ߓߟߏߓߌߟߊߢߐ߲߯ߞߊ߲ ߓߘߊ߫ ߖߏ߬ߛߌ߬",
"sp-contributions-deleted": "{{GENDER:$1|ߟߊ߬ߓߊ߰ߙߊ߬ߟߊ}} ߟߊ߫ ߓߟߏߓߌߟߊߢߐ߲߮ߞߊ߲ ߠߎ߬ ߓߘߊ߫ ߖߏ߬ߛߌ߬",
"ipb-otherblocks-header": "{{PLURAL:$1|ߘߊ߲ߖߐ|ߘߊ߲ߖߐ ߟߎ߬}} ߕߐ߭ ߟߎ߬",
"unblock-hideuser": "ߌ ߕߍߣߊ߬ ߛߋ߫ ߟߊ߫ ߟߊ߬ߓߊ߰ߙߊ߬ߟߊ ߣߌ߲߬ ߓߊ߬ߟߌ߬ߣߍ߲ ߓߐ߫ ߟߊ߫߸ ߓߊߏ߬ ߊ߬ߟߎ߬ ߕߐ߯ ߟߊߓߊ߯ߙߕߊ ߢߡߊߘߏ߲߰ߣߍ߲߫ ߠߋ߬.",
"proxyblocker": "ߟߐ߲߬ߞߋ߬ߟߊ ߓߊ߬ߟߊ߲߬ߟߊ߲",
+ "softblockrangesreason": "ߓߟߏߓߌߟߊߢߐ߲߯ߞߊ߲ߠߊ߫ ߕߐ߯ߒߕߊ߲ ߟߊߘߌ߬ߢߍ߬ߣߍ߲߬ ߕߍ߫ ߌ ߟߊ߫ IP ߛߊ߲߬ߓߊ߬ߕߐ߮ ($1)߸ ߌ ߜߊ߲߬ߞߎ߲߫ ߖߊ߰ߣߌ߲߬.",
+ "cant-see-hidden-user": "ߌ ߦߴߊ߬ ߝߍ߬ ߞߊ߬ ߟߊ߬ߓߊ߰ߙߊ߬ߟߊ ߡߍ߲ ߓߊ߬ߟߌ߬߸ ߏ߬ ߓߊ߬ߟߌ߬ߣߍ߲߬ ߞߘߐ ߟߋ߬ ߞߏ߬ߣߵߊ߬ ߢߡߊߘߏ߲߰ߣߍ߲߫ ߠߋ߬.ߓߊߏ߬ ߟߊ߬ߓߊ߰ߙߊ߬ߟߊ߫ ߢߡߊߘߏ߲߰ߣߍ߲ ߟߊߘߤߊ߬ߣߍ߲߬ ߕߴߌ ߦߋ߫߸ ߌ ߕߍ߫ ߣߊ߬ ߛߋ߫ ߟߴߊ߬ ߦߋ߫ ߟߊ߫. ߥߟߊ߫ ߞߵߊ߬ ߓߊ߬ߟߌ߬ߟߌ ߡߊߝߊ߬ߟߋ߲߬.",
+ "ipbblocked": "ߌ ߕߍ߫ ߣߊ߬ ߛߋ߫ ߟߊ߫ ߟߊ߬ߓߊ߰ߙߊ߬ߟߊ ߘߏ ߟߎ߬ ߓߊ߬ߟߌ߬ ߟߊ߫ ߥߟߊ߫ ߞߵߊ߬ߟߎ߫ ߓߊ߬ߟߌ߬ߣߍ߲ ߓߐ߫߸ ߓߊߏ߬ ߌ ߖߍ߬ߘߍ ߟߋ߬ ߣߴߌ ߖߍ߬ߘߍ߫ ߓߊ߬ߟߌ߬ ߟߊ߫.",
+ "ipbnounblockself": "ߌ ߖߍ߬ߘߍ ߓߊ߬ߟߌ߬ߣߍ߲ ߓߐ ߟߊߘߌ߬ߢߍ߬ߣߍ߲߬ ߕߴߌ ߦߋ߫ ߞߊ߬.",
"lockdb": "ߓߟߏߡߟߊ ߝߊ߲ ߣߍ߰",
"unlockdb": "ߓߟߏߡߟߊ ߝߊ߲ ߟߊߞߊ߬",
+ "lockconfirm": "ߐ߲߬ߐ߲߬ߐ߲߫߸ ߒ ߧߴߊ߬ ߝߍ߬ ߞߊ߬ ߓߟߏߡߟߊߝߊ߲ ߛߐ߰.",
+ "unlockconfirm": "ߐ߲߬ߐ߲߬ߐ߲߫߸ ߒ ߧߴߊ߬ ߝߍ߬ ߞߊ߬ ߓߟߏߡߟߊߝߊ߲ ߘߊߦߟߍ߬.",
"lockbtn": "ߓߟߏߡߟߊ ߝߊ߲ ߣߍ߰",
"unlockbtn": "ߓߟߏߡߟߊ ߝߊ߲ ߟߊߞߊ߬",
"locknoconfirm": "ߌ ߡߊ߫ ߟߊ߬ߛߙߋ߬ߦߊ߬ߟߌ߬ ߞߏ߲ߘߏ ߡߊߝߍߣߍ߲߫.",
"lockdbsuccesssub": "ߓߟߏߡߟߊ ߝߊ߲ ߛߐ߰ߟߌ ߓߘߊ߫ ߛߎߘߊ߲߫",
"unlockdbsuccesssub": "ߛߐ߰ߟߌ ߓߘߊ߫ ߓߐ߫ ߓߟߏߡߟߊ ߝߊ߲ ߞߊ߲߬",
+ "lockdbsuccesstext": "ߓߟߏߡߟߊߝߊ߲ ߓߘߊ߫ ߓߊ߲߫ ߛߐ߰ ߟߊ߫.<br /> ߣߌ߲߬ ߠߊߓߊ߬ߕߏ߬ ߓߊ߫ [[Special:UnlockDB|remove the lock]] ߣߴߌ ߟߊ߫ ߘߐ߬ߓߍ߲߬ߠߌ߲ ߘߝߊ߫ ߘߊ߫.",
"unlockdbsuccesstext": "ߓߟߏߡߟߊ ߝߊ߲ ߓߘߊ߫ ߓߊ߲߫ ߘߊߦߟߍ߬ ߟߊ߫.",
"databaselocked": "ߓߟߏߡߟߊ ߝߊ߲ ߛߐ߰ߣߍ߲߬ ߞߘߐ ߟߋ߬.",
"databasenotlocked": "ߓߟߏߡߟߊ ߝߊ߲ ߛߐ߰ߣߍ߲߬ ߕߍ߫.",
"move-page": "$1 ߛߋ߲߬ߓߐ߫",
"move-page-legend": "ߞߐߜߍ ߛߋ߲߬ߓߐ߫",
+ "namespace-nosubpages": "ߕߐ߯ߛߓߍ ߞߣߍ \"$1\" ߟߊߘߌ߬ߢߍ߬ߣߍ߲߬ ߕߍ߫ ߞߐߜߍߙߋ߲ ߠߎ߬ ߦߋ߫.",
"newtitle": "ߞߎ߲߬ߕߐ߰ ߞߎߘߊ:",
+ "move-watch": "ߓߊߖߎ߫ ߞߐߜߍ ߣߌ߫ ߞߏ߲߰ ߞߐߜߍ ߟߎ߬ ߡߊߝߟߍ߫.",
"movepagebtn": "ߞߐߜߍ ߛߋ߲߬ߓߐ߬ߟߌ",
"pagemovedsub": "ߛߋ߲߬ߓߐ߬ߟߌ ߓߘߊ߫ ߛߎߘߊ߲߫",
+ "cannotmove": "ߞߐߜߍ ߕߍ߫ ߛߐ߲߬ ߛߋ߲߬ߓߐ߬ ߟߊ߫߸ ߞߊ߬ ߓߍ߲߬ {{PLURAL:$1|ߞߎ߲߭|ߞߎ߲߭ ߠߎ߬}} ߡߊ߬.",
+ "movepage-moved": "<strong>\"$1\" ߓߘߊ߫ ߛߋ߲߬ߓߐ߫ ߞߵߊ߬ ߟߊߕߊ߯ \"$2\"</strong>",
+ "movepage-moved-redirect": "ߟߊ߬ߞߎ߲߬ߛߌ߲߬ߠߌ߲ ߓߘߊ߫ ߓߊ߲߫ ߛߌ߲ߘߌ߫ ߟߊ߫.",
+ "movepage-moved-noredirect": "ߟߊ߬ߞߎ߲߬ߛߌ߲߬ߠߌ߲ ߛߌ߲ߘߟߌ ߓߘߊ߫ ߓߊ߲߫ ߖߏ߬ߛߌ߬ ߟߊ߫.",
+ "movepage-delete-first": "ߞߏ߲߰ ߞߐߜߍ ߓߘߊ߫ ߟߊߢߊ߬ ߛߋ߲߬ߧߊ߬ ߦߙߌߞߊ߫ ߞߵߊ߬ ߝߐ߫ ߞߏ߫ ߊ߬ ߘߌ߫ ߖߏ߬ߛߌ߬ ߞߐߜߍ߫ ߛߋ߲߬ߓߐ߬ߣߍ߲ ߘߏ߫ ߘߌ߫. ߖߊ߰ߣߌ߲߫ ߞߐߜߍ ߖߏ߰ߛߌ߬ ߌ ߓߟߏ߫ ߟߊ߫߸ ߞߣߊ߬ ߕߏ߫ ߊ߬ ߡߊߝߍߣߍ߲߫ ߠߊ߫ ߕߎ߲߯.",
+ "articleexists": "ߞߐߜߍ ߕߐ߮ ߣߌ߲߬ ߦߋ߫ ߦߋ߲߬ ߞߘߐ߬ߡߊ߲߬߸ ߥߟߊ߫ ߌ ߟߊ߫ ߕߐ߯ ߛߎߥߊ߲ߘߌߣߍ߲ ߓߍ߲߬ ߣߍ߲߬ ߕߍ߫.\nߕߐ߯ ߜߘߍ߫ ߛߎߥߊ߲ߘߌ߫ ߖߊ߰ߣߌ߲߬.",
+ "cantmove-titleprotected": "ߌ ߕߍ߫ ߣߊ߬ ߛߋ߫ ߟߊ߫ ߞߐߜߍ ߛߋ߲߬ߓߐ߫ ߟߊ߫ ߘߊߞߎ߲ ߣߌ߲߬ ߘߐ߫߸ ߓߊߏ߬ ߞߎ߲߬ߕߐ߰ ߞߎߘߊ ߓߘߊ߫ ߓߊ߲߫ ߟߊߞߊ߲ߘߊ߫ ߟߊ߫ ߛߌ߲ߘߟߌ ߡߊ߬.",
"movetalk": "ߞߎߡߊߢߐ߲߯ߦߊ߫ ߞߐߜߍ߫ ߓߟߏߘߏ߲߬ߣߍ߲ ߠߎ߬ ߛߋ߲߬ߓߐ߫",
"move-subpages": "ߞߐߜߍߙߋ߲ ߠߎ߬ ߛߋ߲߬ߓߐ߫ (ߦߊ߲߬ $1)",
"move-talk-subpages": "ߞߐߜߍߙߋ߲ ߠߎ߬ ߛߋ߲߬ߓߐ߫ ߞߎߡߊߢߐ߲߯ߦߊ߫ ߞߐߜߍ (ߘߐ߫ ߦߊ߲߬ $1)",
+ "movepage-page-exists": "ߞߐߜߍ $1 ߦߋ߫ ߦߋ߲߬ ߞߘߐ߬ߡߊ߲߫߸ ߊ߬ ߘߏ߲߬ ߕߍ߫ ߛߐ߲߬ ߖߏ߰ߛߌ߬ ߞߏ ߡߊ߬ ߞߍߒߖߘߍߦߋߓߟߏߡߊ߬.",
+ "movepage-source-doesnt-exist": "ߞߐߜߍ $1 ߕߍ߫ ߦߋ߲߬߸ ߊ߬ ߘߏ߲߬ ߕߍ߫ ߛߐ߲߬ ߛߋ߲߬ߓߐ߬ ߟߊ߫.",
"movepage-page-moved": "ߞߐߜߍ $1 ߓߘߊ߫ ߓߊ߲߫ ߓߐ߫ ߟߴߊ߬ ߣߐ߭ ߘߐ߫ ߞߊ߬ ߥߊ߫ ߦߊ߲߬ $2",
+ "movepage-page-unmoved": "ߞߐߜߍ $1 ߕߴߛߋ߫ ߓߐ߫ ߟߊ߫ ߦߊ߲߬ ߞߵߊ߬ ߟߊߕߊ߯ $2.",
"movelogpage": "ߜߊ߲߬ߞߎ߲ ߓߐ߫ ߊ߬ ߡߊ߬",
"movelogpagetext": "ߞߐߜߍ߫ ߛߋ߲߬ߓߐ߬ߣߍ߲ ߠߎ߬ ߓߍ߯ ߛߙߍߘߍ ߟߋ߬ ߦߋ߫ ߘߎ߰ߟߊߘߐ.",
"movesubpage": "{{PLURAL:$1|ߞߐߜߍߙߋ߲|ߞߐߜߍߙߋ߲ ߠߎ߬}}",
"newimages-legend": "ߥߊ߬ߣߊߙߌ",
"newimages-label": "ߞߐߕߐ߮ ߕߐ߮ (ߥߟߴߊ߬ ߝߊ߲߭ ߘߏ߫):",
"newimages-user": "IP ߛߊ߲߬ߓߊ߬ߕߐ߮ ߥߟߊ߫ ߟߊ߬ߓߊ߰ߙߊ߬ߕߐ߮:",
- "newimages-newbies": "ߖߊ߬ߕߋ߬ߘߊ߬ ߞߎߘߊ ߟߎ߫ ߘߐߙߐ߲߫ ߠߊ߫ ߓߟߏߓߌߟߊߢߐ߲߯ߞߊ߲ ߦߌ߬ߘߊ߫ ߕߋ߲߬",
"newimages-showbots": "ߓߏߕ ߟߊ߫ ߟߊ߬ߦߟߍ߬ߟߌ ߟߎ߬ ߦߌ߬ߘߊ߬",
"newimages-hidepatrolled": "ߓߍ߬ߙߍ߲߬ߓߍ߬ߙߍ߲߬ߠߌ߲ ߟߊ߬ߦߟߍ߬ߟߌ ߟߎ߬ ߢߡߊߘߏ߲߰",
"newimages-mediatype": "ߡߍ߲ߕߊߦߋߕߊ ߛߎ߯ߦߊ:",
"watchlisttools-raw": "ߜߋ߬ߟߎ߲߬ߠߌ߲߬ ߞߐߜߍ ߡߎ߰ߡߍ ߡߊߦߟߍ߬ߡߊ߲߫",
"signature": "[[{{ns:user}}:$1|$2]] ([[{{ns:user_talk}}:$1|ߓߊ߬ߘߏ߬ߟߌ]])",
"timezone-local": "ߕߌ߲߬ߞߎߘߎ߲",
+ "version": "ߦߌߟߡߊ",
"version-skins": "ߜߟߏ߬ ߡߊߞߍߣߍ߲ ߠߎ߬",
"version-specialpages": "ߞߐߜߍ߫ ߞߙߍߞߙߍߣߍ߲",
"version-parserhooks": "ߞߐ߬ߘߙߍ߬ ߞߎߙߎ߲ߞߎߙߎ߲ߠߊ",
"version-antispam": "ߞߏ߬ߘߏ (ߛߑߔߊߡ) ߢߍߓߍ߲ߠߌ߲",
"version-other": "ߘߏ߫ ߜߘߍ",
"version-hooks": "ߘߎ߲ߓߟߐ ߟߎ߬",
+ "version-hook-name": "ߛߏ߲߭ߓߊ߬ߟߌ ߕߐ߮",
+ "version-hook-subscribedby": "ߕߐ߮ ߛߓߍߣߍ߲߫ ߦߋ߫",
+ "version-no-ext-name": "[ߕߐ߯ ߕߴߊ߬ ߟߊ߫]",
+ "version-skin-colheader-name": "ߝߊ߬ߘߌ",
+ "version-ext-colheader-version": "ߦߌߟߡߊ",
+ "version-ext-colheader-license": "ߕߌ߰ߦߊ",
+ "version-ext-colheader-description": "ߕߐ߯ߟߊߘߏ߲",
+ "version-ext-colheader-credits": "ߛߓߍߦߟߊ",
+ "version-license-title": "$1 ߕߌ߰ߦߊ",
+ "version-software": "ߛߎ߲ߝߘߍ ߓߘߊ߫ ߡߊߞߍ߫",
+ "version-software-product": "ߥߟߏߒߘߐ",
+ "version-software-version": "ߦߌߟߡߊ",
+ "version-entrypoints": "ߘߊߞߎ߲ URL ߟߊߘߏ߲߬",
+ "version-entrypoints-header-entrypoint": "ߘߊߞߎ߲ ߠߊߘߏ߲߬",
+ "version-entrypoints-header-url": "URL",
+ "version-libraries": "ߛߓߍߘߊ ߓߘߊ߫ ߡߊߞߍ߫",
+ "version-libraries-library": "ߛߓߍߘߊ",
+ "version-libraries-version": "ߦߌߟߡߊ",
+ "version-libraries-license": "ߕߌ߰ߦߊ",
+ "version-libraries-description": "ߕߐ߯ߟߊߘߏ߲",
+ "version-libraries-authors": "ߛߓߍߦߟߊ",
"redirect": "ߟߊߞߎ߲߬ߛߌ߲߬ߣߍ߲߬ ߦߋ߫ ߞߐߕߐ߮ ߓߟߏ߫߸ ߟߊ߬ߓߊ߰ߙߊ߬ߟߊ߸ ߞߐߜߍ߸ ߡߛߊ߬ߦߌ߲߬ߠߌ߲߸ ߥߟߊ߫ ߜߊ߲߬ߞߎ߲߬ߠߌ߲ ID",
"redirect-summary": "ߞߐߜߍ߫ ߓߟߏߡߊߞߊ߬ߣߍ߲ ߟߊߞߎ߲߬ߛߌ߲߬ߣߍ߲߬ ߦߋ߫ ߞߐߕߐ߮ (ߞߐߕߐ߮ ߕߐ߮ ߘߌ߫),ߞߐߜߍ (ߦߋ߫ ߡߛߊ߬ߦߌ߲߬ߠߌ߲ ID ߥߟߊ߫ ߞߐߜߍ ID ߘߌ ߞߊ߲߬), ߞߐߜߍ߫ ߟߊߓߊ߯ߙߕߊ ߦߋ߫ (ߟߊ߬ߓߊ߰ߙߟߊ߬ ߦߙߌߞߊ ID ߘߌ ߞߊ߲߬), ߥߟߊ߫ ߜߊ߲߬ߞߎ߲߬ߠߌ߲ ߘߏ߲߬ߕߐ߬ߟߊ ߦߋ߫ (ߜߊ߲߬ߞߎ߲߬ߠߌ߲ ID ߘߌ ߞߊ߲߬). ߟߊ߬ߓߊ߰ߙߊ߬ߟߌ:\n[[{{#Special:Redirect}}/file/Example.jpg]], \n[[{{#Special:Redirect}}/page/64308]],\n[[{{#Special:Redirect}}/revision/328429]], \n[[{{#Special:Redirect}}/user/101]], ߥߟߊ߫ \n[[{{#Special:Redirect}}/logid/186]].",
"redirect-submit": "ߕߊ߯",
"redirect-page": "ߞߐߜߍ߫ ߡߊߟߐ߲ߝߙߍߕߍ",
"redirect-revision": "ߞߐߜߍ ߣߐ߬ߡߊ߬ߛߊ߬ߦߌ߬ ߝߙߍߕߍ",
"redirect-file": "ߞߐߕߐ߯ ߕߐ߮",
+ "redirect-logid": "ߜߊ߲߬ߞߎ߲߬ߠߌ߲ ID",
+ "redirect-not-exists": "ߡߐ߬ߟߐ߲ ߡߊ߬ ߛߐ߬ߘߐ߲߬",
+ "redirect-not-numeric": "ߡߐ߬ߟߐ߲ ߕߍ߫ ߢߎߡߍߙߋ߲ߡߊ߫ ߘߌ߫",
+ "fileduplicatesearch": "ߞߐߕߐ߯ ߓߊߟߌߣߍ߲ ߠߎ߬ ߢߌߣߌ߲߫",
+ "fileduplicatesearch-summary": "ߞߐߕߐ߯ ߓߊߟߌߣߍ߲ ߠߎ߬ ߢߌߣߌ߲߫ ߡߍ߲ ߠߎ߬ ߓߌ߲ߓߌ߲ߣߍ߲߫ ߦߋ߫ ߢߋߙߋ߲ߞߎߟߌ ߡߐ߬ߟߐ߲ ߡߊ߬.",
+ "fileduplicatesearch-filename": "ߞߐߕߐ߮ ߕߐ߮:",
+ "fileduplicatesearch-submit": "ߢߌߣߌ߲ߠߌ߲",
"specialpages": "ߘߎ߲߬ߘߎ߬ߡߊ߬ ߞߐߜߍ ߟߎ߬",
"tag-filter": "[[Special:Tags|ߞߊ߲ߠߊߛߓߍ]] ߢߡߊߘߏ߲߰ߣߍ߲",
"tag-list-wrapper": "[[Special:Tags|{{PLURAL:$1|ߡߊ߬ߛߙߋ |ߡߊ߬ߛߙߋ ߟߎ߬ }}]]: $2",
"watchthispage": "Tlhapetša letlakala le",
"unwatch": "Tloša tlhapešo",
"watchlist-details": "{{PLURAL:$1|$1 ya letlakala|$1 ya matlakala}} a lenano la ditlhapetšo tša gago, re sa bale matlakala a dipoledišano (dipolelo).",
- "wlshowlast": "Laetša $1 diiri $2 matšatši tša gofeta",
"watchlist-options": "Dikgatlego tša lenano la ditlhapetšo",
"watching": "Tlhapeditše...",
"unwatching": "Tlhapetšo eya tlošwa ...",
"uctop": "bjale",
"month": "Go tloga kgweding (le peleng):",
"year": "Go tloga ngwageng (le peleng):",
- "sp-contributions-newbies": "Laetša diabe tša bašumiši ba bafsa fela",
- "sp-contributions-newbies-sub": "Tša tšhupaleloko tše mphsa",
"sp-contributions-blocklog": "''Log'' yago thiba",
"sp-contributions-deleted": "diabe tša mošomiši tšeo di phumutšwego",
"sp-contributions-uploads": "di-\"upload\"",
"showdiff": "Yong-a wallak",
"anoneditwarning": "<strong>Warning:</strong> You are not logged in. Noonook IP-karl-up will be publicly djinang il noonook wallak. Noonook-il <strong>[$1 log in]</strong> or <strong>[$2 create an gudak]</strong>, noonook wallak will be attributed to noonook niall-kwel-le, along with other benefits.",
"blockedtitle": "Niall be nap-nap",
- "blockedtext": "<strong>Your username or IP address has been blocked.</strong>\n\nThe block was made by $1.\nThe reason given is <em>$2</em>.\n\n* Start of block: $8\n* Expiration of block: $6\n* Intended blockee: $7\n\nYou can contact $1 or another [[{{MediaWiki:Grouppage-sysop}}|administrator]] to discuss the block.\nYou cannot use the \"email this user\" feature unless a valid email address is specified in your [[Special:Preferences|account preferences]] and you have not been blocked from using it.\nYour current IP address is $3, and the block ID is #$5.\nPlease include all above details in any queries you make.",
+ "blockedtext": "<strong>Your username or IP address has been blocked.</strong>\n\nThe block was made by $1.\nThe reason given is <em>$2</em>.\n\n* Start of block: $8\n* Expiration of block: $6\n* Intended blockee: $7\n\nYou can contact $1 or another [[{{MediaWiki:Grouppage-sysop}}|administrator]] to discuss the block.\nYou cannot use the \"{{int:emailuser}}\" feature unless a valid email address is specified in your [[Special:Preferences|account preferences]] and you have not been blocked from using it.\nYour current IP address is $3, and the block ID is #$5.\nPlease include all above details in any queries you make.",
"loginreqlink": "yaarlkoorl",
"newarticletext": "Noonook ngwaliny beda bibol uart-yogow yeye.\nWallak bibol qadgin mar waangkin ngardal (djinang [$1 mar yira bibol] ngatta katitjiny)\nWarra bainya noonook nidja, click noonook bowser's <strong>woort koorl</strong>button",
- "anontalkpagetext": "----\n<em>Nidja waangkininy bibol for an anonymous niall uart-quadga gudak, or who does not use it.</em>\nWe therefore have to use the numerical IP-karl-up to identify him/her.\nSuch an IP-karl-up can be shared by several niall.\nIf noonook anonymous niall and feel that irrelevant waangkin have been directed at noonook, please [[Special:CreateAccount|quadga gudak]] or [[Special:UserLogin|log in]] to avoid future confusion with other anonymous niall.",
+ "anontalkpagetext": "----\n<em>Nidja waangkininy bibol for an anonymous niall uart-quadga gudak, or who does not use it.</em>\nWe therefore have to use the numerical IP-karl-up to identify balang.\nSuch an IP-karl-up can be shared by several niall.\nIf noonook anonymous niall and feel that irrelevant waangkin have been directed at noonook, please [[Special:CreateAccount|quadga gudak]] or [[Special:UserLogin|log in]] to avoid future confusion with other anonymous niall.",
"noarticletext": "There is currently no text in this page.\nYou can [[Special:Search/{{PAGENAME}}|search for this page title]] in other pages,\n<span class=\"plainlinks\">[{{fullurl:{{#Special:Log}}|page={{FULLPAGENAMEE}}}} search the related logs],\nor [{{fullurl:{{FULLPAGENAME}}|action=edit}} create this page]</span>.",
"noarticletext-nopermission": "Nidja yeye uart text il nidja bibol.\nNoonook [[Special:Search/{{PAGENAME}}|genuniny-ung nidja bibol katta wir-iny]] bura wam bibol, ka <span class=\"plainlinks\">[{{fullurl:{{#Special:Log}}|page={{FULLPAGENAMEE}}}} genuniny boonadairn]</span>, noonook uart kaya ijow walbirniny nidja bibol.",
"userpage-userdoesnotexist-view": "Niall gaduk $1 be uart yeye-quadga",
"recentchangeslinked-feed": "Noyyang wallak",
"recentchangeslinked-toolbox": "Noyyang wallak",
"recentchangeslinked-title": "Wallak noyyanging $1",
- "recentchangeslinked-summary": "Nidga list-ang wallak yeye bibol beda wer-ang ngela bibol (or il ngela warrangan)\n\nBibol il [[Special:Watchlist|noonook djinanglist]] be <strong>moorn</strong>",
+ "recentchangeslinked-summary": "Nidga list-ang wallak yeye bibol beda wer-ang ngela bibol ({{ns:category}} il ngela warrangan)\n\nBibol il [[Special:Watchlist|noonook djinanglist]] be <strong>moorn</strong>",
"recentchangeslinked-page": "Bibol kwel-le:",
"recentchangeslinked-to": "Yong-a wallak bibol beda nitja bibol",
"upload": "Yirra file",
"watchlist-details": "{{PLURAL:$1|$1 bibol}} noonook Djinanglist (wer waangkin bibol).",
"wlheader-showupdated": "Bibol yallabel wallak kura noonook djinang balgup be yong-a bura <strong>moorn</strong>",
"wlnote": "Ngardal {{PLURAL:$1|yuttock wallak|nidja yuttock <strong>$1</strong> wallak}} il yuttock {{PLURAL:$2|hour|<strong>$2</strong> hours}}, nun o-luk $3, $4.",
- "wlshowlast": "Yong-a yeye $1 hours $2 biryt",
"watchlist-options": "djinanglist nidj-ka-nidja",
"enotif_reset": "djiler yennar bibol nyiny",
"dellogpage": "Barranginy boonadairn",
"uctop": "yeye",
"month": "Month-ang (wer gwytch-ang-at)",
"year": "Year-ang (wer gwytch-ang-at)",
- "sp-contributions-newbies": "Yong-a wallak il ngolango gaduk",
"sp-contributions-blocklog": "nap-nap boonadairn",
"sp-contributions-uploads": "irak",
"sp-contributions-logs": "boonadairn",
"apihelp": "Ajuda de l'API",
"apihelp-no-such-module": "Lo modul « $1 » es introbable.",
"apisandbox": "Nauc de sabla API",
- "apisandbox-api-disabled": "API es desactivat sus aqueste site.",
"apisandbox-submit": "Far la demanda",
"apisandbox-reset": "Escafar",
"apisandbox-retry": "Ensajar tornarmai",
"wlheader-enotif": "La notificacion per corrièr electronic es activada.",
"wlheader-showupdated": "Las paginas que son estadas modificadas dempuèi vòstra darrièra visita son afichadas en '''gras'''.",
"wlnote": "Çaijós {{PLURAL:$1|figura la darrièra modificacion efectuada|figuran las <strong>$1</strong> darrièras modificacions efectuadas}} pendent {{PLURAL:$2|la darrièra ora|las <strong>$2</strong> darrièras oras}}, dempuèi $3, $4.",
- "wlshowlast": "Far veire las darrièras $1 oras, los darrièrs $2 jorns",
"watchlist-hide": "Amagar",
"watchlist-submit": "Afichar",
"wlshowtime": "Periòde afichat :",
"uctop": "actual",
"month": "A partir del mes (e precedents) :",
"year": "A partir de l’annada (e precedentas) :",
- "sp-contributions-newbies": "Far veire sonque las contribucions dels utilizaires novèls",
- "sp-contributions-newbies-sub": "Lista de las contribucions dels utilizaires novèls. Las paginas que son estadas suprimidas son pas afichadas.",
- "sp-contributions-newbies-title": "Las contribucions de l’utilizaire pels comptes novèls",
"sp-contributions-blocklog": "Istoric dels blocatges",
"sp-contributions-suppresslog": "contribucions de l'{{GENDER:$1|utilizaire|utilizaira}} suprimidas",
"sp-contributions-deleted": "contribucions de l'{{GENDER:$1|utilizaire|utilizaira}} suprimidas",
"img-lang-default": "(lenga per defaut)",
"img-lang-info": "Afichar aqueste imatge en $1 $2.",
"img-lang-go": "Amodar",
- "ascending_abbrev": "creissent",
- "descending_abbrev": "descreissent",
"table_pager_next": "Pagina seguenta",
"table_pager_prev": "Pagina precedenta",
"table_pager_first": "Primièra pagina",
"suppress": "ଅଜାଣତ ଅଣଦେଖା",
"querypage-disabled": "ଏହି ବିଶେଷ ପୃଷ୍ଠାଟି ଦେଖଣା କାରଣରୁ ଅଚଳ କରାଯାଇଅଛି ।",
"apisandbox": "API ପରଖଘର",
- "apisandbox-api-disabled": "API ଟି ଏହି ସାଇଟରେ ଅଚଳ କରାଯାଇଛି ।",
"apisandbox-submit": "ଅନୁରୋଧ କରିବେ",
"apisandbox-reset": "ଖାଲି କରିଦିଅନ୍ତୁ",
"apisandbox-examples": "ଉଦାହରଣ",
"wlheader-enotif": "ଇମେଲ ସୂଚନା ସଚଳ କରାଗଲା ।",
"wlheader-showupdated": "ଆପଣ ଶେଷଥର ଦେଖିଥିବା ପୃଷ୍ଠାଗୁଡ଼ିକ '''ମୋଟା ଅକ୍ଷର'''ରେ ଦେଖାଯାଉଅଛି ।",
"wlnote": "$3, $4 ଅନୁସାରେ ବିଗତ {{PLURAL:$2|ଘଣ୍ଟାକରେ|<strong>$2</strong> ଘଣ୍ଟାରେ}}{{PLURAL:$1|ଶେଷ ବଦଳ|ଶେଷ <strong>$1</strong> ବଦଳ ତଳେ ଦିଆଗଲା}} ।",
- "wlshowlast": "ଗତ $1 ଘଣ୍ଟା $2 ଦିନ ଦେଖାନ୍ତୁ",
"wlshowhidecategorization": "ପୃଷ୍ଠା ଶ୍ରେଣୀବିଭାଗ",
"watchlist-options": "ଦେଖଣା ବିକଳ୍ପସବୁ",
"watching": "ଦେଖୁଛି...",
"uctop": "ଏବେକାର",
"month": "ମାସରୁ (ଓ ତା ଆଗରୁ)",
"year": "ବର୍ଷରୁ (ଆଉ ତା ଆଗରୁ)",
- "sp-contributions-newbies": "କେବଳ ନୂଆ ସଭ୍ୟମାନଙ୍କର ଅବଦାନ ଦେଖାଇବେ",
- "sp-contributions-newbies-sub": "ନୂଆ ଖାତାମାନଙ୍କ ନିମନ୍ତେ",
- "sp-contributions-newbies-title": "ନୂଆ ଖାତାମାନଙ୍କ ନିମନ୍ତେ ସଭ୍ୟ ଅବଦାନ",
"sp-contributions-blocklog": "ଲଗଟିକୁ ଅଟକାଇଦେବେ",
"sp-contributions-suppresslog": "ସଭ୍ୟଙ୍କ ଅବଦାନ ଲୁଚାଯାଇଛି",
"sp-contributions-deleted": "ଲିଭାଇ ଦିଆଯାଇଥିବା ସଭ୍ୟଙ୍କ ଅବଦାନସମୂହ",
"img-lang-default": "(ଡିଫଲ୍ଟ ଭାଷା)",
"img-lang-info": "$1ରେ ଏହି ଛବିଟି ରେଣ୍ଡର କରନ୍ତୁ । $2",
"img-lang-go": "ଯାଆନ୍ତୁ",
- "ascending_abbrev": "ସାନରୁ ବଡ କ୍ରମରେ",
- "descending_abbrev": "ବଖାଣ",
"table_pager_next": "ପର ପୃଷ୍ଠା",
"table_pager_prev": "ଆଗ ପୃଷ୍ଠା",
"table_pager_first": "ପ୍ରଥମ ପୃଷ୍ଠା",
"unwatchthispage": "Мауал дар дæ цæст",
"watchlist-details": "{{PLURAL:$1|$1 фарсмæ|$1 фарсмæ}} дæ цæст дарыс, тæрхоны фæрстæ нæ нымайгæйæ.",
"wlnote": "Дæлæ афæстаг '''$2 сахаты дæргъы''' цы $1 {{PLURAL:$1|ивддзинад|ивддзинады}} æрцыди.",
- "wlshowlast": "Фæстæг $1 сахаты, $2 боны дæргъы; .",
"watchlist-options": "Цæстдард рæгъы фадæттæ",
"watching": "Цæстдард фæрсты номхыгъдмæ афтауын...",
"unwatching": "Цæстдард фæрсты номхыгъдæй аиуварс кæнын...",
"uctop": "нырыккон",
"month": "Ацы мæйы (æмæ раздæр):",
"year": "Ацы азы (æмæ раздæр):",
- "sp-contributions-newbies": "Æвдисын æрмæст нæуæг архайджыты бавæрд",
- "sp-contributions-newbies-sub": "Ноггонд аккаунттæ",
"sp-contributions-blocklog": "хъодыты лог",
"sp-contributions-suppresslog": "æмбæхст ивдтытæ",
"sp-contributions-deleted": "æппæрст ивдтытæ",
"watchlist-details": "ਗੱਲ-ਬਾਤ ਸਫ਼ੇ ਨਾ ਗਿਣਦੇ ਹੋਏ, ਤੁਹਾਡੀ ਨਿਗਰਾਨੀ-ਸੂਚੀ ਵਿਚ{{PLURAL:$1|$1 ਸਫ਼ਾ ਹੈ|$1 ਸਫ਼ੇ ਹਨ}}।",
"wlheader-enotif": "ਈਮੇਲ ਸੂਚਨਾ ਚਾਲੂ ਹੈ।",
"wlnote": "$3, $4 ਮੁਤਾਬਕ ਆਖ਼ਰੀ {{PLURAL:$2|ਘੰਟੇ|<strong>$2</strong> ਘੰਟਿਆਂ}} ਵਿਚ {{PLURAL:\n$1|ਤਬਦੀਲੀ ਹੋਈ|<strong>$1</strong> ਤਬਦੀਲੀਆਂ ਹੋਈਆਂ}}, ਹੇਠਾਂ ਵੇਖੋ।",
- "wlshowlast": "ਪਿਛਲੇ $1 ਘੰਟੇ $2 ਦਿਨ ਵਖਾਓ",
"watchlist-hide": "ਲੁਕਾਓ",
"watchlist-submit": "ਦਿਖਾਓ",
"wlshowhideminor": "ਨਿੱਕੀਆਂ ਸੋਧਾਂ",
"uctop": "ਮੌਜੂਦਾ",
"month": "ਇਸ (ਅਤੇ ਪਿਛਲੇ) ਮਹੀਨੇ ਤੋਂ :",
"year": "ਇਸ (ਅਤੇ ਪਿਛਲੇ) ਸਾਲ ਤੋਂ :",
- "sp-contributions-newbies": "ਸਿਰਫ਼ ਨਵੇਂ ਵਰਤੋਂਕਾਰਾਂ ਦੇ ਯੋਗਦਾਨ ਵਖਾਓ",
- "sp-contributions-newbies-sub": "ਨਵੇਂ ਖਾਤਿਆਂ ਲਈ",
"sp-contributions-blocklog": "ਪਾਬੰਦੀ ਚਿੱਠਾ",
"sp-contributions-deleted": "ਮਿਟਾਏ ਗਏ ਵਰਤੋਂਕਾਰ ਯੋਗਦਾਨ",
"sp-contributions-uploads": "ਅੱਪਲੋਡ",
"imgmultigoto": "$1 ਸਫ਼ੇ ਉੱਤੇ ਜਾਓ",
"img-lang-default": "(ਮੂਲ ਭਾਸ਼ਾ)",
"img-lang-go": "ਜਾਓ",
- "ascending_abbrev": "ਵਧਦਾ",
- "descending_abbrev": "ਘਟਦਾ",
"table_pager_next": "ਅਗਲਾ ਸਫ਼ਾ",
"table_pager_prev": "ਪਿਛਲਾ ਸਫ਼ਾ",
"table_pager_first": "ਪਹਿਲਾ ਸਫ਼ਾ",
"mycontris": "Saray entolong",
"anoncontribs": "Saray entolong",
"year": "Taon:",
- "sp-contributions-newbies-sub": "Para balo ran account",
"sp-contributions-blocklog": "log na aper",
"sp-contributions-talk": "tongtongan",
"sp-contributions-submit": "Anapen",
"wlheader-enotif": "Makasalangi (enabled) ing pamipabalu kapamilatan ning e-mail.",
"wlheader-showupdated": "'''Makapal''' la pangasulat deng bulung a miyalilan manibat aniang tauli mu lang pintalan.",
"wlnote": "{{PLURAL:$1|Ing makatuki ing tauling|Ding makatuki ring tauling '''$1''' miyalilan}} kilub {{PLURAL:$2|ning tauling metung a oras|ding tauling '''$2''' oras}}.",
- "wlshowlast": "Pakit la reng tauling $1 oras $2 aldo",
"watchlist-hide": "Isalikut",
"wlshowtime": "Ipakit ya ing tauli:",
"wlshowhideminor": "deng malating edit",
"uctop": "babo",
"month": "Manibat king bulan a (at minuna pa):",
"year": "Manibat banuang (at minuna pa):",
- "sp-contributions-newbies": "Den mung ambag da reng bayung account ing palto",
- "sp-contributions-newbies-sub": "Para kareng bayung account",
"sp-contributions-blocklog": "Sabatan ya ing tala",
"sp-contributions-deleted": "Deng ambag da reng talagamit a mebura",
"sp-contributions-talk": "Pisasabian",
"watchthispage": "Suire l'pache-lo",
"unwatch": "N'poin suire",
"watchlist-details": "{{PLURAL:$1|$1 pache|$1 paches}} din vote lisse à suire, chés paches éd disqhuchon n'sont poin conptées.",
- "wlshowlast": "Montrer darin $1 eûres $2 jours",
"watchlist-options": "Opchons del lisse à suire",
"watching": "Suire…",
"unwatching": "n'poin suire…",
"uctop": "darin",
"month": "Dpuis ch'moés (pi édvant)",
"year": "Del innée (pi avint)",
- "sp-contributions-newbies": "Montrer chés contérbuchons éd chés nouvieus conptes seulemint",
"sp-contributions-blocklog": "jornal éd chés blotcåjhes",
"sp-contributions-deleted": "Contérbuchons abolies",
"sp-contributions-uploads": "téléquértch'mints",
"unwatchthispage": "Nimmi watsche",
"notanarticle": "Ken Blatt",
"watchlist-details": "{{PLURAL:$1|$1 Blatt|$1 Bledder}} uff dei Watch-Lischt, ohne Gschwetz-Bledder",
- "wlshowlast": "Zeig die Enneringe vun de letscht $1 Schtund, $2 Daag odder .",
"watching": "Watsche…",
"unwatching": "Nimmi watsche...",
"enotif_impersonal_salutation": "{{SITENAME}}-Yuuser",
"imgmultipagenext": "neegschtes Blatt →",
"imgmultigo": "OK",
"imgmultigoto": "Geh zu Blatt $1",
- "ascending_abbrev": "uff",
- "descending_abbrev": "ab",
"table_pager_next": "Neegschtes Blatt",
"table_pager_prev": "Letscht Blatt",
"table_pager_first": "Erschtes Blatt",
"unusedcategoriestext": "Die Sachgrubb hodds, a wonnse vun känna onnare Said odda Sachgrubb gnumme werd.",
"pager-newer-n": "{{PLURAL:$1|negschd 1|negschd $1}}",
"pager-older-n": "{{PLURAL:$1|vorisch 1|vorische $1}}",
- "apisandbox-api-disabled": "Die API isch uffm Wiki abgschdelld worre.",
"booksources": "Buchgwelle",
"booksources-search-legend": "Noch Buchgwelle gugge",
"booksources-search": "Gugg",
"watchthispage": "Die Said beowachde",
"unwatch": "Nemme beowachde",
"watchlist-details": "S hodd {{PLURAL:$1|$1 Said|$1 Saide}} uff doina Beowachdungslischd, Dischbediersaide zeeln nedd gdrennd.",
- "wlshowlast": "Die ledschde $1 Schdunnd $2 Daach zaische",
"watchlist-options": "Meschlischkaide vunde Beowachdungslischd",
"watching": "Beowachde ...",
"unwatching": "Nimmi beowachde ...",
"uctop": "geschewedisch",
"month": "än Monad (un frieja):",
"year": "Abm Johr (un frieja):",
- "sp-contributions-newbies": "Zaisch nua Baidräsch vun naije Konde",
"sp-contributions-blocklog": "Schberrlogbuch",
"sp-contributions-uploads": "Nufflade",
"sp-contributions-logs": "Logbischa",
"go": "Przejdź",
"searcharticle": "Przejdź",
"history": "Historia strony",
- "history_short": "historia",
+ "history_short": "Historia",
"history_small": "historia",
"updatedmarker": "zmienione od twojej ostatniej wizyty",
"printableversion": "Wersja do druku",
"nocreate-loggedin": "Nie masz uprawnień do tworzenia nowych stron.",
"sectioneditnotsupported-title": "Edycja sekcji nie jest obsługiwana",
"sectioneditnotsupported-text": "Edycja sekcji na tej stronie nie jest obsługiwana.",
+ "modeleditnotsupported-title": "Edytowanie nie jest wspierane",
+ "modeleditnotsupported-text": "Edytowanie dla modulu zawartości $1 nie jest wspierane.",
"permissionserrors": "Błąd uprawnień",
"permissionserrorstext": "Nie masz uprawnień do tego działania z {{PLURAL:$1|następującej przyczyny|następujących przyczyn}}:",
"permissionserrorstext-withaction": "Nie masz uprawnień do $2 z {{PLURAL:$1|następującego powodu|następujących powodów}}:",
"content-model-css": "CSS",
"content-json-empty-object": "Pusty obiekt",
"content-json-empty-array": "Pusta tablica",
+ "unsupported-content-model": "<strong>Uwaga:</strong> Model zawartości $1 nie jest wspierany na tej wiki.",
+ "unsupported-content-diff": "Różnice dla modelu zawartości $1 nie są wspierane.",
+ "unsupported-content-diff2": "Różnice pomiędzy modelem zawartości $1 a $2 nie są wspierane na tej wiki.",
"deprecated-self-close-category": "Strony zawierające nieprawidłowe samozamykające się znaczniki HTML",
"deprecated-self-close-category-desc": "Strona zawiera samozamykające się znaczniki HTML, takie jak <code><b/></code> lub <code><span/></code>. Ich zachowanie zmieni się na dostosowane do specyfikacji HTML5, więc ich użycie w wikikodzie jest zdeprecjonowane.",
"duplicate-args-warning": "<strong>Ostrzeżenie:</strong> [[:$1]] wywołuje [[:$2]] z więcej niż jedną wartością dla parametru \"$3\". Tylko ostatnia podana wartość zostanie użyta.",
"rcfilters-filter-showlinkedto-label": "Pokaż zmiany na stronach linkujących do",
"rcfilters-filter-showlinkedto-option-label": "<strong>Strony linkujące do</strong> zaznaczonej strony",
"rcfilters-target-page-placeholder": "Wprowadź nazwę strony (lub kategorii)",
- "rcfilters-alldiscussions-label": "Wszystkie dyskusje",
+ "rcfilters-allcontents-label": "Wszystkie (treść)",
+ "rcfilters-alldiscussions-label": "Wszystkie (dyskusje)",
"rcnotefrom": "Poniżej {{PLURAL:$5|pokazano zmianę|pokazano zmiany}} {{PLURAL:$5|wykonaną|wykonane}} po <strong>$3, $4</strong> (nie więcej niż '''$1''' pozycji).",
"rclistfromreset": "Zresetuj wybór daty",
"rclistfrom": "Pokaż nowe zmiany od $3 $2",
"apihelp-no-such-module": "Moduł \"$1\" nie znaleziony.",
"apisandbox": "Środowisko testowe API",
"apisandbox-jsonly": "Do korzystania z brudnopisu API wymagany jest JavaScript.",
- "apisandbox-api-disabled": "API jest wyłączone na tej stronie.",
"apisandbox-intro": "Użyj tej strony do eksperymentowania z <strong>serwisem API MediaWiki</strong>.\nWięcej szczegółów na temat wykorzystywania API można znaleźć w [[mw:API:Main page|dokumentacji API]]. Przykład: [https://www.mediawiki.org/wiki/API#A_simple_example pobranie zawartości strony głównej]. Wybierz akcję, by zobaczyć więcej przykładów.\n\nZwróć uwagę, że chociaż jest to środowisko testowe, to działania, które można przeprowadzać na tej stronie, mogą zmienić zawartość wiki.",
"apisandbox-submit": "Wykonaj zapytanie",
"apisandbox-reset": "Wyczyść",
"wlheader-enotif": "Wysyłanie powiadomień na adres e‐mail jest włączone.",
"wlheader-showupdated": "'''Wytłuszczone''' zostały strony, które zostały zmodyfikowane od Twojej ostatniej wizyty na nich.",
"wlnote": "Poniżej pokazano {{PLURAL:$1|zmianę wykonaną|<strong>$1</strong> zmiany wykonane|<strong>$1</strong> zmian wykonanych}} w ciągu {{PLURAL:$2|ostatniej godziny|ostatnich <strong>$2</strong> godzin}}, licząc od $4 dnia $3.",
- "wlshowlast": "Pokaż ostatnie $1 godzin, $2 dni",
"watchlist-hide": "Ukryj",
"watchlist-submit": "Pokaż",
"wlshowtime": "Okres do wyświetlenia:",
"sessionfailure": "Wydaje się, że wystąpił błąd z Twoją sesją zalogowania;\nto działanie zostało anulowane, aby uniknąć przechwycenia sesji.\nPrześlij formularz jeszcze raz.",
"changecontentmodel": "Edycja modelu zawartości strony",
"changecontentmodel-legend": "Zmienić model zawartości",
- "changecontentmodel-title-label": "Tytuł strony",
+ "changecontentmodel-title-label": "Tytuł strony:",
"changecontentmodel-current-label": "Obecny model zawartości:",
- "changecontentmodel-model-label": "Nowy model zawartości",
+ "changecontentmodel-model-label": "Nowy model zawartości:",
"changecontentmodel-reason-label": "Powód:",
"changecontentmodel-submit": "Zmień",
"changecontentmodel-success-title": "Model zawartości został zmieniony",
"month": "Do miesiąca (włącznie):",
"year": "Do roku (włącznie):",
"date": "Od daty (i wcześniej):",
- "sp-contributions-newbies": "Pokazuj wyłącznie wkład nowych użytkowników",
- "sp-contributions-newbies-sub": "Dla nowych użytkowników",
- "sp-contributions-newbies-title": "Wkład nowych użytkowników",
"sp-contributions-blocklog": "blokady",
"sp-contributions-suppresslog": "utajniony wkład {{GENDER:$1|użytkownika|użytkowniczki}}",
"sp-contributions-deleted": "usunięty wkład {{GENDER:$1|użytkownika|użytkowniczki}}",
"ipb-disableusertalk": "Edytowanie przez tego użytkownika swojej strony dyskusji",
"ipb-change-block": "Zmień ustawienia blokady",
"ipb-confirm": "Potwierdzam blokadę",
- "ipb-sitewide": "Całkowita",
- "ipb-partial": "Częściowa",
+ "ipb-sitewide": "Całkowicie",
+ "ipb-partial": "Częściowo",
"ipb-sitewide-help": "Wszystkie strony na wiki i wszystkie akcje inne edycyjne.",
"ipb-partial-help": "Konkretne strony lub przestrzenie nazw.",
"ipb-pages-label": "Strony",
"newimages-legend": "Filtruj",
"newimages-label": "Nazwa pliku (lub jej fragment):",
"newimages-user": "Adres IP lub nazwa użytkownika",
- "newimages-newbies": "Pokaż wyłącznie wkład nowych użytkowników",
"newimages-showbots": "Pokazuj pliki przesłane przez boty",
"newimages-hidepatrolled": "Ukryj sprawdzone pliki",
"newimages-mediatype": "Rodzaj plików:",
"img-lang-default": "(język domyślny)",
"img-lang-info": "Wyświetl tę ilustrację w $1. $2",
"img-lang-go": "Dalej",
- "ascending_abbrev": "rosn.",
- "descending_abbrev": "mal.",
"table_pager_next": "Następna strona",
"table_pager_prev": "Poprzednia strona",
"table_pager_first": "Pierwsza strona",
"apihelp": "Agiut ëd l'API",
"apihelp-no-such-module": "Ël mòdol «$1» as treuva nen.",
"apisandbox": "Spassi dle preuve API",
- "apisandbox-api-disabled": "API a l'é disabilità ansima a 's sit.",
"apisandbox-intro": "Ch'a deuvra sta pàgina për sperimenté ël '''servissi an sl'aragnà MediaWiki API'''.\nCh'a fasa riferiment a [https://www.mediawiki.org/wiki/API:Main_page la documentassion ëd l'API] për d'àutri detaj an sl'utilisassion ëd l'API. Për esempi: [https://www.mediawiki.org/wiki/API#A_simple_example oten-e ël contnù ëd na pàgina d'Intrada]. Ch'a selession-a n'assion për vëdde d'àutri esempi.",
"apisandbox-submit": "Fé l'arcesta",
"apisandbox-reset": "Scancela",
"wlheader-enotif": "La notìfica për pòsta eletrònica a l'é abilità.",
"wlheader-showupdated": "Le pàgine che a son ëstàite modificà da quand che a l'é passaje ansima l'ùltima vira a resto marcà an '''grassèt'''",
"wlnote": "Ambelessì sota a-i {{PLURAL:$1|é l'ùltima modìfica|son j'ùltime <strong>$1</strong> modìfiche}} ant {{PLURAL:$2|l'ùltima ora|j'ùltime <strong>$2</strong> ore}}, a parte da $3, $4.",
- "wlshowlast": "Smon-e j'ùltime $1 ore $2 di",
"watchlist-options": "Opsion ëd la lista dla ròba ch'as ten sot-euj",
"watching": "Sot-euj...",
"unwatching": "Ën gavand da lòn ch'as ten sot-euj...",
"uctop": "corenta",
"month": "Mèis:",
"year": "Ann:",
- "sp-contributions-newbies": "Smon-e mach ël travaj dij cont neuv",
- "sp-contributions-newbies-sub": "Për j'utent neuv",
- "sp-contributions-newbies-title": "Contribussion ëd j'utent për ij neuv cont",
"sp-contributions-blocklog": "argistr dij blocagi",
"sp-contributions-suppresslog": "contribussion eliminà",
"sp-contributions-deleted": "Modìfiche d'utent scancelà",
"img-lang-default": "(lenga predefinìa)",
"img-lang-info": "Rende costa plancia an $1. $2",
"img-lang-go": "Andé",
- "ascending_abbrev": "a chërse",
- "descending_abbrev": "a calé",
"table_pager_next": "Pàgina anans",
"table_pager_prev": "Pàgina andré",
"table_pager_first": "Prima pàgina",
"wlheader-enotif": "ای-میل نوٹیفیکیشن قابل",
"wlheader-showupdated": " صفے جیہڑے بدلے کۓ تھواڈے آخری وار آن مکرون اونان نوں موٹا کرکے دسیا گیا اے۔",
"wlnote": "تھلے {{PLURAL:$1|آخری تبدیلی|آخری تبدیلیاں '''1$''' }} آخر تے {{PLURAL:$2|کینٹہ|'''2$''' کینٹے}} 3$، 4$.",
- "wlshowlast": "آخری $1 گھنٹے $2 دن وکھاؤ",
"watchlist-options": "نظر تھلے رکھن دیاں راہواں",
"watching": "اکھ تھلے۔۔۔۔",
"unwatching": "اولے",
"uctop": "اتے",
"month": "مہینے توں (تے پہلاں):",
"year": "سال توں (تے پہلاں):",
- "sp-contributions-newbies": "صرف نویں ورتن والیاں دے کم وکھاؤ",
- "sp-contributions-newbies-sub": "نویاں کھاتےآں واسطے",
- "sp-contributions-newbies-title": "نویں کھاتے وچ ورتن والے دے کم",
"sp-contributions-blocklog": "لاگ روکو",
"sp-contributions-deleted": "ورتن والے دے کم مٹادتے گۓ۔",
"sp-contributions-uploads": "چڑھائیاں فائلاں",
"imgmultipagenext": "اگلا صفحہ →",
"imgmultigo": "جاؤ!",
"imgmultigoto": "$1 تے جاؤ",
- "ascending_abbrev": "اے ایس سی",
- "descending_abbrev": "ڈی ایایس سی",
"table_pager_next": "اگلا صفہ",
"table_pager_prev": "پچھلا صفہ",
"table_pager_first": "پہلا صفہ",
"unwatch": "Τέλεμαν τ' ωριαγματί",
"unwatchthispage": "Τέλεμαν ωριαγματί",
"watchlist-details": "{{PLURAL:$1|$1 σελίδα|$1 σελίδας}} ωριάσκουνταν, θέγα τα σελίδας καλατσεματί.",
- "wlshowlast": "Φανέρωμαν τ' υστερναίων $1 ωρίων $2 ημερίων",
"watchlist-options": "Επιλογάς ωριαγματί",
"watching": "Ωριάζω...",
"unwatching": "'κ ωριάζω...",
"uctop": "υστερνά",
"month": "Ασόν μήναν (και πριχού):",
"year": "Ασή χρονίαν (και πριχού):",
- "sp-contributions-newbies": "Τέρεμαν γραψιματίων τη καινούρεων λογαρίων μαναχόν",
- "sp-contributions-newbies-sub": "Για τα καινούρεα τοι λογαρίας",
"sp-contributions-blocklog": "Αρχείον ασπαλιγματίων",
"sp-contributions-logs": "αρχεία",
"sp-contributions-talk": "καλάτσεμαν",
"imgmultipagenext": "επόμενον σελίδα →",
"imgmultigo": "Δέβα!",
"imgmultigoto": "Δέβα σην σελίδαν $1",
- "ascending_abbrev": "ανεβ",
- "descending_abbrev": "κατεβ",
"table_pager_next": "Επόμενον σελίδα",
"table_pager_prev": "Πρωτεζνόν σελίδα",
"table_pager_first": "Πρώτον σελίδα",
"wlheader-enotif": "E-mail pawakīsenei ast enklaūtan.",
"wlheader-showupdated": "Pastāi '''pastarīntan''' pāusai, kawīdai bēi kitawīdintan ezze Twajjai panzdauman tenēisan kāimalukisnan..",
"wlnote": "Zemmais pawaidinnā di {{PLURAL:$1|panzdauman kitawīdinsnan|panzdaumans '''$1''' kitawīdinsnans}} en {{PLURAL:$2|panzdauman stundin|'''$2''' panzdaumans stundins}}.",
- "wlshowlast": "Waidinnais panzdaumans $1 stūndins, $2 dēinans ()",
"watchlist-options": "Nadirītan listis mazīngiskwas",
"watching": "As nadirēi...",
"unwatching": "As wanginna nadirītwei...",
"uctop": "panzdauma kitawīdinsna",
"month": "Pirzdau mīnsin (be ānkstais):",
"year": "Pirzdau mettan (be ānkstais):",
- "sp-contributions-newbies": "Waidinnais tēr endījan stēisan nāunan tērpautajan",
- "sp-contributions-newbies-sub": "Per nāunans tērpautajans",
- "sp-contributions-newbies-title": "Nāunan tērpautajan endīja",
"sp-contributions-blocklog": "blōkisnas registerin",
"sp-contributions-deleted": "aupausintā tērpautajas ēndija",
"sp-contributions-logs": "registerei",
"imgmultipagenext": "ripīntin pāusan →",
"imgmultigo": "Ēis!",
"imgmultigoto": "Ēis en pāusan $1",
- "ascending_abbrev": "ūnzai ēntei",
- "descending_abbrev": "zemmai ēntei",
"table_pager_next": "Ripīntin pāusan",
"table_pager_prev": "Ānkstaisin pāusan",
"table_pager_first": "Pirman pāusan",
"wlheader-enotif": "برېښليک خبرونه چارنه شوې.",
"wlheader-showupdated": "هغه مخونه چې ستاسې د کتلو نه وروسته بدلون موندلی په '''روڼ''' ليک په نښه شوي.",
"wlnote": "دلته لاندې {{PLURAL:$1|وروستی بدلون دی|وروستي '''$1''' بدلونونه دي}} چې په {{PLURAL:$2|تېر ساعت|تېرو '''$2''' ساعتونو}} کې تر $3 نېټې او $4 بجو پېښ شوي.",
- "wlshowlast": "وروستي $1 ساعتونه $2 ورځې ښکاره کول",
"watchlist-hide": "پټول",
"watchlist-submit": "ښکاره کول",
"wlshowtime": "وروستی ښکاره کول:",
"uctop": "اوسنی",
"month": "له مياشتې د (او پخواني):",
"year": "له کال د (او پخواني):",
- "sp-contributions-newbies": "د نوو گڼونونو ونډې ښکاره کول",
- "sp-contributions-newbies-sub": "د نوو گڼونونو لپاره",
- "sp-contributions-newbies-title": "د نويو گڼونونو لپاره د کارن ونډې",
"sp-contributions-blocklog": "د بنديز يادښت",
"sp-contributions-deleted": "د ړنگ شوي {{GENDER:$1|کارن}} ونډې",
"sp-contributions-uploads": "پورته کېدنې",
"imgmultigoto": "د $1 مخ ته ورځه",
"img-lang-default": "(تلواليزه ژبه)",
"img-lang-go": "ورځه",
- "ascending_abbrev": "ختند",
- "descending_abbrev": "مخښکته",
"table_pager_next": "بل مخ",
"table_pager_prev": "تېر مخ",
"table_pager_first": "لومړی مخ",
"nocreate-loggedin": "Você não possui permissão para criar novas páginas.",
"sectioneditnotsupported-title": "Edição por seções não suportada",
"sectioneditnotsupported-text": "Edição por seções não suportada nesta página.",
+ "modeleditnotsupported-title": "Edição não suportada",
+ "modeleditnotsupported-text": "A edição não é suportada para o modelo de conteúdo $1.",
"permissionserrors": "Erro de permissão",
"permissionserrorstext": "Você não possui permissão de fazer isso, {{PLURAL:$1|pelo seguinte motivo|pelos seguintes motivos}}:",
"permissionserrorstext-withaction": "Você não possui permissão para $2, {{PLURAL:$1|pelo seguinte motivo|pelos motivos a seguir}}:",
"content-model-json": "JSON",
"content-json-empty-object": "Objeto vazio",
"content-json-empty-array": "Array vazia",
+ "unsupported-content-model": "<strong>Aviso:</strong> O modelo de conteúdo $1 não é suportado nessa wiki.",
+ "unsupported-content-diff": "Diffs não são suportados para o modelo de conteúdo $1.",
+ "unsupported-content-diff2": "Diferenças entre os modelos de conteúdo $1 e $2 não são suportadas nessa wiki.",
"deprecated-self-close-category": "Páginas com etiquetas HTML de autofechamento não válidas",
"deprecated-self-close-category-desc": "A página contém tags HTML auto-fechadas inválidas, como <code><b/></code> ou <code><span/></code>. O comportamento destas mudará em breve para coincidam com as especificações do HTML5, pelo que seu uso no wikitext está obsoleto.",
"duplicate-args-warning": "<strong> Aviso: </strong> [[:$1]] está chamando [[:$2]] com mais de um valor para o parâmetro \"$3\". Será utilizado apenas o último valor fornecido.",
"apihelp-no-such-module": "Modulo \"$1\" não foram achados.",
"apisandbox": "Caixa de areia da API",
"apisandbox-jsonly": "JavaScript é necessário para usar o sandbox API.",
- "apisandbox-api-disabled": "A API está desabilitada neste site.",
"apisandbox-intro": "Use esta página para fazer experiências com a <strong>API operacional do MediaWiki</strong>.\nConsulte a [[mw:API:Main page|documentação da API]] para informações sobre o seu uso. Exemplo: [https://www.mediawiki.org/wiki/API#A_simple_example obter o conteúdo da Página Principal]. Selecione uma operação para ver mais exemplos.\n\nNote que, embora esta seja uma área de testes, as operações que executar nesta página podem modificar a wiki.",
"apisandbox-submit": "Fazer requisição",
"apisandbox-reset": "Limpar",
"wlheader-enotif": "A notificação por email encontra-se ativada.",
"wlheader-showupdated": "As páginas modificadas desde a sua última visita são mostradas em <strong>negrito</strong>.",
"wlnote": "A seguir {{PLURAL:$1|está a última alteração ocorrida|estão as últimas <strong>$1</strong> alterações ocorridas}} {{PLURAL:$2|na última hora|nas últimas <strong>$2</strong> horas}} até $3, $4.",
- "wlshowlast": "Ver últimas $1 horas $2 dias",
"watchlist-hide": "Ocultar",
"watchlist-submit": "Exibir",
"wlshowtime": "Período de tempo a mostrar:",
"sessionfailure": "Parece haver um problema com sua sessão de login;\nEsta ação foi cancelada como uma precaução contra o seqüestro de sessão.\nPor favor, reenvie o formulário.",
"changecontentmodel": "Alterar o modelo de conteúdo de uma página",
"changecontentmodel-legend": "Alterar o modelo de conteúdo",
- "changecontentmodel-title-label": "Título da página",
+ "changecontentmodel-title-label": "Título da página:",
"changecontentmodel-current-label": "Modelo de conteúdo atual:",
- "changecontentmodel-model-label": "Modelo de conteúdo novo",
+ "changecontentmodel-model-label": "Modelo de conteúdo novo:",
"changecontentmodel-reason-label": "Motivo:",
"changecontentmodel-submit": "Mudar",
"changecontentmodel-success-title": "O modelo de conteúdo foi alterado",
"month": "Mês (inclusive anteriores):",
"year": "Ano (inclusive anteriores):",
"date": "A partir da data (e anterior):",
- "sp-contributions-newbies": "Mostrar apenas as contribuições das novas contas",
- "sp-contributions-newbies-sub": "Para contas novas",
- "sp-contributions-newbies-title": "Contribuições de contas novas",
"sp-contributions-blocklog": "registro de bloqueios",
"sp-contributions-suppresslog": "contribuições suprimidas {{GENDER:$1|do usuário|da usuária}}",
"sp-contributions-deleted": "{{GENDER:$1|contribuições}} eliminadas",
"newimages-legend": "Filtrar",
"newimages-label": "Nome de arquivo (ou parte dele):",
"newimages-user": "Endereço IP ou nome do usuário:",
- "newimages-newbies": "Mostrar apenas as contribuições das novas contas",
"newimages-showbots": "Mostrar uploads realizados por robôs",
"newimages-hidepatrolled": "Ocultar os carregamentos patrulhados.",
"newimages-mediatype": "Tipo de mídia:",
"img-lang-default": "(Idioma padrão)",
"img-lang-info": "Renderizar essa imagem em $1. $2",
"img-lang-go": "Ir",
- "ascending_abbrev": "asc",
- "descending_abbrev": "desc",
"table_pager_next": "Próxima página",
"table_pager_prev": "Página anterior",
"table_pager_first": "Primeira página",
"apihelp-no-such-module": "Módulo \"$1\" não encontrado.",
"apisandbox": "Testes da API",
"apisandbox-jsonly": "Para usar a área de testes da API é necessário o JavaScript.",
- "apisandbox-api-disabled": "A API está desativada neste sítio.",
"apisandbox-intro": "Use esta página para fazer experiências com a <strong>API operacional do MediaWiki</strong>.\nConsulte a [[mw:API:Main page|documentação da API]] para informações sobre o seu uso. Exemplo: [https://www.mediawiki.org/wiki/API#A_simple_example obter o conteúdo da Página Principal]. Selecione uma operação para ver mais exemplos.\n\nNote que, embora esta seja uma área de testes, as operações que executar nesta página podem modificar a wiki.",
"apisandbox-submit": "Fazer o pedido",
"apisandbox-reset": "Limpar",
"wlheader-enotif": "A notificação por correio eletrónico está ativa.",
"wlheader-showupdated": "As páginas modificadas desde a última vez que as visitou aparecem destacadas a <strong>negrito</strong>.",
"wlnote": "A seguir {{PLURAL:$1|está a última alteração ocorrida|estão as últimas <strong>$1</strong> alterações ocorridas}} {{PLURAL:$2|na última hora|nas últimas <strong>$2</strong> horas}} até $3, $4.",
- "wlshowlast": "Ver últimas $1 horas $2 dias",
"watchlist-hide": "Ocultar",
"watchlist-submit": "Mostrar",
"wlshowtime": "Período de tempo a mostrar:",
"month": "Até o mês:",
"year": "Até o ano:",
"date": "Na data (e anteriores):",
- "sp-contributions-newbies": "Mostrar só as contribuições de contas recentes",
- "sp-contributions-newbies-sub": "Para contas novas",
- "sp-contributions-newbies-title": "Contribuições de contas novas",
"sp-contributions-blocklog": "registo de bloqueios",
"sp-contributions-suppresslog": "contribuições suprimidas {{GENDER:$1|do utilizador|da utilizadora}}",
"sp-contributions-deleted": "{{GENDER:$1|contribuições}} eliminadas",
"newimages-legend": "Filtrar",
"newimages-label": "Nome de ficheiro (ou parte dele):",
"newimages-user": "Endereço IP ou nome do utilizador",
- "newimages-newbies": "Mostrar só as contribuições de contas recentes",
"newimages-showbots": "Mostrar carregamentos feitos por robôs",
"newimages-hidepatrolled": "Ocultar carregamentos patrulhados",
"newimages-mediatype": "Tipo de multimédia:",
"img-lang-default": "(língua padrão)",
"img-lang-info": "Compor esta imagem em $1. $2",
"img-lang-go": "Compor",
- "ascending_abbrev": "asc",
- "descending_abbrev": "desc",
"table_pager_next": "Página seguinte",
"table_pager_prev": "Página anterior",
"table_pager_first": "Primeira página",
"versionrequired": "This message is not used in the MediaWiki core, but was introduced with the reason that it could be useful for extensions.\n\nParameters:\n* $1 - MediaWiki version number\nSee also:\n* {{msg-mw|Versionrequiredtext}}",
"versionrequiredtext": "This message is not used in the MediaWiki core, but was introduced with the reason that it could be useful for extensions.\n\nParameters:\n* $1 - MediaWiki version number\nSee also:\n* {{msg-mw|Versionrequired}}",
"ok": "{{Identical|OK}}",
- "pagetitle": "{{Optional}}\n{{doc-important|You most probably do not need to translate this message.}}\nDo '''not''' replace SITENAME with a translation of Wikipedia or some encyclopedic additions. The message has to be neutral for all projects.\n\nParameters:\n* $1 - page title or any one of the following messages:\n** {{msg-mw|Contributions-title}}\n** {{msg-mw|Searchresults-title}}\n** {{msg-mw|Sp-contributions-newbies-title}}",
+ "pagetitle": "{{Optional}}\n{{doc-important|You most probably do not need to translate this message.}}\nDo '''not''' replace SITENAME with a translation of Wikipedia or some encyclopedic additions. The message has to be neutral for all projects.\n\nParameters:\n* $1 - page title or any one of the following messages:\n** {{msg-mw|Contributions-title}}\n** {{msg-mw|Searchresults-title}}",
"pagetitle-view-mainpage": "{{optional}}",
"backlinksubtitle": "{{optional}}\nAppears in subtitle. Parameters:\n* $1 - a link to the page (HTML)",
"retrievedfrom": "Message which appears in the source of every page, but it is hidden. It is shown when printing.\n\nParameters:\n* $1 - a link back to the current page: {{FULLURL:{{FULLPAGENAME}}}}",
"nocreate-loggedin": "Used as error message.\n\nSee also:\n* {{msg-mw|Nocreatetext}}",
"sectioneditnotsupported-title": "Page title of special page, which presumably appears when someone tries to edit a section, and section editing is disabled. Explanation of section editing on [[meta:Help:Section_editing#Section_editing|meta]].",
"sectioneditnotsupported-text": "I think this is the text of an error message, which presumably appears when someone tries to edit a section, and section editing is disabled. Explanation of section editing on [[meta:Help:Section_editing#Section_editing|meta]].",
+ "modeleditnotsupported-title": "Page title used on the edit page when editing is not supported for the page's content model.",
+ "modeleditnotsupported-text": "Error message show on the edit page when editing is not supported for the page's content model..\n\nParameters:\n* $1 - the name of the content model.",
"permissionserrors": "Used as title of error message.\n\nSee also:\n* {{msg-mw|loginreqtitle}}\n{{Identical|Permission error}}",
"permissionserrorstext": "This message is \"without action\" version of {{msg-mw|Permissionserrorstext-withaction}}.\n\nParameters:\n* $1 - the number of reasons that were found why ''the action'' cannot be performed",
"permissionserrorstext-withaction": "This message is \"with action\" version of {{msg-mw|Permissionserrorstext}}.\n\nParameters:\n* $1 - the number of reasons that were found why the action cannot be performed\n* $2 - one of the action-* messages (for example {{msg-mw|action-edit}}) or other such messages tagged with {{tl|doc-action}} in their documentation\n\nPlease report at [[Support]] if you are unable to properly translate this message. Also see [[phab:T16246]] (now closed) for background.",
"content-model-json": "{{optional}}\nName for the JSON content model, used when decribing what type of content a page contains.\n\nThis message is substituted in:\n*{{msg-mw|Bad-target-model}}\n*{{msg-mw|Content-not-allowed-here}}\n{{identical|JSON}}",
"content-json-empty-object": "Used to represent an object with no properties on a JSON content model page.",
"content-json-empty-array": "Used to represent an array with no values on a JSON content model page.",
+ "unsupported-content-model": "Warning shown when trying to display content with an unknown model.\n\nParameters:\n* $1 - the technical name of the content model.",
+ "unsupported-content-diff": "Warning shown when trying to display a diff between content with a model that does not support diffing (perhaps because it's an unknown model).\n\nParameters:\n* $1 - the technical name of the model of the content",
+ "unsupported-content-diff2": "Warning shown when trying to display a diff between content that uses models that do not support diffing with each other.\n\nParameters:\n* $1 - the technical name of the model of the old content\n* $2 - the technical name of the model of the new content.",
"deprecated-self-close-category": "This message is used as a category name for a [[mw:Special:MyLanguage/Help:Tracking categories|tracking category]] where pages are placed automatically if they contain invalid self-closed HTML tags, such as <code><b/></code> or <code><span/></code>. The behavior of these will change soon to be consistent with the HTML5 specification, so their use in wikitext is deprecated.",
"deprecated-self-close-category-desc": "Invalid self-closed HTML tag category description. Shown on [[Special:TrackingCategories]].\n\nSee also:\n* {{msg-mw|deprecated-self-close-category}}",
"duplicate-args-warning": "If a page calls a template and specifies the same argument more than once, such as <code><nowiki>{{foo|bar=1|bar=2}}</nowiki></code> or <code><nowiki>{{foo|bar|1=baz}}</nowiki></code>, this warning is displayed when previewing.\n\nParameters:\n* $1 - The calling page\n* $2 - The called template\n* $3 - The name of the duplicated argument",
"backend-fail-contenttype": "Used as fatal error message. Parameters:\n* $1 - a storage (file) path\n{{Related|Backend-fail}}",
"backend-fail-batchsize": "Error message when the limit of operations to be done at once in the file backend was reached.\nParameters:\n* $1 - the number of operations attempted at once in this case\n* $2 - the maximum number of operations that can be attempted at once\nBoth parameters are PLURAL supported\n\nA \"[[:wikipedia:Front and back ends|backend]]\" is a system or component that ordinary users don't interact with directly and don't need to know about, and that is responsible for a distinct task or service - for example, a storage back-end is a generic system for storing data which other applications can use. Possible alternatives for back-end are \"system\" or \"service\", or (depending on context and language) even leave it untranslated.\n{{Related|Backend-fail}}",
"backend-fail-usable": "Parameters:\n* $1 - the file name, including the path, formatted for the storage backend used\n{{Related|Backend-fail}}",
+ "backend-fail-stat": "Parameters:\n* $1 - the file name, including the path, formatted for the storage backend used\n{{Related|Backend-fail}}",
+ "backend-fail-hash": "Parameters:\n* $1 - the file name, including the path, formatted for the storage backend used\n{{Related|Backend-fail}}",
"filejournal-fail-dbconnect": "Parameters:\n* $1 is the name of the \"[[:wikipedia:Front and back ends|backend]]\" that the file journal logs changes for.",
"filejournal-fail-dbquery": "Parameters:\n* $1 is the name of the \"[[:wikipedia:Front and back ends|backend]]\" that the file journal logs changes for.",
"lockmanager-notlocked": "Parameters:\n* $1 is a resource path (e.g. \"mwstore://media-public/a/ab/file.jpg\").",
"apisandbox": "{{doc-special|ApiSandbox}}",
"apisandbox-summary": "{{ignored}}\n{{doc-specialpagesummary|ApiSandbox}}",
"apisandbox-jsonly": "Displayed as an error message if the browser does not have JavaScript enabled.",
- "apisandbox-api-disabled": "Displayed as an error message if the API is disabled on this site.",
"apisandbox-intro": "Displayed (from JavaScript) as a header on [[Special:ApiSandbox]].",
"apisandbox-submit": "JavaScript button label for submitting the request.",
"apisandbox-reset": "JavaScript button label for clearing the form.\n{{Identical|Clear}}",
"wlheader-enotif": "Message at the top of [[Special:Watchlist]], after {{msg-mw|watchlist-details}}. Has to be a full sentence.\n\nSee also:\n* {{msg-mw|Watchlist-options|fieldset}}\n* {{msg-mw|enotif reset|Submit button text}}",
"wlheader-showupdated": "Message at the top of [[Special:Watchlist]], after {{msg-mw|watchlist-details}}. Has to be a full sentence.",
"wlnote": "Used on [[Special:Watchlist]] when a maximum number of hours or days is specified.\n\nParameters:\n* $1 - the number of changes shown\n* $2 - the number of hours for which the changes are shown\n* $3 - a date alone\n* $4 - a time alone",
- "wlshowlast": "Appears on [[Special:Watchlist]]. Parameters:\n* $1 - a choice of different numbers of hours (\"1 | 2 | 6 | 12\")\n* $2 - a choice of different numbers of days (\"1 | 3 | 7\" and the maximum number of days available)\nClicking on your choice changes the list of changes you see (without changing the default in my preferences).",
"watchlist-hide": "Appears on [[Special:Watchlist]]. It is the first word on a new line with checkboxes to hide/unhide options\n{{Identical|Hide}}",
"watchlist-submit": "Label on the submit button in [[Special:Watchlist]]\n{{Identical|Show}}",
"wlshowtime": "Appears on [[Special:Watchlist]]. Label of a drop-down list used to specify the period of time to display in the watchlist. This period can be {{msg-mw|days}} or {{msg-mw|hours}}.",
"month": "Used in [[Special:Contributions]] and history pages ([{{fullurl:Sandbox|action=history}} example]), as label for a dropdown box to select a specific month to view the edits made in that month, and the earlier months. See also {{msg-mw|year}}.",
"year": "Used in [[Special:Contributions]] and history pages ([{{fullurl:Sandbox|action=history}} example]), as label for an input box to select a specific year to view the edits made in that year, and the earlier years.\n\nSee also:\n* {{msg-mw|month}}",
"date": "Used in [[Special:Contributions]] and history pages ([{{fullurl:Sandbox|action=history}} example]), as label for an input box to select a specific date to view the edits made on that date, and earlier.",
- "sp-contributions-newbies": "Text of radio button on special page [[Special:Contributions]].",
- "sp-contributions-newbies-sub": "Note at the top of the page of results for a search on [[Special:Contributions]] where 'Show contributions for new accounts only' has been selected.",
- "sp-contributions-newbies-title": "The page title in your browser bar, but not the page title.\n\nSee also:\n* {{msg-mw|Sp-contributions-newbies-sub}}",
"sp-contributions-blocklog": "Used as a display name for a link to the block log on for example [[Special:Contributions/Mediawiki default]]\n\nUsed as link title in [[Special:Contributions]] and in [[Special:DeletedContributions]].\n\nSee also:\n* {{msg-mw|Sp-contributions-talk}}\n* {{msg-mw|Change-blocklink}}\n* {{msg-mw|Unblocklink}}\n* {{msg-mw|Blocklink}}\n* {{msg-mw|Sp-contributions-uploads}}\n* {{msg-mw|Sp-contributions-logs}}\n* {{msg-mw|Sp-contributions-deleted}}\n* {{msg-mw|Sp-contributions-userrights}}\n{{Identical|Block log}}",
"sp-contributions-suppresslog": "Used as a display name for a link to log entries of suppressed edits made by that user.\n\nUsed as link title in [[Special:Contributions]] and in [[Special:DeletedContributions]]. Parameters:\n* $1 is a plain text username used for GENDER.\nSee also {{msg-mw|sp-contributions-deleted}}, {{msg-mw|sp-deletedcontributions-contribs}}, {{msg-mw|contributions}}, {{msg-mw|deletedcontributions-title}}.",
"sp-contributions-deleted": "This is a link anchor used in [[Special:Contributions]]/''name'', when user viewing the page has the right to delete pages, or to restore deleted pages.\n\nUsed as link title in [[Special:Contributions]]. Parameters:\n* $1 is a plain text username used for GENDER.\nSee also:\n* {{msg-mw|Sp-contributions-talk}}\n* {{msg-mw|Change-blocklink}}\n* {{msg-mw|Unblocklink}}\n* {{msg-mw|Blocklink}}\n* {{msg-mw|Sp-contributions-blocklog}}\n* {{msg-mw|Sp-contributions-uploads}}\n* {{msg-mw|Sp-contributions-logs}}\n* {{msg-mw|Sp-contributions-userrights}}",
"sp-contributions-footer": "{{ignored}}This is the footer for users that are not anonymous or newbie on [[Special:Contributions]].",
"sp-contributions-footer-anon": "{{ignored}}This is the footer for anonymous users on [[Special:Contributions]].",
"sp-contributions-footer-anon-range": "{{ignored}}This is the footer for IP ranges on [[Special:Contributions]].",
- "sp-contributions-footer-newbies": "{{ignored}}This is the footer for newbie users on [[Special:Contributions]].",
"sp-contributions-outofrange": "Message shown when a user tries to view contributions of an IP range that's too large. $1 is the numerical limit imposed on the CIDR range.",
"whatlinkshere": "The text of the link in the toolbox (on the left, below the search menu) going to [[Special:WhatLinksHere]].\n\nSee also:\n* {{msg-mw|Whatlinkshere}}\n* {{msg-mw|Accesskey-t-whatlinkshere}}\n* {{msg-mw|Tooltip-t-whatlinkshere}}",
"whatlinkshere-title": "Title of the special page [[Special:WhatLinksHere]]. This page appears when you click on the 'What links here' button in the toolbox. $1 is the name of the page concerned.",
"newimages-legend": "Caption of the fieldset for the filter on [[Special:NewImages]]\n\n{{Identical|Filter}}",
"newimages-label": "Caption of the filter editbox on [[Special:NewImages]]",
"newimages-user": "Caption of the username/IP address editbox on [[Special:NewImages]]",
- "newimages-newbies": "Used as label for a checkbox. When checked, [[Special:NewImages]] will only display uploads by new users.",
"newimages-showbots": "Used as label for a checkbox. When checked, [[Special:NewImages]] will also display uploads by users in the bots group.",
"newimages-hidepatrolled": "Used as label for a checkbox. When checked, [[Special:NewImages]] will not display patrolled uploads.\n\nCf. {{msg-mw|tog-hidepatrolled}} and {{msg-mw|apihelp-feedrecentchanges-param-hidepatrolled}}.",
"newimages-mediatype": "Used as label for a multiselect where users can select the media types to display.",
"img-lang-default": "An option in the drop down of a translatable file. For example see [[:File:Gerrit patchset 25838 test.svg]].\n\nUsed when it cannot be determined what the default fallback language is.\n\nHowever it should be noted that most of the time, the content displayed for this option would be in English.\n{{Identical|Default language}}",
"img-lang-info": "Label for drop down box. Appears underneath the image on the image description page. See [[:File:Gerrit patchset 25838 test.svg]] for an example.\n\nParameters:\n* $1 - a drop down box with language options, uses the following messages:\n** {{msg-mw|Img-lang-default}}\n** {{msg-mw|Img-lang-opt}}. e.g. \"English (en)\", \"日本語 (ja)\"\n* $2 - a submit button, which uses the text from {{msg-mw|Img-lang-go}}",
"img-lang-go": "Go button for the language select for translatable files. See [[:File:Gerrit patchset 25838 test.svg]] for an example.\n\nSee also:\n* {{msg-mw|img-lang-info}}\n{{Identical|Go}}",
- "ascending_abbrev": "Abbreviation of ascending order.\nSee also:\n* {{msg-mw|Ascending abbrev}}\n* {{msg-mw|Descending abbrev}}",
- "descending_abbrev": "Abbreviation of descending order.\nSee also:\n* {{msg-mw|Ascending abbrev}}\n* {{msg-mw|Descending abbrev}}",
"table_pager_next": "Used as image button text of pager. See [[Support|example]] (the bottom of the page).\n{{Identical|Next page}}",
"table_pager_prev": "Used as image button text of pager. See [[Support|example]] (the bottom of the page).\n{{Identical|Previous page}}",
"table_pager_first": "Used as image button text of pager. See [[Support|example]] (the bottom of the page).\n{{Identical|First page}}",
"wlheader-enotif": "E-chaskimanta musyachinaman arí nisqañam.",
"wlheader-showupdated": "Qayna watukamusqaykimantapacha hukchasqa p'anqakunataqa '''yanasapa''' nisqapim rikunki.",
"wlnote": "Kay qatiqpiqa {{PLURAL:$1|qhipaq hukchasqam|'''$1''' qhipaq hukchasqakunam}} qhipaq {{PLURAL:$2|urapim|'''$2''' urakunapim}}, musuqchasqa $3, $4.",
- "wlshowlast": "$1 ura, $2 p'unchaw -mantapacha hukchasqakunata rikuchiy",
"watchlist-hide": "Pakay",
"watchlist-options": "Watiqana sutisuyupaq allinkachinakuna",
"watching": "Watiqasqakunaman yapaspa...",
"uctop": "qhipaq hukchasqa",
"month": "Kay killamanta (ñawpaqmantapas):",
"year": "Kay watamanta (ñawpaqmantapas):",
- "sp-contributions-newbies": "Musuq ruraqkunallap llamk'apusqankunata rikuchiy",
- "sp-contributions-newbies-sub": "Musuqkunapaq",
- "sp-contributions-newbies-title": "Musuq ruraqkunap llamk'apusqankuna",
"sp-contributions-blocklog": "Hark'ay hallch'asqakuna",
"sp-contributions-suppresslog": "uraychasqa ruraqpa hukchasqankuna",
"sp-contributions-deleted": "qullusqa ruraqpa hukchasqankuna",
"img-lang-default": "(kikinmanta rimay)",
"img-lang-info": "Rikchata kaypi rindirisay: $1. $2",
"img-lang-go": "Riy",
- "ascending_abbrev": "wich",
- "descending_abbrev": "uray",
"table_pager_next": "Qatiq p'anqa",
"table_pager_prev": "Ñawpaq p'anqa",
"table_pager_first": "Ñawpaq ñiqin p'anqa",
"watchthispage": "Kay pankata rikukuna",
"unwatch": "Ñamana rikuna",
"watchlist-details": "{{PLURAL:$1|$1 pankata|$1 pankakunata}} rikukunki (rimanakuy pankakunata mana yupakpika).",
- "wlshowlast": "$1 pachapi, $2 punchapi rurashka mushuk killkaykunata rikuna",
"watchlist-options": "rikukushka pankakuna pankapa akllaykuna",
"watching": "Ñami chay pankata rikukukripanki...",
"unwatching": "Ñamana rikukuchishpa...",
"uctop": " kipak killkay",
"month": "Kay killamanta (ñawpakmantapash):",
"year": "Kay watamanta (ñawpakmantapash) :",
- "sp-contributions-newbies": "Mushuk rurakkunapallami killkaykunata rikuchiy",
"sp-contributions-blocklog": "Wichkaykunapa kamu",
"sp-contributions-uploads": "apamuykuna",
"sp-contributions-logs": "kamukuna",
"watchthispage": "Ḥḍa tasna ya",
"unwatch": "Ur ḥṭṭa",
"watchlist-details": "{{PLURAL:$1|$1 n Tasniwin|$1 n Tasniwin}} Twaẓrent bla Tasniwin n usiwl.",
- "wlshowlast": "Sseml-ad $1 tisεεatin $2 ussan inggura",
"watching": "Ḥṭṭigh...",
"unwatching": "Ur ḥṭṭigh...",
"deletepage": "ⴽⴽⵙ ⵜⴰⵙⵏⴰ",
"uctop": "ⵜⴰⵎⵉⵔⴰⵏⵜ",
"month": "Zg wayur (d zik):",
"year": "Zg usggwas (d zik):",
- "sp-contributions-newbies": "Ẓar Tabdart n tiggawin n useqdac a deg umiḍan amaynu waha",
- "sp-contributions-newbies-sub": "i imiḍan imaynuten",
"sp-contributions-blocklog": "sbdd tabdart n talghut",
"sp-contributions-talk": "ⵎⵙⴰⵡⵍ",
"sp-contributions-search": "ⵔⵣⵓ ⵅ ⵜⵓⵎⵓⵜⵉⵏ",
"wlheader-enotif": "Il servetsch d'infurmaziun per e-mail è activà.",
"wlheader-showupdated": "Paginas ch'èn vegnidas modifitgadas suenter che ti has vis els la davosa giada èn mussads '''grass'''",
"wlnote": "Sutvart {{PLURAL:$1|è l'ultima midada|èn las ultimas <strong>$1</strong> midadas}} entaifer {{PLURAL:$2|l'ultima ura|las ultimas <strong>$2</strong> uras}}. Actualisà ils $3 las $4.",
- "wlshowlast": "Mussar: las ultimas $1 uras, ils ultims $2 dis.",
"watchlist-options": "Opziuns per la glista d'observaziun",
"watching": "observ...",
"unwatching": "observ betg pli...",
"uctop": "actual",
"month": "dal mais (e pli baud):",
"year": "da l'onn (e pli baud):",
- "sp-contributions-newbies": "Be mussar contribuziuns da contos novs",
- "sp-contributions-newbies-sub": "Per novs contos d'utilisader",
- "sp-contributions-newbies-title": "Contribuziuns da novs contos d'utilisader",
"sp-contributions-blocklog": "protocol da bloccadas",
"sp-contributions-deleted": "Contribuziuns da commembers stizzadas",
"sp-contributions-uploads": "datotecas chargiadas si",
"imgmultipagenext": "proxima pagina →",
"imgmultigo": "Dai!",
"imgmultigoto": "Ir a la pagina $1",
- "ascending_abbrev": "asc",
- "descending_abbrev": "desc",
"table_pager_next": "Proxima pagina",
"table_pager_prev": "Ultima pagina",
"table_pager_first": "Emprima pagina",
"apihelp-no-such-module": "Modulul „$1” nu a fost găsit.",
"apisandbox": "Pagina de teste pentru API",
"apisandbox-jsonly": "Este nevoie de JavaScript pentru a folosi pagina de teste pentru API.",
- "apisandbox-api-disabled": "API este dezactivat pe acest site.",
"apisandbox-intro": "Folosiți această pagină pentru a experimenta cu <strong>API-ul MediaWiki</strong>. Citiți [[mw:API:Main page|documentația API-ului]] pentru mai multe detalii de utilizare. Exemplu: [https://www.mediawiki.org/wiki/API#A_simple_example obțineți conținutul paginii principale]. Selectați o acțiune pentru a vedea mai multe exemple.",
"apisandbox-submit": "Efectuați cererea",
"apisandbox-reset": "Curăță",
"wlheader-enotif": "Notificarea prin e-mail este activată.",
"wlheader-showupdated": "Paginile care au fost modificate după ultima dumneavoastră vizită sunt afișate '''îngroșat'''.",
"wlnote": "Mai jos se află {{PLURAL:$1|ultima schimbare|ultimele <strong>$1</strong> schimbări|ultimele <strong>$1</strong> de schimbări}} din {{PLURAL:$2|ultima oră|ultimele <strong>$2</strong> ore|ultimele <strong>$2</strong> de ore}}, așa cum era situația la $3, $4.",
- "wlshowlast": "Arată ultimele $1 ore $2 zile",
"watchlist-hide": "Ascunde",
"watchlist-submit": "Afișează",
"wlshowtime": "Perioada de timp de afișat:",
"month": "Din luna (și dinainte):",
"year": "Din anul (și dinainte):",
"date": "Din data (și dinainte):",
- "sp-contributions-newbies": "Arată doar contribuțiile conturilor noi",
- "sp-contributions-newbies-sub": "Pentru începători",
- "sp-contributions-newbies-title": "Contribuțiile utilizatorului pentru conturile noi",
"sp-contributions-blocklog": "jurnal blocări",
"sp-contributions-suppresslog": "Contribuții suprimate ale {{GENDER:$1|utilizatorului}}",
"sp-contributions-deleted": "contribuțiile șterse ale {{GENDER:$1|utilizatorului}}",
"newimages-legend": "Filtru",
"newimages-label": "Numele fișierului (sau parte din el):",
"newimages-user": "Adresă IP sau nume de utilizator",
- "newimages-newbies": "Arată doar contribuțiile conturilor noi",
"newimages-showbots": "Arată încărcările roboților",
"newimages-hidepatrolled": "Ascunde încărcările patrulate",
"newimages-mediatype": "Tip media:",
"img-lang-default": "(limba implicită)",
"img-lang-info": "Randează această imagine în $1. $2",
"img-lang-go": "Du-te",
- "ascending_abbrev": "cresc",
- "descending_abbrev": "desc",
"table_pager_next": "Pagina următoare",
"table_pager_prev": "Pagina anterioară",
"table_pager_first": "Prima pagină",
"recentchangeslinked-page": "Nome d'a vôsce:",
"recentchangeslinked-to": "Fa vedè le cangiaminde de le pàggene colleghete a 'na certa pàgene",
"recentchanges-page-added-to-category": "[[:$1]] aggiunde a categorije",
+ "recentchanges-page-removed-from-category": "[[:$1]] luate da 'a categorije",
"recentchanges-page-removed-from-category-bundled": "[[:$1]] luate da 'a categorije, [[Special:WhatLinksHere/$1|sta vôsce ste sckaffate jndr'à otre pàggene]]",
"autochange-username": "Cangiamende automateche de MediaUicchi",
"upload": "Careche 'u file",
"apihelp-no-such-module": "Module \"$1\" none acchiate.",
"apisandbox": "Sandbox de l'API",
"apisandbox-jsonly": "'U JavaScript jè richieste pe ausà 'a sandbox API.",
- "apisandbox-api-disabled": "API non g'è abbiletate sus a stu site.",
"apisandbox-intro": "Ause sta pàgene pe sperimendà cu le <strong>API de le web service pe MediaUicchi</strong>.\nFà referimende a [[mw:API:Main page| 'a documendazione de l'API]] pe cchiù dettaglie de l'ause de l'API.\nEsembie: [https://www.mediawiki.org/wiki/API#A_simple_example pigghie 'u condenute d'a Pàgene Prengepàle]. Scacchie 'n'azione pe 'ndrucà otre esembie.\n\nVide ca, pure ca queste jè 'na buatte de sabbie tu puè carrescià le cangiaminde de sta pàgene sus 'a uicchi.",
"apisandbox-submit": "Fà 'na richieste",
"apisandbox-reset": "Pulizze",
"wlheader-enotif": "* Notifiche pe email abbilitate.",
"wlheader-showupdated": "* Le pàggene ca onne state cangiate da l'urtema visite avènene fatte vedè in '''grascette'''",
"wlnote": "Aqquà sotte {{PLURAL:$1|ste l'urteme cangiamende|stonne l'urteme <strong>$1</strong> cangiaminde}} jndr'à {{PLURAL:$2|l'urtema ore|l'urteme <strong>$2</strong> ore}}, jndr'à $3, $4.",
- "wlshowlast": "Vide l'urteme $1 ore $2 sciurne",
"watchlist-hide": "Scunne",
"watchlist-submit": "Fà 'ndrucà",
"wlshowhideminor": "cangiaminde stuèdeche",
"month": "Da 'u mese (e cchiù recende):",
"year": "Da l'anne (e cchiù recende):",
"date": "Da 'a date (e cchiù recende):",
- "sp-contributions-newbies": "Fà vedè sulamende le condrebbute de le utinde nueve",
- "sp-contributions-newbies-sub": "Pe l'utinde nuève",
- "sp-contributions-newbies-title": "Condrebbute de l'utinde pe le cunde utinde nuéve",
"sp-contributions-blocklog": "Archivije de le Bloccaminde",
"sp-contributions-suppresslog": "condrebbute de {{GENDER:$1|l'utende}} scettate",
"sp-contributions-deleted": "condrebbute de {{GENDER:$1|l'utende}} scangellate",
"newimages-legend": "Filtre",
"newimages-label": "Nome d'u fail (o 'nu stuezze de jidde):",
"newimages-user": "Indirizze IP o nome de l'utende",
- "newimages-newbies": "Fà 'ndrucà sulamende le condrebbute de le utinde nuève",
"newimages-showbots": "Fà vedè le scarecaminde da bot",
"newimages-hidepatrolled": "Scunne le carecaminde condrollate",
"newimages-mediatype": "Tipe de media:",
"img-lang-default": "(lènghe de base)",
"img-lang-info": "Renderizze st'immaggine jndr'à $1. $2",
"img-lang-go": "Véje",
- "ascending_abbrev": "asc",
- "descending_abbrev": "desc",
"table_pager_next": "Pàgena successive",
"table_pager_prev": "Pàgena precedende",
"table_pager_first": "Prima pàgene",
"Serhio Magpie",
"ЛингвоЧел",
"OlegVeliky",
- "Saimongoltinio"
+ "Saimongoltinio",
+ "Wikisaurus"
]
},
"tog-underline": "Подчёркивание ссылок:",
"tog-hideminor": "Скрывать малые изменения из списка свежих правок",
"tog-hidepatrolled": "Скрывать патрулированные правки в списке свежих правок",
"tog-newpageshidepatrolled": "Скрывать отпатрулированные страницы в списке новых страниц",
- "tog-hidecategorization": "СкÑ\80Ñ\8bваÑ\82Ñ\8c каÑ\82егоÑ\80изаÑ\86иÑ\8e Ñ\81Ñ\82Ñ\80аниÑ\86",
+ "tog-hidecategorization": "СкÑ\80Ñ\8bваÑ\82Ñ\8c изменение Ñ\81оÑ\81Ñ\82ава оÑ\82Ñ\81леживаемÑ\8bÑ\85 каÑ\82егоÑ\80ий",
"tog-extendwatchlist": "Расширить список наблюдения, включая все изменения, а не только последние",
"tog-usenewrc": "Группировать изменения в свежих правках и списке наблюдения",
"tog-numberheadings": "Автоматически нумеровать заголовки",
"tog-watchlistunwatchlinks": "Добавить прямые маркеры для включения/исключения из списка наблюдения ({{int:Watchlist-unwatch}}/{{int:Watchlist-unwatch-undo}}) для наблюдаемых страниц с изменениями (для переключения функций требуется JavaScript)",
"tog-watchlisthideanons": "Скрывать правки анонимных участников из списка наблюдения",
"tog-watchlisthidepatrolled": "Скрывать отпатрулированные правки из списка наблюдения",
- "tog-watchlisthidecategorization": "СкÑ\80Ñ\8bваÑ\82Ñ\8c каÑ\82егоÑ\80изаÑ\86иÑ\8e Ñ\81Ñ\82Ñ\80аниÑ\86",
+ "tog-watchlisthidecategorization": "СкÑ\80Ñ\8bваÑ\82Ñ\8c изменение Ñ\81оÑ\81Ñ\82ава оÑ\82Ñ\81леживаемÑ\8bÑ\85 каÑ\82егоÑ\80ий",
"tog-ccmeonemails": "Отправлять мне копии писем, которые я посылаю другим участникам",
"tog-diffonly": "Не показывать содержание страницы под сравнением двух версий",
"tog-showhiddencats": "Показывать скрытые категории",
"nocreate-loggedin": "У вас нет разрешения создавать новые страницы.",
"sectioneditnotsupported-title": "Редактирование разделов не поддерживается",
"sectioneditnotsupported-text": "На этой странице не поддерживается редактирование разделов",
+ "modeleditnotsupported-title": "Редактирование не поддерживается",
+ "modeleditnotsupported-text": "Редактирование не поддерживается моделью содержимого $1.",
"permissionserrors": "Ошибка прав доступа",
"permissionserrorstext": "У вас нет прав на выполнение этой операции по {{PLURAL:$1|1=следующей причине|следующим причинам}}:",
"permissionserrorstext-withaction": "У вас нет прав на выполнение действия «$2» по {{PLURAL:$1|1=следующей причине|следующим причинам}}:",
"content-model-json": "JSON",
"content-json-empty-object": "Пустой объект",
"content-json-empty-array": "Пустой массив",
+ "unsupported-content-model": "<strong>Внимание:</strong> Модель содержимого $1 не поддерживается на этой вики.",
+ "unsupported-content-diff": "Изменения (различия) не поддерживаются моделью содержимого $1.",
+ "unsupported-content-diff2": "Изменения (различия) между моделями содержимого $1 и $2 не поддерживаются на этой вики.",
"deprecated-self-close-category": "Страницы, использующие недопустимые самозакрывающиеся HTML-теги",
"deprecated-self-close-category-desc": "Страница содержит недопустимые самозакрывающиеся HTML-теги, такие как <code><b/></code> или <code><span/></code>. В скором времени их действие изменится, чтобы соответствовать спецификации HTML5, так что использование этих устаревших тегов в вики-тексте нежелательно.",
"duplicate-args-warning": "<strong>Внимание:</strong> [[:$1]] вызывает [[:$2]] с более чем одним значением параметра «$3». Будет использовано только последнее указанное значение.",
"apihelp-no-such-module": "Модуль «$1» не найден.",
"apisandbox": "Песочница API",
"apisandbox-jsonly": "Для использования API-песочницы требуется JavaScript.",
- "apisandbox-api-disabled": "API отключён на этом сайте.",
"apisandbox-intro": "Используйте эту страницу для экспериментов с <strong>MediaWiki API</strong>.\nОбратитесь к документации API ([https://ru.wikipedia.org/w/api.php встроенной] или [[mw:API:Main page|внешней]]) для получения дополнительной информации об использовании API. Например, о том, [https://www.mediawiki.org/wiki/API#A_simple_example как получить содержание Заглавной страницы]. Выберите действие, чтобы увидеть другие примеры.\nОбратите внимание, что, хотя это и песочница, действия, выполненные на этой странице, могут внести изменения в вики.",
"apisandbox-submit": "Сделать запрос",
"apisandbox-reset": "Очистить",
"wlheader-enotif": "Уведомления по эл. почте включены.",
"wlheader-showupdated": "Страницы, изменившиеся с вашего последнего их посещения, выделены <strong>полужирным</strong> шрифтом.",
"wlnote": "Ниже {{PLURAL:$1|показано последнее изменение|показаны <strong>$1</strong> последние изменения|показаны <strong>$1</strong> последних изменений}} за {{PLURAL:$2|последний час|последние <strong>$2</strong> часа|последние <strong>$2</strong> часов}}, по состоянию на $3 $4.",
- "wlshowlast": "Показать за последние $1 часов $2 дней",
"watchlist-hide": "Скрыть",
"watchlist-submit": "Показать",
"wlshowtime": "Период времени для отображения:",
"month": "С месяца (и ранее):",
"year": "С года (и ранее):",
"date": "С даты (и ранее):",
- "sp-contributions-newbies": "Показать только вклад, сделанный с новых учётных записей",
- "sp-contributions-newbies-sub": "С новых учётных записей",
- "sp-contributions-newbies-title": "Вклад с недавно созданных учётных записей",
"sp-contributions-blocklog": "блокировки",
"sp-contributions-suppresslog": "удалённый вклад {{GENDER:$1|участника|участницы}}",
"sp-contributions-deleted": "удалённые правки {{GENDER:$1|участника|участницы}}",
"ipb-confirm": "Подтвердить блокировку",
"ipb-sitewide": "Во всём проекте",
"ipb-partial": "Частичная",
- "ipb-sitewide-help": "Каждая страница вики и все другие действия вклада.",
+ "ipb-sitewide-help": "Каждая страница вики и все другие действия.",
"ipb-partial-help": "Конкретные страницы или пространства имён.",
"ipb-pages-label": "Страницы",
"ipb-namespaces-label": "Пространства имён",
"movereason": "Причина:",
"revertmove": "возврат",
"delete_and_move_text": "Страница с именем «[[:$1]]» уже существует. \nХотите удалить её, чтобы сделать возможным переименование?",
- "delete_and_move_confirm": "Ð\94а, Ñ\83далиÑ\82Ñ\8c Ñ\8dÑ\82Ñ\83 Ñ\81Ñ\82Ñ\80аниÑ\86Ñ\83",
+ "delete_and_move_confirm": "Ð\94а, Ñ\83далиÑ\82Ñ\8c Ñ\81Ñ\82Ñ\80аниÑ\86Ñ\83, на коÑ\82оÑ\80Ñ\83Ñ\8e пÑ\80оизводиÑ\82Ñ\81Ñ\8f пеÑ\80еименование",
"delete_and_move_reason": "Удалено для возможности переименования «[[$1]]»",
"selfmove": "Невозможно переименовать страницу: исходное и новое имя страницы совпадают.",
"immobile-source-namespace": "Невозможно переименовывать страницы в пространстве имён «$1»",
"newimages-legend": "Фильтр",
"newimages-label": "Имя файла (или его часть):",
"newimages-user": "IP-адрес или имя участника",
- "newimages-newbies": "Показать только вклад, сделанный с новых учётных записей",
"newimages-showbots": "Показать загрузки ботов",
"newimages-hidepatrolled": "Скрыть отпатрулированные загрузки",
"newimages-mediatype": "Тип медиафайла:",
"img-lang-default": "(язык по умолчанию)",
"img-lang-info": "Показать это изображение на языке $1 $2",
"img-lang-go": "Применить",
- "ascending_abbrev": "возр",
- "descending_abbrev": "убыв",
"table_pager_next": "Следующая страница",
"table_pager_prev": "Предыдущая страница",
"table_pager_first": "Первая страница",
"logentry-block-block": "$1 заблокировал{{GENDER:$2||а}} {{GENDER:$4|$3}} на период $5 $6",
"logentry-block-unblock": "$1 разблокировал{{GENDER:$2||а}} {{GENDER:$4|$3}}",
"logentry-block-reblock": "$1 {{GENDER:$2|изменил|изменила}} срок блокировки {{GENDER:$4|$3}} на период $5 $6",
- "logentry-partialblock-block-page": "{{PLURAL:$1|страница|страницы}} $2",
+ "logentry-partialblock-block-page": "{{PLURAL:$1|страницы|страниц}} $2",
"logentry-partialblock-block-ns": "{{PLURAL:$1|пространство имён|пространства имён}} $2",
"logentry-partialblock-block": "$1 {{GENDER:$2|заблокировал|заблокировала}} {{GENDER:$4|$3}} на редактирование $7 на период $5 $6",
"logentry-partialblock-reblock": "$1 {{GENDER:$2|изменил|изменила}} настройки блокировки {{GENDER:$4|$3}}, предотвращающий правки $7 на период $5 $6",
"wlheader-enotif": "Упозорнїня ел. поштов є запнуте.",
"wlheader-showupdated": "Сторінкы, котры ся змінили од вашой послїднёй навщівы суть вказаны '''грубо'''",
"wlnote": "Ниже є {{PLURAL:$1|остатня зміна|остатнї $1 зміны|остатнїх $1 змін}} за {{PLURAL:$2|остатнїй|остатнї|остатнїх}} <b>$2</b> {{PLURAL:$2|годину|годины|годин}} до do $4, $3.",
- "wlshowlast": "Вказати послїднїх $1 годин $2 днїв",
"watchlist-hide": "Сховати",
"watchlist-submit": "Вказати",
"wlshowhideminor": "малы едітації",
"uctop": "остатня",
"month": "Од місяця (і скоре):",
"year": "Од року (і скоре):",
- "sp-contributions-newbies": "Вказати приспівкы лем новых конт",
- "sp-contributions-newbies-sub": "Новы хоснователї",
- "sp-contributions-newbies-title": "Приспівкы новый хоснователїв",
"sp-contributions-blocklog": "Лоґ блокованя",
"sp-contributions-deleted": "вымазаны приспевкы хоснователя",
"sp-contributions-uploads": "наладованы файлы",
"imgmultipagenext": "далша сторінка →",
"imgmultigo": "Перейти!",
"imgmultigoto": "Перейти на сторінку $1",
- "ascending_abbrev": "зрост",
- "descending_abbrev": "спад",
"table_pager_next": "Далша сторінка",
"table_pager_prev": "Попередня сторінка",
"table_pager_first": "Перша сторінка",
"wlheader-enotif": "वि-पत्रस्य सूचनाः सक्रियाः ।",
"wlheader-showupdated": " येषु पृष्ठेषु भवता/भवत्या परिवर्तनं कृतम् आसीत्, तानि पृष्ठानि अत्र <strong>bold</strong> प्राप्यन्ते ।",
"wlnote": "$3 : $4 वादनं यावत् <strong>$2</strong> होरां यवात् {{PLURAL:$2|होरायां|होरासु}} {{PLURAL:$1|एकं परिवर्तनं|परिवर्तनानि <strong>$1</strong>}} अधः {{PLURAL:$1|अस्ति|सन्ति}}।",
- "wlshowlast": "अन्तिमाः $1 होराः, अन्तिमानि $2 दिनानि दृश्यन्ताम्",
"watchlist-options": "निरीक्षासूचेः विकल्पाः",
"watching": "निरीक्षते...",
"unwatching": "निरीक्षाम् अपाकरोति...",
"uctop": "वर्तमानः",
"month": "अस्मात् मासात् (प्राक्तनानि च):",
"year": "अस्मात् वर्षात् (प्राक्तनानि च):",
- "sp-contributions-newbies": "केवलं नूतनयोजकानां योगदानानि दृश्यन्ताम्",
- "sp-contributions-newbies-sub": "नूतनलेखार्थम् ।",
- "sp-contributions-newbies-title": "नूतनलेखार्थं योजकयोगदानम् ।",
"sp-contributions-blocklog": "अवरोधाऽऽवलिः",
"sp-contributions-suppresslog": "अपमर्जितानि योजकयोगदानानि",
"sp-contributions-deleted": "सदस्यस्य अपाकृतं योगदानम्",
"img-lang-default": "(यदभावे भाषा)",
"img-lang-info": "$1 इत्मात् एतत् चित्रं स्थापितम् । $2",
"img-lang-go": "गम्यताम्",
- "ascending_abbrev": "आरुह्",
- "descending_abbrev": "अवरुह्",
"table_pager_next": "अग्रिमं पृष्ठम्",
"table_pager_prev": "पूर्वतनं पृष्ठम्",
"table_pager_first": "प्रथमं पृष्ठम्",
"apihelp-no-such-module": "\"$1\" муодул көстүбэтэ.",
"apisandbox": "API песочница",
"apisandbox-jsonly": "API-песочницаны туһанарга JavaScript ирдэнэр.",
- "apisandbox-api-disabled": "Бу сайтка API араарыллыбыт.",
"apisandbox-intro": "Бу сирэйи <strong>MediaWiki API</strong> тургутан көрөргө туһан.\nAPI-ни туттар туһунан сиһилии манна ааҕыахха сөп [[mw:API:Main page|API туһунан]]. Холобура, [https://www.mediawiki.org/wiki/API#A_simple_example Сүрүн сирэй иһинээҕитин хайдах ылар туһунан]. Атын холобурдары көрөргө сигэни баттаа.\nБолҕой: бу тургутар сирэй эрээри, манна суруйбутуҥ биикигэ уларытыыны оҥоруон сөп.",
"apisandbox-submit": "Ыйытык оҥоруу",
"apisandbox-reset": "Сот",
"wlheader-enotif": "Эл. почтанан биллэрии холбоммут.",
"wlheader-showupdated": "Бүтэһик киирииҥ кэннэ уларыйбыт сирэйдэр '''модьу''' бичигинэн бэлиэтэннилэр.",
"wlnote": "Манна кэлиҥҥи {{PLURAL:$2|чаас|<strong>$2</strong> чаас}} иһигэр оҥоһуллубут бүтэһик <strong>$1</strong> уларытыы көрдөрүлүннэ, бу кэминээҕи туругунан $3, $4.",
- "wlshowlast": "Бүтэһик $2 күҥҥэ $1 чааска көрдөр",
"watchlist-hide": "Кистээ",
"watchlist-submit": "Көрдөр",
"wlshowtime": "Бу ыккардыгар буолбуту көрдөр:",
"uctop": "билиҥҥи",
"month": "Ыйтан бэттэх:",
"year": "Сылтан бэттэх:",
- "sp-contributions-newbies": "Саҥа эрэ ааттан оҥоһуллубут уларытыылары көрдөр",
- "sp-contributions-newbies-sub": "Саҥа ааттартан",
- "sp-contributions-newbies-title": "Саҥа бэйэлэрин билиһиннэрбит дьон уларытыылара",
"sp-contributions-blocklog": "Бобуу сурунаала",
"sp-contributions-suppresslog": "{{GENDER:$1|кыттааччы}} сотуллубут көннөрүүлэрэ",
"sp-contributions-deleted": "{{GENDER:$1|кыттааччы}} сотуллубут көннөрүүлэрэ",
"newimages-legend": "Фильтр",
"newimages-label": "Билэ аата (эбэтэр сорҕото):",
"newimages-user": "Кыттааччы аата эбэтэр IP-та",
- "newimages-newbies": "Саҥа бэлиэ ааттартан эрэ оҥоһуллубуту көрдөр",
"newimages-showbots": "Руобаттар хачайдааһыннарын көрдөр",
"newimages-hidepatrolled": "Кэтэммит хачайданыылары сабыы.",
"newimages-mediatype": "Миэдьийэ көрүҥэ:",
"img-lang-default": "(эппэтэххэ талыллар тыла)",
"img-lang-info": "Бу ойууну $1 тылынан көрдөр. $2",
"img-lang-go": "Толор",
- "ascending_abbrev": "улаатыннар",
- "descending_abbrev": "кыччат",
"table_pager_next": "Аныгыскы сирэй",
"table_pager_prev": "Иннинээҕи сирэй",
"table_pager_first": "Бастакы сирэй",
"watchlist-details": "{{PLURAL:$1 ᱥᱟᱦᱴᱟ|$1 ᱥᱟᱦᱴᱟᱠᱚ}} ᱟᱢᱟᱜ ᱧᱮ ᱞᱤᱥᱴᱤ ᱨᱮ ᱢᱮᱱᱟᱜ-ᱟ (ᱨᱚᱲ ᱥᱟᱦᱴᱟ ᱠᱚᱦᱚᱸ)",
"wlheader-showupdated": "ᱟᱢᱟᱜ ᱢᱩᱪᱟᱹᱫ ᱵᱚᱞᱚᱝᱨᱮ ᱡᱟᱸᱦᱟᱸ ᱥᱟᱦᱴᱟ ᱠᱚᱢ ᱵᱚᱫᱚᱞ ᱞᱮᱫᱟ ᱚᱱᱟᱠᱩ ᱧᱮᱞᱚᱜ-ᱟ <strong>bold</strong>.",
"wlnote": "ᱞᱟᱛᱟᱨ ᱨᱮᱱᱟᱜ {{PLURAL:$1|ᱫᱚ ᱢᱩᱪᱟᱹᱫ ᱵᱚᱫᱚᱞ ᱠᱟᱱᱟ|ᱠᱚ ᱫᱚ ᱢᱩᱪᱟᱹᱫ <strong>$1</strong> ᱵᱚᱫᱚᱞᱠᱟᱱᱟ}} ᱢᱩᱪᱟᱹᱫ ᱨᱮ {{PLURAL:$2|ᱴᱟᱲᱟᱝ|<strong>$2</strong> ᱴᱟᱲᱟᱝ}}, $3, $4 ᱞᱮᱠᱟᱛᱮ ᱾",
- "wlshowlast": "ᱢᱩᱪᱟᱹᱛ ᱩᱫᱩᱜᱢᱮ $1 ᱴᱟᱲᱟᱝ $2 ᱢᱟᱦᱟᱸ",
"watchlist-options": "ᱧᱮᱞᱚᱜ ᱛᱟᱹᱞᱠᱟᱹ ᱨᱮᱭᱟᱜ ᱥᱚᱝᱠᱮᱛᱠᱩ",
"watching": "ᱧᱮᱞᱚᱜ ᱠᱟᱱᱟ...",
"enotif_reset": "ᱱᱤᱱᱦᱟᱹᱭᱢᱮ ᱡᱚᱛᱚ ᱥᱟᱦᱴᱟ ᱦᱤᱨᱤᱭᱟᱠᱟᱱᱟ",
"uctop": "ᱱᱤᱛᱚᱜ",
"month": "ᱪᱟᱸᱫᱚ ᱠᱷᱚᱱ (ᱟᱨ ᱞᱟᱦᱟᱨᱮᱭᱟᱜ)",
"year": "ᱱᱚᱣᱟ ᱥᱮᱨᱢᱟ ᱠᱷᱚᱡ (ᱟᱨ ᱞᱟᱦᱟᱨᱮᱭᱟᱜ):",
- "sp-contributions-newbies": "ᱱᱟᱣᱟ ᱮᱠᱟᱶᱩᱴ ᱨᱮᱱᱟᱜ ᱮᱱᱮᱢᱠᱚ ᱩᱫᱩᱜᱽ ᱢᱮ",
"sp-contributions-blocklog": "ᱠᱩᱞᱩᱯ ᱮᱥᱮᱫ",
"sp-contributions-uploads": "ᱞᱟᱫᱮᱠᱩ",
"sp-contributions-logs": "ᱛᱟᱞᱟᱠᱩ",
"unwatchthispage": "Boga custa pàgina dae sa watchlist tua",
"notanarticle": "Custa pàgina no est unu artìculu",
"watchlist-details": "Tenes {{PLURAL:$1|$1 pàgina annotada paris a sa pagina de cuntierra sua|$1 pàginas annotadas paris a is pàginas de cuntierra issoro}}.",
- "wlshowlast": "Ammustra is ùrtimas $1 oras, $2 dies",
"watchlist-options": "Optziones subra sa lista de pàginas annotadas",
"watching": "Giunghende a sa watchlist...",
"unwatching": "Boghende dae sa watchlist...",
"uctop": "atuale",
"month": "Dae su mese (e in segus):",
"year": "Dae s'annu (e in segus):",
- "sp-contributions-newbies": "Ammustra feti is contributziones de is contos noos",
- "sp-contributions-newbies-sub": "Pro is contos noos",
"sp-contributions-blocklog": "registru de is bloccos",
"sp-contributions-uploads": "carrigamentos",
"sp-contributions-logs": "registros",
"wlheader-enotif": "La nutìfica via posta elittrònica è attivata.",
"wlheader-showupdated": "Li pàggini ca foru canciati dâ tò ùrtima vìsita sunnu evidinziati n <strong>grassettu</strong>.",
"wlnote": "Sutta attrovi l'ùrtim{{PLURAL:$1|u canciamentu|i <strong>$1</strong> canciamenti}} fatti nta l'ùrtim{{PLURAL:$1|a ura|i <strong>$2</strong> uri}}, aggiurnati ê $4 dû $3.",
- "wlshowlast": "Ammustra l'ùrtimi $1 uri $2 jorna",
"watchlist-options": "Opzioni dâ lista taliata",
"watching": "Agghiunciuta â lista taliata...",
"unwatching": "Cancillata dâ lista taliata...",
"uctop": "attuali",
"month": "A pàrtiri dû misi (e pricidenti):",
"year": "A pàrtiri di l'annu (e pricidenti):",
- "sp-contributions-newbies": "Ammustra sulu li cuntribbuti di l'utenti novi",
- "sp-contributions-newbies-sub": "Di l'utenti novi",
- "sp-contributions-newbies-title": "Cuntribbuti di l'utenti novi",
"sp-contributions-blocklog": "riggistru dî blocchi",
"sp-contributions-suppresslog": "cuntribbuti suppressi di l'utenti",
"sp-contributions-deleted": "cuntribbuti cancillati di l'utenti",
"img-lang-default": "(lingua pridifinuta)",
"img-lang-info": "Gènira sta mmàggini n $1. $2",
"img-lang-go": "Vai",
- "ascending_abbrev": "crisc",
- "descending_abbrev": "dicrisc",
"table_pager_next": "Pàggina succissiva",
"table_pager_prev": "Pàggina pricidenti",
"table_pager_first": "Prima pàggina",
"wlheader-enotif": "Wab-mail annooncemant is enabled.",
"wlheader-showupdated": "Pages that hae been chynged sin ye last veesitit thaim ar shawn in '''baud'''.",
"wlnote": "Ablo {{PLURAL:$1|is the laist chynge|ae the laist <strong>$1</strong> chynges}} in the laist {{PLURAL:$2|hoor|<strong>$2</strong> hoors}}, aes o $3, $4.",
- "wlshowlast": "Shaw the hainmaist $1 hoors $2 days",
"watchlist-options": "Watchleet opties",
"watching": "Watchin...",
"unwatching": "Onwatchin...",
"uctop": "current",
"month": "Fae month (n afore):",
"year": "Fae year (n afore):",
- "sp-contributions-newbies": "Shaw contreebutions o freish accoonts ainlie",
- "sp-contributions-newbies-sub": "Fer new accoonts",
- "sp-contributions-newbies-title": "Uiser contreebutions fer new accoonts",
"sp-contributions-blocklog": "the block log",
"sp-contributions-suppresslog": "suppressed uiser contreebutions",
"sp-contributions-deleted": "delytit uiser contreebutions",
"img-lang-default": "(defaut leid)",
"img-lang-info": "Render this eemage in $1. $2",
"img-lang-go": "Gang",
- "ascending_abbrev": "asc",
- "descending_abbrev": "desc",
"table_pager_next": "Page aifter",
"table_pager_prev": "Page afore",
"table_pager_first": "First page",
"revdelete-hide-image": "فائيل جو مواد لڪايو",
"revdelete-hide-name": "هدف ۽ نيمپيما لڪايو",
"revdelete-hide-comment": "سنوار جو تتُ",
- "revdelete-hide-user": "اÙ\8aÚ\8aÙ\8aٽر جÙ\88 Ù\88اپرائÙ\8aÙ\86دÚ\99-Ù\86اÙ\86Ø¡Ù\8f/آءÙ\90Ù¾Ù\90ي پتو",
+ "revdelete-hide-user": "سÙ\86Ù\88ارÙ\8aÙ\86دÚ\99 جÙ\88 Ù\88اپرائÙ\8aÙ\86دÚ\99-Ù\86اÙ\86Ø¡Ù\8f/آئÙ\90Ù¾ي پتو",
"revdelete-hide-restricted": "منتظمن توڙي ٻين کان مليل اعداد دٻايو",
"revdelete-radio-same": "(نہ بدلايو)",
"revdelete-radio-set": "لڪل",
"rcfilters-filter-editsbyother-label": "ٻين پاران تبديليون",
"rcfilters-filtergroup-user-experience-level": "واپرائيندڙن جي رجسٽريشن ۽ تجربو",
"rcfilters-filter-user-experience-level-registered-label": "رجسٽر ٿيل",
- "rcfilters-filter-user-experience-level-registered-description": "داخÙ\84 Ù¿Ù\8aÙ\84 اÙ\8aÚ\8aÙ\8aٽر.",
+ "rcfilters-filter-user-experience-level-registered-description": "داخÙ\84 Ù¿Ù\8aÙ\84 سÙ\86Ù\88ارÙ\8aÙ\86دÚ\99.",
"rcfilters-filter-user-experience-level-unregistered-label": "اڻرجسٽر ٿيل",
"rcfilters-filter-user-experience-level-unregistered-description": "سنواريندڙ جيڪي داخل ٿيل ناھن.",
"rcfilters-filter-user-experience-level-newcomer-label": "نوان ايندڙ",
"imagelinks": "فائيل جو استعمال",
"linkstoimage": "ھن فائيل کي {{PLURAL:$1|ھيٺيون صفحو استعمال ڪري ٿو|$1 ھيٺيان صفحا استعمال ڪن ٿا}}:",
"nolinkstoimage": "ڪي بہ صفحا ناھن جيڪي ھن فائيل کي استعمال ڪندا ھجن.",
+ "linkstoimage-redirect": "$1 (فائيل چورڻو) $2",
"sharedupload": "هيءَ فائيل $1 کان آهي ۽ ان کي ٻيون رٿائون به استعمال ڪري سگھن ٿيون.",
"sharedupload-desc-here": "ھي فائيل $1 مان آھي ۽ ٻين رٿائن پاران پڻ استعمال ٿي سگھي ٿو. تشريح انجي [[$2 جو تشريحي صفحو]] ھيٺان ڏنل آھي.",
"filepage-nofile": "ھن نالي سان ڪوبہ فائيل وجود نٿو رکي.",
"unwatchthispage": "نظر ۾ رکڻ ڇڏيو",
"notanarticle": "غير موادي صفحو",
"watchlist-details": "توھان جي نظر ۾ فھرست (گڏوگڏ بحث صفحن تي) {{PLURAL:$1|$1 صفحو آھي|$1 صفحا آھن}}.",
- "wlshowlast": "گذريل $1 ڪلاڪ $2 ڏينهن ڏيکاريو",
"watchlist-hide": "لڪايو",
"watchlist-submit": "ڏيکاريو",
"wlshowtime": "ڪيترو عرصو ڏيکارجي:",
"protectlogpage": "تحفظ لاگ",
"protectedarticle": "محفوظ ٿيل \"[[$1]]\"",
"modifiedarticleprotection": "\"[[$1]]\" جي تحفظ جي سطح تبديل ڪئي",
+ "unprotectedarticle": "\"[[$1]]\" تان تحفظ ھٽايو ويو",
"movedarticleprotection": "\"[[$2]]\" جو حفاظت درجو \"[[$1]]\" جي طرف منتقل ڪيو",
+ "unprotectedarticle-comment": "\"[[$1]]\" تان {{GENDER:$2|تحفظ ھٽايو}}",
"prot_1movedto2": "[[$1]] کي چوري [[$2]] تي رکيو ويو",
"protect-legend": "تحفظڻ جي پڪ ڪريو",
"protectcomment": "سبب:",
"uctop": "هاڻوڪو",
"month": "مھيني کان (۽ اڳوڻيون):",
"year": "سال کان (۽ اڳوڻيون):",
- "sp-contributions-newbies": "صرف نون کاتن جون ڀاڱيداريون ڏيکاريو",
- "sp-contributions-newbies-sub": "نون کاتن لاءِ",
- "sp-contributions-newbies-title": "نون کاتن جي لاءِ واپرائيندڙ جون ڀاڱيداريون",
"sp-contributions-blocklog": "بندش لاگ",
"sp-contributions-suppresslog": "{{GENDER:$1|واپرائيندڙ}} جو دٻايل ڀاڱيداريون",
"sp-contributions-deleted": "{{GENDER:$1|واپرائيندڙ}} جون ڊاٿل ڀاڱيداريون",
"confirm-unwatch-button": "ٺيڪ",
"confirm-unwatch-top": "هيءُ صفحو پنهنجي نظر ۾ فهرست مان هٽائيندا؟",
"confirm-rollback-top": "ھن صفحي ۾ ڪيل سنوارون واپس ورايون؟",
+ "semicolon-separator": "؛ ",
+ "comma-separator": "، ",
"quotation-marks": "\"$1\"",
"imgmultipageprev": "← اڳوڻو صفحو",
"imgmultipagenext": "اڳيون صفحو ←",
"htmlform-cloner-delete": "هٽايو",
"htmlform-title-not-exists": "$1 وجود نٿو رکي.",
"logentry-delete-delete": "$1 {{GENDER:$2|ڊاٿو}} صفحو $3",
+ "logentry-delete-restore": "$1 {{GENDER:$2|بحاليو}} صفحو $3 ($4)",
"logentry-delete-revision": "$1 $3: $4 صفحي تي {{PLURAL:$5|ھڪ مسودي|$5 مسودن}} جي ظاھريت {{GENDER:$2|تبديل ڪئي}}",
"revdelete-content-hid": "مواد لڪيل",
"revdelete-uname-hid": "واپرائيندڙ-نانءُ لڪل",
+ "revdelete-unrestricted": "منتظمن تان پابنديون ھٽايون ويون",
"logentry-block-block": "$1، {{GENDER:$4|$3}} تي $5 وقت جي خاتمي تائين {{GENDER:$2|بندش هئي آهي}} $6",
"logentry-move-move": "$1 {{GENDER:$2|چوريو}} صفحو $3 ڏانهن $4",
"logentry-move-move-noredirect": "$1 $3 صفحي کي $4 ڏانھن {{GENDER:$2|چوريو}} سواءِ ڪو ريڊائريڪٽ ڇڏيندي",
"logentry-patrol-patrol-auto": "$1 پاڻمرادو صفحي $3 جي $4 مسودي تي گشت ڪيل طور {{GENDER:$2|نشان لڳايو}}",
"logentry-newusers-create": "واپرائيندڙ کاتو $1 {{GENDER:$2|سرجيو ويو}}",
"logentry-newusers-autocreate": "واپرائيندڙ کاتو $1 پاڻمرادو {{GENDER:$2|کوليو ويو}}",
+ "logentry-protect-unprotect": "$1 $3 تان تحفظ {{GENDER:$2|ھٽايو}}",
"logentry-protect-protect": "$1 {{GENDER:$2|محفوظ ڪيو}} $3 $4",
"logentry-upload-upload": "$1 {{GENDER:$2|چاڙهيو}} $3",
"logentry-upload-overwrite": "$1 $3 جو ھڪ نئون ورزن {{GENDER:$2|چاڙھيو}}",
"mw-widgets-usersmultiselect-placeholder": "وڌيڪ شامل ڪيو...",
"date-range-from": "تاريخ کان:",
"date-range-to": "تاريخ تائين:",
+ "randomrootpage": "بلاترتيب پاڙ صفحو",
"log-action-filter-all": "سڀ"
}
"wlheader-enotif": "La nutìfica via postha erettrònica è attiba.",
"wlheader-showupdated": "Li pàgini chi so isthaddi mudìfiggaddi daboi l'ulthima vìsita so evidenziaddi in '''grasseddu'''",
"wlnote": "Inogghi {{PLURAL:$1|è erencadda la mudìfigga più rizzenti arriggadda|so erencaddi li '''$1''' mudìfigghi più rizzenti arriggaddi}} {{PLURAL:$2|i' la ulthima ora|i' li ulthimi '''$2''' ori}}.",
- "wlshowlast": "Musthra li ùlthimi $1 ori $2 dì",
"watchlist-options": "Opzioni abbaidaddi ippiziari",
"watching": "Aggiunta a l'abbaidaddi ippiziari...",
"unwatching": "Eliminazioni da l'abbaidaddi ippiziari...",
"uctop": "currenti",
"month": "A parthì da lu mesi (e prizzidenti):",
"year": "A parthì da l'anni (e prizzidenti):",
- "sp-contributions-newbies": "Musthra soru li cuntributi di li nobi utenti",
- "sp-contributions-newbies-sub": "Pa li nobi utenti",
"sp-contributions-blocklog": "Brocchi",
"sp-contributions-uploads": "carriggamentu",
"sp-contributions-logs": "rigisthri",
"imgmultipagenext": "pàgina sighenti →",
"imgmultigo": "Vai",
"imgmultigoto": "Vai a la pàgina $1",
- "ascending_abbrev": "crisc",
- "descending_abbrev": "miminan",
"table_pager_next": "Pàgina sighenti",
"table_pager_prev": "Pàgina prizzidenti",
"table_pager_first": "Primma pàgina",
"watch": "چاودێری بکە",
"unwatch": "لاوردن چاودێری",
"watchlist-details": "بێجگە پەڕەگان وەتوویش، {{PLURAL:$1|$1 پەڕە}} لە پێرست چاودێریەگەتە.",
- "wlshowlast": "دۊایین $1 دەمژمار $2 ڕووژ نیشان بدە",
"watchlist-options": "ھەڵوژیاێەگان پێرست چاودێری",
"actioncomplete": "کردارەگە وە ئەنجام رەسی",
"actionfailed": "کردارەگە سەرنەکەفت",
"uctop": "ئێرەنگە",
"month": "لە مانگ (و پێشتر لەوە):",
"year": "لە ساڵ (و پێشتر لەوە):",
- "sp-contributions-newbies": "تەنیا بەشداریەگان ئەوکاربەرە تازەگان نیشان بدە",
"sp-contributions-blocklog": "پێرست بەساێن",
"sp-contributions-uploads": "بارکردنەگان",
"sp-contributions-logs": "پێرستەگان",
"wlheader-enotif": "E-poastaalmmuhusat leat anus.",
"wlheader-showupdated": "Siiddut, mat leat rievdaduvvon du maŋimus geavahangearddi maŋŋá leat merkojuvvon '''buoiddes teavsttain'''",
"wlnote": "Vuolábealde lea '''$1''' {{PLURAL:$1|rievdadus|rievdadusa}} maŋimus {{PLURAL:$2||'''$2'''}} diimma siste.",
- "wlshowlast": "Čájet maŋimus $1 diimmu dahje $2 beaivvi",
"watching": "Lasihuvvo čuovvunlistui...",
"unwatching": "Sihkojuvvo čuovvunlisttus...",
"enotif_reset": "Merke buot siidduid gehččojuvvon",
"uctop": "ođđaseamos",
"month": "Mánotbadji",
"year": "Jahki",
- "sp-contributions-newbies": "Čájet ođđa geavaheddjiid rievdadusaid",
- "sp-contributions-newbies-sub": "Ođđa geavaheddjiid rievdadusat",
"sp-contributions-blocklog": "cakkastallamat",
"sp-contributions-logs": "loggat",
"sp-contributions-talk": "ságastallan",
"imgmultipageprev": "← ovddit siidu",
"imgmultipagenext": "čuovvovaš siidu →",
"imgmultigo": "Mana!",
- "ascending_abbrev": "loktaneaddji",
- "descending_abbrev": "vuolláneaddji",
"table_pager_next": "Čuovvovaš siidu",
"table_pager_prev": "Ovddit siidu",
"table_pager_first": "Vuosttas siidu",
"watchthispage": "Cáminot jan páhina",
"unwatch": "Diicáminot",
"unwatchthispage": "Diicáminot jan páhina",
- "wlshowlast": "Cohuatlöx hun $1 ixáap quij iitax $2 ixáap",
"watching": "Cáminot...",
"unwatching": "Necáminot...",
"enotif_impersonal_salutation": "{{SITENAME}} caitom",
"wlheader-enotif": "Bataga bayrandiyan n' ka tunandi.",
"wlheader-showupdated": "Moɲey kaŋ barmay za cee koraa kaŋ war n'i guna ga cebandi harfu <strong>warga</strong> ra.",
"wlnote": "Ne ganda {{PLURAL:$1|ti barmay kokorante <strong>$1</strong>}} za {{PLURAL:$2|guuru kokorante <strong>$2</strong> ra}}, $3 hane, $4 waate.",
- "wlshowlast": "Guuru $1 zaari $2 kokorante cebe",
"watchlist-options": "Hawgayhaya suubarey",
"watching": "Goo ma hawgay…",
"unwatching": "Ši ma guna…",
"uctop": "sohõda",
"month": "Za handu (wal'a se jine):",
"year": "Za jiiri (wal'a se jine):",
- "sp-contributions-newbies": "Kanbuzaamawey cebe kontu taagey hinne se",
- "sp-contributions-newbies-sub": "Kontu taagey se",
- "sp-contributions-newbies-title": "Goykaw kanbuzaamawey kontu taagey se",
"sp-contributions-blocklog": "margari taariki",
"sp-contributions-suppresslog": "goykaw kanbuzaamay munantey",
"sp-contributions-deleted": "goykaw kanbuzaamay tuusantey",
"img-lang-default": "(tilasu šenni)",
"img-lang-info": "Biyoo woo kaataray $1 ra. $2",
"img-lang-go": "Koy",
- "ascending_abbrev": "ziji",
- "descending_abbrev": "zunbu",
"table_pager_next": "Jinehere moɲoo",
"table_pager_prev": "Moo bisantaa",
"table_pager_first": "Moo jinaa",
"wlheader-enotif": "El. pašta primėnėmā ijongtė īr.",
"wlheader-showupdated": "Poslapē, katros kažėkas pakeitė nug Tamstas paskotėnė apsilonkīma, īr pažīmietė <strong>stuorā</strong>.",
"wlnote": "Apatiuo ī {{PLURAL:$1|vielībāsis pakeitėms|vielībė̄jė <strong>$1</strong> pakeitėmā}} par {{PLURAL:$2|paskotėnė adīna|paskotėnės <strong>$2</strong> adīnas|paskotėniu <strong>$2</strong> adīnu}} tap, kap daba ī $3, $4.",
- "wlshowlast": "Ruodītė paskotėniu $1 adīnu, $2 dėinū pakeitėmus",
"watchlist-hide": "Kavuotė",
"watchlist-submit": "Ruodītė",
"wlshowhideminor": "maži pakeitėmā",
"uctop": " vielībs",
"month": "Nug mienėsė (ėr onkstiau):",
"year": "Nug metu (ėr onkstiau):",
- "sp-contributions-newbies": "Ruodītė tėktās naujū prieteliu duovius",
- "sp-contributions-newbies-sub": "Naujuoms paskīruoms",
- "sp-contributions-newbies-title": "Nauduotuoju keitėmā naujuoms paskīruoms",
"sp-contributions-blocklog": "Bluokavėmu istuorėjė",
"sp-contributions-suppresslog": "panaikėnts nauduotuojė duovis",
"sp-contributions-deleted": "ėštrints nauduotuojė duovis",
"imgmultigo": "Ētė!",
"imgmultigoto": "Ētė i poslapi $1",
"img-lang-default": "(kalba kāp nustatīta)",
- "ascending_abbrev": "dėdiejėma tvarka",
- "descending_abbrev": "mažiejontė tvarka",
"table_pager_next": "Kėts poslapis",
"table_pager_prev": "Onkstesnis poslapis",
"table_pager_first": "Pėrms poslapis",
"nocreate-loggedin": "Nemate dopuštenje da kreirate nove stranice.",
"sectioneditnotsupported-title": "Uređivanje sekcije nije podržano",
"sectioneditnotsupported-text": "Uređivanje sekcije nije podržano na ovoj stranici.",
+ "modeleditnotsupported-title": "Uređivanje nije podržano",
+ "modeleditnotsupported-text": "Uređivanje nije podržano za sadržajni model $1.",
"permissionserrors": "Greška pri odobrenju",
"permissionserrorstext": "Nemate dopuštenje da to uradite, iz {{PLURAL:$1|slijedećeg razloga|slijedećih razloga}}:",
"permissionserrorstext-withaction": "Nemate dozvolu za $2, zbog {{PLURAL:$1|sljedećeg|sljedećih}} razloga:",
"content-model-css": "CSS",
"content-json-empty-object": "Prazan objekat",
"content-json-empty-array": "Prazan niz",
+ "unsupported-content-model": "<strong>Upozorenje:</strong> Sadržajni model $1 nije podržan na ovom wikiju.",
+ "unsupported-content-diff": "Razlike nisu podržane za sadržajni model $1.",
+ "unsupported-content-diff2": "Razlike između sadržajnih modela $1 i $2 nisu podržane na ovom wikiju.",
"deprecated-self-close-category": "Stranice s neispravnim samozatvorenim HTML oznakama",
"deprecated-self-close-category-desc": "Stranica sadrži neispravne samozatvorene HTML oznake, kao što su <code><b/></code> ili <code><span/></code>. Njihovo funkcioniranje uskoro će se promijeniti da bude u skladu sa specifikacijama za HTML5. Ovo znači da su zastarjeli i ne bi se trebali upotrebljavati u wikitekstu.",
"duplicate-args-warning": "<strong>Upozorenje:</strong> [[:$1]] poziva na [[:$2]] sa više od jedne vrijednosti za parametar \"$3\". Koristit će se samo posljednja navedena vrijednost.",
"apihelp-no-such-module": "Modul \"$1\" nije pronađen.",
"apisandbox": "Izvršnički pješčanik",
"apisandbox-jsonly": "Upotreba ovoga izvršničkog pješčanika zahtijeva JavaScript.",
- "apisandbox-api-disabled": "Izvršnik je onemogućen na ovom sajtu.",
"apisandbox-intro": "Stranica služi za eksperimentiranje s <strong>API-jem MediaWiki</strong>.\n\nViše o korištenju ovog API-ja možete pronaći na [[mw:API:Main page|njegovoj dokumentaciji]]. Primjer: [https://www.mediawiki.org/wiki/API#A_simple_example preuzimanje sadržaja glavne stranice]. Odaberite radnju da biste vidjeli više primjera.\n\nImajte na umu da se ono što radite na ovoj stranici može odraziti na wikiju, iako je to pješčanik.",
"apisandbox-submit": "Napravi zahtjev",
"apisandbox-reset": "Očisti",
"wlheader-enotif": "* Obavještavanje e-poštom je omogućeno.",
"wlheader-showupdated": "* Stranice koje su izmijenjene od kad ste ih posljednji put posjetili su prikazane '''podebljanim slovima'''",
"wlnote": "Ispod {{PLURAL:$1|je najskorija izmjena|su <strong>$1</strong> najskorije izmjene|<strong>$1</strong> najskorijih izmjena}} načinjenih {{PLURAL:$2|posljednjeg sata|u posljednjih <strong>$2</strong> sata|u posljednjih <strong>$2</strong> sati}}, od $3, $4.",
- "wlshowlast": "Prikaži posljednjih $1 sati $2 dana",
"watchlist-hide": "Sakrij",
"watchlist-submit": "Prikaži",
"wlshowtime": "Period za prikaz:",
"month": "Od mjeseca (i ranije):",
"year": "Od godine (i ranije):",
"date": "Od datuma (i ranije):",
- "sp-contributions-newbies": "Pokaži doprinose samo novih korisnika",
- "sp-contributions-newbies-sub": "Prikaži samo doprinose novih korisnika",
- "sp-contributions-newbies-title": "Doprinosi novih korisnika",
"sp-contributions-blocklog": "registar blokiranja",
"sp-contributions-suppresslog": "izbrisani doprinosi {{GENDER:$1|korisnika|korisnice}}",
"sp-contributions-deleted": "izbrisani doprinosi {{GENDER:$1|korisnika|korisnice}}",
"newimages-legend": "Filter",
"newimages-label": "Ime datoteke (ili dio imena):",
"newimages-user": "IP adresa ili korisničko ime",
- "newimages-newbies": "Prikaži samo doprinose novih računa",
"newimages-showbots": "Prikaži otpremanja botova",
"newimages-hidepatrolled": "Sakrij ispatrolirana otpremanja",
"newimages-mediatype": "Tip medija:",
"img-lang-default": "(podrazumijevani jezik)",
"img-lang-info": "Ispiši sliku na $1. $2",
"img-lang-go": "Prikaži",
- "ascending_abbrev": "rast",
- "descending_abbrev": "opad",
"table_pager_next": "Sljedeća stranica",
"table_pager_prev": "Prethodna stranica",
"table_pager_first": "Prva stranica",
"watchthispage": "ⴹⴼⵓⵔ ⵜⴰⵙⵏⴰ ⴰⴷ",
"unwatch": "ⵙⴱⴷⴷ ⴰⴹⴼⴼⵓⵔ",
"watchlist-details": "{{PLURAL:$1|$1 ⵜⴰⵙⵏⴰ|$1 ⵜⴰⵙⵏⵉⵡⵉⵏ}} ⴳ ⵜⵍⴳⴰⵎⵜ {{GENDER:|ⵏⵏⴽ|ⵏⵏⵎ}} ⵏ ⵓⴹⴼⴼⵓⵔ, not separately counting talk pages.",
- "wlshowlast": "ⵎⵍ $1 ⵜⵙⵔⴰⴳⵉⵏ ⴳⴳⵯⵔⴰⵏⵉⵏ, $2 ⵡⵓⵙⵙⴰⵏ ⴳⴳⵯⵔⴰⵏⵉⵏ",
"watchlist-hide": "ⵙⵙⵏⵜⵍ",
"wlshowhidebots": "ⵉⵔⵓⴱⵓⵜⵏ",
"watchlist-options": "ⵜⵉⵙⵖⴰⵍ ⵏ ⵜⵍⴳⴰⵎⵜ ⵏ ⵓⴹⴼⴼⵓⵔ",
"uctop": "ⵜⴰⵎⵉⵔⴰⵏⵜ",
"month": "ⵣⵖ ⵡⴰⵢⵢⵓⵔ (ⴷ ⵣⵉⴽⴽ ⵏⵏⵙ):",
"year": "ⵣⵖ ⵓⵙⴳⴳⵯⴰⵙ (ⴷ ⵣⵉⴽⴽ ⵏⵏⵙ):",
- "sp-contributions-newbies": "ⵎⵍ ⵖⴰⵔ ⵜⵉⴷⵔⴰⵡⵉⵏ ⵏ ⵉⵎⵉⴹⴰⵏⵏ ⵉⵎⴰⵢⵏⵓⵜⵏ",
- "sp-contributions-newbies-sub": "ⵜⵉⵏ ⵉⵎⵉⴹⴰⵏⵏ ⵉⵎⴰⵢⵏⵓⵜⵏ ⴽⴰ",
- "sp-contributions-newbies-title": "Tiwuriwin n umqdac z imḍan imaynutn",
"sp-contributions-blocklog": "Tinɣmas n willi ttuyqqanin (blocage)",
"sp-contributions-deleted": "Tiwuriwin lli ittuykkasnin",
"sp-contributions-uploads": "Iwidn",
"imgmultigo": "ⵍⴽⵎ ⵏⵏ !",
"imgmultigoto": "ⴼⵜⵓ ⵙ ⵜⴰⵙⵏⴰ $1",
"img-lang-default": "(ⵜⵓⵜⵍⴰⵢⵜ ⵙ ⵓⵡⵏⵓⵍ)",
- "ascending_abbrev": "aryaqliw",
- "descending_abbrev": "aritgiiz",
"table_pager_next": "ⵜⴰⵙⵏⴰ ⵜⵓⴹⴼⵉⵔⵜ",
"table_pager_prev": "tawriqt izrin",
"table_pager_first": "tawriqt tamzwarut",
"watchlist-details": "{{PLURAL:$1|ၼႃႈလိၵ်ႈ $1 ၼႃႈ|ၸိူဝ်းၼႃႈလိၵ်ႈ $1 ၼႃႈ}} ၼႆႉမီးဝႆႉ တီႈၼႂ်းသဵၼ်ႈမၢႆတူၺ်းၸဝ်ႈၵဝ်ႇသေ ၸိူဝ်းပၼ်ၼႃႈလိၵ်ႈ ဢုပ်ႇဢူဝ်းၼၼ်ႉတႄႉ ဢမ်ႇဢၢၼ်ႇၶဝ်ႈပႃး။",
"wlheader-showupdated": "ဝၢႆးသေၸဝ်ႈၵဝ်ႇ တူၺ်းမႃးသေ ဢၼ်ပဵၼ်ၼႃႈလိၵ်ႈ ၸိူဝ်းမီးလွင်ႈလႅၵ်ႈလၢႆႈၼၼ်ႉ ဢဝ်\nသင် နောက်ဆုံးကြည့်ရှုခဲ့ပြီးနောက် ပြောင်းလဲမှုရှိခဲ့သော စာမျက်နှာများကို <strong>တူဝ်လိၵ်ႈလမ်</strong>သေ ၼႄဝႆႉပၼ်ယူႇ။",
"wlnote": "ၼႂ်းၵႃႈ တေႃႇထိုင် $3၊ $4 ၼၼ်ႉ ၵမ်းလိုၼ်းသုတ်း {{PLURAL:$2|မူင်း|<strong>$2</strong> မူင်း}}ၼၼ်ႉမီႈ{{PLURAL:$1|လွင်ႈလႅၵ်ႈလၢႆႈ ဝႆႉဢၼ်ၼိုင်ႈ|လွင်ႈၸိူဝ်းလႅၵ်ႈလၢႆႈဝႆႉ <strong>$1</strong> ဢၼ်}}",
- "wlshowlast": "ၼႄ ၶၢဝ်းယၢမ်းလိုၼ်းသုတ်း $1 မူင်း $2 ဝၼ်း",
"watchlist-hide": "သိူင်ႇ",
"watchlist-submit": "ၼႄ",
"wlshowtime": "ပွင်ႈၶၢဝ်းယၢမ်း တွၼ်ႈတႃႇ ဢွၵ်ႇၼႄ:",
"month": "တႄႇဢဝ်လိူၼ် (လႄႈ ဢၼ်ပူၼ်ႉမႃး):",
"year": "တႄႇဢဝ်ပီ (လႄႈ ဢၼ်ပူၼ်ႉမႃး):",
"date": "ၸႄႇဢဝ်ဝၼ်းထီႉ (လႄႈ ၸဝ်ႉသေၼၼ်ႉ):",
- "sp-contributions-newbies": "ၼႄပၼ်လွင်ႈၶဝ်ႈႁူမ်ႈ ၶွင် ဢၶွင်ႉဢၼ်မႂ်ႇလၢႆလၢႆၵူၺ်းလႄႈ",
- "sp-contributions-newbies-sub": "တွၼ်ႈတႃႇဢၶွင်ႉ ဢၼ်မႂ်ႇ",
"sp-contributions-blocklog": "မၢႆတမ်းၵၢၼ်ႁေႉတတ်း",
"sp-contributions-suppresslog": "လွင်ႈၶဝ်ႈႁူမ်ႈ {{GENDER:$1|ၽူႈၸႂ်ႉတိုဝ်း}} ဢၼ်ႁူမ်ႇလပ်ႉဝႆႉ",
"sp-contributions-deleted": "လွင်ႈၶဝ်ႈႁူမ်ႈ {{GENDER:$1|ၽူႈၸႂ်ႉတိုဝ်း}} ဢၼ်မွတ်ႇဝႆႉ",
"watchlist-details": "{{PLURAL:$1|$1 n usebter|$1 n isebtar}} di tebdart-ik n uḍfaṛ (akked isebtar n usqerdec).",
"wlheader-showupdated": "Isebtar ttubeddlen segwasmi tkecmeḍ tikelt taneggarut ttbanen-d s uḍris <strong>aberbuz</strong>.",
"wlnote": "Ddaw-a {{PLURAL:$1|ad twaliḍ abeddel aneggaru yettwagen|ad twaliḍ <strong>$1</strong> n ibeddilen ineggura yettwagen}} deg {{PLURAL:$2| usrag aneggaru|di <strong>$2</strong> n yisragen ineggura}}, arama d $3, $4.",
- "wlshowlast": "Sken wid n $1 n isragen ineggura, wid n $2 n wussan ineggura",
"watchlist-submit": "Ssken",
"watchlist-options": "Iɣewwaṛen n tebdart n uḍfaṛ",
"enotif_reset": "Rcem akk isebtar mmeẓren",
"uctop": "amiran",
"month": "Seg uggur (d wid uqbel):",
"year": "Seg useggwas (d wid uqbel):",
- "sp-contributions-newbies": "Ssken tikkin n yimseqdacen imaynuten kan",
"sp-contributions-blocklog": "aɣmis n uɛeṭṭil",
"sp-contributions-uploads": "izdamen",
"sp-contributions-logs": "iɣmisen",
"apihelp": "API උදවු",
"apihelp-no-such-module": "ආකෘතිය \"$1\" හමුවුනේ නැත.",
"apisandbox": "API වැලිපිල්ල",
- "apisandbox-api-disabled": "මෙම අඩවියෙහි API අක්රීය කොට ඇත.",
"apisandbox-intro": "'''මාධ්යවිකි API''' සමඟ අත්හදා බැලීම සඳහා මෙම පිටුව භාවිතා කරන්න.\n\tAPI භාවිතය පිලිබඳ වැඩිදුර විස්තර සඳහා [https://www.mediawiki.org/wiki/API:Main_page API ප්රලේඛනය] හී ඉල්ලීමක් කරන්න.",
"apisandbox-submit": "අයදුමක් සිදු කරන්න",
"apisandbox-reset": "හිස් කරන්න",
"wlheader-enotif": "විද්යුත් තැපැල් දැනුම්දීම සක්රීයයි.",
"wlheader-showupdated": "ඔබ විසින් ඒවාට අවසන් වරට පිවිසුනු පසුව වෙනස්ව තිබෙන පිටු <strong>තදකුරු</strong> වලින් පෙන්වා ඇත.",
"wlnote": "පහත දැක්වෙන්නේ $3, $4 මෙන්, අවසන් {{PLURAL:$2|පැය|පැය '''$2''' }} තුලදී සිදු කෙරී ඇති {{PLURAL:$1|අවසන් වෙනස්වීම්යි |අවසන් වෙනස්වීම් '''$1''' යි}}.",
- "wlshowlast": "පසුගිය පැය $1 දින $2 පෙන්වන්න",
"watchlist-hide": "සඟවන්න",
"watchlist-submit": "පෙන්වන්න",
"wlshowhideminor": "සුළු සංස්කරණ",
"uctop": "වත්මන්",
"month": "මෙම මස (හා ඉන් පෙර) සිට:",
"year": "මෙම වසර (හා ඉන් පෙරාතුව) සිට:",
- "sp-contributions-newbies": "නව ගිණුම් වලට පමණක් අදාල දායකත්ව පෙන්වන්න",
- "sp-contributions-newbies-sub": "නව ගිණුම් වලට අදාල",
- "sp-contributions-newbies-title": "නව ගිණුම් වලට අදාල පරිශීලක දායකත්ව",
"sp-contributions-blocklog": "වාරණ සටහන",
"sp-contributions-deleted": "මකාදැමූ පරිශීලක දායකත්වයන්",
"sp-contributions-uploads": "උඩුගත කිරීම්",
"imgmultigoto": " $1 පිටුවට යන්න",
"img-lang-default": "(පෙරනිමි භාෂාව)",
"img-lang-go": "යන්න",
- "ascending_abbrev": "ආරෝහණ",
- "descending_abbrev": "අවරෝහණ",
"table_pager_next": "ඊළඟ පිටුව",
"table_pager_prev": "පෙර පිටුව",
"table_pager_first": "පළමු පිටුව",
"Matěj Suchánek",
"Vlad5250",
"Robert Važan",
- "Vegetator"
+ "Vegetator",
+ "Luky001"
]
},
"tog-underline": "Podčiarkovať odkazy:",
"virus-scanfailed": "kontrola zlyhala (kód $1)",
"virus-unknownscanner": "neznámy antivírus:",
"logouttext": "<strong>Práve ste sa odhlásili.</strong>\n\nUvedomte si, že niektoré stránky sa môžu naďalej zobrazovať ako keby ste boli prihlásený, až kým nevymažete vyrovnávaciu pamäť vášho prehliadača.",
- "logging-out-notify": "Prebieha vaše odhlásenie, prosím čekejte.",
+ "logging-out-notify": "Prebieha vaše odhlásenie, prosím, čakajte.",
"logout-failed": "Teraz nie je možné odhlásiť sa:$1",
"cannotlogoutnow-title": "Teraz nie je možné odhlásiť sa",
"cannotlogoutnow-text": "Nie je možné odhlásiť sa, keď používate $1",
"rcfilters-preference-help": "Zruší novú podobu rozhrania z roku 2017 a všetky nástroje odvtedy pridané.",
"rcfilters-watchlist-preference-label": "Skryť vylepšenú verziu sledovaných stránok",
"rcfilters-watchlist-preference-help": "Zruší novú podobu rozhrania z roku 2017 a všetky nástroje odvtedy pridané.",
+ "rcfilters-filter-showlinkedfrom-label": "Zobraziť zmeny stránok, na ktoré sa odkazuje",
+ "rcfilters-filter-showlinkedfrom-option-label": "<strong>Stránky odkazované z</strong> vybranej stránky",
+ "rcfilters-filter-showlinkedto-option-label": "<strong>Stránky odkazujúce na</strong> vybranú stránku",
"rcnotefrom": "Nižšie {{PLURAL:$5|je zobrazená úprava|sú zobrazené úpravy}} od <strong>$2</strong> (do <strong>$1</strong>).",
"rclistfromreset": "Obnoviť výber údajov",
"rclistfrom": "Zobraziť nové úpravy počnúc od $3 $2",
"apihelp-no-such-module": "Modul „$1” nebol nájdený.",
"apisandbox": "API pieskovisko",
"apisandbox-jsonly": "Na použitie pieskoviska API je nutný JavaScript.",
- "apisandbox-api-disabled": "API je na tejto stránke vypnuté.",
"apisandbox-intro": "Pomocou tejto stránky môžete experimentovať s <strong>API webovej služby MediaWiki</strong>.\nPodrobnosti využitia API nájdete v [[mw:API:Main page|jeho dokumentácii]]. Príklad: [https://www.mediawiki.org/wiki/API#A_simple_example získanie obsahu Hlavnej stránky]. Ďalšie príklady uvidíte vybraním operácie.\n\nUvedomte si, že napriek tomu, že ste na pieskovisku, môžu operácie vykonané na tejto stránke wiki zmeniť.",
"apisandbox-submit": "Odoslať dopyt",
"apisandbox-reset": "Vyčistiť",
"activeusers-intro": "Toto je zoznam používateľov, ktorí $1 {{PLURAL:$1|za posledný 1 deň|za posledné $1 dni|za posledných $1 dní}} vykonali nejakú aktivitu.",
"activeusers-count": "$1 {{PLURAL:$1|operácia|operácie|operácií}} za {{PLURAL:$3|posledný deň|posledné $3 dni|posledných $3 dní}}",
"activeusers-from": "Zobraziť používateľov počínajúc:",
+ "activeusers-groups": "Zobraziť používateľov patriacich do skupín:",
+ "activeusers-excludegroups": "Nezobrazovať používateľov patriacich do skupín:",
"activeusers-noresult": "Neboli nájdení žiadni používatelia.",
"activeusers-submit": "Zobraziť aktívnych používateľov",
"listgrouprights": "Práva skupín používateľov",
"wlheader-enotif": "Upozorňovanie e-mailom je zapnuté.",
"wlheader-showupdated": "Stránky, ktoré boli zmenené od vašej poslednej návštevy sú zobrazené '''tučne'''.",
"wlnote": "Nižšie {{PLURAL:$1|je posledná úprava|sú posledné <strong>$1</strong> úpravy|je posledných <strong>$1</strong> úprav}} za {{PLURAL:$2|poslednú hodinu|posledné <strong>$2</strong> hodiny|posledných <strong>$2</strong> hodín}} do $4, $3.",
- "wlshowlast": "Zobraziť posledných $1 hodín $2 dní",
"watchlist-hide": "Skryť",
"watchlist-submit": "Zobraziť",
"wlshowtime": "Obdobie:",
"uctop": "aktuálne",
"month": "Mesiac:",
"year": "Rok:",
- "sp-contributions-newbies": "Zobraziť len príspevky nových účtov",
- "sp-contributions-newbies-sub": "Príspevky nováčikov",
- "sp-contributions-newbies-title": "Príspevky nových používateľov",
"sp-contributions-blocklog": "záznam blokovaní",
"sp-contributions-suppresslog": "utajené príspevky {{GENDER:$1|používateľa|používateľky}}",
"sp-contributions-deleted": "zmazané príspevky {{GENDER:$1|používateľa|používateľky}}",
"img-lang-default": "(predvolený jazyk)",
"img-lang-info": "Vykresliť tento obrázok v jazyku $1 $2",
"img-lang-go": "Vykonať",
- "ascending_abbrev": "vzostupne",
- "descending_abbrev": "zostupne",
"table_pager_next": "Ďalšia stránka",
"table_pager_prev": "Predošlá stránka",
"table_pager_first": "Prvá stránka",
"watch": "اکھ تلے رکھو",
"unwatch": "اکھ ہیٹھوں ہٹاؤ",
"watchlist-details": "{{PLURAL:$1|$1 ورقہ ہے|$1 ورقے ہن}} تہاݙیاں نظراں ہیٹھ (تے ڳالھ مہاڑ آلے ورقے).",
- "wlshowlast": "ݙیکھاؤ چھیکڑی $1 گھنٹے $2 ݙینہ",
"watchlist-hide": "لُکاؤ",
"watchlist-submit": "ݙِکھاؤ",
"wlshowtime": "ظاہر تھیوݨ دی مدت:",
"uctop": "موجودہ",
"month": "مہینے توں (تے پہلاں):",
"year": "سال توں (تے پہلاں):",
- "sp-contributions-newbies": "صرف نویں ورتݨ آلیاں دے کم ݙکھاؤ",
"sp-contributions-blocklog": "پابندی دی لاڳ",
"sp-contributions-uploads": "اپلوڈ کردہ",
"sp-contributions-logs": "لاگز",
"apihelp-no-such-module": "Modula »$1« nismo našli.",
"apisandbox": "Peskovnik API",
"apisandbox-jsonly": "Za uporabo peskovnika API je zahtevan JavaScript.",
- "apisandbox-api-disabled": "API je onemogočen na tej spletni strani.",
"apisandbox-intro": "Uporabite to stran za preizkušanje <strong>API spletnih storitev MediaWiki</strong>.\nOglejte si [[mw:API:Main page|dokumentacijo API]] za nadaljnje podrobnosti o uporabi API. Primer: [https://www.mediawiki.org/wiki/API#A_simple_example pridobi vsebino Glavne strani]. Izberite dejanje, da si ogledate več primerov.\n\nPomnite, da čeprav je to peskovnik, bodo dejanja, izvedena na tej strani, morda spremenila wiki.",
"apisandbox-submit": "Izvedi zahtevo",
"apisandbox-reset": "Počisti",
"wlheader-enotif": "Obveščanje po elektronski pošti je omogočeno.",
"wlheader-showupdated": "Strani, spremenjene od vašega zadnjega ogleda, so prikazane '''krepko'''.",
"wlnote": "{{PLURAL:$1|Navedena je zadnja|Navedeni sta zadnji|Navedene so zadnje|Navedenih je zadnjih}} <strong>$1</strong> {{PLURAL:$1|sprememba|spremembi|spremembe|sprememb}} v {{PLURAL:$2|zadnji <strong>$2</strong> uri|zadnjih <strong>$2</strong> urah}}, od $3, $4.",
- "wlshowlast": "Prikaži zadnjih $1 ur; $2 dni",
"watchlist-hide": "Skrij",
"watchlist-submit": "Prikaži",
"wlshowtime": "Časovno obdobje za prikaz:",
"month": "Od meseca (in prej):",
"year": "Od leta (in prej):",
"date": "Od datuma (in prej):",
- "sp-contributions-newbies": "Prikaži samo prispevke novih računov",
- "sp-contributions-newbies-sub": "Prispevki novincev",
- "sp-contributions-newbies-title": "Uporabniški prispevki novih računov",
"sp-contributions-blocklog": "dnevnik blokiranja",
"sp-contributions-suppresslog": "zatrti {{GENDER:$1|uporabnikovi|uporabničini}} prispevki",
"sp-contributions-deleted": "izbrisani zatrti {{GENDER:$1|uporabnikovi|uporabničini}} prispevki",
"newimages-legend": "Filter",
"newimages-label": "Ime datoteke (ali njen del):",
"newimages-user": "IP-naslov ali uporabniško ime",
- "newimages-newbies": "Prikaži samo prispevke novih računov",
"newimages-showbots": "Prikaži nalaganja botov",
"newimages-hidepatrolled": "Skrij nadzorovana nalaganja",
"newimages-mediatype": "Vrsta predstavnosti:",
"img-lang-default": "(privzeti jezik)",
"img-lang-info": "Upodobi sliko v $1. $2",
"img-lang-go": "Pojdi",
- "ascending_abbrev": "nar",
- "descending_abbrev": "pad",
"table_pager_next": "Naslednja stran",
"table_pager_prev": "Prejšnja stran",
"table_pager_first": "Prva stran",
"wlheader-enotif": "Dar E-Mail-Benoachrichtigungsdienst ies aktiviert.",
"wlheader-showupdated": "Seyta miet noo ne gesehenen Änderunga waan '''fett''' dargestellt.",
"wlnote": "Is {{PLURAL:$1|folgt de letzte Änderung|folga de letzta '''$1''' Änderunga}} dar letzta {{PLURAL:$2|Stunde|'''$2''' Stunda}}.",
- "wlshowlast": "Zeige de Änneronga dar letzta $1 Stonda, $2 Taage oder .",
"watchlist-options": "Oazeegeoptiona",
"watching": "Beobachta …",
"unwatching": "Nee beobachta …",
"uctop": "aktuell",
"month": "on Moonat:",
"year": "bis Joahr:",
- "sp-contributions-newbies": "Zeige oack Beiträge neuer Benutzer",
- "sp-contributions-newbies-sub": "Fier Neulinge",
- "sp-contributions-newbies-title": "Nutzerbeiträge vu neua Nutzern",
"sp-contributions-blocklog": "Sperr-Logbuch",
"sp-contributions-deleted": "Geläschte Beiträge",
"sp-contributions-uploads": "Hochgeladene Dateien",
"imgmultipageprev": "← vurherige Seite",
"imgmultipagenext": "nächste Seite →",
"imgmultigoto": "Gieh zo Seite $1",
- "ascending_abbrev": "uff",
- "descending_abbrev": "oab",
"table_pager_next": "Nächste Seite",
"table_pager_prev": "Vurherige Seite",
"table_pager_first": "Erschte Seite",
"unwatch": "Ha waardiyeynin",
"unwatchthispage": "Jooji waardiyeyntiisa",
"watchlist-details": "{{PLURAL:$1|$1 bog|$1 boggag ah}} aa ku jirto liiskaaga waardiyaha, ma lagu darin boggaga wadahadalka.",
- "wlshowlast": "Itus wixii ka danbeeyay $1 saacadood $2 maalmood",
"watchlist-options": "Dooqyada liiska waardiyaha",
"watching": "Daawasho...",
"enotif_subject_created": "{{SITENAME}} Bogga $1 Qof ayaa sameeyey {{gender:$2|$2}}",
"uctop": "kor",
"month": "Bilaawga bisha (iyo wixii ka danbeeyay):",
"year": "Bilaawga sanadka (iyo wixii ka danbeeyay):",
- "sp-contributions-newbies": "Itus akoonada cusub kaliya oo wax ku darsaday",
"sp-contributions-blocklog": "mamnuucyada",
"sp-contributions-uploads": "wixii la soo geliyay",
"sp-contributions-logs": "Guda galayaasha",
"apihelp-no-such-module": "Moduli \"$1\" nuk u gjet.",
"apisandbox": "API livadhi",
"apisandbox-jsonly": "JavaScript është e domosdoshme që të përdorni API livadhi.",
- "apisandbox-api-disabled": "API nuk është në dispozicion për këtë faqe.",
"apisandbox-submit": "Bëj kërkesë",
"apisandbox-reset": "Pastro",
"apisandbox-retry": "Riprovo",
"wlheader-enotif": "Është aktivizuar njoftimi me email.",
"wlheader-showupdated": "Faqet që kanë ndryshuar nga vizita juaj e fundit do të tregohen të <strong>trasha</strong>.",
"wlnote": "Më poshtë {{PLURAL:$1|është ndryshimi i fundit|janë <strong>$1</strong>''' ndryshimet e fundit}} në {{PLURAL:$2|orën e fundit|<strong>$2</strong>''' orët e fundit}}, që nga $3, $4.",
- "wlshowlast": "Trego $1 orët $2 ditët e fundit",
"watchlist-hide": "Fshih",
"watchlist-submit": "Shfaq",
"wlshowtime": "Periudha e kohës për ta treguar:",
"uctop": "aktual",
"month": "Nga muaji (dhe më herët):",
"year": "Nga viti (dhe më herët):",
- "sp-contributions-newbies": "Trego vetëm redaktimet e llogarive të reja",
- "sp-contributions-newbies-sub": "Për newbies",
- "sp-contributions-newbies-title": "Kontributet e përdoruesit për kontot e reja",
"sp-contributions-blocklog": "Regjistri i bllokimeve",
"sp-contributions-suppresslog": "u fshehën kontributet e {{GENDER:$1|user}}",
"sp-contributions-deleted": "kontributet e grisura të {{GENDER:$1|user}}",
"newimages-legend": "Filtrues",
"newimages-label": "Emri i skedës (ose një pjesë e tij):",
"newimages-user": "Adresë IP ose emër përdoruesi",
- "newimages-newbies": "Trego vetëm redaktimet e llogarive të reja",
"newimages-showbots": "Trego ngarkimet nga robotët",
"newimages-hidepatrolled": "Fshih ngarkimet e patrolluara",
"newimages-mediatype": "Tipi i medias:",
"img-lang-default": "(gjuha e parazgjedhur)",
"img-lang-info": "Shfaqe këtë imazh në $1. $2",
"img-lang-go": "Shko",
- "ascending_abbrev": "ngritje",
- "descending_abbrev": "zbritje",
"table_pager_next": "Faqja tjetër",
"table_pager_prev": "Faqja e mëparshme",
"table_pager_first": "Faqja e parë",
"nocreate-loggedin": "Немате дозволу да правите нове странице.",
"sectioneditnotsupported-title": "Уређивање одељка није подржано",
"sectioneditnotsupported-text": "Уређивање одељка није подржано на овој страници.",
+ "modeleditnotsupported-title": "Уређивање није подржано",
+ "modeleditnotsupported-text": "Уређивање није подржано за модел садржаја $1.",
"permissionserrors": "Грешка у дозволи",
"permissionserrorstext": "Немате дозволу за ову радњу из {{PLURAL:$1|следећег|следећих}} разлога:",
"permissionserrorstext-withaction": "Немате дозволу да $2 из {{PLURAL:$1|следећег|следећих}} разлога:",
"content-model-json": "ЈСОН-а",
"content-json-empty-object": "Празан објекат",
"content-json-empty-array": "Празан низ",
+ "unsupported-content-model": "<strong>Упозорење:</strong> Модел садржаја $1 није подржан на овом викију.",
"deprecated-self-close-category": "Странице које користе невалидне самозатварајуће HTML тагове",
"duplicate-args-warning": "<strong>Упозорење:</strong> [[:$1]] позива [[:$2]] са више од једне вредности за параметар „$3“. Само последња наведена вредност ће бити коришћена.",
"duplicate-args-category": "Странице с дуплираним аргументима код позива шаблона",
"rcfilters-clear-all-filters": "Обришите све филтере",
"rcfilters-show-new-changes": "Нове промене од $1",
"rcfilters-search-placeholder": "Филтрирајте промене (користите мени или претражите име филтера)",
+ "rcfilters-search-placeholder-mobile": "Филтери",
"rcfilters-invalid-filter": "Неважећи филтер",
"rcfilters-empty-filter": "Нема активних филтера. Сви доприноси су приказани.",
"rcfilters-filterlist-title": "Филтери",
"rcfilters-filter-showlinkedto-label": "Прикажи промене на страницама ка којима воде везе",
"rcfilters-filter-showlinkedto-option-label": "<strong>Странице ка којима воде везе са</strong> изабране странице",
"rcfilters-target-page-placeholder": "Унесите име странице (или категорије)",
+ "rcfilters-allcontents-label": "Сви садржаји",
+ "rcfilters-alldiscussions-label": "Све дискусије",
"rcnotefrom": "Испод {{PLURAL:$5|је промена|су промене}} од <strong>$3, $4</strong> (до <strong>$1</strong> приказано).",
"rclistfromreset": "Ресетуј избор датума",
"rclistfrom": "Прикажи нове промене почев од $2, $3",
"apihelp-no-such-module": "Модул „$1“ није пронађен.",
"apisandbox": "API песак",
"apisandbox-jsonly": "Јаваскрипт је неопходан за коришћење АПИ песка.",
- "apisandbox-api-disabled": "АПИ је онемогућен на овом сајту.",
"apisandbox-submit": "Пошаљи захтев",
"apisandbox-reset": "Обриши",
"apisandbox-retry": "Покушај поново",
"wlheader-enotif": "Обавештавање е-поруком је омогућено.",
"wlheader-showupdated": "Странице које су промењене откад сте их последњи пут посетили су <strong>подебљане</strong>.",
"wlnote": "Испод {{PLURAL:$1|је последња промена|су последње <strong>$1</strong> промене|је последњих <strong>$1</strong> промена}} у {{PLURAL:$2|претходном сату|претходна <strong>$2</strong> сата|претходних <strong>$2</strong> сати}}, закључно са $3, $4.",
- "wlshowlast": "Прикажи последњих $1 сати, $2 дана",
"watchlist-hide": "Сакриј",
"watchlist-submit": "Прикажи",
"wlshowtime": "Период за приказ:",
"sessionfailure": "Изгледа да постоји проблем с вашом сесијом;\nова радња је отказана да би се избегла злоупотреба.\nМолимо, поново пошаљите образац.",
"changecontentmodel": "Промена модела садржаја странице",
"changecontentmodel-legend": "Промени модел садржаја",
- "changecontentmodel-title-label": "Наслов странице",
- "changecontentmodel-model-label": "Нови модел садржаја",
+ "changecontentmodel-title-label": "Наслов странице:",
+ "changecontentmodel-current-label": "Тренутни модел садржаја:",
+ "changecontentmodel-model-label": "Нови модел садржаја:",
"changecontentmodel-reason-label": "Разлог:",
"changecontentmodel-submit": "Промени",
"changecontentmodel-success-title": "Модел садржаја је промењен",
"month": "од месеца (и раније):",
"year": "од године (и раније):",
"date": "Од датума (и раније):",
- "sp-contributions-newbies": "Прикажи само доприносе нових налога",
- "sp-contributions-newbies-sub": "За нове кориснике",
- "sp-contributions-newbies-title": "Доприноси нових корисника",
"sp-contributions-blocklog": "дневник блокирања",
"sp-contributions-suppresslog": "избрисани доприноси {{GENDER:$1|корисника|кориснице}}",
"sp-contributions-deleted": "избрисани доприноси {{GENDER:$1|корисника|кориснице}}",
"move-subpages": "Премести и подстранице (до $1)",
"move-talk-subpages": "Премести подстранице странице за разговор (до $1)",
"movepage-page-exists": "Страница $1 већ постоји и не може се заменити.",
+ "movepage-source-doesnt-exist": "Страница $1 не постоји и не може бити премештена.",
"movepage-page-moved": "Страница $1 је премештена на $2.",
"movepage-page-unmoved": "Страница $1 не може да се премести на $2.",
"movepage-max-pages": "Највише $1 {{PLURAL:$1|страница је премештена|странице су премештене|страница је премештено}} и више не може да буде аутоматски премештено.",
"delete_and_move_reason": "Избрисано да се ослободи место за премештање из „[[$1]]“",
"selfmove": "Наслов је истоветан;\nне можете преместити страницу преко саме себе.",
"immobile-source-namespace": "Не могу преместити странице у именски простор „$1“.",
+ "immobile-source-namespace-iw": "Странице на осталим викијима не могу бити премештене са овог викија.",
"immobile-target-namespace": "Не могу преместити странице у именски простор „$1“.",
"immobile-target-namespace-iw": "Међувики веза није важеће одредиште за премештање странице.",
"immobile-source-page": "Ова страница се не може преместити.",
"immobile-target-page": "Премештање није могуће на одредишни наслов.",
+ "movepage-invalid-target-title": "Тражено име није ваљано.",
"bad-target-model": "Жељено одредиште користи други модел садржаја. Није могуће конвертовати из $1 у садржај $2.",
"imagenocrossnamespace": "Датотека се не може преместити у именски простор који не припада датотекама.",
"nonfile-cannot-move-to-file": "Не-датотеке не можете преместити у именски простор за датотеке",
"newimages-legend": "Филтер",
"newimages-label": "Назив датотеке (или њен део):",
"newimages-user": "IP адреса или корисничко име",
- "newimages-newbies": "Прикажи само доприносе нових налога",
"newimages-showbots": "Прикажи отпремања ботова",
"newimages-hidepatrolled": "Сакриј патролирана отпремања",
"newimages-mediatype": "Врста медијума:",
"img-lang-default": "(подразумевани језик)",
"img-lang-info": "Рендеруј ову слику у $1. $2",
"img-lang-go": "Иди",
- "ascending_abbrev": "раст.",
- "descending_abbrev": "опад.",
"table_pager_next": "Следећа страница",
"table_pager_prev": "Претходна страница",
"table_pager_first": "Прва страница",
"permanentlink": "Трајна веза",
"permanentlink-revid": "ID измене",
"permanentlink-submit": "Пређи на измену",
+ "newsection": "Нови одељак",
+ "newsection-page": "Одредишна страница",
+ "newsection-submit": "Иди на страницу",
"dberr-problems": "Дошло је до техничких проблема.",
"dberr-again": "Сачекајте неколико минута и поново учитајте страницу.",
"dberr-info": "(Не могу приступити бази података: $1)",
"apihelp-no-such-module": "Modul „$1“ nije pronađen.",
"apisandbox": "API pesak",
"apisandbox-jsonly": "JavaScript je neophodan za korišćenje API peska.",
- "apisandbox-api-disabled": "API je onemogućen na ovom sajtu.",
"apisandbox-submit": "Pošalji zahtev",
"apisandbox-reset": "Obriši",
"apisandbox-retry": "Pokušaj ponovo",
"wlheader-enotif": "Obaveštavanje e-porukom je omogućeno.",
"wlheader-showupdated": "Stranice koje su promenjene otkad ste ih poslednji put posetili su <strong>podebljane</strong>.",
"wlnote": "Ispod {{PLURAL:$1|je poslednja promena|su poslednje <strong>$1</strong> promene|je poslednjih <strong>$1</strong> promena}} u {{PLURAL:$2|prethodnom satu|prethodna <strong>$2</strong> sata|prethodnih <strong>$2</strong> sati}}, zaključno sa $3, $4.",
- "wlshowlast": "Prikaži poslednjih $1 sati, $2 dana",
"watchlist-hide": "Sakrij",
"watchlist-submit": "Prikaži",
"wlshowtime": "Period za prikaz:",
"month": "od meseca (i ranije):",
"year": "od godine (i ranije):",
"date": "Od datuma (i ranije):",
- "sp-contributions-newbies": "Prikaži samo doprinose novih naloga",
- "sp-contributions-newbies-sub": "Za nove korisnike",
- "sp-contributions-newbies-title": "Doprinosi novih korisnika",
"sp-contributions-blocklog": "dnevnik blokiranja",
"sp-contributions-suppresslog": "izbrisani doprinosi {{GENDER:$1|korisnika|korisnice}}",
"sp-contributions-deleted": "izbrisani doprinosi {{GENDER:$1|korisnika|korisnice}}",
"newimages-legend": "Filter",
"newimages-label": "Naziv datoteke (ili njen deo):",
"newimages-user": "IP adresa ili korisničko ime",
- "newimages-newbies": "Prikaži samo doprinose novih naloga",
"newimages-showbots": "Prikaži otpremanja botova",
"newimages-hidepatrolled": "Sakrij patrolirana otpremanja",
"newimages-mediatype": "Tip medija:",
"img-lang-default": "(podrazumevani jezik)",
"img-lang-info": "Renderuj ovu sliku u $1. $2",
"img-lang-go": "Idi",
- "ascending_abbrev": "rast.",
- "descending_abbrev": "opad.",
"table_pager_next": "Sledeća stranica",
"table_pager_prev": "Prethodna stranica",
"table_pager_first": "Prva stranica",
"watchthispage": "Tan luku a papira disi",
"unwatch": "No tan luku",
"watchlist-details": "{{PLURAL:$1|Wan papira|$1 papira}} de ini yu Tan Luku réy, sondro fu teri den kruderi papira.",
- "wlshowlast": "Sori laste $1 yuru, $2 dey ()",
"watching": "A wiki e poti a papira disi ini yu Tan Luku...",
"unwatching": "A wiki e puru a papira disi fu yu Tan Luku...",
"deletepage": "Disi papira trowe",
"uctop": "a moro nyun kenki",
"month": "Fu a mun (nanga moro owru):",
"year": "Fu a yari (nanga moro owru):",
- "sp-contributions-newbies-sub": "Gi nyun account",
"sp-contributions-blocklog": "Log buku fu den tapu pasi",
"sp-contributions-deleted": "Trowe kenki fu masyin",
"sp-contributions-talk": "Taki",
"monthsall": "ala",
"confirm_purge_button": "oki",
"imgmultigo": "Go!",
- "ascending_abbrev": "opo.",
- "descending_abbrev": "afo.",
"table_pager_limit_submit": "Go",
"autosumm-new": "Nyon papira: $1",
"watchlisttools-view": "Sori Tan Luku réy",
"wlheader-enotif": "E-Mail-Beskeed is aktivierd.",
"wlheader-showupdated": "Sieden, do ätter dien lääste Besäik annerd wuuden sunt, wäide '''fat''' deerstoald.",
"wlnote": "Hier {{PLURAL:$1|foulget do lääste Annerenge|foulgje do lääste '''$1''' Annerengen}} fon do lääste {{PLURAL:$2|Uur|'''$2''' Uuren}}.",
- "wlshowlast": "Wies do lääste $1 Uuren, $2 Deege, of (in do lääste 30 Deege).",
"watchlist-options": "Anwiesoptione",
"watching": "Beooboachtje …",
"unwatching": "Nit beooboachtje …",
"uctop": "aktuäl",
"month": "un Mound:",
"year": "bit Jier:",
- "sp-contributions-newbies": "Wies bloot Biedraage fon näie Benutsere",
- "sp-contributions-newbies-sub": "Foar Näilinge",
- "sp-contributions-newbies-title": "Benutserbiedraage fon näie Benutsere",
"sp-contributions-blocklog": "Speerlogbouk",
"sp-contributions-deleted": "Läskede Benutserbiedraage",
"sp-contributions-uploads": "Hoochleedene Doatäie",
"imgmultipagenext": "naiste Siede →",
"imgmultigo": "OK",
"imgmultigoto": "Gung tou Siede $1",
- "ascending_abbrev": "ap",
- "descending_abbrev": "fon",
"table_pager_next": "Naiste Siede",
"table_pager_prev": "Foarige Siede",
"table_pager_first": "Eerste Siede",
"watchlist-details": "Көсәтеү күцермәлегегестә, уйлап ҡарау питләрне исәпләмәйен, {{PLURAL:$1|$1 пит}} пар.",
"wlheader-showupdated": "Сеснең суңҡы пашҡартыулартан суң пашҡарған питләр <strong>ҡалын</strong> шрифт пелән күргәселгән.",
"wlnote": "Түмәнтә $3 $4 уаҡытта суңҡы {{PLURAL:$2|1=сәғәт|$2 сәғәт}} эцтә эшләнкән {{PLURAL:$1|1=пашҡартыу|$1пашҡартыулар}} күргәселгән.",
- "wlshowlast": "Суңҡы $1 сәғәт $2 көн эцентәгесен күргәскәле",
"watchlist-options": "Көсәтеү күцермәлекнең ҡоролошлары",
"enotif_reset": "Пөтөн питләрне ҡаралған тип пилгеләгәле",
"dellogpage": "Уйыуларның журналы",
"uctop": "ҡәсерге",
"month": "Айтан пашлап (анан алттараҡ та):",
"year": "Йылтан пашлап (анан алттараҡ та):",
- "sp-contributions-newbies": "Йаңа исәп йасмалартан ҡылынҡан эшне генә күргәскәле",
"sp-contributions-blocklog": "тыйыулар",
"sp-contributions-uploads": "төйәүләр",
"sp-contributions-logs": "журналлар",
"apihelp-no-such-module": "Modul \"$1\" teu kapanggih.",
"apisandbox": "Kotrétan API",
"apisandbox-jsonly": "JavaScript diperlukeun pikeun maké kotrétan API.",
- "apisandbox-api-disabled": "API dipareuman dina ieu situs.",
"apisandbox-submit": "Jieun pundutan",
"apisandbox-reset": "Bersihan",
"apisandbox-retry": "Cobaan deui",
"wlheader-enotif": "Iber surélék diaktifkeun.",
"wlheader-showupdated": "Kaca nu robah ti panungtungan anjeun sindang ditémbongkeun <strong>kandel</strong>.",
"wlnote": "Di handap ieu mangrupa {{PLURAL:$1|robahan|robahan}} <strong>$1</strong> panungtung salila {{PLURAL:$2|jam|<strong>$2</strong> jam}}, ti $3, $4.",
- "wlshowlast": "Témbongkeun $1 jam $2 poé panungtung",
"watchlist-hide": "Sumputkeun",
"watchlist-submit": "Témbongkeun",
"wlshowtime": "Periodeu waktu ajang dipidangkeun:",
"uctop": "ayeuna",
"month": "Ti bulan (jeung saméméhna):",
"year": "Ti taun (jeung saméméhna):",
- "sp-contributions-newbies": "Témbongkeun kontribusi ti akun anyar wungkul",
- "sp-contributions-newbies-sub": "Pikeun akun anyar",
- "sp-contributions-newbies-title": "Kontribusi pamaké pikeun akun anyar",
"sp-contributions-blocklog": "log peungpeuk",
"sp-contributions-suppresslog": "kontribusi {{GENDER:$1|pamaké}} nu disamunikeun",
"sp-contributions-deleted": "kontribusi {{GENDER:$1|pamaké}} nu dipupus",
"newimages-legend": "Saringan",
"newimages-label": "Ngaran berkas (atawa sawaréh tina ngaranna):",
"newimages-user": "Alamat IP atawa sandiasma",
- "newimages-newbies": "Témbongkeun kontribusi ti akun anyar wungkul",
"newimages-showbots": "Témbongkeun unjalan ku bot",
"newimages-hidepatrolled": "Sumputkeun unjalan nu geus diriksa",
"newimages-mediatype": "Tipeu média:",
"img-lang-default": "(basa default)",
"img-lang-info": "Jadikeun ieu gambar dina $1. $2",
"img-lang-go": "Jung",
- "ascending_abbrev": "naék",
- "descending_abbrev": "turun",
"table_pager_next": "Kaca salajengna",
"table_pager_prev": "Kaca saacana",
"table_pager_first": "Kaca mimiti",
"apihelp-no-such-module": "Modulen ”$1” hittades inte",
"apisandbox": "API-sandlåda",
"apisandbox-jsonly": "JavaScript krävs för att använda API-sandlådan.",
- "apisandbox-api-disabled": "API är inaktiverat på denna webbplats.",
"apisandbox-intro": "Använd den här sidan för att experimentera med <strong>MediaWikis API för webbtjänster</strong>.\nSe [[mw:API:Main page|API-dokumentationen]] för ytterligare detaljer kring API-användningen. Exempel: [https://www.mediawiki.org/wiki/API#A_simple_example få innehållet från en huvudsida]. Välj en handling för att se fler exempel.\n\nObservera att även om detta är en sandlåda kan handlingar du utför på denna sida påverka wikin.",
"apisandbox-submit": "Utför begäran",
"apisandbox-reset": "Rensa",
"wlheader-enotif": "E-postmeddelanden är aktiverade.",
"wlheader-showupdated": "Sidor som har ändrats sedan ditt senaste besök visas i '''fetstil.'''",
"wlnote": "Nedan finns {{PLURAL:$1|den senaste ändringen|de senaste <strong>$1</strong> ändringarna}} under {{PLURAL:$2|den senaste timmen|de senaste <strong>$2</strong> timmarna}} från den $3 kl. $4.",
- "wlshowlast": "Visa senaste $1 timmarna $2 dygnen",
"watchlist-hide": "Dölj",
"watchlist-submit": "Visa",
"wlshowtime": "Tidsperiod att visa:",
"month": "Från månad (och tidigare):",
"year": "Från år (och tidigare):",
"date": "Från datum (och tidigare):",
- "sp-contributions-newbies": "Visa endast bidrag från nya konton",
- "sp-contributions-newbies-sub": "Från nya konton",
- "sp-contributions-newbies-title": "Bidrag från nya konton",
"sp-contributions-blocklog": "blockeringslogg",
"sp-contributions-suppresslog": "censurerade {{GENDER:$1|användarbidrag}}",
"sp-contributions-deleted": "raderade {{GENDER:$1|användarbidrag}}",
"newimages-legend": "Filter",
"newimages-label": "Filnamn (eller en del av det):",
"newimages-user": "IP-adress eller användarnamn",
- "newimages-newbies": "Visa endast bidrag från nya konton",
"newimages-showbots": "Visa uppladdningar av botar",
"newimages-hidepatrolled": "Dölj patrullerade uppladdningar",
"newimages-mediatype": "Mediatyp:",
"img-lang-default": "(standardspråk)",
"img-lang-info": "Rendera denna bild i $1. $2",
"img-lang-go": "Gå",
- "ascending_abbrev": "stigande",
- "descending_abbrev": "fallande",
"table_pager_next": "Nästa sida",
"table_pager_prev": "Föregående sida",
"table_pager_first": "Första sidan",
"wlheader-enotif": "Huduma ya kuarifu kwa barua-pepe imewezeshwa.",
"wlheader-showupdated": "Kurasa zilizobadilika tangu ulivyotembelea mara ya mwisho zinaonyeshwa <strong>bold</strong>.",
"wlnote": "{{PLURAL:$1|is the last change|Mabadiliko '''$1''' ya}} mwisho katika {{PLURAL:$2|hour|masaa '''$2''' yaliyopita yanaonyeshwa}} chini, ilivyokuwa saa $4, tarehe $3.",
- "wlshowlast": "Onyesha kutoka masaa $1 siku $2",
"watchlist-hide": "Ficha",
"watchlist-submit": "Onyesha",
"wlshowhideminor": "mabadiliko madogo",
"uctop": "ya kisasa",
"month": "Kutoka mwezi (na zamani zaidi):",
"year": "Kutoka mwakani (na zamani zaidi):",
- "sp-contributions-newbies": "Onyesha michango ya akaunti mpya tu",
- "sp-contributions-newbies-sub": "Kwa akaunti mpya",
- "sp-contributions-newbies-title": "Michango ya watumiaji wenye akaunti mpya",
"sp-contributions-blocklog": "Kumbukumbu ya uzuio",
"sp-contributions-deleted": "michango iliyofutwa ya mtumiaji",
"sp-contributions-uploads": "vipakizaji",
"imgmultigo": "Nenda!",
"imgmultigoto": "Uende kwenye ukurasa wa $1",
"img-lang-go": "Enda",
- "ascending_abbrev": "pand",
- "descending_abbrev": "shuk",
"table_pager_next": "Ukurasa ujao",
"table_pager_prev": "Ukurasa uliotangulia",
"table_pager_first": "Ukurasa wa kwanza",
"tog-watchlisthideown": "Schow moje pomjyńańa we artiklach, na kere dowom pozůr",
"tog-watchlisthidebots": "Schow pomjyńańa sprowjone bez boty we artiklach, na kere dowom pozůr",
"tog-watchlisthideminor": "Schow ńywjelge pomjyńańa w artiklach, na kere dowom pozůr",
- "tog-watchlisthideliu": "Schow sprowjyńo zalůgowanych sprowjaczy na pozorliśće",
+ "tog-watchlisthideliu": "Skryj edycyje ôd zalogowanych używŏczōw we ôbserwowanych",
"tog-watchlisthideanons": "Schow sprowjyńa anůńimowych sprowjoczy na liśće artikli, na kere dowom pozůr",
"tog-watchlisthidepatrolled": "Schowej sprowdzůne sprowjyńa na pozorliśće",
"tog-ccmeonemails": "Przesyłej mi kopje e-brifůw co żech je posłoł inkszym sprowjaczom",
"portal-url": "Project:Portal społeczności",
"privacy": "Prawidła chrōniyniŏ prywatności",
"privacypage": "Project:Prawidła chrōniyniŏ prywatności",
- "badaccess": "Felerne uprawńyńo",
+ "badaccess": "Felerne uprawniynia",
"badaccess-group0": "Ńy mosz uprawńyń coby wykůnać ta uoperacyjo.",
"badaccess-groups": "Ta uoperacyjo mogům wykůnać ino użytkownicy ze keryjś z {{PLURAL:$2|grupy|grup}}: $1.",
"versionrequired": "Wymagano MediaWiki we wersyji $1",
"toc": "Wykŏz treści",
"showtoc": "uobejrzij",
"hidetoc": "schrůń",
- "collapsible-collapse": "Zwjyń",
- "collapsible-expand": "Rozwjyń",
+ "collapsible-collapse": "Skryj",
+ "collapsible-expand": "Pokŏż",
"thisisdeleted": "Pokoż/wćepej nazod $1",
"viewdeleted": "Uobejrzij $1",
"restorelink": "{{PLURAL:$1|jedna wyćepano wersyjo|$1 wyćepane wersyje|$1 wyćepanych wersyjůw}}",
"parser-template-recursion-depth-warning": "Przekroczůno limit głymbokośći rekurencyji mustru ($1)",
"undo-success": "Sprowjyńy zostoło wycofane. Prosza pomjarkować ukozane půniżyj dyferencyje mjyndzy wersyjůma, coby zweryfikować jejich poprawność, potym zaś naszkryflać pomjyńańo coby zakończyć uoperacyjo.",
"undo-failure": "Ta edycyjŏ niy może być cŏfniyntŏ skuli kōnfliktu ze wersyjami postrzednimi.",
- "undo-norev": "Sprowjyńo ńy idźe cofnůńć skuli tego, co ńy istńije abo uostoło wyćepane.",
+ "undo-norev": "Edycyje niy idzie cŏfnōńć, bo ôna niy istniyje abo była wyciepniyntŏ.",
"undo-summary": "Wycůfańy wersyji $1 naszkryflanej bez [[Special:Contributions/$2|$2]] ([[User talk:$2|godka]])",
"cantcreateaccount-text": "Tworzyńy kůnta s tygo adresu IP ('''$1''') uostoło zawarte bez użytkowńika [[User:$3|$3]].\n\nSkuli: ''$2''",
"viewpagelogs": "Ôbejzdrz regesty dlŏ tyj strōny",
"mergehistory-box": "Skupluj gyszichta sprowjyń dwůch zajtůw:",
"mergehistory-from": "Zdrzůdłowo zajta:",
"mergehistory-into": "Zajta docelowo:",
- "mergehistory-list": "Gyszichta půmjyńań do śe skuplować",
+ "mergehistory-list": "Historyjõ edycyji idzie scalić",
"mergehistory-merge": "Nastympujůnce půmjyńyńo zajty [[:$1]] idźe scalić s [[:$2]]. Uoznocz we kolůmńy kropkům kero zmjana, wroz ze wcześńijszymi, mo być scalůno. Użyće linkůw uod nawigacyji kasuje wybůr we kolůmńy.",
"mergehistory-go": "Pokoż půmjyńańo kere idźe scalić",
"mergehistory-submit": "Scal historyjo půmjyńań",
"mergehistory-empty": "Ńy mo historyje zmjan do scalyńo.",
"mergehistory-done": "$3 {{PLURAL:$3|pomjyńańe|pomjyńańa|pomjyńań}} we $1 ze sukcesym uostało scalonych ze [[:$2]].",
- "mergehistory-fail": "Ńy idźe scalić historyje půmjyńań. Zmjyń sztalowańo parametrůw tyj uoperacyji.",
+ "mergehistory-fail": "Niy idzie scalić historyji. Wejzdrzij na parametry strōny i czasu.",
"mergehistory-no-source": "Ńy ma sam zajty zdrzůdłowyj $1.",
"mergehistory-no-destination": "Ńy ma sam zajty docelowyj $1.",
"mergehistory-invalid-source": "Zajta zdrzůdłowo muśi mjeć poprawne mjano.",
"mergehistory-reason": "Kůmyntorz:",
"mergelog": "Regest scalyń",
"revertmerge": "Uodkupluj",
- "mergelogpagetext": "Půńiżyj je lista uostatńich kuplowań historyji půmjyńań zajtůw.",
+ "mergelogpagetext": "Niżyj je wykŏz ôstatnich scalyń jednyj historyje strōny ze inkszōm.",
"history-title": "Historyjŏ wersyji strōny „$1”",
"difference-title": "$1: Porōwnanie wersyji",
"difference-multipage": "(Porůwnańy zajt)",
"right-noratelimit": "Ńy mo uograńičyń přepustowośći",
"right-import": "Import zajtůw s inkšych Wiki",
"right-importupload": "Import zajtůw ze wćepanygo plika",
- "right-patrol": "Uoznocz sprowjyńo kej przezdrzane",
+ "right-patrol": "Ôznŏcz edycyje za przejzdrzane",
"right-autopatrol": "Naštaluj na autůmatyčne uoznačańy sprowjyń kej přezdřane",
"right-patrolmarks": "Podglůnd značnikůw patrolowańo pomjeńanych na uostatku – uoznačańo kej „sprawdzůne”",
"right-unwatchedpages": "Pokož lista zajtůw na kere žodyn ńy dowo pozoru",
"right-mergehistory": "Pouůnč historyjo sprowjyń do zajtůw",
- "right-userrights": "Sprowjej wšyjske uprawńyńo užytkowńikůw",
- "right-userrights-interwiki": "Sprowjej uprawńyńo užytkowńikůw na zajtach inkšych Wiki",
+ "right-userrights": "Edytuj uprawniynia wszyjskich używŏczōw",
+ "right-userrights-interwiki": "Edytuj uprawniynia używŏczōw na inkszych wiki",
"right-siteadmin": "Zawjerańy i uodmykańy bazy danych",
"newuserlogpage": "Ksiōnżka nowych używŏczōw",
"newuserlogpagetext": "To je rejer uostatńo utworzůnych kůnt użytkowńikůw",
"action-createpage": "tworzyńo zajtůw",
"action-createtalk": "tworzyńo zajtůw godki",
"action-createaccount": "stworzynie tego kōnta używŏcza",
- "action-minoredit": "do uoznačyńo tygo sprowjyńo kej drobne půmjyńańe",
+ "action-minoredit": "ôznaczynie tyj edycyje za małõ",
"action-move": "přećepańe tyj zajty",
"action-move-subpages": "přećepańo tyj zajty uoroz s jeij podzajtůma",
"action-move-rootuserpages": "Překludzańy zajtůw uod užytkowńikůw (nale bes jeich podzajtůw)",
"action-suppressrevision": "podglůndu a wćepańo nazod tyj wersyje schrůńůnyj",
"action-suppressionlog": "podglůndu rejera schrůńańo",
"action-block": "zawarća uod sprowjyń tygo spowjořa",
- "action-protect": "půmjyńań poźůmu zawarćo tyj zajty",
+ "action-protect": "zmiany poziōmōw zabezpieczyń na tyj strōnie",
"action-import": "importu tyj zajty s inkšyj wiki",
"action-importupload": "importu tyj zajty bez wćepańe plika",
- "action-patrol": "označyńo sprowjyńo kej „sprowdzůne”",
- "action-autopatrol": "uoznačyńo wuasnygo sprowjyńo kej „sprawdzonygo”",
+ "action-patrol": "ôznaczynie edycyje za sprawdzōnõ",
+ "action-autopatrol": "ôznaczynie włŏsnyj edycyje za przejzdrzanõ",
"action-unwatchedpages": "podglůndu listy zajtůw na kere ńikt ńy dowo pozoru",
"action-mergehistory": "skuplowańo historyje sprowjyń tyj zajty",
"action-userrights": "sprowjańo uprowńyń wszyjstkich sprowjorzy",
"recentchanges-legend": "Ôpcyje ôstatnich zmian",
"recentchanges-summary": "Na tyj strōnie idzie śledzić ôstatnie zmiany na wiki.",
"recentchanges-noresult": "Żŏdne zmiany we podanym ôkresie niy pasujōm tym kryteriōm.",
- "recentchanges-feed-description": "Dowej pozůr na půmjyÅ\84ane na uostatku na tyj wiki.",
+ "recentchanges-feed-description": "Dowej pozÅ\8dr na ôstatnie zmiany na tyj wiki.",
"recentchanges-label-newpage": "Ta edycyjŏ stworziła nowõ strōnã",
"recentchanges-label-minor": "To je małŏ zmiana",
"recentchanges-label-bot": "To je zmiana zrobiōnŏ ôd bota",
"recentchanges-label-plusminus": "Strōna zmiyniyła srogość ô tela bajtōw",
"recentchanges-legend-heading": "<strong>Legynda:</strong>",
"recentchanges-legend-newpage": "{{int:recentchanges-label-newpage}} (ôbejzdrzij tyż [[Special:NewPages|listã nowych strōn]])",
+ "rcfilters-other-review-tools": "Inksze nŏrzyńdzia kōntrole",
+ "rcfilters-filter-humans-label": "Czowiek (niy bot)",
+ "rcfilters-liveupdates-button": "Aktualizacyje na żywo",
+ "rcfilters-liveupdates-button-title-on": "Zastŏw aktualizacyje na żywo",
"rcnotefrom": "Niżyj {{PLURAL:$5|je zmiana|sōm zmiany}} ôd <strong>$3, $4</strong> ({{PLURAL:$5|je pokŏzanŏ|sōm pokŏzane}} nojwyżyj <strong>$1</strong>).",
"rclistfrom": "Pokŏż zmiany ôd $3 $2",
"rcshowhideminor": "$1 małe zmiany",
"listusers-submit": "Uobejrzij",
"listusers-noresult": "Ńy znejdźůno žodnygo užytkowńika.",
"activeusers-noresult": "Niy szło znŏjść żŏdnych używŏczōw",
- "listgrouprights": "Uprawńyńo grup użytkowńikůw",
- "listgrouprights-summary": "Půńiży znojdowo śe spis grup użytkowńikůw zdefińjowanych na tyj wiki, s wyszczygůlńyńym przidźelůnych im prow dostympu.\nSprowdź zajta [[{{MediaWiki:Listgrouprights-helppage}}|s dodatkowymi informacjami]] uo uprowńyńach użytkowńikůw.",
+ "listgrouprights": "Uprawniynia grup używŏczōw",
+ "listgrouprights-summary": "Niżyj widać wykŏz grup używŏczōw zdefiniowanych na tyj wiki, społym ze jejich prawami dostympu.\n[[{{MediaWiki:Listgrouprights-helppage}}|Ekstra informacyje]] ô uprawniyniach.",
"listgrouprights-key": "* <span class=\"listgrouprights-granted\">Dane uprawńyńy</span>\n* <span class=\"listgrouprights-revoked\">Uodebrane uprawńyńy</span>",
"listgrouprights-group": "Grupa",
- "listgrouprights-rights": "Uprawńyńo",
+ "listgrouprights-rights": "Uprawniynia",
"listgrouprights-helppage": "Help:Uprawńyńo grup użytkowńikůw",
"listgrouprights-members": "(lista czōnkōw grupy)",
"listgrouprights-addgroup": "Idźe dodać do {{PLURAL:$2|grupy|grup}}: $1",
"wlheader-enotif": "Wysůuańy powjadůmjyń na adres e-brif je zouůnčůne",
"wlheader-showupdated": "Zajty, co były zmiyniane ôd twojij ôstatnij nŏwiydzki na nich ôstały ukŏzane <strong>na rubo</strong>.",
"wlnote": "Niżyj {{PLURAL:$1|je ôstaniŏ zmiana|sōm ôstatnie <strong>$1</strong> zmiany|je ôstatnie <strong>$1</strong> zmian}} ze {{PLURAL:$2|ôstatnij godziny|ôstatnich <strong>$2</strong> godzin}}, na $3, $4.",
- "wlshowlast": "Pokŏż ôstatnie $1 godzin $2 dni",
"watchlist-options": "Ôpcyje ôbserwowanych",
"watching": "Dowom pozor...",
"unwatching": "Ńy dowům pozůr.",
"rollback": "Wycofej sprowjyńe",
"rollbacklink": "cŏfej",
"rollbacklinkcount": "cŏfnij $1 {{PLURAL:$1|edycyjõ|edycyje|edycyji}}",
- "rollbackfailed": "Ńy idźe wycofać sprowjyńo",
+ "rollbackfailed": "Niy szło wycŏfać zmiany",
"cantrollback": "Ńy idże cofnůńć pomjyńyńo, sam je ino jedna wersyja tyi zajty.",
"alreadyrolled": "Ńy idźe lů zajty [[:$1|$1]] cofnůńć uostatńygo pomjyńeńa, kere wykonoł [[User:$2|$2]] ([[User talk:$2|godka]]{{int:pipe-separator}}[[Special:Contributions/$2|{{int:contribslink}}]]).\nKto inkszy zdůnżůł już to zrobić abo wprowadźił własne poprowki do treśći zajty.\n\nAutorym ostatńygo pomjyńyńo je terozki [[User:$3|$3]] ([[User talk:$3|godka]]{{int:pipe-separator}}[[Special:Contributions/$3|{{int:contribslink}}]]).",
"editcomment": "Sprowjyńe uopisano: <em>$1</em>.",
"uctop": "terŏźnŏ",
"month": "Do miesiōnca:",
"year": "Do roku:",
- "sp-contributions-newbies": "Pokŏż ino wkłŏd ôd nowych kōnt",
- "sp-contributions-newbies-sub": "Dlo nowych užytkowńikůw",
- "sp-contributions-newbies-title": "Wkłod nowych użytkowńików",
"sp-contributions-blocklog": "zawarcia",
"sp-contributions-deleted": "skasowany wkłŏd ôd {{GENDER:$1|używŏcza|używŏczki}}",
"sp-contributions-uploads": "zaladowane zbiory",
"ipb-blocklist": "Zoboč istńijůnce zawarća",
"ipb-blocklist-contribs": "Wkłod $1",
"block-expiry": "Wygaso:",
- "unblockip": "Uodymkńij sprowjyńo užytkowńikowi",
+ "unblockip": "Ôdblokuj używŏcza",
"unblockiptext": "Ůžyj formulořa půńižej coby přiwrůćić možliwość sprowjańo s wčeśńij zawartygo adresu IP abo užytkowńikowi.",
"ipusubmit": "Uodymkńij sprowjyńo užytkowńikowi",
"unblocked": "[[User:$1|$1]] zostou uodymkńynty.",
"creditspage": "Autořy",
"nocredits": "Brak informacyji uo autorach tyi zajty.",
"spamprotectiontitle": "Filter antyspamowy",
- "spamprotectiontext": "Zajta, kero żeś průbowou naszkryflać, uostoła zawarta bez filter antyspamowy.\nNojprawdopodobńij zostoło to spowodowane bez link do zewnyntrznyj zajty internecowyj kero je na czornyj liśće.",
+ "spamprotectiontext": "Strōna, co jōm {{GENDER:prōbowołś|prōbowałaś|prōbujesz}} spamiyntać, ôstała zawartŏ ôd filtra antyspamowego.\nNojpewnij stało sie to skuli linka do zewnyntrznyj strōny, co je na czŏrnyj liście.",
"spamprotectionmatch": "Filtr antyspamowy śe zouůnčůu s kuli tygo co znod tekst: $1",
"spambot_username": "MediaWiki – wyćepywańe spamu",
"spam_reverting": "Přiwracańy uostatńij wersyji we kerej ńy bůuo linkůw do $1",
"imgmultipagenext": "nastympnŏ strōna →",
"imgmultigo": "Idź!",
"imgmultigoto": "Idź do strōny $1",
- "ascending_abbrev": "rosn.",
- "descending_abbrev": "mal.",
"table_pager_next": "Nostympno zajta",
"table_pager_prev": "Popředńo zajta",
"table_pager_first": "Pjyrwšo zajta",
"apihelp-no-such-module": "''$1'' என்ற மாடுயூல் காணப்படவில்லை.",
"apisandbox": "API மணற்தொட்டி",
"apisandbox-jsonly": "API மணல்தொட்டியை பயன்படுத்த ஜாவாகிறிட்டு தேவை",
- "apisandbox-api-disabled": "இத் தளத்தில் API செயலிழக்கம் செய்யப்பட்டுள்ளது.",
"apisandbox-submit": "கோரிக்கை செய்",
"apisandbox-reset": "வெறுமையாக்கு",
"apisandbox-retry": "மறு முயற்சி செய்",
"wlheader-enotif": "மின்னஞ்சல் அறிவிப்புகள் செயல்படுத்தப்பட்டுள்ளன.",
"wlheader-showupdated": "உங்கள் கடைசி வருகைக்குப் பின்னர் மாற்றங்கள் செய்யப்பட்ட பக்கங்கள் '''தடித்த எழுத்துக்களில்''' காட்டப்பட்டுள்ளன",
"wlnote": "பின்வருவன கடைசி {{PLURAL:$2|மணித்தியாலத்தில்|'''$2''' மணித்தியாலங்களில்}} செய்யப்பட்ட {{PLURAL:$1|கடைசி ஒரு மாற்றமாகும்|கடைசி $1 மாற்றங்களாகும்}}.",
- "wlshowlast": "கடைசி $1 மணித்தியாலங்கள் $2 நாட்களைக் காட்டு",
"watchlist-hide": "மறை",
"watchlist-submit": "காட்டு",
"wlshowtime": "காட்டவேண்டிய நேர அளவு:",
"uctop": "தற்போதைய",
"month": "மாதம் உட்பட முந்திய:",
"year": "ஆண்டு உட்பட முந்திய:",
- "sp-contributions-newbies": "புதிய கணக்குகளின் பங்களிப்புகளை மட்டும் காட்டு",
- "sp-contributions-newbies-sub": "புதிய கணக்குகளுக்கு",
- "sp-contributions-newbies-title": "புதிய கணக்குகளுக்கு பயனரின் பங்களிப்புகள்",
"sp-contributions-blocklog": "தடைப் பதிகை",
"sp-contributions-suppresslog": "பயனரின் நீக்கப்பட்ட பங்களிப்புகள்",
"sp-contributions-deleted": "பயனரின் நீக்கப்பட்ட பங்களிப்புக்கள்",
"img-lang-default": "(இயல்பு நிலை மொழி)",
"img-lang-info": "$1. $2 இல் இப்படத்தை தோன்றச் செய்",
"img-lang-go": "செல்",
- "ascending_abbrev": "ஏறு",
- "descending_abbrev": "இறங்கு",
"table_pager_next": "அடுத்த பக்கம்",
"table_pager_prev": "முந்திய பக்கம்",
"table_pager_first": "முதலாவது பக்கம்",
"watchlist-details": "cyux maki’ sa binkgan kktan sa kinlhangan su’ mita’ ga {{PLURAL:$1|$1 kwara’ zngazyan}} (kwara’ kina zngazyan na mpkayal).",
"wlheader-showupdated": "Suqun su’ minblaq mita’ squw pucingbalay lga, sinbah su’ zngazyan qasa ga musa’ yan nqaniy <strong>qthuy na biru’<strong> pkaykita’.",
"wlnote": "Kwara’ nyux kyahu’ ka aring sa glaing na $3 $4 ga, kinbalay niya’ sa {{PLURAL:$2|<strong>$2</strong> tmucing lga}}, {{PLURAL:$1|min<strong>$1</strong> niya’ smbah}}.",
- "wlshowlast": "Pkt’aniy misuw balay $1 spung $2 ryax",
"watchlist-hide": "Lqing",
"watchlist-submit": "Pkaykita’",
"wlshowhideminor": "msnzik sa spzyang balay sinr’zyut miru’",
"uctop": "misuw qaniy ga",
"month": "Pcingan na sniyan naha’ ryax na byacing:",
"year": "Pcingan na sniyan naha’ ryax na kawas",
- "sp-contributions-newbies": "Nanak yaquw mniq pincyuwagan nagiqas na canghaw quw spkita’",
- "sp-contributions-newbies-sub": "Pptzyuwaw sa kkbalay sa giqas na Canghaw",
"sp-contributions-blocklog": "qmhut smu’ut sa bniru’",
"sp-contributions-uploads": "pawsa’ sa kktan",
"sp-contributions-logs": "pinhknyan sraral",
"imgmultigoto": "Usa’ sa gnyahan lpgan tay $1",
"img-lang-default": "(pinnama’ smi’ na kay’)",
"img-lang-go": "Musa’",
- "ascending_abbrev": "pskkrawn paybkuw",
- "descending_abbrev": "pshhyu’un paybkuw",
"table_pager_next": "Llpgan tay suruw",
"table_pager_prev": "Llpgan tay glaing",
"table_pager_first": "T’ringan balay na llpgan",
"wlheader-enotif": "ಈ-ಮೈಲ್ ಸೂಚನೆ ಸಕ್ರಿಯ ಆತ್ಂಡ್.",
"wlheader-showupdated": "ಈರ್ ಅಕೇರಿಗ್ ಭೇಟಿ ಕೊರಿ ಬೊಕ್ಕ ಬದಲಾವಣೆ ಆಯಿನ ಪುಟೊಕುಲೆನ್ '''ದಪ್ಪ ಅಕ್ಷರೊಲೆಡ್''' ತೋಜಾದ್ಂಡ್.",
"wlnote": "$3, $4 ದ ಪ್ರಕಾರ ಕರಿನ {{PLURAL:$2|ಗಂಟೆಡ್|<strong>$2</strong> ಗಂಟೆಲೆಡ್}} ಆಯಿನ ಅಕೇರಿದ {{PLURAL:$1|ಬದಲಾವಣೆನ್|<strong>$1</strong> ಬದಲಾವಣೆಲೆನ್}} ತಿರ್ತ್ ತೋಜಾದ್ಂಡ್.",
- "wlshowlast": "ಕರಿನ $1 ಗಂಟೆಲು $2 ದಿನೊಕುಲು ತೋಜಾಲೆ",
"watchlist-hide": "ದೆಂಗಾವು",
"watchlist-submit": "ತೋಜಾವು",
"wlshowtime": "ತೋಜಾವೊಡಾಯಿನ ಪೊರ್ತುದ ಅವಧಿ:",
"uctop": "ಇತ್ತೆದ",
"month": "ಈ ತಿಂಗೊಲುಡ್ದು (ಬೊಕ್ಕ ದುಂಬುದ):",
"year": "ಈ ಒರ್ಸೊಡ್ದು(ಬೊಕ್ಕ ದುಂಬುದ):",
- "sp-contributions-newbies": "ಪೊಸ ಖಾತೆಲೆನ ಕಾಣಿಕೆಲೆನ್ ಮಾತ್ರ ತೊಜ್ಪಾವು",
"sp-contributions-blocklog": "ತಡೆಪತ್ತುನ ದಾಖಲೆ",
"sp-contributions-deleted": "ಮಾಜಿದಿನ {{GENDER:$1|ಸದಸ್ಯೆರೆ}} ಕಾಣಿಕೆಲು",
"sp-contributions-uploads": "ಅಪ್ಲೋಡ್ಲು",
"tog-norollbackdiff": "రోల్బ్యాక్ చేసాక తేడాలు చూపించవద్దు",
"tog-useeditwarning": "ఏదైనా పేజీని నేను వదిలివెళ్తున్నప్పుడు దానిలో భద్రపరచని మార్పులు ఉంటే నన్ను హెచ్చరించు",
"tog-prefershttps": "లాగిన్ అయి ఉన్నప్పుడెల్లా భద్ర కనెక్షనునే వాడు",
+ "tog-showrollbackconfirmation": "రోల్బ్యాక్ లింకును నొక్కినపుడు నిర్ధారించుకునే సందేశాన్ని చూపించు",
"underline-always": "ఎల్లప్పుడూ",
"underline-never": "ఎప్పటికీ వద్దు",
"underline-default": "అలంకారపు లేదా విహారిణి అప్రమేయం",
"index-category": "సూచీకరించిన పేజీలు",
"noindex-category": "సూచీకరించని పేజీలు",
"broken-file-category": "తెగిపోయిన ఫైలులింకులు గల పేజీలు",
+ "categoryviewer-pagedlinks": "($1) ($2)",
+ "category-header-numerals": "$1–$2",
"about": "గురించి",
"article": "విషయపు పేజీ",
"newwindow": "(కొత్త విండోలో వస్తుంది)",
"versionrequired": "మీడియావికీ సాఫ్టువేరు వెర్షను $1 కావాలి",
"versionrequiredtext": "ఈ పేజీని వాడటానికి మీకు మీడియావికీ సాఫ్టువేరు వెర్షను $1 కావాలి. [[Special:Version|వెర్షను పేజీ]]ని చూడండి.",
"ok": "సరే",
+ "pagetitle": "$1 - {{SITENAME}}",
+ "pagetitle-view-mainpage": "{{SITENAME}}",
+ "backlinksubtitle": "← $1",
"retrievedfrom": "\"$1\" నుండి వెలికితీశారు",
"youhavenewmessages": "మీకు $1 ఉన్నాయి ($2).",
"youhavenewmessagesfromusers": "{{PLURAL:$4|మీకు}} {{PLURAL:$3|మరో వాడుకరి|$3 వాడుకరుల}} నుండి $1 ($2).",
"page-rss-feed": "\"$1\" RSS ఫీడు",
"page-atom-feed": "\"$1\" ఆటమ్ ఫీడు",
"feed-atom": "యాటమ్",
+ "feed-rss": "RSS",
"red-link-title": "$1 (పుట లేదు)",
"sort-descending": "అవరోహణ క్రమంలో అమర్చు",
"sort-ascending": "ఆరోహణ క్రమంలో అమర్చు",
"virus-scanfailed": "స్కాన్ విఫలమైంది (సంకేతం $1)",
"virus-unknownscanner": "అజ్ఞాత యాంటీవైరస్:",
"logouttext": "<strong>ఇప్పుడు మీరు లాగౌటయ్యారు.</strong>\n\nఅయితే, ఓ గమనిక.. మీ విహారిణిలోని కోశాన్ని ఖాళీ చేసేవరకూ కొన్ని పేజీలు మీరింకా లాగినై ఉన్నట్లుగానే చూపించవచ్చు.",
+ "logging-out-notify": "మిమ్మల్ని లాగౌటు చేస్తున్నాం, ఆగండి.",
"logout-failed": "ఇప్పుడు లాగౌట్ అవలేరు: $1",
"cannotlogoutnow-title": "ఇప్పుడు లాగౌట్ అవలేరు",
"cannotlogoutnow-text": "$1 ను వాడుతూండగా లాగౌట్ అవలేరు.",
"nocookiesnew": "ఖాతాని సృష్టించాం, కానీ మీరు ఇంకా లోనికి ప్రవేశించలేదు.\nవాడుకరుల ప్రవేశానికి {{SITENAME}} కూకీలను వాడుతుంది.\nమీరు కూకీలని అచేతనం చేసివున్నారు.\nదయచేసి వాటిని చేతనంచేసి, మీ కొత్త వాడుకరి పేరు, సంకేతపదాలతో లోనికి ప్రవేశించండి.",
"nocookieslogin": "వాడుకరుల ప్రవేశానికై {{SITENAME}} కూకీలను వాడుతుంది.\nమీరు కుకీలని అచేతనం చేసివున్నారు.\nవాటిని చేతనంచేసి ప్రయత్నించండి.",
"nocookiesfornew": "మూలాన్ని కనుక్కోలేకపోయాం కాబట్టి, ఈ వాడుకరి ఖాతాను సృష్టించలేకపోయాం.\nమీ కంప్యూటర్లో కూకీలు చేతనమై ఉన్నాయని నిశ్చయించుకొని, ఈ పేజీని తిరిగి లోడు చేసి, మళ్ళీ ప్రయత్నించండి.",
+ "nocookiesforlogin": "{{int:nocookieslogin}}",
"createacct-loginerror": "ఖాతా విజయవంతంగా సృష్టించబడింది, కానీ ఆటోమాటిగ్గా లాగిన్ అవలేరు. స్వయంగా మీరే [[Special:UserLogin|లాగినవండి]].",
"noname": "మీరు సరైన వాడుకరి పేరు ఇవ్వలేదు.",
"loginsuccesstitle": "లాగినయ్యారు",
"user-mail-no-body": "ఈమెయిలును ఖాళీగానో, మరీ తక్కువ విషయంతోనో పంపేందుకు ప్రయత్నించారు.",
"changepassword": "సంకేతపదాన్ని మార్చండి",
"resetpass_announce": "లాగిన్ను పూర్తిచేసేందుకు, తప్పనిసరిగా కొత్త సంకేతపదాన్ని ఇవ్వాలి:",
+ "resetpass_text": "<!-- ఇక్కడ పాఠ్యం చేర్చండి -->",
"resetpass_header": "ఖాతా సంకేతపదం మార్పు",
"oldpassword": "పాత సంకేతపదం:",
"newpassword": "కొత్త సంకేతపదం:",
"headline_tip": "2వ స్థాయి శీర్షిక",
"nowiki_sample": "ఫార్మాటు చేయని పాఠ్యాన్ని ఇక్కడ చేర్చండి",
"nowiki_tip": "వికీ ఫార్మాటును పట్టించుకోవద్దు",
+ "image_sample": "Example.jpg",
"image_tip": "ఇమిడ్చిన ఫైలు",
+ "media_sample": "Example.ogg",
"media_tip": "దస్త్రపు లంకె",
"sig_tip": "సమయంతో సహా మీ సంతకం",
"hr_tip": "అడ్డగీత (అరుదుగా వాడండి)",
"template-protected": "(సంరక్షితం)",
"template-semiprotected": "(సెమీ-రక్షణలో ఉంది)",
"hiddencategories": "ఈ పేజీ {{PLURAL:$1|ఒక దాచిన వర్గంలో|$1 దాచిన వర్గాల్లో}} ఉంది:",
+ "edittools-upload": "-",
"nocreatetext": "{{SITENAME}}లో కొత్త పేజీలు సృష్టించడాన్ని నియంత్రించారు.\nమీరు వెనక్కి వెళ్ళి వేరే పేజీలు మార్చవచ్చు, లేదా [[Special:UserLogin|లోనికి ప్రవేశించండి లేదా ఖాతా సృష్టించుకోండి]].",
"nocreate-loggedin": "కొత్త పేజీలను సృష్టించేందుకు మీకు అనుమతి లేదు.",
"sectioneditnotsupported-title": "విభాగపు దిద్దుబాట్లకు తోడ్పాటు లేదు",
"content-not-allowed-here": "స్లాట్ \"$3\" లో [[:$2]] పేజీలో పాఠ్యం \"$1\" కి అనుమతి లేదు",
"editwarning-warning": "ఈ పేజీని వదిలివెళ్ళడం వల్ల మీరు చేసిన మార్పులను కోల్పోయే అవకాశం ఉంది.\nమీరు లాగిన్ అయివుంటే, ఈ హెచ్చరికని మీ అభిరుచులలోని \"{{int:prefs-editing}}\" విభాగంలో అచేతనం చేసుకోవచ్చు.",
"editpage-invalidcontentmodel-title": "ఈ కంటెంటు మోడలుకు మద్దతు లేదు",
+ "editpage-invalidcontentmodel-text": "\"$1\" అనే కంటెంటు మోడలుకు మద్దతు లేదు.",
"editpage-notsupportedcontentformat-title": "పాఠ్యపు ఆకృతికి మద్దతు లేదు",
"editpage-notsupportedcontentformat-text": "$2 పాఠ్యపు మోడల్, పాఠ్యపు ఆకృతి $1 కి మద్దతు ఇవ్వదు",
"slot-name-main": "ప్రధాన",
"content-model-text": "సాదా పాఠ్యం",
"content-model-javascript": "జావాస్క్రిప్ట్",
"content-model-css": "CSS",
+ "content-model-json": "JSON",
"content-json-empty-object": "ఖాళీ అంశం",
"content-json-empty-array": "ఖాళీ అరే",
"duplicate-args-warning": "<strong>హెచ్చరిక:</strong> [[:$1]], \"$3\" పరామితికి ఒకటి కంటే ఎక్కువ విలువలు ఇచ్చి [[:$2]] ను పిలుస్తోంది. చిట్టచివరిగా ఇచ్చిన విలువను మాత్రమే వాడుతాం.",
"mergehistory-comment": "[[:$1]]ని [[:$2]] లోనికి విలీనం చేసారు: $3",
"mergehistory-same-destination": "మూల, గమ్యస్థాన పేజీలు ఒకటే కాకూడదు",
"mergehistory-reason": "కారణం:",
+ "mergehistory-revisionrow": "$1 ($2) $3 . . $4 $5 $6",
"mergelog": "విలీనాల చిట్టా",
"revertmerge": "విలీనాన్ని రద్దుచెయ్యి",
"mergelogpagetext": "ఒక పేజీ చరితాన్ని మరో పేజీ చరితం లోకి ఇటీవల చేసిన విలీనాల జాబితా ఇది.",
"youremail": "ఈమెయిలు:",
"username": "{{GENDER:$1|వాడుకరి పేరు}}:",
"prefs-memberingroups": "ఈ {{PLURAL:$1|గుంపులో|గుంపులలో}} {{GENDER:$2|సభ్యుడు|సభ్యురాలు}}:",
+ "prefs-memberingroups-type": "$1",
"group-membership-link-with-expiry": "$1 ($2 వరకు)",
"prefs-registration": "నమోదైన సమయం:",
+ "prefs-registration-date-time": "$1",
"yourrealname": "అసలు పేరు:",
"yourlanguage": "భాష:",
"yourvariant": "విషయపు భాషా వైవిధ్యం:",
"prefs-advancedwatchlist": "ఉన్నత ఎంపికలు",
"prefs-displayrc": "ప్రదర్శన ఎంపికలు",
"prefs-displaywatchlist": "ప్రదర్శన ఎంపికలు",
+ "prefs-changesrc": "చూపించే మార్పులు",
+ "prefs-changeswatchlist": "చూపించే మార్పులు",
+ "prefs-pageswatchlist": "వీక్షించే పేజీలు",
"prefs-tokenwatchlist": "టోకెన్",
"prefs-diffs": "తేడాలు",
"prefs-help-prefershttps": "ఈ అభిరుచి మీరు పైసారి లాగినైనపుడు అమలౌతుంది.",
"saveusergroups": "{{GENDER:$1|వాడుకరి}} గుంపులను భద్రపరచు",
"userrights-groupsmember": "సభ్యులు:",
"userrights-groupsmember-auto": "సంభావిత సభ్యులు:",
+ "userrights-groupsmember-type": "$1",
"userrights-groups-help": "ఈ వాడుకరి ఏయే గుంపులలో ఉండాలో మీరు మార్చవచ్చు.\n* టిక్కు పెట్టివుంటే సదరు గుంపులో ఈ వాడుకరి ఉన్నట్టు.\n* టిక్కు లేకుంటే సదరు గుంపులో ఈ వాడుకరి లేనట్టు.\n* * గుర్తు ఉంటే ఒకసారి ఆ గుంపుకు చేర్చాక మీరు తీసివేయలేరు, లేదా తీసివేసాక తిరిగి చేర్చలేరు.\n* ఈ # గుర్తు ఉంటే ఆ గుంపు కాలం తీరిపోయే సమయాన్ని పెంచగలరు; దాన్ని తగ్గించలేరు.",
"userrights-reason": "కారణం:",
"userrights-no-interwiki": "ఇతర వికీలలో వాడుకరి హక్కులను మార్చడానికి మీకు అనుమతి లేదు.",
"userrights-nodatabase": "$1 అనే డేటాబేసు లేదు లేదా అది స్థానికం కాదు.",
"userrights-changeable-col": "మీరు మార్చదగిన గుంపులు",
"userrights-unchangeable-col": "మీరు మార్చలేని గుంపులు",
+ "userrights-irreversible-marker": "$1*",
+ "userrights-no-shorten-expiry-marker": "$1#",
"userrights-expiry-current": "కాలంతీరే వ్యవధి $1",
"userrights-expiry-none": "ఎన్నటికీ కాలం తీరిపోదు",
"userrights-expiry": "కాలం తీరిపోయే వ్యవధి",
"action-applychangetags": "మీ మార్పులతో ట్యాగులను ఆపాదించే",
"action-deletechangetags": "డేటాబేసు నుండి ట్యాగులను తొలగించే",
"action-purge": "ఈ పేజీని పర్జ్ చేసే",
+ "action-bigdelete": "పెద్ద చరితం ఉన్న పేజీలను తొలగించు",
"action-blockemail": "ఈమెయిలు పంపకుండా వాడుకరిని నిరోధించే",
"action-bot": "ఆటోమాటిక్ ప్రాసెస్ లాగా భావించే",
"action-editsemiprotected": "\"{{int:protect-level-autoconfirmed}}\" గా సంరక్షించబడ్డ పేజీలను మార్చే",
"action-override-export-depth": "5 లింకుల లోతు వరకు ఉన్న పేజీలతో సహా, పేజీలను ఎగుమతి చేసే",
"action-suppressredirect": "పేజీని తరలించేటపుడు పాత పేరు నుండి దారిమార్పును సృష్టించకుండా చేసే",
"nchanges": "{{PLURAL:$1|ఒక మార్పు|$1 మార్పులు}}",
+ "ntimes": "$1×",
"enhancedrc-since-last-visit": "{{PLURAL:$1|చివరి సందర్శన తరువాత}}, $1",
"enhancedrc-history": "చరిత్ర",
"recentchanges": "ఇటీవలి మార్పులు",
"recentchanges-label-plusminus": "ఈ పేజి పరిమాణంలో జరిగిన మార్పుల బైట్ల సంఖ్య",
"recentchanges-legend-heading": "<strong>సూచిక :</strong>",
"recentchanges-legend-newpage": "{{int:recentchanges-label-newpage}} ([[Special:NewPages|కొత్త పేజీల జాబితా]]ను కూడా చూడండి)",
+ "recentchanges-legend-plusminus": "(<em>±123</em>)",
"recentchanges-submit": "చూపించు",
"rcfilters-tag-remove": "'$1'ను తీసివెయ్యి",
"rcfilters-legend-heading": "<strong>సంక్షేపాల (ఎబ్రీవియేషన్లు) జాబితా:</strong>",
"rcfilters-clear-all-filters": "వడపోతకాలన్నింటినీ తుడిచెయ్యి",
"rcfilters-show-new-changes": "$1 నుండి జరిగిన సరికొత్త మార్పులను చూడండి",
"rcfilters-search-placeholder": "మార్పులను వడకట్టండి (మెనూను వాడండి లేదా వడపోత పేరు కోసం వెతకండి)",
+ "rcfilters-search-placeholder-mobile": "వడపోతలు",
"rcfilters-invalid-filter": "తప్పు వడపోతకం",
"rcfilters-empty-filter": "చేతనంగా ఉన్న వడపోతకాలేమీ లేవు. మార్పుచేర్పు లన్నిటినీ చూపించాం.",
"rcfilters-filterlist-title": "వడపోతలు",
"rcfilters-filter-logactions-label": "చిట్టాల్లోకి చేరిన కార్యకలాపాలు",
"rcfilters-filter-logactions-description": "నిర్వాహక పనులు, ఖాతాల సృష్టి, పేజీ తొలగింపులు, ఎక్కింపులు...",
"rcfilters-hideminor-conflicts-typeofchange": "కొన్ని రకాల మార్పులను \"చిన్న\" మార్పులుగా సూచించ జాలరు. అంచేత ఈ వడపోత కింది మార్పు రకాల వడపోతలతో ఘర్షిస్తోంది: $1",
+ "rcfilters-typeofchange-conflicts-hideminor": "ఈ రకపు వడపోత \"చిన్న మార్పుల\" వడపోతతో ఘర్షణ పడుతుంది. కొన్ని రకాల మార్పులను \"చిన్న\" అని సూచించలేం.",
"rcfilters-filtergroup-lastrevision": "ఇటీవలి కూర్పులు",
"rcfilters-filter-lastrevision-label": "ఇటీవలి కూర్పు",
"rcfilters-filter-lastrevision-description": "పేజీలో ఇటీవల జరిగిన చిట్టచివరి మార్పు.",
"rcfilters-filter-showlinkedto-label": "ఓ పేజీ నుండి లింకై ఉన్న పేజీల్లో జరిగిన మార్పులను చూపించు",
"rcfilters-filter-showlinkedto-option-label": "ఎంచుకున్న పేజీకి <strong>లింకైన పేజీలు</strong>",
"rcfilters-target-page-placeholder": "పేజీ (లేదా వర్గం) పేరు ఇవ్వండి",
+ "rcfilters-allcontents-label": "కంటెంటులన్నీ",
+ "rcfilters-alldiscussions-label": "చర్చలన్నీ",
"rcnotefrom": "<strong>$3, $4</strong> తరువాత జరిగిన {{PLURAL:$5|మార్పు|మార్పులు}} కింద ఇచ్చాం (<strong>$1</strong> దాకా చూపించాం).",
"rclistfromreset": "తేదీ ఎంపికను రీసెట్ చెయ్యి",
"rclistfrom": "$3, $2 తో మొదలుపెట్టి ఆ తరువాత జరిగిన మార్పులను చూపించు",
"minoreditletter": "చి",
"newpageletter": "కొ",
"boteditletter": "బా",
+ "unpatrolledletter": "!",
+ "rc-change-size": "$1",
"rc-change-size-new": "మార్పు తర్వాత $1 {{PLURAL:$1|బైటు|బైట్లు}}",
"newsectionsummary": "/* $1 */ కొత్త విభాగం",
"rc-enhanced-expand": "వివరాలను చూపించు",
"recentchangeslinked-page": "పేజీ పేరు:",
"recentchangeslinked-to": "లేదంటే, ఇచ్చిన పేజీకి లింకయివున్న పేజీలలో జరిగిన మార్పులను చూపించు",
"recentchanges-page-added-to-category": "[[:$1]] ను వర్గానికి చేర్చాం",
- "recentchanges-page-added-to-category-bundled": "[[:$1]] వరà±\8dà°\97ానిà°\95à°¿ à°\9aà±\87à°°à±\8dà°\9aబడిà°\82ది, [[Special:WhatLinksHere/$1|à°\88 à°ªà±\87à°\9cà±\80 à°\87తర à°ªà±\87à°\9cà±\80à°²à±\8dà°²à±\8b à°\9aà±\87à°°à±\8dà°\9aబడింది]]",
+ "recentchanges-page-added-to-category-bundled": "[[:$1]] వరà±\8dà°\97ానిà°\95à°¿ à°\9aà±\87à°°à±\8dà°\9aారà±\81, [[Special:WhatLinksHere/$1|à°\88 à°ªà±\87à°\9cà±\80 à°\87తర à°ªà±\87à°\9cà±\80à°²à±\8dà°²à±\8b à°\9aà±\87à°°à°¿ à°\89ంది]]",
"recentchanges-page-removed-from-category": "[[:$1]] వర్గం నుండి తీసివేయబడింది",
- "recentchanges-page-removed-from-category-bundled": "[[:$1]] వరà±\8dà°\97à°\82 à°¨à±\81à°\82à°¡à°¿ à°¤à±\80సివà±\87యబడిà°\82ది, [[Special:WhatLinksHere/$1|ఈ పేజీ ఇతర పేజీల్లో చేర్చబడింది]]",
+ "recentchanges-page-removed-from-category-bundled": "[[:$1]] వరà±\8dà°\97à°\82 à°¨à±\81à°\82à°¡à°¿ à°¤à±\80సివà±\87సారà±\81, [[Special:WhatLinksHere/$1|ఈ పేజీ ఇతర పేజీల్లో చేర్చబడింది]]",
"autochange-username": "MediaWiki ఆటోమాటిక్ మార్పు",
"upload": "దస్త్రపు ఎక్కింపు",
"uploadbtn": "దస్త్రాన్ని ఎక్కించు",
"uploaddisabledtext": "ఫైళ్ళ ఎక్కింపులను అచేతనం చేసారు.",
"php-uploaddisabledtext": "PHPలో ఫైలు ఎక్కింపులు అచేతనమై ఉన్నాయి.\nదయచేసి file_uploads అమరికని చూడండి.",
"uploadscripted": "ఈ ఫైల్లో HTML కోడు గానీ స్క్రిప్టు కోడు గానీ ఉంది. వెబ్ బ్రౌజరు దాన్ని పొరపాటుగా అనువదించే అవకాశం ఉంది.",
+ "upload-scripted-dtd": "అప్రామాణిక DTD డిక్లరేషన్ను కలిగి ఉన్న SVG ఫైళ్ళను అప్లోడు చెయ్యలేరు.",
"uploadscriptednamespace": "ఈ SVG ఫైలులోని పేరుబరి \"<nowiki>$1</nowiki>\" చెల్లనిది",
"uploadinvalidxml": "ఎక్కించిన ఫైలులోని XML ను పార్సు చెయ్యలేకపోయాం.",
"uploadvirus": "ఈ ఫైలులో వైరస్ ఉంది! వివరాలు: $1",
"apihelp": "API సహాయం",
"apihelp-no-such-module": "\"$1\" మాడ్యూలు కనబడలేదు.",
"apisandbox": "API ప్రయోగశాల",
- "apisandbox-api-disabled": "ఈ సైటులో API అచేతనమై ఉంది.",
"apisandbox-submit": "అభ్యర్ధించు",
"apisandbox-reset": "తుడిచివేయి",
"apisandbox-retry": "మళ్ళీ ప్రయత్నించు",
"apisandbox-add-multi": "చేర్చు",
"apisandbox-results": "ఫలితాలు",
"apisandbox-request-url-label": "అభ్యర్థన URL:",
+ "apisandbox-request-format-json-label": "JSON",
"apisandbox-request-time": "అభ్యర్ధన సమయం: {{PLURAL:$1|$1 మి.సె.}}",
"apisandbox-continue": "కొనసాగించు",
"apisandbox-continue-clear": "తుడిచివేయి",
"apisandbox-multivalue-all-values": "$1 (అన్ని విలువలు)",
"booksources": "పుస్తక మూలాలు",
"booksources-search-legend": "పుస్తక మూలాల కోసం వెతుకు",
+ "booksources-isbn": "ISBN:",
"booksources-search": "వెతుకు",
"booksources-text": "కొత్త, పాత పుస్తకాలు అమ్మే ఇతర సైట్లకు లింకులు కింద ఇచ్చాం. మీరు వెతికే పుస్తకాలకు సంబంధించిన మరింత సమాచారం కూడా అక్కడ దొరకొచ్చు:",
"booksources-invalid-isbn": "మీరిచ్చిన ISBN సరైనదిగా అనిపించుటలేదు; అసలు మూలాన్నుండి కాపీ చేయడంలో పొరపాట్లున్నాయేమో చూసుకోండి.",
"listgrouprights-rights": "హక్కులు",
"listgrouprights-helppage": "Help:గుంపు హక్కులు",
"listgrouprights-members": "(సభ్యుల జాబితా)",
+ "listgrouprights-right-display": "<span class=\"listgrouprights-granted\">$1 <code>($2)</code></span>",
+ "listgrouprights-right-revoked": "<span class=\"listgrouprights-revoked\">$1 <code>($2)</code></span>",
"listgrouprights-addgroup": "{{PLURAL:$2|గుంపుని|గుంపులను}} చేర్చగలరు: $1",
"listgrouprights-removegroup": "{{PLURAL:$2|గుంపుని|గుంపులను}} తొలగించగలరు: $1",
"listgrouprights-addgroup-all": "అన్ని గుంపులను చేర్చగలరు",
"listgrants": "గ్రాంట్లు",
"listgrants-grant": "గ్రాంటు",
"listgrants-rights": "హక్కులు",
+ "listgrants-grant-display": "$1 <code>($2)</code>",
"trackingcategories": "పహారా కాయు వర్గాలు",
"trackingcategories-msg": "పహారా కాయు వర్గము",
"trackingcategories-name": "సందేశం పేరు",
"emailuserfooter": "ఈ ఈమెయిలును $1, {{GENDER:$2|$2}} కు {{SITENAME}} లోని \"{{int:emailuser}}\" ఫంక్షను ద్వారా {{GENDER:$1|పంపించారు}}. {{GENDER:$2|మీరు}} ఈ ఈమెయిలుకు జవాబు పంపిస్తే, {{GENDER:$2|మీ}} మెయిలును నేరుగా {{GENDER:$1|ఒరిజినల్ సెండరుకు}} పంపిస్తాం. దీనితో, {{GENDER:$2|మీ}} ఈమెయిలు అడ్రసు {{GENDER:$1|వారికి}} తెలిసిపోతుంది.",
"usermessage-summary": "వ్యవస్థ సందేశాన్ని వదిలివేస్తున్నాం.",
"usermessage-editor": "వ్యవస్థ సందేశకులు",
+ "usermessage-template": "MediaWiki:UserMessage",
"watchlist": "వీక్షణ జాబితా",
"mywatchlist": "వీక్షణ జాబితా",
"watchlistfor2": "$1 కొరకు $2",
"wlheader-enotif": "ఈ-మెయిలు గమనికలు పంపబడతాయి.",
"wlheader-showupdated": "మీ గత సందర్శన తరువాత మారిన పేజీలు <strong>బొద్దు</strong>గా చూపించబడ్డాయి.",
"wlnote": "$3, $4 ల సమయానికి, అంతకు ముందరి {{PLURAL:$2|గంటలో|<strong>$2</strong> గంటల్లో}} జరిగిన {{PLURAL:$1|మార్పును|<strong>$1</strong> మార్పులను}} కింద ఇచ్చాం.",
- "wlshowlast": "గత $1 గంటల $2 రోజులకు చూపించు",
"watchlist-hide": "దాచు",
"watchlist-submit": "చూపించు",
"wlshowtime": "చూపించాల్సిన కాలం:",
"deleting-backlinks-warning": "<strong>హెచ్చరిక:</strong> మీరు తొలగించబోతున్న పేజీకి [[Special:WhatLinksHere/{{FULLPAGENAME}}|ఇతర పేజీల]] నుండి లింకులు ఉన్నాయి. లేదా ఇతర పేజీల్లో అది ట్రాన్స్క్లూడు అవుతోంది.",
"deleting-subpages-warning": "<strong>హెచ్చరిక:</strong> మీరు తొలగించబోతున్న పేజీకి [[Special:PrefixIndex/{{FULLPAGENAME}}/|{{PLURAL:$1|ఒక ఉపపేజీ ఉంది|$1 ఉపపేజీలున్నాయి|51=50 కి పైగా ఉపపేజీలున్నాయి}}]].",
"rollback": "దిద్దుబాట్లను రద్దుచేయి",
+ "rollback-confirmation-confirm": "నిర్ధారించండి:",
+ "rollback-confirmation-yes": "రోల్బ్యాక్ చెయ్యి",
"rollback-confirmation-no": "రద్దుచేయి",
"rollbacklink": "రద్దుచేయి",
"rollbacklinkcount": "$1 {{PLURAL:$1|మార్పును|మార్పులను}} రద్దుచేయి",
"protect-fallback": "\"$1\" అనుమతి ఉన్న వాడుకరులను మాత్రమే అనుమతించు",
"protect-level-autoconfirmed": "స్వయన్నిర్ధారిత వాడుకరులను మాత్రమే అనుమతించు",
"protect-level-sysop": "నిర్వాహకులను మాత్రమే అనుమతించు",
+ "protect-summary-desc": "[$1=$2] ($3)",
"protect-summary-cascade": "కాస్కేడింగు",
"protect-expiring": "$1 (UTC)న కాలం చెల్లుతుంది",
"protect-expiring-local": "$1న కాలం చెల్లుతుంది",
"undelete-error-long": "ఫైలు $1 తొలగింపును రద్దు పరచడంలో లోపాలు దొర్లాయి",
"undelete-show-file-confirm": "$2 నాడు $3 సమయాన ఉన్న \"<nowiki>$1</nowiki>\" ఫైలు యొక్క తొలగించిన కూర్పుని మీరు నిజంగానే చూడాలనుకుంటున్నారా?",
"undelete-show-file-submit": "అవును",
+ "undelete-revision-row2": "$1 ($2) $3 . . $4 $5 $6 $7 $8",
"namespace": "పేరుబరి:",
"invert": "ఎంపికను తిరగవెయ్యి",
"tooltip-invert": "ఎంచుకున్న పేరుబరి (చెక్ చేసి ఉంటే అనుబంధ పేరుబరి కూడా) లోని పేజీల్లో జరిగిన మార్పులను దాచేందుకు ఈ పెట్టెను చెక్ చెయ్యండి",
"mycontris": "నా మార్పులు",
"anoncontribs": "మార్పుచేర్పులు",
"contribsub2": "{{GENDER:$3|$1}} ($2) కొరకు",
+ "contributions-subtitle": "{{GENDER:$3|$1}} కొరకు",
"contributions-userdoesnotexist": "వాడుకరి ఖాతా \"$1\" నమోదుకాలేదు.",
+ "negative-namespace-not-supported": "నెగటివ్ విలువలున్న పేరుబరులకు మద్దతు లేదు.",
"nocontribs": "ఈ విధమైన మార్పులేమీ దొరకలేదు.",
"uctop": "ప్రస్తుత",
"month": "ఈ నెల నుండి (అంతకు ముందువి):",
"year": "ఈ సంవత్సరం నుండి (అంతకు ముందువి):",
"date": "ఈ తేదీవి (అంతకు ముందువీ):",
- "sp-contributions-newbies": "కొత్త ఖాతాల యొక్క రచనలని మాత్రమే చూపించు",
- "sp-contributions-newbies-sub": "కొత్త ఖాతాల కోసం",
- "sp-contributions-newbies-title": "కొత్త ఖాతాల వాడుకరుల మార్పుచేర్పులు",
"sp-contributions-blocklog": "నిరోధాల చిట్టా",
"sp-contributions-suppresslog": "అణచిపెట్టబడిన {{GENDER:$1|వాడుకరి}} రచనలు",
"sp-contributions-deleted": "తొలగించబడిన {{GENDER:$1|వాడుకరి}} రచనలు",
"ipb-confirm": "నిరోధాన్ని ధృవపరచండి",
"ipb-sitewide": "సైట్ వ్యాప్తంగా",
"ipb-partial": "పాక్షికం",
+ "ipb-partial-help": "ప్రత్యేకించిన పేజీలు లేదా పేరుబరులు.",
"ipb-pages-label": "పేజీలు",
+ "ipb-namespaces-label": "పేరుబరులు",
"badipaddress": "సరైన ఐ.పి. అడ్రసు కాదు",
"blockipsuccesssub": "నిరోధం విజయవంతం అయింది",
"blockipsuccesstext": "[[Special:Contributions/$1|$1]] నిరోధించబడింది.<br />\nనిరోధాల సమీక్ష కొరకు [[Special:BlockList|నిరోధాల జాబితా]] చూడండి.",
"newimages-legend": "పడపోత",
"newimages-label": "ఫైలుపేరు (లేదా దానిలోని భాగం):",
"newimages-user": "ఐపీ చిరునామా లేదా వాడుకరి పేరు",
- "newimages-newbies": "కొత్త ఖాతాల రచనలని మాత్రమే చూపించు",
"newimages-showbots": "బాట్లు చేసిన అప్లోడ్లు చూపించు",
"newimages-hidepatrolled": "నిఘాలో ఉన్న ఎక్కింపులను దాచు",
"newimages-mediatype": "మాధ్యమ రకం:",
"img-lang-default": "(అప్రమేయ భాష)",
"img-lang-info": "ఈ బొమ్మను $1 లో చూపెట్టు. $2",
"img-lang-go": "వెళ్ళు",
- "ascending_abbrev": "ఆరోహణ",
- "descending_abbrev": "అవరోహణ",
"table_pager_next": "తరువాతి పేజీ",
"table_pager_prev": "ముందరి పేజీ",
"table_pager_first": "మొదటి పేజీ",
"watchthispage": "Hateke pájina ne'e",
"unwatch": "La hateke ona",
"watchlist-details": "{{PLURAL:$1|Pájina ida (1)|Pájina $1}} iha Ita-nia \"lista hateke\" (la ho pájina diskusaun).",
- "wlshowlast": "Hatudu $1 hora $2 loron ikus",
"watching": "Hateke...",
"unwatching": "La hateke...",
"enotif_impersonal_salutation": "Uza-na'in {{SITENAME}} nian",
"uctop": "versaun atuál",
"month": "Fulan (ho molok):",
"year": "Tinan (ho molok):",
- "sp-contributions-newbies": "Hatudu de'it kontribuisaun uza-na'in foun sira-nia",
"sp-contributions-talk": "diskusaun",
"sp-contributions-search": "Buka kontribuisaun",
"sp-contributions-username": "Diresaun IP ka naran uza-na'in:",
"wlheader-enotif": "Иттилоорасонии тариқи почтаи электронӣ (E-mail) фаъол шудааст.",
"wlheader-showupdated": "Саҳифаҳое, ки пас аз охирин сар заданатон ба онҳо тағйир кардаанд '''пурранг''' нишон дода шудаанд",
"wlnote": "Дар зер {{PLURAL:$1|охирин тағйир|'''$1''' охирин тағйирот}} дар $2 соати охир {{PLURAL:омадааст|омадаанд}}.",
- "wlshowlast": "Намоиши охирин $1 соат $2 рӯзҳо",
"watchlist-hide": "Пинҳон",
"watchlist-submit": "Намоиш",
"wlshowhidebots": "ботҳо",
"uctop": "кунунӣ",
"month": "Дар ин моҳ (ва қабл аз он):",
"year": "Дар ин сол (ва қабл аз он):",
- "sp-contributions-newbies": "Фақат ҳиссагузориҳои ҳисобҳои ҷадидро нишон деҳ",
- "sp-contributions-newbies-sub": "Барои навкорон",
"sp-contributions-blocklog": "Гузориши басташуданҳо",
"sp-contributions-deleted": "Ҳиссагузориҳои ҳазфшудаи корбар",
"sp-contributions-uploads": "боргузориҳо",
"imgmultipagenext": "саҳифаи баъдӣ →",
"imgmultigo": "Бирав!",
"imgmultigoto": "Ба саҳифаи $1 равед",
- "ascending_abbrev": "афзуншаванда",
- "descending_abbrev": "поёнӣ",
"table_pager_next": "Саҳифаи навбатӣ",
"table_pager_prev": "Саҳифаи гузашта",
"table_pager_first": "Саҳифаи аввал",
"wlheader-enotif": "Ittiloorasoniji tariqi poctai elektronī (E-mail) imkonpazir ast.",
"wlheader-showupdated": "Sahifahoe, ki pas az oxirin sar zadanaton ba onho taƣjir kardaand '''purrang''' nişon doda şudaand",
"wlnote": "Dar zer {{PLURAL:$1|oxirin taƣjir|'''$1''' oxirin taƣjirot}} dar $2 soati oxir {{PLURAL:omadaast|omadaand}}.",
- "wlshowlast": "Namoişi oxirin $1 soat $2 rūzho",
"watchlist-options": "Ixtijoroti fehristi pajgiriho",
"watching": "Pajgiri...",
"unwatching": "Tavqifi pajgiri...",
"uctop": "bolo",
"month": "Dar in moh (va qabl az on):",
"year": "Dar in sol (va qabl az on):",
- "sp-contributions-newbies": "Faqat hissaguzorihoi hisobhoi çadidro nişon deh",
- "sp-contributions-newbies-sub": "Baroi navkoron",
"sp-contributions-blocklog": "Guzorişi bastaşudanho",
"sp-contributions-search": "Çustuçūi hissaguzoriho",
"sp-contributions-username": "IP nişona jo nomi korbar:",
"imgmultipagenext": "sahifai ba'd →",
"imgmultigo": "Birav!",
"imgmultigoto": "Ba sahifai $1 raved",
- "ascending_abbrev": "afzunşavanda",
- "descending_abbrev": "pojonī",
"table_pager_next": "Sahifai navbatī",
"table_pager_prev": "Sahifai guzaşta",
"table_pager_first": "Sahifai avval",
"querypage-disabled": "หน้าพิเศษนี้ถูกปิดใช้งานด้วยเหตุผลด้านสมรรถภาพ",
"apihelp-no-such-module": "ไม่พบมอดูล \"$1\"",
"apisandbox": "ทดลองเขียนเอพีไอ",
- "apisandbox-api-disabled": "ไซต์นี้ไม่เปิดใช้ API",
"apisandbox-submit": "ส่งคำขอ",
"apisandbox-reset": "ล้าง",
"apisandbox-retry": "ลองใหม่",
"wlheader-enotif": "เปิดใช้งานการแจ้งเตือนผ่านอีเมล",
"wlheader-showupdated": "หน้าที่มีการเปลี่ยนแปลงตั้งแต่คุณเยี่ยมครั้งสุดท้ายแสดงด้วย<strong>ตัวหนา</strong>",
"wlnote": "ด้านล่างเป็น{{PLURAL:$1|การเปลี่ยนแปลงหลังสุด| <strong>$1</strong> การเปลี่ยนแปลงหลังสุด}} ใน{{PLURAL:$2|ชั่วโมง| <strong>$2</strong> ชั่วโมง}}ที่หลังสุด จนถึง $3, $4",
- "wlshowlast": "แสดง $1 ชั่วโมง $2 วันล่าสุด",
"watchlist-hide": "ซ่อน",
"watchlist-submit": "แสดง",
"wlshowtime": "ระยะเวลาที่แสดง:",
"month": "ตั้งแต่เดือน (และก่อนหน้า):",
"year": "ตั้งแต่ปี (และก่อนหน้า):",
"date": "ตั้งแต่วันที่ (และก่อนหน้า):",
- "sp-contributions-newbies": "แสดงการเข้ามีส่วนร่วมของบัญชีใหม่เท่านั้น",
- "sp-contributions-newbies-sub": "สำหรับบัญชีใหม่",
- "sp-contributions-newbies-title": "การเข้ามีส่วนร่วมสำหรับบัญชีใหม่",
"sp-contributions-blocklog": "ปูมการบล็อก",
"sp-contributions-suppresslog": "ระงับการมีส่วนร่วมของผู้ใช้",
"sp-contributions-deleted": "การมีส่วนร่วมของผู้ใช้ที่ถูกลบ",
"newimages-legend": "ตัวกรอง",
"newimages-label": "ชื่อไฟล์ (หรือส่วนหนึ่งของชื่อ):",
"newimages-user": "เลขที่อยู่ไอพีหรือชื่อผู้ใช้",
- "newimages-newbies": "แสดงเฉพาะการมีส่วนร่วมของบัญชีใหม่",
"newimages-showbots": "แสดงไฟล์ที่บอตอัปโหลด",
"newimages-hidepatrolled": "ซ่อนการอัปโหลดที่ตรวจสอบแล้ว",
"newimages-mediatype": "ชนิดสื่อ:",
"img-lang-default": "(ภาษาโดยปริยาย)",
"img-lang-info": "เรนเดอร์ภาพนี้ใน $1 $2",
"img-lang-go": "ไป",
- "ascending_abbrev": "ลำดับขึ้น",
- "descending_abbrev": "ลำดับลง",
"table_pager_next": "หน้าถัดไป",
"table_pager_prev": "หน้าก่อนหน้า",
"table_pager_first": "หน้าแรก",
"wlheader-enotif": "E-poçta bilen habar beriş açyk.",
"wlheader-showupdated": "Soňky gezek baryp görenizden soňra üýtgedilen sahypalar '''goýy şrift''' bilen görkezilýär.",
"wlnote": "Aşakda soňky {{PLURAL:$2|bir sagatda|'''$2''' sagatda}} edilen {{PLURAL:$1|soňky üýtgeşme|soňky '''$1''' üýtgeşme}} görkezilýär.",
- "wlshowlast": "Soňky $1 sagady $2 güni görkez",
"watchlist-options": "Gözegçilik sanawynyň opsiýalary",
"watching": "Gözegçilige alynýar...",
"unwatching": "Gözegçilikden aýyrylýar...",
"uctop": "häzirki",
"month": "Aý:",
"year": "Ýyl:",
- "sp-contributions-newbies": "Diňe täze hasap açan ulanyjylaryň goşantlaryny görkez",
- "sp-contributions-newbies-sub": "Täze hasaplar üçin",
- "sp-contributions-newbies-title": "Täze hasaplar üçin ulanyjy goşantlary",
"sp-contributions-blocklog": "Blokirleme gündeligi",
"sp-contributions-deleted": "öçürilen ulanyjy goşantlary",
"sp-contributions-uploads": "ýüklemeler",
"imgmultipagenext": "indiki sahypa →",
"imgmultigo": "Git!",
"imgmultigoto": "$1 sahypasyna git",
- "ascending_abbrev": "kiçiden ula",
- "descending_abbrev": "uludan kiçä",
"table_pager_next": "Indiki sahypa",
"table_pager_prev": "Öňki sahypa",
"table_pager_first": "Birinji sahypa",
"suppress": "Tagapagingat-tago",
"querypage-disabled": "Hindi pinagagana ang natatanging pahinang ito para sa mga dahilan ng pagganap.",
"apisandbox": "Kahong buhanginan ng API",
- "apisandbox-api-disabled": "Hindi pinagagana ang API sa sityong ito.",
"apisandbox-intro": "Gamitin ang pahinang ito upang mag-eksperimento sa pamamagitan ng '''Paglilingkod na pangsangkasaputan ng API ng MediaWiki'''.\nSumangguni sa [https://www.mediawiki.org/wiki/API:Main_page dokumentasyon ng API] para sa karagdagan pang mga detalye sa paggamit ng API. Halimbawa: [https://www.mediawiki.org/wiki/API#A_simple_example kuhanin ang nilalaman ng isang Pangunahing Pahina]. Pumili ng isang galaw upang makakita ng mas marami pang mga halimbawa.",
"apisandbox-submit": "Gumawa ng kahilingan",
"apisandbox-reset": "Hawiin",
"wlheader-enotif": "Umiiral ang pagpapahayag sa pamamagitan ng e-liham.",
"wlheader-showupdated": "Ipinapakitang may '''makakapal na mga panitik''' ang nabagong/binagong mga pahina mula pa noong huli mong pagdalaw sa kanila",
"wlnote": "Nasa ibaba ang {{PLURAL:$1|pinakahuling pagbabago|pinakahuling <strong>$1</strong> pagbabago}} sa loob ng huling {{PLURAL:$2|oras|<strong>$2</strong> oras}}, magmula noong $3 sa ganap na $4.",
- "wlshowlast": "Ipakita ang huling $1 oras, $2 araw",
"watchlist-hide": "Itago",
"wlshowhideminor": "mga maliliit na edit",
"wlshowhidebots": "mga bot",
"uctop": "kasalukuyan",
"month": "Mula sa buwan (at nauna):",
"year": "Mula sa taon (at nauna):",
- "sp-contributions-newbies": "Ipakita ang mga ambag ng mga bagong account lamang",
- "sp-contributions-newbies-sub": "Para sa mga bagong account",
- "sp-contributions-newbies-title": "Mga ambag ng tagagamit para sa mga bagong account",
"sp-contributions-blocklog": "Tala ng paglipat",
"sp-contributions-deleted": "naburang mga ambag ng tagagamit",
"sp-contributions-uploads": "mga ikinargang paitaas",
"imgmultipagenext": "susunod na pahina →",
"imgmultigo": "Punta!",
"imgmultigoto": "Pumunta sa pahinang $1",
- "ascending_abbrev": "taas",
- "descending_abbrev": "baba",
"table_pager_next": "Susunod na pahina",
"table_pager_prev": "Nakaraang pahina",
"table_pager_first": "Unang pahina",
"watch": "Думотоно егыниеј",
"unwatch": "Думотоно ныегыниеј",
"watchlist-details": "Мызокирә сәһифон ныашмардеј, шымә ноғо доә сијоһиәдә {{PLURAL:$1|$1 сәһифәје|$1 сәһифәје}}.",
- "wlshowlast": "Нишо дој бә охонә $1 саат $2 руж",
"watchlist-options": "Ноғо доә сијоһи пеғандон",
"actioncomplete": "Һәрәкәт иҹро кардә быә",
"actionfailed": "Һәрәкәт иҹро кардә бәни",
"uctop": "есәтнә",
"month": "Че мангику (һәнијән рә):",
"year": "Че сорику (һәнијән рә):",
- "sp-contributions-newbies": "Әнҹәх нујә иштирокәкон гәнҹи нишо дој",
"sp-contributions-blocklog": "бастә быә чијон",
"sp-contributions-uploads": "бо жә быә чијон",
"sp-contributions-logs": "журналон",
"wlheader-enotif": "Kuo fakamafeiaʻi tala mei he tohila",
"wlheader-showupdated": "*Ko e ngaahi peesi kuo liliu talu he taimi hoʻo ʻaʻahi ki ai, ʻoku ʻasi mai fakasinolahi",
"wlnote": "ʻOku ʻasi ʻi lalo ʻa e liliu fakamuimui ʻe $1 ʻi he houa fakamuimui ʻe <b>$2</b>.",
- "wlshowlast": "ʻAsi mai houa fakamuimui ʻe $1, ʻaho ʻe $2,",
"watching": "ʻOku leʻo...",
"unwatching": "ʻOku taʻeleʻo...",
"created": "kuo fakatupu",
"imgmultipageprev": "← Peesi ki muʻa",
"imgmultipagenext": "Peesi hoko →",
"imgmultigo": "Fai ā!",
- "ascending_abbrev": "hake",
- "descending_abbrev": "hifo",
"table_pager_next": "Peesi hoko",
"table_pager_prev": "Peesi ki muʻa",
"table_pager_first": "Peesi ʻuluaki",
"unwatchthispage": "Pinis long lukautim",
"watchlist-details": "$1 pes istap long lukautbuk (dispela namba i no kaunim ol pes bilong toktok).",
"wlheader-showupdated": "Ol pes i senis pinis bihain long taim yu lukim ol igat nem i '''strongpela'''",
- "wlshowlast": "Lukim dispela $1 aua $2 de",
"watchlist-options": "Ol laik bilong Lukautbuk",
"watching": "Wet liklik, i go insait long lukautbuk nau...",
"unwatching": "Wet liklik, i raus nau long lukautbuk...",
"TmY e12",
"Dual",
"ToprakM",
- "Suvarioglu"
+ "Suvarioglu",
+ "BaRaN6161 TURK"
]
},
"tog-underline": "Bağlantıların altını çizme:",
"mainpage": "Anasayfa",
"mainpage-description": "Anasayfa",
"policy-url": "Project:Politika",
- "portal": "Topluluk portali",
+ "portal": "Topluluk portalı",
"portal-url": "Project:Topluluk portali",
"privacy": "Gizlilik politikası",
"privacypage": "Project:Gizlilik Politikası",
"systemblockedtext": "Kullanıcı adınız veya IP adresiniz MediaWiki tarafından otomatik olarak engellendi.\nSebebi:\n\n:<em>$2</em>\n\n* Engelin başlangıcı: $8\n* Engelin süresi: $6\n* Engellenmesi istenen: $7\n\nMevcut IP adresiniz $3.\nLütfen yukarıdaki tüm ayrıntıları, yaptığınız sorgularda belirtin.",
"blockednoreason": "sebep verilmedi",
"blockedtext-composite": "<strong>Kullanıcı adınız veya IP adresiniz engellendi.</strong>\n\nSebebi:\n\n:<em>$2</em>.\n\n* Engel başlama tarihi: $8\n* Engelin süresi: $6\n\n* $5\n\nGeçerli IP adresiniz $3.\nLütfen yukarıdaki tüm detayları yaptığınız tüm sorgulara dahil ediniz.",
+ "blockedtext-composite-ids": "İlgili engelleme kimlikleri: $1 (IP adresiniz de kara listeye alınmış olabilir)",
+ "blockedtext-composite-no-ids": "IP adresiniz birden fazla kara listede görünüyor",
"blockedtext-composite-reason": "Hesabınızda ve/veya IP adresinizde birden fazla engel mevcut.",
"whitelistedittext": "Değişiklik yapabilmek için $1.",
"confirmedittext": "Sayfa değiştirmeden önce e-posta adresinizi onaylamalısınız. Lütfen [[Special:Preferences|tercihler]] kısmından e-postanızı ekleyin ve onaylayın.",
"search-interwiki-more": "(daha çok)",
"search-interwiki-more-results": "daha fazla sonuç",
"search-relatedarticle": "ilgili",
+ "search-invalid-sort-order": "$1 sıralama düzeni tanınmazsa, varsayılan sıralama uygulanır. Geçerli sıralama emirleri: $2",
+ "search-unknown-profile": "$1 arama profili tanınmadı, varsayılan arama profili uygulanacak.",
"searchrelated": "ilgili",
"searchall": "tümü",
"showingresults": "$2. sonuçtan başlayarak {{PLURAL:$1|'''1''' sonuç |'''$1''' sonuç }} aşağıdadır:",
"right-editmyusercss": "Kendi kullanıcı CSS dosyaları düzenle",
"right-editmyuserjson": "Kendi kullanıcı JSON dosyalarını düzenle",
"right-editmyuserjs": "Kendi kullanıcı JavaScript dosyalarını düzenle",
+ "right-editmyuserjsredirect": "Yönlendirmeleri olan kendi kullanıcı JavaScript dosyalarınızı düzenleyin",
"right-viewmywatchlist": "Kendi izleme listeni gör",
"right-editmywatchlist": "Kendi izleme listeni düzenle. Not, bazı eylemler bu yetki olmadan da sayfa ekleyebilir.",
"right-viewmyprivateinfo": "Kendi özel bilgilerini görüntüle (e-posta adresi, gerçek isim vb.)",
"action-editmyusercss": "kendi kullanıcı CSS dosyaları düzenle",
"action-editmyuserjson": "kendi kullanıcı JSON dosyalarını düzenle",
"action-editmyuserjs": "kendi kullanıcı JavaScript dosyalarını düzenle",
+ "action-editmyuserjsredirect": "yönlendiren kendi JavaScript dosyalarını düzenleyebilir",
"action-viewsuppressed": "herhangi bir kullanıcıdan saklanan sürümleri göster",
"action-hideuser": "Herkesten gizleyerek bir kullanıcı adını engelle",
"action-ipblock-exempt": "IP engellemelerini, otomatik engellemelerini ve aralık engellemelerini atla",
"rcfilters-clear-all-filters": "Tüm süzgeçleri temizle",
"rcfilters-show-new-changes": "$1 tarihinden bu yana yapılan yeni değişiklikleri görüntüleyin",
"rcfilters-search-placeholder": "Son değişiklikleri filtrele (menüyü kullanın veya süzgeç adını arayın)",
+ "rcfilters-search-placeholder-mobile": "Filtreler",
"rcfilters-invalid-filter": "Geçersiz süzgeç",
"rcfilters-empty-filter": "Etkin süzgeç bulunmuyor. Tüm katkıları gösteriliyor.",
"rcfilters-filterlist-title": "Süzgeçler",
"rcfilters-preference-help": "Filtre olmadan arama yapma veya işlevselliği vurgulamadan SonDeğişiklikler'i yükler.",
"rcfilters-watchlist-preference-label": "JavaScript olmayan bir arayüz kullanın",
"rcfilters-watchlist-preference-help": "Filtre Listesini arama olmadan veya işlevselliği vurgulayarak İzleme Listesi'ni yükler.",
+ "rcfilters-filter-showlinkedfrom-label": "Bağlantısı verilen sayfalarda değişiklikleri göster",
+ "rcfilters-filter-showlinkedfrom-option-label": "Seçilen sayfadan <strong>bağlanmış sayfalar</strong>",
+ "rcfilters-filter-showlinkedto-label": "Bağlantı veren sayfalarda değişiklikleri göster",
+ "rcfilters-filter-showlinkedto-option-label": "Seçilen sayfaya <strong>bağlantı veren sayfalar</strong>",
"rcfilters-target-page-placeholder": "Bir sayfa (ya da kategori) adı girin",
"rcfilters-allcontents-label": "Tüm içerikler",
+ "rcfilters-alldiscussions-label": "Tüm tartışmalar",
"rcnotefrom": "<strong>$3, $4</strong> tarihinden itibaren yapılan {{PLURAL:$5|değişiklik|değişiklik}} aşağıdadır (<strong>$1</strong> tarhine kadar olanlar gösterilmektedir).",
"rclistfromreset": "Tarih seçimini sıfırla",
"rclistfrom": "$3 $2 tarihinden itibaren yeni değişiklikleri göster",
"uploaded-script-svg": "Yüklenen SVG dosyasında komutlanabilir (scriptable) öğe bulundu: \"$1\"",
"uploaded-hostile-svg": "Yüklenen SVG dosyasının \"style\" öğesinde güvensiz CSS bulundu.",
"uploaded-event-handler-on-svg": "SVG dosyalarında event-handler özniteliğini <code>$1=\"$2\"</code> şeklinde ayarlanmasına izin verilmiyor.",
+ "uploaded-href-attribute-svg": "<a>öğeler yalnızca (href) veri: (gömülü dosya), http:// veya https:// veya fragman (#, aynı belge) hedeflerine bağlanabilir. <image> gibi diğer öğeler için yalnızca veri: ve parçalara izin verilir. SVG'nizi dışa aktarırken görüntü gömmeyi deneyin. <code><$1 $2=\"$3\"></code> bulundu.",
"uploaded-href-unsafe-target-svg": "Yüklenen SVG dosyasında <code><$1 $2=\"$3\"></code> güvensiz hedefine href veri: URI bulundu.",
"uploaded-animate-svg": "\"animate\" etiketi bulundu, href'i değiştiriyor olabilir. Yüklenen SVG dosyasındaki \"from\" özniteliği kullanılıyor <code><$1 $2=\"$3\"></code>",
"uploaded-setting-event-handler-svg": "Olay işleyicisi özniteliklerini ayarlama engellenir, yüklenen SVG dosyasında <code><$1 $2=\"$3\"></code> bulundu.",
"uploaded-setting-href-svg": "Üst ögeye \"href\" özelliğini eklemek için \"set\" etiketinin kullanılması engellenir.",
+ "uploaded-wrong-setting-svg": "Herhangi bir özniteliğe uzak/veri/ komut dosyası hedefi eklemek için \"set\" etiketinin kullanılması engellenir. Yüklenen SVG dosyasında <code><set to=\"$1\"></code> olarak bulundu.",
+ "uploaded-setting-handler-svg": "Kumanda/veri/komut dosyası ile \"işleyicisi\" özelliğini ayarlayan SVG engelleniyor. Yüklenen SVG dosyasında <code>$1=\"$2\"</code> bulundu.",
+ "uploaded-remote-url-svg": "Uzak URL ile herhangi bir stil özniteliği ayarlayan SVG engellenir. Yüklenen SVG dosyasında <code>$1=\"$2\"</code> bulundu.",
+ "uploaded-image-filter-svg": "Yüklenen SVG dosyasında bağlantı: <code><$1 $2=\"$3\"></code> bulunan resim filtresi bulundu.",
"uploadscriptednamespace": "Bu SVG dosyası geçersiz \"<nowiki>$1</nowiki>\" alan adını içermektedir.",
"uploadinvalidxml": "Yüklenen dosyadaki XML işlenemedi.",
"uploadvirus": "Bu dosya virüslüdür! Detayları: $1",
"upload-options": "Yükleme seçenekleri",
"watchthisupload": "Bu dosyayı izle",
"filewasdeleted": "Bu isimde bir dosya yakın zamanda yüklendi ve ardından hizmetliler tarafından silindi. Dosyayı yüklemeden önce, $1 sayfasına bir göz atınız.",
+ "filename-thumb-name": "Bu küçük resim başlığına benziyor. Lütfen küçük resimleri aynı wiki'ye geri yüklemeyin. Aksi takdirde, lütfen dosya adını düzeltin, böylece daha anlamlı olur ve küçük resim önekine sahip olmaz.",
"filename-bad-prefix": "Yüklemekte olduğunuz dosyanın adı, genel olarak dijital kameralar tarafından otomatik olarak ekelenen ve açıklayıcı olmayan '''\"$1\"''' ile başlamaktadır.\nLütfen dosyanız için daha açıklayıcı bir isim seçin.",
"filename-prefix-blacklist": " #<!-- leave this line exactly as it is --> <pre>\n# Syntax is as follows:\n# * Everything from a \"#\" character to the end of the line is a comment\n# * Every non-blank line is a prefix for typical file names assigned automatically by digital cameras\nCIMG # Casio\nDSC_ # Nikon\nDSCF # Fuji\nDSCN # Nikon\nDUW # some mobile phones\nIMG # generic\nJD # Jenoptik\nMGP # Pentax\nPICT # misc.\n #</pre> <!-- leave this line exactly as it is -->",
"upload-proto-error": "Hatalı protokol",
"upload-too-many-redirects": "URL çok fazla yönlendirme içeriyor",
"upload-http-error": "Bir HTTP hatası oluştu: $1",
"upload-copy-upload-invalid-domain": "Kopya yüklemeler bu etki alanında mevcut değil.",
+ "upload-foreign-cant-upload": "Bu wiki, istenen yabancı dosya havuzuna dosya yükleyecek şekilde yapılandırılmamış.",
+ "upload-foreign-cant-load-config": "Yabancı dosya havuzuna dosya yükleme yapılandırması yüklenemedi.",
+ "upload-dialog-disabled": "Bu iletişim kutusunu kullanarak dosya yüklemeleri bu wikide devre dışı.",
"upload-dialog-title": "Dosya Yükle",
"upload-dialog-button-cancel": "İptal",
"upload-dialog-button-back": "Geri",
"upload-dialog-button-upload": "Yükle",
"upload-form-label-infoform-title": "Ayrıntılar",
"upload-form-label-infoform-name": "Ad",
+ "upload-form-label-infoform-name-tooltip": "Dosya adı olarak kullanılacak, dosya için benzersiz bir açıklayıcı başlık. Düz dili boşluklarla kullanabilirsiniz. Dosya uzantısını dahil etmeyin.",
"upload-form-label-infoform-description": "Açıklama",
+ "upload-form-label-infoform-description-tooltip": "İşle ilgili dikkate değer her şeyi kısaca açıklayın.\nBir fotoğraf için, anlatılan ana şeylerden, fırsattan veya yerden bahsedin.",
"upload-form-label-usage-title": "Kullanımı",
"upload-form-label-usage-filename": "Dosya adı",
"upload-form-label-own-work": "Bu benim kendi çalışmam",
"upload-form-label-infoform-categories": "Kategoriler",
"upload-form-label-infoform-date": "Tarih",
+ "upload-form-label-own-work-message-generic-local": "{{SITENAME}} üzerindeki hizmet şartlarını ve lisans politikalarını izleyerek bu dosyayı yüklediğimi onaylıyorum.",
+ "upload-form-label-not-own-work-message-generic-local": "Bu dosyayı {{SITENAME}} ilkeleri kapsamında yükleyemiyorsanız, lütfen bu iletişim kutusunu kapatın ve başka bir yöntem deneyin.",
+ "upload-form-label-not-own-work-local-generic-local": "[[Special:Upload|varsayılan yükleme sayfası]] denemek de isteyebilirsiniz.",
+ "upload-form-label-own-work-message-generic-foreign": "Anladığım kadarıyla bu dosyayı paylaşılan bir havuza yüklüyorum. Buradaki hizmet şartlarını ve lisans politikalarını izleyerek yaptığımı onaylıyorum.",
+ "upload-form-label-not-own-work-message-generic-foreign": "Bu dosyayı paylaşılan havuzun ilkeleri altına yükleyemiyorsanız, lütfen bu iletişim kutusunu kapatın ve başka bir yöntem deneyin.",
+ "upload-form-label-not-own-work-local-generic-foreign": "Bu dosya kendi politikaları dahilinde yüklenebiliyorsa, [[Special:Upload|{{SITENAME}} sayfasındaki yükleme]] sayfasını da kullanmayı deneyebilirsiniz.",
"backend-fail-stream": "$1 dosyası okunamadı.",
"backend-fail-backup": "\"$1\" dosyası yedeklenemedi.",
"backend-fail-notexists": "$1 dosyası mevcut değil.",
"uploadstash-errclear": "Dosyaların silinmesi başarısız oldu.",
"uploadstash-refresh": "Dosya listelerini yenile",
"uploadstash-thumbnail": "küçük resmi görüntüle",
+ "uploadstash-exception": "Yükleme ($1) deposunda saklanamadı: \"$2\".",
"uploadstash-bad-path": "Yol mevcut değil.",
"uploadstash-bad-path-invalid": "Yol geçerli değil.",
"uploadstash-bad-path-unknown-type": "Bilinmeyen tür \"$1\".",
"uploadstash-bad-path-unrecognized-thumb-name": "Tanınmayan başparmak adı.",
+ "uploadstash-bad-path-no-handler": "$1 dosyasının $2 mim değeri için işleyici bulunamadı.",
+ "uploadstash-bad-path-bad-format": "\"$1\" anahtarı uygun biçimde değil.",
+ "uploadstash-file-not-found": "\"$1\" anahtarı, saklama içinde bulunamadı.",
"uploadstash-file-not-found-no-thumb": "Küçük resim alınamadı.",
"uploadstash-file-not-found-no-local-path": "Ölçeklenmiş öge için yerel yol yok.",
"uploadstash-file-not-found-no-object": "Küçük resim için yerel dosya nesnesi oluşturulamadı.",
"uploadstash-file-not-found-no-remote-thumb": "Küçük resim alma başarısız oldu: $1\nURL = $2",
+ "uploadstash-file-not-found-missing-content-type": "Eksik içerik tipi başlığı.",
+ "uploadstash-file-not-found-not-exists": "Düz bir dosya bulunamıyor veya bulunamıyor.",
+ "uploadstash-file-too-large": "$1 bayttan daha büyük bir dosya sunulamaz.",
+ "uploadstash-not-logged-in": "Hiçbir kullanıcı oturum açmamış, dosyalar kullanıcılara ait olmalıdır.",
"uploadstash-wrong-owner": "Bu dosya ($1) mevcut kullanıcıya ait değil.",
+ "uploadstash-no-such-key": "Böyle bir anahtar ($1) kaldırılamaz.",
"uploadstash-no-extension": "Geçersiz uzantı.",
"uploadstash-zero-length": "Dosya boyutu sıfır.",
"invalid-chunk-offset": "Geçersiz öbek ofset",
"pageswithprop-legend": "Bir sayfa özelliğine sahip sayfalar",
"pageswithprop-text": "Bu sayfa belirli bir sayfa özelliğini kullanan sayfaları listeler.",
"pageswithprop-prop": "Özellik adı:",
+ "pageswithprop-reverse": "Ters sıraya göre sırala",
+ "pageswithprop-sortbyvalue": "Özellik değerine göre sırala",
"pageswithprop-submit": "Git",
"pageswithprop-prophidden-long": "uzun metin özellik değeri gizlendi ($1)",
"pageswithprop-prophidden-binary": "ikili özellik değeri gizlendi ($1)",
"move": "Taşı",
"movethispage": "Sayfayı taşı",
"unusedimagestext": "Aşağıdaki dosyalar mevcuttur ancak herhangi bir sayfada gömülü değildir.\nLütfen unutmayın ki, diğer web siteleri bir dosyaya doğrudan bir URL ile bağlantı verebilir, ve bu yüzden etkin kullanımda olmasa bile hala burada listenebilir.",
+ "unusedimagestext-categorizedimgisused": "Aşağıdaki dosyalar var, ancak hiçbir sayfaya gömülmüyor. Kategorilere ayrılmış görüntüler, herhangi bir sayfaya gömülmemelerine rağmen kullanıldığı gibi kabul edilir.\nDiğer web sitelerinin doğrudan bağlantılı bir dosyaya bağlanabileceğini ve aktif kullanımda olmasına rağmen burada listelenebileceğini lütfen unutmayın.",
"unusedcategoriestext": "Aşağıda bulunan kategoriler mevcut olduğu halde, hiçbir madde ya da kategori tarafından kullanılmıyor.",
"notargettitle": "Hedef yok",
"notargettext": "Bu fonksiyonu uygulamak için bir hedef sayfası ya da kullanıcısı belirtmediniz.",
"apihelp": "API yardımı",
"apihelp-no-such-module": "\"$1\" modülü bulunamadı.",
"apisandbox": "API deneme tahtası",
- "apisandbox-api-disabled": "API bu sitede devre dışı bırakılmış.",
+ "apisandbox-jsonly": "API sanal alanını kullanmak için JavaScript gereklidir.",
+ "apisandbox-intro": "<strong>MediaWiki web hizmeti API'sini</strong> denemek için bu sayfayı kullanın.\nAPI kullanımı hakkında daha fazla bilgi için [[mw:API:Main page|API dokümantasyonu]] bölümüne bakın. Örnek: [https://www.mediawiki.org/wiki/API#A_simple_example bir Ana Sayfanın içeriğini alın]. Daha fazla örnek görmek için bir eylem seçin.",
"apisandbox-submit": "İstek yap",
"apisandbox-reset": "Temizle",
"apisandbox-retry": "Tekrar dene",
+ "apisandbox-loading": "\"$1\" API modülü için bilgi yükleniyor...",
+ "apisandbox-load-error": "\"$1\" API modülü için bilgi yüklenirken bir hata oluştu: $2",
"apisandbox-no-parameters": "Bu API modülünde parametre yok.",
"apisandbox-helpurls": "Yardım bağlantıları",
"apisandbox-examples": "Örnekler",
"apisandbox-dynamic-parameters": "Ek parametreler",
"apisandbox-dynamic-parameters-add-label": "Parametre ekle:",
"apisandbox-dynamic-parameters-add-placeholder": "Parametre adı",
+ "apisandbox-dynamic-error-exists": "\"$1\" isimli bir parametre zaten var.",
+ "apisandbox-templated-parameter-reason": "Bu [[Special:ApiHelp/main#main/templatedparams|şablonlu parametresi]], $2’nin {{PLURAL:$1|değeri|değeri}} dayanarak sunulur.",
"apisandbox-deprecated-parameters": "Onaylanmamış parametreler",
"apisandbox-fetch-token": "Anahtarı otomatik olarak doldur",
"apisandbox-add-multi": "Ekle",
"apisandbox-sending-request": "API isteği gönderiliyor...",
"apisandbox-loading-results": "API sonuçları alınıyor...",
"apisandbox-results-error": "API sorgusu yanıtı yüklenirken bir hata oluştu: $1.",
+ "apisandbox-results-login-suppressed": "Bu istek, tarayıcının Same-Origin güvenliğini atlamak için kullanılabileceği için çıkış yapmış bir kullanıcı olarak işlendi. API sanal alanının otomatik belirteç işlemesinin bu tür isteklerle düzgün şekilde çalışmadığını unutmayın, lütfen bunları el ile doldurun.",
+ "apisandbox-request-selectformat-label": "İstek verilerini şu şekilde göster:",
"apisandbox-request-url-label": "İstek URL:",
"apisandbox-request-time": "İstek zamanı: {{PLURAL:$1|$1 ms}}",
"apisandbox-continue": "Devam et",
"wlheader-enotif": "E-posta bildirimi etkin.",
"wlheader-showupdated": "Sayfaları son ziyaretinizden beri değişen sayfalar '''kalın''' gösterilmiştir.",
"wlnote": "$3 saat $4 itibariyle son {{PLURAL:$2|bir saatte|'''$2''' saatte}} yapılan {{PLURAL:$1|son değişiklik|son '''$1''' değişiklik}} aşağıdadır.",
- "wlshowlast": "Son $1 saati $2 günü göster",
"watchlist-hide": "Gizle",
"watchlist-submit": "Göster",
"wlshowtime": "Gösterilecek zaman aralığı:",
"month": "Bu aya kadar (ve önceki aylar):",
"year": "Bu yıla kadar (ve önceki yıllar):",
"date": "Şu tarihe kadar:",
- "sp-contributions-newbies": "Sadece yeni kullanıcıların katkılarını göster",
- "sp-contributions-newbies-sub": "Yeni kullanıcılar için",
- "sp-contributions-newbies-title": "Yeni hesaplar için kullanıcı katkıları",
"sp-contributions-blocklog": "engelleme günlüğü",
"sp-contributions-suppresslog": "{{GENDER:$1|kullanıcının}} baskılanmış katkıları",
"sp-contributions-deleted": "{{GENDER:$1|kullanıcının}} silinen katkıları",
"img-lang-default": "(varsayılan dil)",
"img-lang-info": "Bu resmi $1 ile işle. $2",
"img-lang-go": "Gönder",
- "ascending_abbrev": "küçükten büyüğe",
- "descending_abbrev": "azalan",
"table_pager_next": "Sonraki sayfa",
"table_pager_prev": "Önceki sayfa",
"table_pager_first": "İlk",
"watch": "Watch",
"unwatch": "Unwatch",
"watchlist-details": "{{PLURAL:$1|$1 page|$1 pages}} on your watchlist, not counting talk pages.",
- "wlshowlast": "Maḥway li aŞuḥlofe dıtsimi meqım $1 Sa³ayat $2 Yawme",
"watchlist-options": "Watchlist options",
"actioncomplete": "uDuboro kamıl",
"actionfailed": "Action failed",
"uctop": "ḥaroyo",
"month": "muYarḥo",
"year": "hul iŞato:",
- "sp-contributions-newbies": "Bes maḥway Maṫwoṭo dHadome ḥaṭe",
"sp-contributions-blocklog": "Block log",
"sp-contributions-deleted": "Maṫwoṭo slige",
"sp-contributions-uploads": "Fayl masalqo",
"watchlist-details": "Leexan patas gmraka su mseupu kana o niqan {{PLURAL:$1|$1 kngkingal ruwahan patas}} (supu kana pprngaw ruwahan patas).",
"wlheader-showupdated": "Ga su mniq tnhici bi kingal babaw qmita wada kmpriyux smalu ruwahan patas mha saw muda <strong>patas qthur</strong> pqita.",
"wlnote": "Truma nii asaw paah $3 $4 brah na {{PLURAL:$2|<strong>$2</strong> kska iyax}} tuki snluuan {{PLURAL:$1|<strong>$1</strong> snsul kmpriyux}}.",
- "wlshowlast": "Pqita snii $1 {{PLURAL:$1|iyax}} tuki $2 {{PLURAL:$2|jiyax}}",
"watchlist-hide": "lmiying",
"watchlist-submit": "pqita",
"enotif_reset": "Pnskraya kana ruwahan patas asaw wada pqita",
"uctop": "sayang",
"month": "Jiyax nhdaan kngkingal idas:",
"year": "Jiyax bitaq hngkawas:",
- "sp-contributions-newbies": "Wana pqita bgurah sspgan patas ka suyang qnpahan",
"sp-contributions-blocklog": "hmuk jiyax rnisuh patas",
"sp-contributions-uploads": "",
"sp-contributions-logs": "jiyax rnisuh patas",
"show-big-image-preview": "Muda qmita prparu ni blbila: $1.",
"show-big-image-other": "Duma {{PLURAL:$2|msleexan qtaan}}: $1.",
"show-big-image-size": "$1 × $2 patas hnigan",
- "newimages-newbies": "Wana pqita bgurah sspgan patas ka suyang qnpahan",
"ilsubmit": "Miying",
"metadata-help": "Kska pusu patas nii supu kana duma pniyahan kari, pniyahan kari nii o yaa bi paah suwi kikay mangal hnigan aji uri o kikay powda miing rnisuh patas ga phiyug aji uri o saw kska suwi endaan mrana da.\nNasi pusu patas paah balay bi npusu na o wada psbgrahan smmalu, duma leexan balay patas o yaa bi ungat klaan mttuku tkkla wada psbgrahan smmalu pusu patas.",
"metadata-fields": "Ga kska ka saw pngkla kari bngkgan ka EXIF patas pngkla ngali ka nniqan nii supu kana ka patas pqita ruwahan patas, pida patas pgkla ka smeeliq siida wana pqita truma nii pngkla.\nDuma ka patas pngkla o gnama asaw lmiing.\n* make\n* model\n* datetimeoriginal\n* exposuretime\n* fnumber\n* isospeedratings\n* focallength\n* artist\n* copyright\n* imagedescription\n* gpslatitude\n* gpslongitude\n* gpsaltitude",
"watchthispage": "Languta tluka leri",
"unwatch": "Ungalanguti",
"watchlist-details": "{{PLURAL:$1|$1 tluka|$1 wa matluka}} eka nxaxamelo wa leswi uswilanguteke, kungasi hlayiwa matluka yu mbulavulo.",
- "wlshowlast": "Komba $1 wati awara $2 wa masiku kumbe",
"watchlist-options": "Minhlawulo ya nxaxamelo wa leswilangutiweke",
"watching": "Ulangutile...",
"unwatching": "Utshika ku languta...",
"uctop": "Henhla",
"month": "Kusukela e ka nhweti ya (kuya endhzaku):",
"year": "Ku sukela e ka lembe ra (kuya endhzaku):",
- "sp-contributions-newbies": "Komba minyikela ya ti akhawunti tintswa ntsena",
- "sp-contributions-newbies-sub": "Eka ti akhawunti ti ntswa",
"sp-contributions-blocklog": "Ngula ya nxaxamelo wa kusivela",
"sp-contributions-uploads": "Nxaxamelo wa ku nghenisa",
"sp-contributions-logs": "Nghula ya nxaxamelo",
"wlheader-enotif": "Электрон почта аша белдерүләр ачык.",
"wlheader-showupdated": "Сез соңгы карап чыгудан соң үзгәртелгән битләр <strong>калын</strong> хәрефләр белән күрсәтелгән.",
"wlnote": "Түбәндә $3 көнгә $4 вакытка соңгы {{PLURAL:$2|бер сәгать|<strong>$2</strong> сәгать}} эчендә ясалган соңгы {{PLURAL:$1|үзгәреш|<strong>$1</strong> үзгәреш}} күрсәтелгән.",
- "wlshowlast": "Соңгы $1 сәгать $2 көн эчендә күрсәтү",
"watchlist-hide": "Яшерү",
"watchlist-submit": "Күрсәтү",
"wlshowtime": "Вакыт эчендә күрсәтергә:",
"month": "Айдан башлап (һәм элегрәк):",
"year": "Елдан башлап (һәм элегрәк):",
"date": "Датадан башлап (һәм элегрәк):",
- "sp-contributions-newbies": "Яңа хисап язмаларыннан ясалган кертемне генә карау",
- "sp-contributions-newbies-sub": "Яңа хисап язмалары өчен",
"sp-contributions-blocklog": "тыю көндәлеге",
"sp-contributions-uploads": "төяүләр",
"sp-contributions-logs": "көндәлекләр",
"newimages-legend": "Сөзгеч",
"newimages-label": "Файл исеме (яки аның өлеше):",
"newimages-user": "IP адресы яки кулланучы исеме",
- "newimages-newbies": "Яңа хисап язмаларыннан ясалган кертемне генә күрсәтергә",
"newimages-showbots": "Бот төяүләрен күрсәтергә",
"newimages-hidepatrolled": "Тикшерелгән төяүләрне яшерергә",
"newimages-mediatype": "Медиа төре:",
"imgmultigoto": "$1 битенә күчү",
"img-lang-default": "(гадәттәге тел)",
"img-lang-go": "Башкару",
- "ascending_abbrev": "үсү",
- "descending_abbrev": "кимү",
"table_pager_next": "Киләсе бит",
"table_pager_prev": "Алдагы бит",
"table_pager_first": "Беренче бит",
"unwatch": "Küzätmäw",
"notanarticle": "Mäqälä tügel",
"watchlist-details": "Küzätü isemlegegezdä, bäxäs bitlären sanamıyça, {{PLURAL:$1|$1 bit|$1 bit}} bar.",
- "wlshowlast": "Bayağı $1 säğät $2 kön eçendä yäki nı kürsät",
"watchlist-hide": "Yäşerü",
"watchlist-options": "Küzätü isemlege köyläwläre",
"watching": "Küzätü isemlegemä östäwe…",
"uctop": "axırğı",
"month": "Aydan başlap (häm elegräk):",
"year": "Yıldan başlap (häm elegräk):",
- "sp-contributions-newbies": "Yaña xisap yazmalarınnan yasalğan kertemne genä qaraw",
- "sp-contributions-newbies-sub": "Yaña xisap yazmaları öçen",
"sp-contributions-blocklog": "tıyu köndälege",
"sp-contributions-logs": "köndäleklär",
"sp-contributions-talk": "bäxäs",
"imgmultipagenext": "aldağı bit →",
"imgmultigo": "Küçü!",
"imgmultigoto": "$1 bitenä küçü",
- "ascending_abbrev": "üsü",
- "descending_abbrev": "kimü",
"table_pager_next": "Kiläse bit",
"table_pager_prev": "Aldağı bit",
"table_pager_first": "Berençe bit",
"unwatch": "Хайгааравас",
"unwatchthispage": "Бо арынны хайгаарабас",
"watchlist-details": "Чугаалажылга арыннарын санаваска, хайгаарал даңзыңарда {{PLURAL:$1|$1 арын}} бар.",
- "wlshowlast": "Сөөлү $1 шак болгаш $2 хүн иштинде көргүзери",
"watchlist-options": "Хайгаарал даңзының эдиглери",
"watching": "Хайгаарап турар...",
"unwatching": "Хайгааравайн турар...",
"uctop": "амгы",
"month": "Айдан:",
"year": "Чылдан:",
- "sp-contributions-newbies": "Чүгле чаа кежигүннерниң салыышкыннарын көргүзери",
"sp-contributions-blocklog": "кызыгаарлаашкынның журналы",
"sp-contributions-uploads": "киирген чүүлдер",
"sp-contributions-logs": "журналдар",
"watchlistfor2": "ⵉ $1 $2",
"watch": "ⵥⵕ",
"unwatch": "ⵙⴱⴻⴷⴷ ⵍⵄⵙⵙⴰ",
- "wlshowlast": "ⵉⵥⵕⵉ ⵏⵉⴹⵏ $1 ⵜⴰⵔⴰⴳⵉⵏ $2 ⵓⵙⵙⴰⵏ",
"changed": "ⵜⴱⴷⴷⴻⵍⴷ",
"delete-legend": "ⵓⴽⵓⵙ",
"protectcomment": "ⴰⵙⵔⴰⴳ:",
"mycontris": "ⴰⵎⴰⵡⴰⵙⵏ",
"contribsub2": "ⵉ $1 ($2)",
"uctop": "ⴰⴼⵍⵍⴰ",
- "sp-contributions-newbies-sub": "ⵉ ⵉⵙⴷⴰⵡⵏ ⵉⵎⴰⵢⵏⵓⵜⵏ",
"sp-contributions-talk": "ⴰⵎⵢⴰⵏⵏⴰⵏ",
"sp-contributions-submit": "ⴰⵔⵣⵣⵓ",
"whatlinkshere": "ⵎⴰ ⵢⵣⴷⵉⵏ ⵖⵉ",
"uctop": "бызьыны",
"month": "Толэзьысен (вазен но):",
"year": "Арысен (вазен но):",
- "sp-contributions-newbies": "Юрттэт чотын гинэ вылез возьма",
"sp-contributions-blocklog": "блокировкаосыз",
"sp-contributions-deleted": "{{GENDER:$1|викиавторлэн}} быдтэм тупатонъёсыз",
"sp-contributions-logs": "журналъёс",
"suppress": "چەكلەش",
"querypage-disabled": "بۇ ئالاھىدە بەت ئۈنۈم سەۋەبىدىن چەكلەندى.",
"apisandbox": "API قۇم ساندۇقى",
- "apisandbox-api-disabled": "مەزكۇر بېكەتتە API چەكلەندى.",
"apisandbox-intro": "بۇ بەت ئارقىلىق '''MediaWiki تور مۇلازىمىتى ئەپ ئېغىزى (API)نى سىناڭ'''.\nبۇ API نى ئىشلىتىشنىڭ تەپسىلاتىنى بىلمەكچى بولسىڭىز [https://www.mediawiki.org/wiki/API:Main_page the API قوللانمىسى]نى كۆرۈڭ. مەسىلەن: [https://www.mediawiki.org/wiki/API#A_simple_example مەلۇم ئاساسىي بەتنىڭ مەزمۇنىغا ئېرىشىش]، ئاندىن بىر مەشغۇلاتنى تاللاپ تېخىمۇ كۆپ ئۈلگە مىسالنى كۆرۈڭ.",
"apisandbox-submit": "ئىلتىماس يوللا",
"apisandbox-reset": "تازىلا",
"wlheader-enotif": "ئېلخەتتە ئەسكەرتىش ئىقتىدارى قوزغىتىلدى.",
"wlheader-showupdated": "سىز ئالدىنقى قېتىم كۆرگەندىن كېيىن ئۆزگەرتىلگەن بەتلەر '''توم''' كۆرۈنىدۇ",
"wlnote": "تۆۋەندىكىسى يېقىنقى {{PLURAL:$2|سائەت}} ئىچىدىكى ئاخىرقى '{{PLURAL:$1| قېتىملىق}} ئۆزگەرتىش، $3 $4 گىچە.",
- "wlshowlast": "يېقىنقى $1 سائەت $2 كۈنلۈك ئۆزگەرتىشىنى كۆرسەت",
"watchlist-options": "كۆزەت تىزىملىك تاللانما",
"watching": "كۆزەت قىلىۋاتىدۇ…",
"unwatching": "كۆزەت قىلمايۋاتىدۇ…",
"uctop": "نۆۋەتتىكى",
"month": "ئايدىن بۇيان (ياكى ئىلگىرى):",
"year": "يىلدىن بۇيان (ياكى ئىلگىرى):",
- "sp-contributions-newbies": "يېڭى قۇرۇلغان ئىشلەتكۈچى تۆھپىسىنىلا كۆرسەت",
- "sp-contributions-newbies-sub": "يېڭى ھېسابات",
- "sp-contributions-newbies-title": "يېڭى ھېساباتنىڭ ئىشلەتكۈچى تۆھپىسى",
"sp-contributions-blocklog": "چەكلەنگەن خاتىرە",
"sp-contributions-deleted": "ئۆچۈرۈلگەن ئىشلەتكۈچىنىڭ تۆھپىسى",
"sp-contributions-uploads": "يۈكلەر",
"imgmultipagenext": "كېيىنكى بەت →",
"imgmultigo": "يوللاش!",
"imgmultigoto": "$1 .بەتكە يۆتكىلىش",
- "ascending_abbrev": "ئۆسكۈچى",
- "descending_abbrev": "كېمەيگۈچى",
"table_pager_next": "كېيىنكى بەت",
"table_pager_prev": "ئالدىنقى بەت",
"table_pager_first": "بىرىنچى بەت",
"apihelp-no-such-module": "Додаток \"$1\" не знайдено.",
"apisandbox": "Майданчик для тестування API",
"apisandbox-jsonly": "Для використання API-пісочниці потрібен JavaScript.",
- "apisandbox-api-disabled": "API вимкнуто на цьому сайті.",
"apisandbox-intro": "Ця сторінка служить для експериментування з <strong>MediaWiki веб-API</strong>.\nЗверніться до [[mw:API:Main page|документації]] для докладнішої інформації про використання API. Приклад: [https://www.mediawiki.org/wiki/API#A_simple_example як отримати вміст головної сторінки]. Виберіть дію, щоб побачити більше прикладів.\n\nЗверніть увагу, що, хоча це пісочниця, дії, виконані вами, на цій сторінці можуть змінити вікі.",
"apisandbox-submit": "Зробити запит",
"apisandbox-reset": "Очистити",
"wlheader-enotif": "Сповіщення електронною поштою ввімкнено.",
"wlheader-showupdated": "Сторінки, що змінилися після Вашого останнього їх відвідування, виділені '''жирним''' шрифтом.",
"wlnote": "Нижче наведено {{PLURAL:$1|останнє $1 редагування|останні $1 редагування|останні $1 редагувань}} за {{PLURAL:$2|останню|останні|останні}} <strong>$2</strong> {{PLURAL:$2|годину|години|годин}}, на час $3 $4.",
- "wlshowlast": "Показати зміни за останні $1 годин $2 днів",
"watchlist-hide": "Приховати",
"watchlist-submit": "Показати",
"wlshowtime": "Період часу для відображення:",
"month": "До місяця (включно):",
"year": "До року (включно):",
"date": "З дати (і раніше):",
- "sp-contributions-newbies": "Показати лише внесок з нових облікових записів",
- "sp-contributions-newbies-sub": "Внесок новачків",
- "sp-contributions-newbies-title": "Внесок з нових облікових записів",
"sp-contributions-blocklog": "журнал блокувань",
"sp-contributions-suppresslog": "прихований внесок {{GENDER:$1|користувача|користувачки}}",
"sp-contributions-deleted": "вилучені редагування {{GENDER:$1|користувача|користувачки}}",
"newimages-legend": "Фільтр",
"newimages-label": "Назва файлу (або її частина):",
"newimages-user": "IP-адреса або ім'я користувача.",
- "newimages-newbies": "Показувати лише внесок нових користувачів",
"newimages-showbots": "Показати завантаження ботами",
"newimages-hidepatrolled": "Приховати відпатрульовані завантаження",
"newimages-mediatype": "Тип медіа:",
"img-lang-default": "(типова мова)",
"img-lang-info": "Візуалізувати це зображення у $1. $2",
"img-lang-go": "Перейти",
- "ascending_abbrev": "зрост",
- "descending_abbrev": "спад",
"table_pager_next": "Наступна сторінка",
"table_pager_prev": "Попередня сторінка",
"table_pager_first": "Перша сторінка",
"apihelp-no-such-module": "ماڈیول \"$1\" نہیں ملا",
"apisandbox": "اے پی آئی کا تختۂ مشق",
"apisandbox-jsonly": "اے پی آئی کے تختۂ مشق کو استعمال کرنے کے لیے جاوا اسکرپٹ درکار ہے۔",
- "apisandbox-api-disabled": "اس سائٹ پر اے پی آئی غیر فعال ہے۔",
"apisandbox-submit": "بنانے کی درخواست",
"apisandbox-reset": "واضح",
"apisandbox-retry": "دوبارہ کوشش کریں",
"wlheader-enotif": "ای میل کی اطلاع فعال ہے ۔",
"wlheader-showupdated": "آپ کی آخری آمد کے بعد جن صفحات میں تبدیلی ہوئی ہے وہ <strong>جلی حروف</strong> میں نظر آئیں گے۔",
"wlnote": "ذیل میں گزشتہ {{PLURAL:$2|گھنٹے|<strong>$2</strong> گھنٹوں}} میں ہونے والی {{PLURAL:$1|تبدیلی|<strong>$1</strong> تبدیلیوں}} کی فہرست درج ہے، تاریخ تجدید $3، $4",
- "wlshowlast": "آخری $1 گھنٹے $2 دن دکھائیں",
"watchlist-hide": "چھپائیں",
"watchlist-submit": "دکھائیں",
"wlshowtime": "ظاہر ہونے کی مدت:",
"month": "مہینہ (اور اُس سے قبل):",
"year": "سال (اور اُس سے قبل):",
"date": "تاریخ سے (اور اس سے قبل)",
- "sp-contributions-newbies": "محض جدید صارفین کی شراکتیں دکھائیں",
- "sp-contributions-newbies-sub": "جدید صارفین کے",
- "sp-contributions-newbies-title": "جدید صارفین کی شراکتیں",
"sp-contributions-blocklog": "نوشتۂ پابندی",
"sp-contributions-suppresslog": "{{GENDER:$1|صارف}} کی پوشیدہ شراکتیں",
"sp-contributions-deleted": "{{GENDER:$1|صارف}} کی حذف شدہ شراکتیں",
"newimages-legend": "مقطر",
"newimages-label": "فائل کا نام (یا اس کا جزو):",
"newimages-user": "آئی پی پتہ یا صارف نام",
- "newimages-newbies": "محض نئے کھاتوں کی شراکتیں دکھائیں",
"newimages-showbots": "روبہ جات کے ذریعہ اپلوڈ کردہ فائلیں دکھائیں",
"newimages-hidepatrolled": "مراجعت شدہ اپلوڈ چھپائیں",
"newimages-mediatype": "میڈیا قسم:",
"img-lang-default": "(طے شدہ زبان)",
"img-lang-info": "تصویر کا اس زبان میں ترجمہ کریں $1۔ $2",
"img-lang-go": "چلیں",
- "ascending_abbrev": "صعودی",
- "descending_abbrev": "نزولی",
"table_pager_next": "اگلا صفحہ",
"table_pager_prev": "پچھلا صفحہ",
"table_pager_first": "پہلا صفحہ",
"watchlist-details": "Sizning kuzatuv roʻyxatingizda hozirda {{PLURAL:$1|bitta sahifa|$1ta sahifa}} mavjud (munozara sahifalarini hisobga olmaganda).",
"wlheader-showupdated": "Siz oxirgi marta kirganingizdan keyin oʻzgartirilgan sahifalar '''qalin''' yozuv bilan ajratib koʻrsatilgan.",
"wlnote": "Quyida oxirgi $2 soat ichida sodir boʻlgan {{PLURAL:$1|oxirgi oʻzgarish|<strong>$1</strong> ta oʻzgarishlar}} koʻrsatilgan. $3, $4.",
- "wlshowlast": "Oxirgi $1 soatdagi $2 kundagi tahrirlarni koʻrsatish",
"watchlist-submit": "Koʻrsat",
"watchlist-options": "Kuzatuv roʻyxati moslamalari",
"watching": "Kuzatish...",
"month": "Oydan (va avvalroq)",
"year": "Yildan (va avvalroq)",
"date": "Shu sanadan avvalroq:",
- "sp-contributions-newbies": "Faqatgina yangi foydalanuvchilarning hissalarini koʻrsat",
- "sp-contributions-newbies-sub": "Yangi hisob yozuvlaridan",
- "sp-contributions-newbies-title": "Yangi hisob yozuvlarining hissalari",
"sp-contributions-blocklog": "chetlatishlar",
"sp-contributions-deleted": "oʻchirilgan tahrirlar",
"sp-contributions-uploads": "yuklamalar",
"wlheader-enotif": "Xe ativà la notifica via e-mail.",
"wlheader-showupdated": "Le pagine che xe stà canbià da l'ultima olta che te le ghè viste, a le xe segnà in <strong>groso</strong>.",
"wlnote": "Cuà soto te cati {{PLURAL:$1|'l ultimo canbiamento|i ultimi <strong>$1</strong> canbiamenti}} inte {{PLURAL:$2|l'ultema ora|łe ultime <strong>$2</strong> ore}}; i dati i xe axornai a łe $4 del $3.",
- "wlshowlast": "Mostra le ultime $1 ore $2 zorni",
"watchlist-options": "Inpostassion de le pagine tegnùe d'ocio",
"watching": "Taco a tegner d'ocio...",
"unwatching": "Desmeto de tegner d'ocio...",
"uctop": "de dèsso",
"month": "Dal mese (e quei prima):",
"year": "Da l'ano (e quei prima):",
- "sp-contributions-newbies": "Fame védar solo i contributi de i utenti novi",
- "sp-contributions-newbies-sub": "Par i novi utenti",
- "sp-contributions-newbies-title": "Contributi dei utenti novi",
"sp-contributions-blocklog": "blochi",
"sp-contributions-deleted": "contributi utente scancelà",
"sp-contributions-uploads": "caricamenti",
"imgmultigoto": "Và a la pagina $1",
"img-lang-default": "(lengua predefinìa)",
"img-lang-go": "Và",
- "ascending_abbrev": "cresc",
- "descending_abbrev": "decresc",
"table_pager_next": "Pagina sucessiva",
"table_pager_prev": "Pagina precedente",
"table_pager_first": "Prima pagina",
"notvisiblerev": "Versijad oma čutud",
"watchlist-details": "Teiden kaclendnimikirjuteses om {{PLURAL:$1|$1 lehtpol'|$1 lehtpol't}}. Lodulehtpoled ei olgoi neciš lugus.",
"wlheader-enotif": "Tedotand e-počtadme om kävutamas.",
- "wlshowlast": "Ozutada jäl'gmäižiš $1 časuiš da $2 päiviš",
"watchlist-options": "Kaclendnimikirjutesen järgendused",
"watching": "Ližaduz kaclendnimikirjuteshe...",
"unwatching": "Heitmine kaclendnimikirjutesespäi...",
"uctop": "nügüdläine",
"month": "Ku:",
"year": "Voz’:",
- "sp-contributions-newbies": "Ozutada vaiše uziden kävutajiden tondad",
- "sp-contributions-newbies-sub": "Uziden registracijoiden täht",
- "sp-contributions-newbies-title": "Uziden kävutajiden tond",
"sp-contributions-blocklog": "Blokiruindoiden aigkirj",
"sp-contributions-deleted": "Čutud kävutajan tond",
"sp-contributions-uploads": "jügutoitandad",
"imgmultipagenext": "jäl'ghine lehtpol' →",
"imgmultigo": "Mända!",
"imgmultigoto": "Mända lehtpolele $1",
- "ascending_abbrev": "lib.",
- "descending_abbrev": "lask.",
"table_pager_next": "Jäl'ghine lehtpol'",
"table_pager_prev": "Edeline lehtpol'",
"table_pager_first": "Ezmäine lehtpol’",
"apihelp-no-such-module": "Không tìm thấy mô đun “$1”",
"apisandbox": "Chỗ thử API",
"apisandbox-jsonly": "Cần phải có JavaScript để sử dụng API sandbox.",
- "apisandbox-api-disabled": "API đã bị vô hiệu hóa trên trang web này.",
"apisandbox-intro": "Trang này dùng để thử nghiệm với <strong>API dịch vụ Web của MediaWiki</strong>.\nHãy tra cứu [[mw:API:Main page|tài liệu API]] để biết chi tiết về cách sử dụng API. Ví dụ: [https://www.mediawiki.org/wiki/API#A_simple_example lấy nội dung của Trang Chính]. Chọn một tác vụ để xem thêm ví dụ.\n\nLưu ý rằng, mặc dù đây là một chỗ thử, nhưng các tác vụ của bạn tại trang này có thể thực hiện các thay đổi trên wiki.",
"apisandbox-submit": "Yêu cầu",
"apisandbox-reset": "Tẩy trống",
"wlheader-enotif": "Đã bật thông báo qua thư điện tử.",
"wlheader-showupdated": "Các trang đã thay đổi kể từ lần cuối bạn xem chúng được in <strong>đậm</strong>.",
"wlnote": "Dưới đây là {{PLURAL:$1|thay đổi duy nhất|<strong>$1</strong> thay đổi gần nhất}} trong {{PLURAL:$2|giờ|<strong>$2</strong> giờ}} qua, tính tới $3 lúc $4.",
- "wlshowlast": "Hiển thị $1 giờ $2 ngày gần đây",
"watchlist-hide": "Ẩn",
"watchlist-submit": "Xem",
"wlshowtime": "Thời gian để hiển thị:",
"month": "Từ tháng (trở về trước):",
"year": "Từ năm (trở về trước):",
"date": "Từ ngày (trở về trước):",
- "sp-contributions-newbies": "Chỉ hiển thị đóng góp của tài khoản mới",
- "sp-contributions-newbies-sub": "Các thành viên mới",
- "sp-contributions-newbies-title": "Đóng góp của các thành viên mới",
"sp-contributions-blocklog": "nhật trình cấm",
"sp-contributions-suppresslog": "đóng góp của {{GENDER:$1}}người dùng đã bị xóa hẳn",
"sp-contributions-deleted": "đóng góp đã bị xóa của {{GENDER:$1}}thành viên",
"newimages-legend": "Bộ lọc",
"newimages-label": "Tên tập tin (hoặc một phần tên):",
"newimages-user": "Địa chỉ IP hoặc tên người dùng",
- "newimages-newbies": "Chỉ hiển thị đóng góp của tài khoản mới",
"newimages-showbots": "Xem các tập tin do bot tải lên",
"newimages-hidepatrolled": "Ẩn tập tin tải lên đã tuần tra",
"newimages-mediatype": "Kiểu phương tiện:",
"img-lang-default": "(ngôn ngữ mặc định)",
"img-lang-info": "Kết xuất hình này trong $1. $2",
"img-lang-go": "Xem",
- "ascending_abbrev": "tăng",
- "descending_abbrev": "giảm",
"table_pager_next": "Trang sau",
"table_pager_prev": "Trang trước",
"table_pager_first": "Trang đầu",
"watchthispage": "Dii sajdn undâr beoobachdung nämâ",
"unwatch": "Nimmä beoobachdn",
"watchlist-details": "Duu häldsch {{PLURAL:$1|1 sajdn|$1 sajdn}} undâr beoobachdung.",
- "wlshowlast": "Dsajch dii ändrunga fo di ledsdn $1 schdundn, $2 dooch odär",
"watchlist-options": "Was un wii alles af Dajnâr beobachdungslisdn dsajchd wärn sol",
"watching": "Ghumd undâr beoobachdung ...",
"unwatching": "Beobachdn ajschränggn",
"uctop": "agduell",
"month": "bis moonad:",
"year": "bis dsum jôôr:",
- "sp-contributions-newbies": "Bloos bajdrääch fo naj Ôôgmeldâ dsajchn",
"sp-contributions-blocklog": "Schbär-brodoghol",
"sp-contributions-uploads": "Houchglodne Daddein",
"sp-contributions-logs": "Logbäicher",
"wlheader-enotif": "Nunam medü pot leäktronik pemögükon.",
"wlheader-showupdated": "Pads pos visit lätik ola pevotüköls papenons '''me tonats bigik'''",
"wlnote": "Is palisedons votükam{{PLURAL:$1| lätik|s lätik '''$1'''}} dü düp{{PLURAL:$2| lätik|s lätik '''$2'''}}.",
- "wlshowlast": "Jonolöd: düpis lätik $1, delis lätik $2,",
"watchlist-options": "Paramets galädaliseda",
"watching": "Papladon ini galädalised...",
"unwatching": "Pamoükon se galädalised...",
"uctop": "anuik",
"month": "De mul (e büiks):",
"year": "De yel (e büiks):",
- "sp-contributions-newbies": "Jonolöd te keblünotis kalas nulik",
- "sp-contributions-newbies-sub": "Tefü kals nulik",
- "sp-contributions-newbies-title": "Gebanakeblünots pro kals nulik",
"sp-contributions-blocklog": "Jenotalised blokamas",
"sp-contributions-deleted": "gebanakeblünots pemoüköl",
"sp-contributions-uploads": "löpükams",
"imgmultipagenext": "pad sököl →",
"imgmultigo": "Gololöd!",
"imgmultigoto": "Lü pad: $1",
- "ascending_abbrev": "löpio",
- "descending_abbrev": "donio",
"table_pager_next": "Pad sököl",
"table_pager_prev": "Pad büik",
"table_pager_first": "Pad balid",
"watchthispage": "Katso sitä cülciä",
"unwatch": "Lõpõt kattsõõmin",
"watchlist-details": "Kattsõspiizgall on {{PLURAL:$1|$1 cülci|$1 cülciä}} (ilma juttucülciit).",
- "wlshowlast": "Näüt viimeized $1 tunnia vai $2 päivää",
"watchlist-options": "Kattsõspiizgaa valimizõd",
"watching": "Kattsõõn…",
"unwatching": "Kattsõõmizõõ lõpõttõmin…",
"uctop": "ülez",
"month": "Kuu",
"year": "Voosi:",
- "sp-contributions-newbies": "Näüt uusijõõ cäüttijee muutuhsõd",
"sp-contributions-blocklog": "piättelemized",
"sp-contributions-uploads": "lassausõd",
"sp-contributions-logs": "logid",
"wlheader-enotif": "E-postiga teedäqandmisõq ommaq käügin.",
"wlheader-showupdated": "Leheq, midä om muudõt päält su viimäst käümist, ommaq '''paksun kirän'''.",
"wlnote": "Tan om {{PLURAL:$1|viimäne muutminõ|viimädseq <strong>$1</strong> muutmist}} viimädse {{PLURAL:$2|tunni|<strong>$2</strong> tunni}} joosul saisuga $3, kell $4.",
- "wlshowlast": "Näütäq viimädseq $1 tunni $2 päivä",
"watchlist-options": "Perräkaemisnimekirä säädmine",
"watching": "Pandas perräkaemisnimekirjä...",
"unwatching": "Võetas perräkaemisõ alt maaha...",
"uctop": "parhillanõ",
"month": "Alostõn kuust (ja varrampa):",
"year": "Alostõn aastagast (ja varrampa):",
- "sp-contributions-newbies": "Näütäq õnnõ vahtsidõ pruukjidõ toimõnduisi",
- "sp-contributions-newbies-sub": "Vahtsidõ pruukjidõ toimõndusõq",
"sp-contributions-blocklog": "Kinniqpidämisnimekiri",
"sp-contributions-uploads": "üleslaatmisõq",
"sp-contributions-logs": "muutmisnimekiräq",
"imgmultipagenext": "järgmäne leht →",
"imgmultigo": "Mineq!",
"imgmultigoto": "Mineq lehekülele $1",
- "ascending_abbrev": "ülespoolõ",
- "descending_abbrev": "allapoolõ",
"table_pager_next": "Järgmäne leht",
"table_pager_prev": "Mineväne leht",
"table_pager_first": "Edimäne leht",
"wlheader-enotif": "Li notifiaedje pa emile est en alaedje.",
"wlheader-showupdated": "Les pådjes k' ont candjî dispoy vosse dierinne vizite sont metowes e <strong>cråssès letes</strong>.",
"wlnote": "Chal pa dzo {{PLURAL:$1|li dierin candjmint|les <strong>$1</strong> dierins candjmints}} {{PLURAL:$2|del dierinne eure|des <strong>$2</strong> dierinnès eures}}, disk' å $3 a $4.",
- "wlshowlast": "Mostrer les dierin(nè)s $1 eures, $2 djoûs",
"watchlist-hide": "Catchî",
"watchlist-submit": "Mostrer",
"watchlist-options": "Tchuzes del djivêye des shuvous",
"uctop": "dierinne",
"month": "dispu l' moes (et pus timpe)",
"year": "Dispu l' anêye (et pus timpe):",
- "sp-contributions-newbies": "Mostrer seulmint les contribouwaedjes des noveas contes",
- "sp-contributions-newbies-sub": "Emey les noveas uzeus",
- "sp-contributions-newbies-title": "Contribouwaedjes des noveas uzeus",
"sp-contributions-blocklog": "djournå des blocaedjes",
"sp-contributions-deleted": "contribouwaedjes disfacés di l' uzeu{{GENDER:$1||se}}",
"sp-contributions-uploads": "eberwetaedjes",
"imgmultipageprev": "← pådje di dvant",
"imgmultipagenext": "pådje shuvante →",
"imgmultigo": "Potchî !",
- "ascending_abbrev": "crexh.",
- "descending_abbrev": "discr.",
"table_pager_next": "Pådje shuvante",
"table_pager_prev": "Pådje di dvant",
"table_pager_first": "Prumire pådje",
"watchlist-details": "{{PLURAL:$1|$1 nga pakli|$1 nga mga pakli}} aada ha imo talaan nga binabantayan (upod an mga hiruhimangraw-nga-pakli).",
"wlheader-showupdated": "An mga pakli nga nagbag-o tikang ha imo urhi nga pagbisita in ginpapakita hin <strong>madakmol nga kasurat</strong>.",
"wlnote": "Ha ilarom {{PLURAL:$1|amo an urhi nga pagbag-o|amo an mga urhi nga <strong>$1</strong> nga pagbag-o}} ha urhi nga {{PLURAL:$2|oras|<strong>$2</strong> mga oras}}, han $3, $4.",
- "wlshowlast": "Igpakita an katapusan nga $1 ka mga oras $2 ka mga adlaw",
"watchlist-hide": "Tago-a",
"watchlist-submit": "Pakit-a",
"wlshowtime": "Kaiha han oras ha pagdisplay:",
"uctop": "pagkayana",
"month": "Tikang ha bulan (ngan uruunhan):",
"year": "Tikang ha tuig (ngan uruunhan):",
- "sp-contributions-newbies": "Igpakita an mga amot hin mga bag-o nga akawnt la",
- "sp-contributions-newbies-sub": "Para han bag-o nga mga akawnt",
"sp-contributions-blocklog": "Talaan han pagpugong",
"sp-contributions-uploads": "mga ginkarga-paigbaw",
"sp-contributions-logs": "Mga talaan",
"imgmultigo": "Pakadto!",
"imgmultigoto": "Pakadto ha pakli $1",
"img-lang-go": "Kadto",
- "ascending_abbrev": "pasaka",
- "descending_abbrev": "paubos",
"table_pager_next": "Sunod nga pakli",
"table_pager_prev": "Naha-una nga pakli",
"table_pager_first": "Una nga pakli",
"watchlist-details": "Topp nga $1 {{PLURAL:$1|xët|ciy xët}}, soo waññiwaalewul xëti waxtaanuwaay yi.",
"wlheader-showupdated": "Xët yi ñu soppiwoon ca sa duggu bu mujj ñoom la ñu fesal ñu <b>xëm</b>",
"wlnote": "Fii ci suuf {{PLURAL:$1| ngay gis coppite yu mujj yi|ngay gis $1 coppite yu mujj}} ci {{PLURAL:$2|waxtu gu mujj gi|<b>$2</b> waxtu yu mujj}}.",
- "wlshowlast": "wone $1 waxtu yu mujj, $2 bess yu mujj, walla .",
"watchlist-options": "Tànneefi limu toppte bi",
"watching": "Topp...",
"unwatching": "Farug toppte gi ...",
"uctop": "bi mujj",
"month": "Tambali ci weeru (ak yi jiitu) :",
"year": "Tambali ci atum (ak yi jiitu) :",
- "sp-contributions-newbies": "Wone cëru yu jëfandikukat yu yees yi rekk",
- "sp-contributions-newbies-sub": "yu jëfandikukat yu yees yi",
- "sp-contributions-newbies-title": "Cëru yu jëfandikukat yu yees yi",
"sp-contributions-blocklog": "Jaar-jaaru téye yi",
"sp-contributions-deleted": "cëru yi ñu far",
"sp-contributions-logs": "Yéenekaay",
"watchlist-details": "有$1页垃拉侬关注表高头(包括讨论页)。",
"wlheader-showupdated": "勒侬上趟查看之后修改过个页面<strong>加粗</strong>显示。",
"wlnote": "下底是{{PLURAL:$2|过去<strong>$2</strong>个钟头}}个{{PLURAL:$1|阿末<strong>$1</strong>趟更改}},截至$3 $4。",
- "wlshowlast": "显示上$1个钟头$2日天",
"watchlist-hide": "囥脱",
"wlshowhidemine": "我个编辑",
"watchlist-options": "关注表选项",
"uctop": "此垡",
"month": "从箇月往前:",
"year": "从箇年往前:",
- "sp-contributions-newbies": "只显示新用户个贡献",
"sp-contributions-blocklog": "查封记录",
"sp-contributions-deleted": "删脱个{{GENDER:$1|用户}}贡献",
"sp-contributions-uploads": "上传",
"imgmultipagenext": "下一页 →",
"imgmultigo": "去!",
"imgmultigoto": "去到第$1页",
- "ascending_abbrev": "升序",
- "descending_abbrev": "降序",
"table_pager_next": "下页",
"table_pager_prev": "上页",
"table_pager_first": "头一页",
"watchthispage": "Эн халхиг шинҗлх",
"unwatch": "Шинҗлх биш",
"watchlist-details": "Тана оврлңд меткәнә халхас бус $1 халх.",
- "wlshowlast": "Сүл $1 цагин $2 өдрин туршк үзүлх",
"watchlist-options": "Шинҗллһнә сеткүлин көгүд",
"watching": "Шинҗллһнә бүтлклд немлһн...",
"unwatching": "Шинҗлһнә бүрткләс һарһлһн...",
"uctop": "отхн",
"month": "Эн сарас (болн эртәр):",
"year": "Эн җиләс (болн эртәр):",
- "sp-contributions-newbies": "Шин бичгдлһтә кесн демнлһн һанцхн үзүлх",
"sp-contributions-blocklog": "бүсллһнә сеткүл",
"sp-contributions-deleted": "һарһсн демнчна сольлһн",
"sp-contributions-talk": "меткән",
"watchthispage": "თე ხასილაშ კონტროლ",
"unwatch": "კონტროლიშ გოუქვაფა",
"watchlist-details": "{{PLURAL:$1|$1 ხასჷლა|$1 ხასჷლა}} რე თქვან კონტროლიშ ერკებულს, სხუნუაშ ხასჷლეფიშ უმეუკოროცხუო.",
- "wlshowlast": "ეკონია $1 საათიშ $2 დღაშ ძირაფა",
"watchlist-options": "კონტროლიშ ერკებულიშ ოფციეფ",
"watching": "კონტროლირებად...",
"unwatching": "კონტროლ მონწყუმილ რე ...-შა",
"uctop": "დუდ",
"month": "ათე თუთაშე (დო უადრაშე):",
"year": "ათე წანაშე (დო უადრაშე):",
- "sp-contributions-newbies": "ქოძირით ხვალე ახალ მახვარებუეფიშ მიშაღალირ თიეფ",
- "sp-contributions-newbies-sub": "ახალეფშოთ",
"sp-contributions-blocklog": "ბლოკირაფაშ ისტორია",
"sp-contributions-uploads": "ეხარგუეფ",
"sp-contributions-logs": "ჟურნალეფი",
"img-lang-default": "(საწყისი ენა)",
"img-lang-info": "აჩვენე ეს გამოსახულება $1, $2-ში",
"img-lang-go": "მიდი",
- "ascending_abbrev": "დაბრ",
- "descending_abbrev": "აღწერა",
"table_pager_next": "შემდეგი გვერდი",
"table_pager_prev": "წინა გვერდი",
"table_pager_first": "პირველი გვერდი",
"watchlist-details": "niSo’ kakita’an ray qintan babaw saeboeh hayza’ $1 yemien ( nom maehraehrang yemien saeboeh).",
"wlheader-showupdated": "niSo’ ray ’ima maybi:il monhael komita sizaeh ka pinonrowa’ yemian ’am ’anoka <strong>\npinakrarahoe’ kina:at </strong> Sipinakita’.",
"wlnote": "hani wahoer ’ima ’aring $3 $4 kaysa’an <strong>$2</strong> kakita’an hahila: pinaskayzayzaeh <strong>$1</strong> pinapaybi:il ka pyenti:",
- "wlshowlast": "pinakita’ haysani’ $1 kakita’an ka hahila: $2 hahila:",
"watchlist-hide": " Sa:il",
"watchlist-submit": "pinakita’",
"enotif_reset": "pinSakira:a’ ray yemien kinita’ ila saeboeh",
"uctop": " ’isahini",
"month": "kalokngoran ka ’ilaS:",
"year": "kalokngoran ka tinal’oemaeh:",
- "sp-contributions-newbies": "pinakita’ nanaw ka ’ima SaSo’ zhanghaw ka pinatawaw",
"sp-contributions-blocklog": " soksok ka pinatawaw",
"sp-contributions-logs": "pinatawaw",
"sp-contributions-talk": " kapaehrahrangan",
"show-big-image-preview": " pinaSawaSak kinSopaloy:$1.",
"show-big-image-other": " ’aroma’ {{PLURAL:$2||}} kin tilka:an :$1.$1",
"show-big-image-size": "$1 × $2 kakita’an ka hinoba:ang",
- "newimages-newbies": "pinakita’ nanaw ka ’ima SaSo’ zhanghaw ka pinatawaw",
"ilsubmit": " komi:im",
"metadata": " pinqyuanSe’ ka kina:at",
"metadata-help": "hini tang’an ’izo’ hani saeboeh ka ’aroma’ kakra:aman, hini saeboeh kakra:aman ra:amen ’inaySu’wey kakSaSing a kikay nom Sawmya ray pinaskayzaeh a Su’weyhwa’ ’izo’ baba:aw rinpa:, So: tang’an ’inay’a’aringan pinonrowa’, pinakita’ kina:at ra:amen ’oka’ nanaw pakita’ ka pinonrowa’ tang’an",
"wlheader-enotif": "ע-פאסט מעלדונג ערמעגליכט.",
"wlheader-showupdated": "בלעטער געענדערט זײַט אײַער לעצטן וויזיט זען געוויזן '''דיק'''.",
"wlnote": "אונטן {{PLURAL:$1|איז די לעצטע ענדערונג|זענען די לעצטע <strong>$1</strong> ענדערונגען}} אין {{PLURAL:$2|דער לעצטער שעה|די לעצטע <strong>$2</strong> שעה'ן}} ביז $3, $4.",
- "wlshowlast": "ווײַזן די לעצטע $1 שעה'ן $2 טעג",
"watchlist-hide": "באַהאַלטן",
"watchlist-submit": "ווײַזן",
"wlshowtime": "צייט־פעריאד צו ווייזן:",
"uctop": "לויפֿיק",
"month": "ביז חודש:",
"year": "ביז יאר:",
- "sp-contributions-newbies": "ווײַזן בײַשטײַערונגען נאר פֿון נײַע באַניצערס",
- "sp-contributions-newbies-sub": "פאר נייע קאנטעס",
- "sp-contributions-newbies-title": "ביישטייערונגען פון נייע באַניצער",
"sp-contributions-blocklog": "בלאקירן לאג",
"sp-contributions-suppresslog": "אונטערדריקטע {{GENDER:$1|באַניצער}} בײַשטײַערונגען",
"sp-contributions-deleted": "אויסגעמעקטע {{GENDER:$1|באַניצער|באַניצערין}} בײַשטײַערונגען",
"imgmultigoto": "אריבער צו בלאט $1",
"img-lang-default": "(גרונטשפראך)",
"img-lang-go": "גיין",
- "ascending_abbrev": "ארויף",
- "descending_abbrev": "נידערן",
"table_pager_next": "נעקסטער בלאט",
"table_pager_prev": "פריערדיקער בלאט",
"table_pager_first": "ערשטער בלאט",
"wlheader-enotif": "Ìfitónilétí e-mail wà ní gbígbàláyè.",
"wlheader-showupdated": "Àwọn ojúewé tí wọn ti ní àtúnṣe láti ẹ̀yìn ìgbà tí ẹ ṣàbẹ̀wò si wọn gbẹ̀yìn jẹ́ fífihàn ní lẹ́tà <strong>kedere</strong>.",
"wlnote": "Lábẹ́ {{PLURAL:$1|ni àtúnṣe tó gbẹ̀yìn|ni àwọn àtúnṣe <strong>$1</strong> tí wọn gbẹ̀yìn}} ní {{PLURAL:$2|wákàtí kan|wákàtí <strong>$2</strong>}} sẹ́yìn, títí dí ọjọ́ $3, $4.",
- "wlshowlast": "Ìfihàn wákàtí $1 ọjọ́ $2 gbẹ̀yìn",
"watchlist-hide": "Ìbòmọ́lẹ̀",
"watchlist-submit": "Ìfihàn",
"wlshowhideminor": "àwọn àtúnṣe kékéèké",
"uctop": "lówọ́",
"month": "Láti osù (àti sẹ́yìn):",
"year": "Láti ọdún (àti sẹ́yìn):",
- "sp-contributions-newbies": "Àfihàn àwọn àfikún àwọn àpamọ́ tuntun nìkan",
- "sp-contributions-newbies-sub": "Fún àwọn àpamọ́ tuntun",
- "sp-contributions-newbies-title": "Àwọn àfikún oníṣe fún àwọn àpamọ́ tuntun",
"sp-contributions-blocklog": "Àkọsílẹ̀ ìdínà",
"sp-contributions-suppresslog": "ṣèmúkúrò {{GENDER:$1|àwọn àfikún}} oníṣẹ́ yìí",
"sp-contributions-deleted": "àwọn àfikún píparẹ́ oníṣe",
"imgmultigo": "Lọ!",
"imgmultigoto": "Lọ sí ojúewé $1",
"img-lang-default": "(èdè látìbẹ̀rẹ̀)",
- "ascending_abbrev": "ròkè",
- "descending_abbrev": "relẹ̀",
"table_pager_next": "Ojúewé tóúnbọ̀",
"table_pager_prev": "Ojúewé tókọjá",
"table_pager_first": "Ojúewé ìkíní",
"apihelp-no-such-module": "搵唔到模組「$1」。",
"apisandbox": "API沙盤",
"apisandbox-jsonly": "需要JavaScript來用API沙盤。",
- "apisandbox-api-disabled": "爾個網站閂咗API。",
"apisandbox-submit": "提交請求",
"apisandbox-reset": "清除",
"apisandbox-retry": "再試過",
"wlheader-enotif": "電郵通知已經啟用咗。",
"wlheader-showupdated": "標'''粗體字'''嘅頁響你上次嚟之後畀人改過。",
"wlnote": "下面係直到$3 $4為止,最近'''$2'''個鐘之內嘅最新$1次修改。",
- "wlshowlast": "顯示最近 $1 個鐘 $2 日",
"watchlist-hide": "收埋",
"watchlist-submit": "顯示",
"wlshowtime": "顯示最後:",
"month": "由呢個月 (同更早):",
"year": "由呢一年 (同更早):",
"date": "開始日期(同更早之前):",
- "sp-contributions-newbies": "只顯示新戶口嘅貢獻",
- "sp-contributions-newbies-sub": "新戶口嘅貢獻",
- "sp-contributions-newbies-title": "新戶口嘅用戶貢獻",
"sp-contributions-blocklog": "封鎖日誌",
"sp-contributions-suppresslog": "壓制咗{{GENDER:$1|user}}嘅用戶貢獻",
"sp-contributions-deleted": "刪除咗嘅用戶貢獻",
"newimages-legend": "過濾",
"newimages-label": "檔名(或佢嘅一部份):",
"newimages-user": "IP地址或用戶名:",
- "newimages-newbies": "淨係顯示新戶口嘅貢獻",
"newimages-showbots": "顯示機械人嘅上載",
"newimages-mediatype": "媒體類:",
"noimages": "冇嘢去睇。",
"img-lang-default": "(預設語言)",
"img-lang-info": "整幅$1版嘅圖。 $2",
"img-lang-go": "去",
- "ascending_abbrev": "增",
- "descending_abbrev": "減",
"table_pager_next": "下一版",
"table_pager_prev": "上一版",
"table_pager_first": "第一版",
"watchthispage": "Bekiek deêze bladzie",
"unwatch": "Nie meêr volge",
"watchlist-details": "Er {{PLURAL:$1|sti eên pagina|staen $1 pagina's}} op je volglieste, exclusief overlegpagina's.",
- "wlshowlast": "Laetste $1 uur, $2 daegen bekieken ()",
"watchlist-options": "Opties vò volglieste",
"actioncomplete": "Actie uutgevoerd",
"actionfailed": "De handelienge is mislukt.",
"uctop": "laetste wiezigieng",
"month": "Von maend (en eêder):",
"year": "Von jaer (en eêder):",
- "sp-contributions-newbies": "Alleên de biedraen von nuwe hebrukers bekiek'n",
"sp-contributions-blocklog": "blokkeerlogboek",
"sp-contributions-uploads": "uploads",
"sp-contributions-logs": "logboek'n",
"monthsall": "aolle",
"imgmultipageprev": "← vorrege bladzie",
"imgmultipagenext": "volgende bladzie →",
- "ascending_abbrev": "opl",
"table_pager_next": "Volgende bladzie",
"table_pager_prev": "Vorrege bladzie",
"autosumm-blank": "Bladzie leeggemaekt",
"watchlist-details": "{{PLURAL:$1|$1 ⵜⴰⵙⵏⴰ|$1 ⵏ ⵜⴰⵙⵏⵉⵡⵉⵏ}} ⴳ ⵜⵍⴳⴰⵎⵜ ⵏ ⵓⴹⴼⴼⵓⵔ ⵏⵏⴽ (ⴰⴽⴷ ⵜⴰⵙⵏⵉⵡⵉⵏ ⵏ ⵓⵎⵙⴰⵡⴰⵍ).",
"wlheader-showupdated": "ⵜⴰⵙⵏⵉⵡⵉⵏ ⵏⵏⴰ ⵉⵜⵜⵓⵙⵏⴼⵍⵏ ⵙⴳ ⵜⵔⵣⴼⵜ ⵏⵏⴳ ⵜⴰⵎⴳⴳⴰⵔⵓⵜ ⵜⵜⵓⵙⴽⴰⵏⴻⵏⵜ ⵙ <strong>ⴰⵣⵓⵔⴰⵔ</strong>.",
"wlnote": "ⴳ ⵓⴼⵍⵍⴰ, {{PLURAL:$1|ⵢⵓⵎⴰⵏ ⵓⵙⵏⴼⵍ ⴰⵎⴳⴳⴰⵔⵓ ⵉⵜⵜⵡⴰⵙⴽⴰⵔⵏ|ⵓⵎⴰⵏⴻⵏ <strong>$1</strong> ⵏ ⵉⵙⵏⵉⴼⵉⵍⵏ ⵉⵎⴳⴳⵓⵔⴰ ⵉⵜⵜⵢⴰⵙⴽⴰⵔⵏ}} {{PLURAL:$2|ⵢⴰⵜ ⵜⵙⵔⴰⴳⵜ ⴰⵢⴰ|ⵢⴰⵏ <strong>$2</strong> ⵏ ⵜⵙⵔⴰⴳⵉⵏ ⴰⵢⴰ}}, ⴰⵔ $3, $4.",
- "wlshowlast": "ⵙⴽⵏ $1 ⵜⴰⵙⵔⴰⴳⵉⵏ $2 ⵓⵙⵙⴰⵏ ⵉⵎⴳⴳⵓⵔⴰ",
"watchlist-options": "ⵜⵉⴷⵖⵔⵉⵏ ⵏ ⵜⵍⴳⴰⵎⵜ ⵏ ⵓⴹⴼⴼⵓⵔ",
"enotif_reset": "ⴷⵔⵣ ⵜⴰⵙⵏⵉⵡⵉⵏ ⴰⴽⴽ ⵏⵏⴰ ⵜⵔⵣⴼⴷ",
"deletepage": "ⴽⴽⵙ ⵜⴰⵙⵏⴰ",
"uctop": "ⴰⵎⵉⵔⴰⵏ",
"month": "ⵙⴳ ⵡⴰⵢⵢⵓⵔ (and earlier):",
"year": "ⵙⴳ ⵓⵙⴳⴳⵯⴰⵙ (and earlier):",
- "sp-contributions-newbies": "ⵙⴽⵏ ⵜⵓⵎⵓⵜⵉⵏ ⵏ ⵉⵎⵉⴹⴰⵏ ⵉⵎⴰⵢⵏⵓⵜⵏ ⴽⴰⵏ",
"sp-contributions-blocklog": "ⵜⴰⵎⵙⵙⴽⵜⵉⵜ ⵏ ⵓⴳⴷⴷⵓⵍ",
"sp-contributions-uploads": "ⵉⵙⴽⵜⴰⵔⵏ",
"sp-contributions-logs": "ⵜⵉⵎⵙⵙⴽⵜⵉⵢⵉⵏ",
"Suchichi02",
"神樂坂秀吉",
"WQL",
- "Looong"
+ "Looong",
+ "予弦"
]
},
"tog-underline": "链接下划线:",
"apihelp-no-such-module": "找不到模块“$1”。",
"apisandbox": "API 沙盒",
"apisandbox-jsonly": "需要JavaScript以使用API沙盒。",
- "apisandbox-api-disabled": "API在该网站停用。",
"apisandbox-intro": "使用这个页面来试验<strong>MediaWiki Web 服务应用程序接口(API)</strong>。欲知API使用详情,请参阅[[mw:API:Main page|API文档]]。例如:[https://www.mediawiki.org/wiki/API#A_simple_example 取得某个主页的内容],然后选择一个操作来看更多范例。\n\n请注意,虽然这是一个沙盒,但是您在这个页面上的改动可能会修改维基。",
"apisandbox-submit": "提交请求",
"apisandbox-reset": "清除",
"wlheader-enotif": "已启用电子邮件通知。",
"wlheader-showupdated": "您上次访问后发生更改的页面<strong>加粗</strong>显示。",
"wlnote": "下面是{{PLURAL:$2|过去<strong>$2</strong>小时}}的{{PLURAL:$1|最后<strong>$1</strong>个更改}},截至$3 $4。",
- "wlshowlast": "显示过去$1小时$2天",
"watchlist-hide": "隐藏",
"watchlist-submit": "显示",
"wlshowtime": "显示时段:",
"month": "截止月份:",
"year": "截止年份:",
"date": "起始日期(及更早):",
- "sp-contributions-newbies": "只显示新账户的贡献",
- "sp-contributions-newbies-sub": "新账户的贡献",
- "sp-contributions-newbies-title": "新账户的用户贡献",
"sp-contributions-blocklog": "封禁日志",
"sp-contributions-suppresslog": "被屏蔽的{{GENDER:$1|用户}}贡献",
"sp-contributions-deleted": "被删除的{{GENDER:$1|用户}}贡献",
"movepage-moved-redirect": "重定向已创建。",
"movepage-moved-noredirect": "重定向的创建已被禁用。",
"movepage-delete-first": "作为页面移动的一部分,目标页面有太多的修改要删除。请先手动删除网页,然后再试一次。",
- "articleexists": "该名称的页面已存在,或者您使用的名称无效。请另选一名。",
+ "articleexists": "该名称的页面已存在,或者您使用的名称无效。请另外选一个名称。",
"cantmove-titleprotected": "您无法将页面移动到该位置,因为新标题已被保护以防止创建。",
"movetalk": "移动关联的讨论页",
"move-subpages": "移动子页面(最多$1页)",
"newimages-legend": "过滤",
"newimages-label": "文件名(或它的一部份):",
"newimages-user": "IP地址或用户名",
- "newimages-newbies": "只显示新账户的贡献",
"newimages-showbots": "显示机器人上传",
"newimages-hidepatrolled": "隐藏已巡查的上传",
"newimages-mediatype": "媒体类型:",
"img-lang-default": "(默认语言)",
"img-lang-info": "以$1生成本图像。$2",
"img-lang-go": "提交",
- "ascending_abbrev": "升",
- "descending_abbrev": "降",
"table_pager_next": "下一页",
"table_pager_prev": "上一页",
"table_pager_first": "首页",
"createacct-loginerror": "已成功建立帳號,但無法自動登入。\n請繼續 [[Special:UserLogin|手動登入]]。",
"noname": "您輸入的使用者名稱無效。",
"loginsuccesstitle": "已登入",
- "loginsuccess": "<strong>{{GENDER:|您|妳|你}}現在已經以 \"$1\" 的身分登入了 {{SITENAME}}。</strong>",
+ "loginsuccess": "<strong>您現在已經以「$1」的身分登入了{{SITENAME}}。</strong>",
"nosuchuser": "查無名稱為 \"$1\" 的使用者。\n使用者名稱有大小寫區分,\n請檢查您拼寫是否正確,或者 [[Special:CreateAccount|建立新帳號]]。",
"nosuchusershort": "查無使用者「$1」,請檢查您拼寫是否正確。",
"nouserspecified": "您必須指定一個使用者名稱。",
"apihelp-no-such-module": "查無模組 \"$1\"。",
"apisandbox": "API 沙盒",
"apisandbox-jsonly": "需要 JavaScript 才能使用 API 沙箱。",
- "apisandbox-api-disabled": "此網站已關閉 API。",
"apisandbox-intro": "使用此頁面可測試 <strong>MediaWiki web service API</strong>。\n請參考 [[mw:API:Main page|API 說明文件]] 以取得詳細資訊。例:[https://www.mediawiki.org/wiki/API#A_simple_example 取得主頁的內容]。 請選擇動作以取得更多範例。\n\n請注意,雖然此為沙盒,您在此頁所執行的動作仍有可能會修改到 Wiki。",
"apisandbox-submit": "發出請求",
"apisandbox-reset": "清除",
"trackingcategories-nodesc": "沒有可用的描述。",
"trackingcategories-disabled": "已停用分類",
"mailnologin": "沒有傳送位址",
- "mailnologintext": "您必須先 [[Special:UserLogin|登入]]\n並在 [[Special:Preferences|偏好設定]]\n中設定一個有效的電子郵件地址才可以傳送郵件給其他使用者。",
+ "mailnologintext": "您必須先[[Special:UserLogin|登入]]並在[[Special:Preferences|偏好設定]]中設定一個有效的電子郵件地址才可以傳送郵件給其他使用者。",
"emailuser": "Email 聯絡此使用者",
"emailuser-title-target": "Email 聯絡此{{GENDER:$1|使用者}}",
"emailuser-title-notarget": "Email 聯絡使用者",
"wlheader-enotif": "已開啟電子郵件通知功能。",
"wlheader-showupdated": "在您最後一次檢視過後修改的頁面會以 <strong>粗體</strong> 顯示。",
"wlnote": "以下為自 $3 $4 之前的 <strong>$2</strong> 小時內所做的 <strong>$1</strong> 次變更。",
- "wlshowlast": "顯示最近 $1 小時 $2 天",
"watchlist-hide": "隱藏",
"watchlist-submit": "顯示",
"wlshowtime": "要顯示的時間長度:",
"logentry-contentmodel-change-revert": "還原",
"protectlogpage": "保護日誌",
"protectlogtext": "以下為變更頁面保護的清單。\n請參考 [[Special:ProtectedPages|受保護頁面清單]] 檢視目前受保護頁面。",
- "protectedarticle": "已保護 \"[[$1]]\"",
+ "protectedarticle": "已保護「[[$1]]」",
"modifiedarticleprotection": "已變更 \"[[$1]]\" 的保護層級",
"unprotectedarticle": "已解除「[[$1]]」的保護",
"movedarticleprotection": "已移動 \"[[$2]]\" 的保護設定至 \"[[$1]]\"",
"month": "截止月份:",
"year": "截止年份:",
"date": "開始日期(更早之前):",
- "sp-contributions-newbies": "僅顯示新帳號的貢獻",
- "sp-contributions-newbies-sub": "新帳號的貢獻",
- "sp-contributions-newbies-title": "新帳號的使用者貢獻",
"sp-contributions-blocklog": "封鎖日誌",
"sp-contributions-suppresslog": "已禁止顯示的{{GENDER:$1|使用者}}貢獻",
"sp-contributions-deleted": "已刪除的{{GENDER:$1|使用者}}貢獻",
"movepage-moved-redirect": "已建立重新導向頁面。",
"movepage-moved-noredirect": "已取消建立重新導向頁面。",
"movepage-delete-first": "目標頁面有太多修訂,而無法刪除作為頁面移動的部份。請先手動刪除頁面後再重試。",
- "articleexists": "該頁面名稱已存在,或您選擇的名稱無效。\n請改選擇其他名稱。",
+ "articleexists": "該頁面名稱已存在,或您選擇的名稱無效。請改選擇其他名稱。",
"cantmove-titleprotected": "您選擇的新標題已被禁止使用,您不可移動頁面到該位置。",
"movetalk": "移動相關的討論頁面",
"move-subpages": "移動子頁面(至多 $1 頁)",
"import-interwiki-submit": "匯入",
"import-mapping-default": "匯入至預設位置",
"import-mapping-namespace": "匯入至命名空間:",
- "import-mapping-subpage": "匯入做為以下頁面的子頁面:",
+ "import-mapping-subpage": "匯入作爲以下頁面的子頁面:",
"import-upload-filename": "檔案名稱:",
"import-upload-username-prefix": "跨 wiki 字首:",
"import-assign-known-users": "分配編輯至所命名使用者已存在本地的本地使用者",
"newimages-legend": "篩選",
"newimages-label": "檔案名稱 (或部份檔名):",
"newimages-user": "IP 位址或使用者名稱",
- "newimages-newbies": "僅顯示新帳號的貢獻",
"newimages-showbots": "顯示由機器人上傳的檔案",
"newimages-hidepatrolled": "隱藏己巡查上傳",
"newimages-mediatype": "媒體類型:",
"img-lang-default": "(預設語言)",
"img-lang-info": "顯示此圖片於 $1。$2",
"img-lang-go": "前往",
- "ascending_abbrev": "升冪",
- "descending_abbrev": "降冪",
"table_pager_next": "下一頁",
"table_pager_prev": "上一頁",
"table_pager_first": "第一頁",
"intentionallyblankpage": "此頁故意留白。",
"disabledspecialpage-disabled": "此頁面已被系統管理員給停用。",
"external_image_whitelist": " #請勿修改本行文字<pre>\n#請於下方填寫正規表示法 (只需 // 之間的內容)\n#將會檢查外部連結的圖片是否符合這些條件\n#符合條件的連結會以圖片顯示,否則只顯示連結\n#以 # 開頭的行會被做為註解\n#此條件不區分大小寫\n\n#請將所有正規表示法輸入在此行上方,請勿修改本行文字</pre>",
- "tags": "有效變更標籤",
+ "tags": "已定義的變更標籤",
"tag-filter": "[[Special:Tags|標籤]]搜尋:",
"tag-filter-submit": "篩選器",
"tag-list-wrapper": "[[Special:Tags|{{PLURAL:$1|標籤}}]]:$2",
"newpages-username": "用戶名稱:",
"speciallogtitlelabel": "目標 (標題或用戶):",
"checkbox-select": "選擇: $1",
+ "emailuser": "Email 聯絡此用戶",
"emailusername": "用戶名稱:",
"wlshowhidebots": "機械人",
"blanknamespace": "(主要)",
* @author Ibrahim
* @author Kaganer
* @author Soroush
+ * @author ToJack
* @author Urhixidur
* @author לערי ריינהארט
*/
NS_CATEGORY_TALK => 'Баҳси_гурӯҳ',
];
+$specialPageAliases = [
+ 'Activeusers' => [ 'Корбарони_фаъол' ],
+ 'Allmessages' => [ 'Паёмҳои_системавӣ' ],
+ 'AllMyUploads' => [ 'Тамоми_парвандаҳои_ман' ],
+ 'Allpages' => [ 'Тамоми_саҳифаҳо' ],
+ 'Badtitle' => [ 'Номи_номусоид' ],
+ 'Blankpage' => [ 'Саҳифаи_холӣ' ],
+ 'Block' => [ 'Бастан' ],
+ 'Booksources' => [ 'Манобеи_китобҳо' ],
+ 'BrokenRedirects' => [ 'Саҳифаҳои_равонакунии_кандашуда' ],
+ 'Categories' => [ 'Гурӯҳҳо' ],
+ 'ChangeEmail' => [ 'Тағйири_почтаи_электронӣ' ],
+ 'ChangePassword' => [ 'Тағйири_гузарвожа' ],
+ 'ComparePages' => [ 'Муқоисаи_саҳафот' ],
+ 'Confirmemail' => [ 'Тасдиқи_почтаи_электронӣ' ],
+ 'Contributions' => [ 'Ҳиссагузориҳо' ],
+ 'CreateAccount' => [ 'Сохтани_ҳисоби_корбарӣ' ],
+ 'Deadendpages' => [ 'Саҳифаҳои_бемаъно' ],
+ 'DeletedContributions' => [ 'Саҳми_ҳазфшуда' ],
+ 'Diff' => [ 'Тағйирот' ],
+ 'DoubleRedirects' => [ 'Саҳифаҳои_равонакунии_дукарата' ],
+ 'EditWatchlist' => [ 'Таҳрири_феҳристи_пайгириҳо' ],
+ 'Emailuser' => [ 'Навиштани_мактуб_ба_корбар' ],
+ 'ExpandTemplates' => [ 'Густариши_шаблонҳо' ],
+ 'Export' => [ 'Экспорт' ],
+ 'Fewestrevisions' => [ 'Камтарин_нусха' ],
+ 'FileDuplicateSearch' => [ 'Ҷустани_парвандаҳои_такрорӣ' ],
+ 'Filepath' => [ 'Масири_парванда' ],
+ 'Import' => [ 'Импорт' ],
+ 'Invalidateemail' => [ 'Қатъ_намудани_тасдиқоти_нишонаи_почтаи_электронӣ' ],
+ 'JavaScriptTest' => [ 'Тести_JavaScript' ],
+ 'BlockList' => [ 'Феҳристи_басташудаҳо' ],
+ 'LinkSearch' => [ 'Ҷустани_пайвандҳо' ],
+ 'Listadmins' => [ 'Феҳристи_мудирон' ],
+ 'Listbots' => [ 'Феҳристи_ботҳо' ],
+ 'Listfiles' => [ 'Феҳристи_аксҳо' ],
+ 'Listgrouprights' => [ 'Феҳристи_гурӯҳҳои_корбарӣ' ],
+ 'Listredirects' => [ 'Феҳкристи_саҳифаҳои_равонакунӣ' ],
+ 'ListDuplicatedFiles' => [ 'Феҳристи_парвандаҳои_такрорӣ' ],
+ 'Listusers' => [ 'Феҳристи_корбарон' ],
+ 'Lockdb' => [ 'Қуфл_намудани_пойгоҳи_додаҳо' ],
+ 'Log' => [ 'Гузоришҳо' ],
+ 'Lonelypages' => [ 'Саҳифаҳои_ятим' ],
+ 'Longpages' => [ 'Саҳифаҳои_калон' ],
+ 'MergeHistory' => [ 'Идғоми_таърихча' ],
+ 'MIMEsearch' => [ 'Ҷустуҷӯи_MIME' ],
+ 'Mostcategories' => [ 'Сергурӯҳтарин_саҳафот' ],
+ 'Mostimages' => [ 'Серистифодашавандатарин_парвандаҳо' ],
+ 'Mostinterwikis' => [ 'Бештарин_миёнавики' ],
+ 'Mostlinked' => [ 'Истифодашавандатарин_саҳифаҳо' ],
+ 'Mostlinkedcategories' => [ 'Истифодашавандатарин_гурӯҳҳо' ],
+ 'Mostlinkedtemplates' => [ 'Истифодашавандатарин_шаблонҳо' ],
+ 'Mostrevisions' => [ 'Саҳифаҳо_бо_бештарин_нусха' ],
+ 'Movepage' => [ 'Интиқоли_саҳифа' ],
+ 'Mycontributions' => [ 'Саҳми_ман' ],
+ 'MyLanguage' => [ 'Забони_ман' ],
+ 'Mypage' => [ 'Саҳифаи_ман' ],
+ 'Mytalk' => [ 'Баҳси_ман' ],
+ 'Myuploads' => [ 'Парвандаҳои_фиристодаи_ман' ],
+ 'Newimages' => [ 'Парвандаҳои_нав' ],
+ 'Newpages' => [ 'Саҳифаҳои_нав' ],
+ 'PasswordReset' => [ 'Партофтани_гузарвожа' ],
+ 'PermanentLink' => [ 'Пайванди_доимӣ' ],
+ 'Preferences' => [ 'Танзимот' ],
+ 'Prefixindex' => [ 'Намои_пешвандӣ' ],
+ 'Protectedpages' => [ 'Саҳифаҳои_муфозатшуда' ],
+ 'Protectedtitles' => [ 'Номҳои_муҳофизатшуда' ],
+ 'Randompage' => [ 'Саҳифаи_тасодуфӣ' ],
+ 'Randomredirect' => [ 'Саҳифаи_равонакунии_тасодуфӣ' ],
+ 'Recentchanges' => [ 'Тағйироти_охирин' ],
+ 'Recentchangeslinked' => [ 'Вироишоти_вобаста' ],
+ 'Revisiondelete' => [ 'Вироишоти_ҳазфшуда' ],
+ 'Search' => [ 'Ҷустуҷӯ' ],
+ 'Shortpages' => [ 'Саҳифаҳои_хурд' ],
+ 'Specialpages' => [ 'Саҳифаҳои_вижа' ],
+ 'Statistics' => [ 'Омор' ],
+ 'Tags' => [ 'Барчасбҳо' ],
+ 'Unblock' => [ 'Боз_кардан' ],
+ 'Uncategorizedcategories' => [ 'Гурӯҳҳои_бе_гурӯҳ' ],
+ 'Uncategorizedimages' => [ 'Парвандаҳои_бе_гурӯҳ' ],
+ 'Uncategorizedpages' => [ 'Саҳифаҳои_бе_гурӯҳ' ],
+ 'Uncategorizedtemplates' => [ 'Шаблонҳои_бе_гурӯҳ' ],
+ 'Undelete' => [ 'Эҳёи_саҳифаи_ҳазфшуда' ],
+ 'Unlockdb' => [ 'Боз_кардани_пойгоҳи_додаҳо' ],
+ 'Unusedcategories' => [ 'Гурӯҳҳои_истифоданашуда' ],
+ 'Unusedimages' => [ 'Парвандаҳои_истифоданашуда' ],
+ 'Unusedtemplates' => [ 'Шаблонҳои_истифоданашуда' ],
+ 'Upload' => [ 'Боргузории_парванда' ],
+ 'UploadStash' => [ 'Боркунии_пинҳонӣ' ],
+ 'Userlogin' => [ 'Вуруд' ],
+ 'Userlogout' => [ 'Хуруҷ' ],
+ 'Userrights' => [ 'Идораи_гурӯҳҳои_корбарӣ' ],
+ 'Version' => [ 'Нусха' ],
+ 'Wantedcategories' => [ 'Гурӯҳҳҳои_дархостӣ' ],
+ 'Wantedfiles' => [ 'Парвандаҳои_дархостӣ' ],
+ 'Wantedpages' => [ 'Саҳифаҳои_дархостӣ' ],
+ 'Wantedtemplates' => [ 'Шаблонҳои_дархости' ],
+ 'Watchlist' => [ 'Феҳристи_пайгириҳо' ],
+ 'Whatlinkshere' => [ 'Пайвандҳо_ба_инҷо' ],
+ 'Withoutinterwiki' => [ 'Бе_интервики' ],
+];
+
+$magicWords = [
+ 'redirect' => [ '0', '#равона', '#REDIRECT' ],
+ 'notoc' => [ '0', '__БЕ_ФЕҲРИСТ__', '__NOTOC__' ],
+ 'nogallery' => [ '0', '__БЕ_НИГОРХОНА__', '__NOGALLERY__' ],
+ 'forcetoc' => [ '0', '__БО_ФЕҲРИСТ__', '__FORCETOC__' ],
+ 'toc' => [ '0', '__ФЕҲРИСТ__', '__TOC__' ],
+ 'noeditsection' => [ '0', '__БЕ_ВИРОИШИ_ҶУЗЪӢ__', '__NOEDITSECTION__' ],
+ 'currentmonth' => [ '1', 'МОҲИ_КУНУНӢ', 'МОҲИ_КУНУНӢ_2', 'CURRENTMONTH', 'CURRENTMONTH2' ],
+ 'currentmonth1' => [ '1', 'МОҲИ_КУНУНӢ_1', 'CURRENTMONTH1' ],
+ 'currentmonthname' => [ '1', 'НОМИ_МОҲИ_КУНУНӢ', 'CURRENTMONTHNAME' ],
+ 'currentmonthnamegen' => [ '1', 'НОМИ_МОҲИ_КУНУНӢ_ТАСРИФ', 'CURRENTMONTHNAMEGEN' ],
+ 'currentmonthabbrev' => [ '1', 'НОМИ_МОҲИ_КУНУНӢ_ИХТИСОР', 'CURRENTMONTHABBREV' ],
+ 'currentday' => [ '1', 'РӮЗИ_КУНУНӢ', 'CURRENTDAY' ],
+ 'currentday2' => [ '1', 'РӮЗИ_КУНУНИ_2', 'CURRENTDAY2' ],
+ 'currentdayname' => [ '1', 'НОМИ_РӮЗИ_КУНУНӢ', 'CURRENTDAYNAME' ],
+ 'currentyear' => [ '1', 'СОЛИ_КУНУНӢ', 'CURRENTYEAR' ],
+ 'currenttime' => [ '1', 'ЗАМОНИ_КУНУНӢ', 'CURRENTTIME' ],
+ 'currenthour' => [ '1', 'СОАТИ_КУНУНӢ', 'CURRENTHOUR' ],
+ 'localmonth' => [ '1', 'МОҲИ_МАҲАЛЛӢ', 'МОҲИ_МАҲАЛЛӢ_2', 'LOCALMONTH', 'LOCALMONTH2' ],
+ 'localmonth1' => [ '1', 'МОҲИ_МАҲАЛЛӢ_1', 'LOCALMONTH1' ],
+ 'localmonthname' => [ '1', 'НОМИ_МОҲИ_МАҲАЛЛӢ', 'LOCALMONTHNAME' ],
+ 'localmonthnamegen' => [ '1', 'НОМИ_МОҲИ_МАҲАЛЛӢ_ТАСРИФ', 'LOCALMONTHNAMEGEN' ],
+ 'localmonthabbrev' => [ '1', 'НОМИ_МОҲИ_МАҲАЛЛӢ_ИХТИСОР', 'LOCALMONTHABBREV' ],
+ 'localday' => [ '1', 'РӮЗИ_МАҲАЛЛӢ', 'LOCALDAY' ],
+ 'localday2' => [ '1', 'РӮЗИ_МАҲАЛЛӢ_2', 'LOCALDAY2' ],
+ 'localdayname' => [ '1', 'НОМИ_РӮЗИ_МАҲАЛЛӢ', 'LOCALDAYNAME' ],
+ 'localyear' => [ '1', 'СОЛИ_МАҲАЛЛӢ', 'LOCALYEAR' ],
+ 'localtime' => [ '1', 'ЗАМОНИ_МАҲАЛЛӢ', 'LOCALTIME' ],
+ 'localhour' => [ '1', 'СОАТИ_МАҲАЛЛӢ', 'LOCALHOUR' ],
+ 'numberofpages' => [ '1', 'ШУМОРАИ_САҲИФАҲО', 'NUMBEROFPAGES' ],
+ 'numberofarticles' => [ '1', 'ШУМОРАИ_МАҚОЛАҲО', 'NUMBEROFARTICLES' ],
+ 'numberoffiles' => [ '1', 'ШУМОРАИ_ПАРВАНДАҲО', 'NUMBEROFFILES' ],
+ 'numberofusers' => [ '1', 'ШУМОРАИ_КОРБАРОН', 'NUMBEROFUSERS' ],
+ 'numberofactiveusers' => [ '1', 'ШУМОРАИ_КОРБАРОНИ_ФАЪОЛ', 'NUMBEROFACTIVEUSERS' ],
+ 'numberofedits' => [ '1', 'ШУМОРАИ_ВИРОИШОТ', 'NUMBEROFEDITS' ],
+ 'pagename' => [ '1', 'НОМИ_САҲИФА', 'PAGENAME' ],
+ 'pagenamee' => [ '1', 'НОМИ_САҲИФА_2', 'PAGENAMEE' ],
+ 'namespace' => [ '1', 'ФАЗОИ_НОМ', 'NAMESPACE' ],
+ 'namespacee' => [ '1', 'ФАЗОИ_НОМ_2', 'NAMESPACEE' ],
+ 'namespacenumber' => [ '1', 'РАҚАМИ_ФАЗОИ_НОМ', 'NAMESPACENUMBER' ],
+ 'talkspace' => [ '1', 'ФАЗОИ_БАҲСҲО', 'TALKSPACE' ],
+ 'talkspacee' => [ '1', 'ФАЗОИ_БАҲСҲО_2', 'TALKSPACEE' ],
+ 'subjectspace' => [ '1', 'ФАЗОИ_МАҚОЛАҲО', 'SUBJECTSPACE', 'ARTICLESPACE' ],
+ 'subjectspacee' => [ '1', 'ФАЗОИ_МАҚОЛАҲО_2', 'SUBJECTSPACEE', 'ARTICLESPACEE' ],
+ 'fullpagename' => [ '1', 'НОМИ_ПУРРАИ_САҲИФА', 'FULLPAGENAME' ],
+ 'fullpagenamee' => [ '1', 'НОМИ_ПУРРАИ_САҲИФА_2', 'FULLPAGENAMEE' ],
+ 'subpagename' => [ '1', 'НОМИ_ЗЕРГУРӮҲ', 'SUBPAGENAME' ],
+ 'subpagenamee' => [ '1', 'НОМИ_ЗЕРГУРӮҲ_2', 'SUBPAGENAMEE' ],
+ 'basepagename' => [ '1', 'АСОСИИ_НОМИ_САҲИФА', 'BASEPAGENAME' ],
+ 'basepagenamee' => [ '1', 'АСОСИИ_НОМИ_САҲИФА_2', 'BASEPAGENAMEE' ],
+ 'talkpagename' => [ '1', 'НОМИ_САҲИФАИ_БАҲС', 'TALKPAGENAME' ],
+ 'talkpagenamee' => [ '1', 'НОМИ_САҲИФАИ_БАҲС_2', 'TALKPAGENAMEE' ],
+ 'subjectpagename' => [ '1', 'НОМИ_САҲИФА_МАҚОЛА', 'SUBJECTPAGENAME', 'ARTICLEPAGENAME' ],
+ 'subjectpagenamee' => [ '1', 'НОМИ_САҲИФА_МАҚОЛА_2', 'SUBJECTPAGENAMEE', 'ARTICLEPAGENAMEE' ],
+ 'msg' => [ '0', 'ПАЁМ:', 'MSG:' ],
+ 'subst' => [ '0', 'МОНДАН:', 'SUBST:' ],
+ 'safesubst' => [ '0', 'МОНДАНИҲИФЗ:', 'SAFESUBST:' ],
+ 'msgnw' => [ '0', 'ПАЁМ_БЕ_ВИКИ:', 'MSGNW:' ],
+ 'img_thumbnail' => [ '1', 'мини', 'миниатюра', 'thumb', 'thumbnail' ],
+ 'img_manualthumb' => [ '1', 'мини=$1', 'миниатюра=$1', 'thumbnail=$1', 'thumb=$1' ],
+ 'img_right' => [ '1', 'рост', 'right' ],
+ 'img_left' => [ '1', 'чап', 'left' ],
+ 'img_none' => [ '1', 'бе', 'none' ],
+ 'img_width' => [ '1', '$1пкс', '$1px' ],
+ 'img_center' => [ '1', 'марказ', 'center', 'centre' ],
+ 'img_framed' => [ '1', 'чаҳорчӯба', 'рамка', 'frame', 'framed', 'enframed' ],
+ 'img_frameless' => [ '1', 'бе_чаҳорчӯба', 'бе_рамка', 'frameless' ],
+ 'img_page' => [ '1', 'саҳифа=$1', 'саҳифа $1', 'page=$1', 'page $1' ],
+ 'img_upright' => [ '1', 'болорост', 'боло_рост=$1', 'болорост $1', 'upright', 'upright=$1', 'upright $1' ],
+ 'img_border' => [ '1', 'сарҳад', 'border' ],
+ 'img_baseline' => [ '1', 'асос', 'baseline' ],
+ 'img_sub' => [ '1', 'поён', 'sub' ],
+ 'img_super' => [ '1', 'боло', 'super', 'sup' ],
+ 'img_top' => [ '1', 'аз_боло', 'top' ],
+ 'img_text_top' => [ '1', 'матнболо', 'text-top' ],
+ 'img_middle' => [ '1', 'дарбайн', 'middle' ],
+ 'img_bottom' => [ '1', 'дарпоён', 'bottom' ],
+ 'img_text_bottom' => [ '1', 'матнпоён', 'text-bottom' ],
+ 'img_link' => [ '1', 'пайванд=$1', 'link=$1' ],
+ 'img_alt' => [ '1', 'алт=$1', 'alt=$1' ],
+ 'int' => [ '0', 'ДАРУН:', 'INT:' ],
+ 'sitename' => [ '1', 'НОМИ_СОМОНА', 'НОМИ_САЙТ', 'SITENAME' ],
+ 'ns' => [ '0', 'ПИ:', 'NS:' ],
+ 'nse' => [ '0', 'ПИК:', 'NSE:' ],
+ 'localurl' => [ '0', 'СУРОҒАИ_ЛОКАЛӢ:', 'LOCALURL:' ],
+ 'localurle' => [ '0', 'СУРОҒАИ_ЛОКАЛӢ_2:', 'LOCALURLE:' ],
+ 'articlepath' => [ '0', 'МАСИРИ_САҲИФА', 'ARTICLEPATH' ],
+ 'pageid' => [ '0', 'ИДЕНТИФИКАТОРИ_САҲИФА', 'PAGEID' ],
+ 'server' => [ '0', 'СЕРВЕР', 'SERVER' ],
+ 'servername' => [ '0', 'НОМИ_СЕРВЕР', 'SERVERNAME' ],
+ 'scriptpath' => [ '0', 'МАСИРИ_СКРИПТ', 'SCRIPTPATH' ],
+ 'stylepath' => [ '0', 'МАСИРИ_УСЛУБ', 'STYLEPATH' ],
+ 'grammar' => [ '0', 'ТАСРИФ:', 'GRAMMAR:' ],
+ 'gender' => [ '0', 'ҶИНС:', 'GENDER:' ],
+ 'notitleconvert' => [ '0', '__БЕ_ТАҒЙИРИ_САРЛАВҲА__', '__NOTITLECONVERT__', '__NOTC__' ],
+ 'nocontentconvert' => [ '0', '__БЕ_ТАҒЙИРИ_МАТН__', '__NOCONTENTCONVERT__', '__NOCC__' ],
+ 'currentweek' => [ '1', 'ХАФТАИ_КУНУНӢ', 'CURRENTWEEK' ],
+ 'currentdow' => [ '1', 'РӮЗИ_КУНУНИИ_ҲАФТА', 'CURRENTDOW' ],
+ 'localweek' => [ '1', 'ҲАФТАИ_МАҲАЛЛӢ', 'LOCALWEEK' ],
+ 'localdow' => [ '1', 'РУЗИ_ҲАФТАИ_МАҲАЛЛӢ', 'LOCALDOW' ],
+ 'revisionid' => [ '1', 'ИД_НУСХА', 'REVISIONID' ],
+ 'revisionday' => [ '1', 'РӮЗИ_НУСХА', 'REVISIONDAY' ],
+ 'revisionday2' => [ '1', 'РӮЗИ_НУСХА_2', 'REVISIONDAY2' ],
+ 'revisionmonth' => [ '1', 'МОҲИ_НУСХА', 'REVISIONMONTH' ],
+ 'revisionmonth1' => [ '1', 'МОҲИ_НУСХА_1', 'REVISIONMONTH1' ],
+ 'revisionyear' => [ '1', 'СОЛИ_НУСХА', 'REVISIONYEAR' ],
+ 'revisiontimestamp' => [ '1', 'НИШОНИ_ЗАМОНИ_НУСХА', 'REVISIONTIMESTAMP' ],
+ 'revisionuser' => [ '1', 'НУСХАИ_КОРБАР', 'REVISIONUSER' ],
+ 'plural' => [ '0', 'ШАКЛИ_ҶАМЪ:', 'PLURAL:' ],
+ 'fullurl' => [ '0', 'СУРОҒАИ_ПУРРА:', 'FULLURL:' ],
+ 'fullurle' => [ '0', 'СУРОҒАИ_ПУРРА_2:', 'FULLURLE:' ],
+ 'lcfirst' => [ '0', 'ҲАРФИ_АВВАЛ_ХУРД:', 'LCFIRST:' ],
+ 'ucfirst' => [ '0', 'ҲАРФИ_АВВАЛ_КАЛОН:', 'UCFIRST:' ],
+ 'lc' => [ '0', 'БО_ҲАРФҲОИ_ХУРД:', 'LC:' ],
+ 'uc' => [ '0', 'БО_ҲАРФҲОИ_КАЛОН:', 'UC:' ],
+ 'raw' => [ '0', 'ХОМ:', 'RAW:' ],
+ 'displaytitle' => [ '1', 'НАМОИШИ_САРЛАВҲА', 'DISPLAYTITLE' ],
+ 'rawsuffix' => [ '1', 'Н', 'R' ],
+ 'newsectionlink' => [ '1', '__ПАЙВАНД_БА_ҚИСМАТИ_НАВ__', '__NEWSECTIONLINK__' ],
+ 'nonewsectionlink' => [ '1', '__БЕ_ПАЙВАНД_БА_ҚИСМАТИ_НАВ__', '__NONEWSECTIONLINK__' ],
+ 'currentversion' => [ '1', 'НУСХАИ_КУНУНӢ', 'CURRENTVERSION' ],
+ 'urlencode' => [ '0', 'СУРОҒАИ_РАМЗ:', 'URLENCODE:' ],
+ 'anchorencode' => [ '0', 'РАМЗКУНИИ_БАРЧАСБ', 'ANCHORENCODE' ],
+ 'currenttimestamp' => [ '1', 'БАРЧАСБИ_ЗАМОНИ_КУНУНӢ', 'CURRENTTIMESTAMP' ],
+ 'localtimestamp' => [ '1', 'БАРЧАСБИ_ЗАМОНИ_МАҲАЛЛӢ', 'LOCALTIMESTAMP' ],
+ 'directionmark' => [ '1', 'МАСИРИ_ПАЁМ', 'DIRECTIONMARK', 'DIRMARK' ],
+ 'language' => [ '0', '#ЗАБОН:', '#LANGUAGE:' ],
+ 'contentlanguage' => [ '1', 'ЗАБОНИ_МӮҲТАВО', 'CONTENTLANGUAGE', 'CONTENTLANG' ],
+ 'pagesinnamespace' => [ '1', 'САҲИФАҲО_ДАР_ФАЗОҲОИ_НОМ:', 'PAGESINNAMESPACE:', 'PAGESINNS:' ],
+ 'numberofadmins' => [ '1', 'ШУМОРАИ_МУДИРОН', 'NUMBEROFADMINS' ],
+ 'formatnum' => [ '0', 'ФОРМАТИ_РАҚАМ', 'FORMATNUM' ],
+ 'padleft' => [ '0', 'АЗ_ТАРАФИ_ЧАП', 'PADLEFT' ],
+ 'padright' => [ '0', 'АЗ_ТАРАФИ_РОСТ', 'PADRIGHT' ],
+ 'special' => [ '0', 'ВИЖА', 'special' ],
+ 'defaultsort' => [ '1', 'ТАРТИБ_БА_ТАВРИ_ПЕШФАРЗ:', 'КАЛИДИ_ТАРТИБ:', 'DEFAULTSORT:', 'DEFAULTSORTKEY:', 'DEFAULTCATEGORYSORT:' ],
+ 'filepath' => [ '0', 'МАСИРИ_ПАРВАНДА:', 'FILEPATH:' ],
+ 'tag' => [ '0', 'барчасб', 'тег', 'тэг', 'tag' ],
+ 'hiddencat' => [ '1', '__ГУРӮҲИ_ПИНҲОН__', '__HIDDENCAT__' ],
+ 'pagesincategory' => [ '1', 'САҲИФА_ДАР_ГУРӮҲ', 'PAGESINCATEGORY', 'PAGESINCAT' ],
+ 'pagesize' => [ '1', 'АНДОЗАИ_САҲИФА', 'PAGESIZE' ],
+ 'index' => [ '1', '__ИНДЕКС__', '__INDEX__' ],
+ 'noindex' => [ '1', '__БЕ_ИНДЕКС__', '__NOINDEX__' ],
+ 'numberingroup' => [ '1', 'РАҚАМ_ДАР_ГУРӮҲ', 'NUMBERINGROUP', 'NUMINGROUP' ],
+ 'staticredirect' => [ '1', '__РАВОНАИ_СТАТИСТИКӢ__', '__STATICREDIRECT__' ],
+ 'protectionlevel' => [ '1', 'ДАРАҶАИ_МУҲОФИЗАТ', 'PROTECTIONLEVEL' ],
+ 'formatdate' => [ '0', 'форматисана', 'formatdate', 'dateformat' ],
+ 'url_path' => [ '0', 'МАСИР', 'PATH' ],
+ 'url_wiki' => [ '0', 'ВИКИ', 'WIKI' ],
+ 'url_query' => [ '0', 'ДАРХОСТ', 'QUERY' ],
+ 'pagesincategory_all' => [ '0', 'ҳама', 'all' ],
+ 'pagesincategory_pages' => [ '0', 'саҳифаҳо', 'pages' ],
+ 'pagesincategory_subcats' => [ '0', 'зергурӯҳҳо', 'subcats' ],
+ 'pagesincategory_files' => [ '0', 'аксҳо', 'files' ],
+];
+
$datePreferences = [
'default',
'dmy',
// Respond to ResourceLoader request
$resourceLoader->respond( $context );
-Profiler::instance()->setTemplated( true );
+Profiler::instance()->setAllowOutput();
$mediawiki = new MediaWiki();
$mediawiki->doPostOutputShutdown( 'fast' );
+ $wgProfiler
+ [ 'threshold' => $wgProfileLimit ]
);
- $profiler->setTemplated( true );
+ $profiler->setAllowOutput();
Profiler::replaceStubInstance( $profiler );
}
$res = $dbw->select( 'content', 'content_address', [], __METHOD__, [ 'DISTINCT' ] );
$blobStore = MediaWikiServices::getInstance()->getBlobStore();
foreach ( $res as $row ) {
+ // @phan-suppress-next-line PhanUndeclaredMethod
$textId = $blobStore->getTextIdFromAddress( $row->content_address );
if ( $textId ) {
$cur[] = $textId;
*/
public function execute() {
$siteStore = MediaWikiServices::getInstance()->getSiteStore();
- $siteStore->reset();
+ if ( method_exists( $siteStore, 'reset' ) ) {
+ // @phan-suppress-next-line PhanUndeclaredMethod
+ $siteStore->reset();
+ }
$globalId = $this->getArg( 0 );
$group = $this->getArg( 1 );
$siteStore->saveSites( [ $site ] );
if ( method_exists( $siteStore, 'reset' ) ) {
+ // @phan-suppress-next-line PhanUndeclaredMethod
$siteStore->reset();
}
require __DIR__ . '/../commandLine.inc';
-use Wikimedia\Rdbms\IMaintainableDatabase;
-
/**
* Maintenance script that upgrade for log_id/log_deleted fields in a
* replication-safe way.
class UpdateLogging {
/**
- * @var IMaintainableDatabase
+ * @var Database
*/
public $dbw;
public $batchSize = 1000;
public $minTs = false;
function execute() {
- $this->dbw = $this->getDB( DB_MASTER );
+ $this->dbw = wfGetDB( DB_MASTER );
$logging = $this->dbw->tableName( 'logging' );
$logging_1_10 = $this->dbw->tableName( 'logging_1_10' );
$logging_pre_1_10 = $this->dbw->tableName( 'logging_pre_1_10' );
DELETE {
?category ?x ?y
} WHERE {
+ ?category ?x ?y
VALUES ?category {
%s
}
} INSERT {
%s
} WHERE {
+ ?category ?x ?y
VALUES ?category {
%s
}
}
public function execute() {
- global $wgRCMaxAge;
-
$this->initialize();
$startTS = new MWTimestamp( $this->getOption( "start" ) );
$endTS = new MWTimestamp( $this->getOption( "end" ) );
$now = new MWTimestamp();
+ $rcMaxAge = $this->getConfig()->get( 'RCMaxAge' );
- if ( $now->getTimestamp() - $startTS->getTimestamp() > $wgRCMaxAge ) {
- $this->error( "Start timestamp too old, maximum RC age is $wgRCMaxAge!" );
+ if ( $now->getTimestamp() - $startTS->getTimestamp() > $rcMaxAge ) {
+ $this->error( "Start timestamp too old, maximum RC age is $rcMaxAge!" );
}
- if ( $now->getTimestamp() - $endTS->getTimestamp() > $wgRCMaxAge ) {
- $this->error( "End timestamp too old, maximum RC age is $wgRCMaxAge!" );
+ if ( $now->getTimestamp() - $endTS->getTimestamp() > $rcMaxAge ) {
+ $this->error( "End timestamp too old, maximum RC age is $rcMaxAge!" );
}
$this->startTS = $startTS->getTimestamp();
* TODO: For now, we do full update even though some data hasn't changed,
* e.g. parents for parent cat and counts for child cat.
*/
+ $childPages = [];
+ $parentCats = [];
foreach ( $batch as $row ) {
$childPages[$row->rc_cur_id] = true;
$parentCats[$row->rc_title] = true;
$pages = [];
$deleteUrls = [];
- if ( !empty( $childPages ) ) {
+ if ( $childPages ) {
// Load child rows by ID
$childRows = $dbr->select(
[ 'page', 'page_props', 'category' ],
}
}
- if ( !empty( $parentCats ) ) {
+ if ( $parentCats ) {
// Load parent rows by title
$joinConditions = [
'page' => [
}
private function loadThing( &$dependencies, $name, $extensions, $skins ) {
- global $wgExtensionDirectory, $wgStyleDirectory;
+ $extDir = $this->getConfig()->get( 'ExtensionDirectory' );
+ $styleDir = $this->getConfig()->get( 'StyleDirectory' );
$queue = [];
$missing = false;
foreach ( $extensions as $extension ) {
- $path = "$wgExtensionDirectory/$extension/extension.json";
+ $path = "$extDir/$extension/extension.json";
if ( file_exists( $path ) ) {
// 1 is ignored
$queue[$path] = 1;
}
foreach ( $skins as $skin ) {
- $path = "$wgStyleDirectory/$skin/skin.json";
+ $path = "$styleDir/$skin/skin.json";
if ( file_exists( $path ) ) {
$queue[$path] = 1;
$this->addToDependencies( $dependencies, [], [ $skin ], $name );
"$IP/tests/phpunit/phpunit.php",
"$IP/tests/phpunit/suites/LessTestSuite.php"
];
+ // @phan-suppress-next-line PhanUndeclaredMethod
$textUICommand->run( $argv );
}
}
* all values are in that range. Drop ones that aren't.
*/
public function execute() {
- global $wgHiddenPrefs, $wgDefaultUserOptions;
-
$dbw = $this->getDB( DB_MASTER );
$hidden = $this->hasOption( 'hidden' );
$unknown = $this->hasOption( 'unknown' );
// Remove hidden prefs. Iterate over them to avoid the IN on a large table
if ( $hidden ) {
- if ( !$wgHiddenPrefs ) {
+ $hiddenPrefs = $this->getConfig()->get( 'HiddenPrefs' );
+ if ( !$hiddenPrefs ) {
$this->output( "No hidden preferences, skipping\n" );
}
- foreach ( $wgHiddenPrefs as $hiddenPref ) {
+ foreach ( $hiddenPrefs as $hiddenPref ) {
$this->deleteByWhere(
$dbw,
'Dropping hidden preferences',
// Remove unknown preferences. Special-case 'userjs-' as we can't control those names.
if ( $unknown ) {
+ $defaultUserOptions = $this->getConfig()->get( 'DefaultUserOptions' );
$where = [
'up_property NOT' . $dbw->buildLike( 'userjs-', $dbw->anyString() ),
- 'up_property NOT IN (' . $dbw->makeList( array_keys( $wgDefaultUserOptions ) ) . ')',
+ 'up_property NOT IN (' . $dbw->makeList( array_keys( $defaultUserOptions ) ) . ')',
];
// Allow extensions to add to the where clause to prevent deletion of their own prefs.
Hooks::run( 'DeleteUnknownPreferences', [ &$where, $dbw ] );
protected function doOperations( FileRepo $tempRepo, array $ops ) {
$status = $tempRepo->getBackend()->doQuickOperations( $ops );
if ( !$status->isOK() ) {
+ // @phan-suppress-next-line PhanUndeclaredMethod
$this->error( print_r( $status->getErrorsArray(), true ) );
}
}
return;
}
+ /** @var WikitextContent $content */
+ '@phan-var WikitextContent $content';
$text = strval( $content->getText() );
$output1 = $parser1->parse( $text, $title, $this->options );
$this->fatalError( "Error: Closures cannot be converted to JSON. " .
"Please move your extension function somewhere else."
);
- }
- // check if $func exists in the global scope
- if ( function_exists( $func ) ) {
+ } elseif ( function_exists( $func ) ) {
+ // check if $func exists in the global scope
$this->fatalError( "Error: Global functions cannot be converted to JSON. " .
"Please move your extension function ($func) into a class."
);
$this->fatalError( "Error: Closures cannot be converted to JSON. " .
"Please move the handler for $hookName somewhere else."
);
- }
- // Check if $func exists in the global scope
- if ( function_exists( $func ) ) {
+ } elseif ( function_exists( $func ) ) {
+ // Check if $func exists in the global scope
$this->fatalError( "Error: Global functions cannot be converted to JSON. " .
"Please move the handler for $hookName inside a class."
);
$this->json[$realName] = $value;
}
+ /**
+ * @param string $realName
+ * @param array[] $value
+ * @suppress PhanTypeInvalidDimOffset
+ */
protected function handleResourceModules( $realName, $value ) {
$defaults = [];
$remote = $this->hasOption( 'skin' ) ? 'remoteSkinPath' : 'remoteExtPath';
}
$res = $dbw->query( "SELECT l_from FROM $links LIMIT 1" );
+ // @phan-suppress-next-line PhanUndeclaredMethod
if ( $dbw->fieldType( $res, 0 ) == "int" ) {
$this->output( "Schema already converted\n" );
// backends in FileBackendMultiWrite (since they get writes second, they have
// higher timestamps). However, when copying the other way, this hits loads of
// false positives (possibly 100%) and wastes a bunch of time on GETs/PUTs.
+ // @phan-suppress-next-line PhanTypeArraySuspiciousNullable
$same = ( $srcStat['mtime'] <= $dstStat['mtime'] );
} else {
// This is the slowest method which does many per-file HEADs (unless an object
/** @var LocalFile $file */
$file = $repo->newFile( $row->fa_name );
+ '@phan-var LocalFile $file';
try {
$file->lock();
} catch ( LocalFileLockError $e ) {
$this->output( "Deleted version '$key' ($ts) of file '$name'\n" );
} else {
$this->output( "Failed to delete version '$key' ($ts) of file '$name'\n" );
+ // @phan-suppress-next-line PhanUndeclaredMethod
$this->output( print_r( $status->getErrorsArray(), true ) );
}
} else {
/**
* A resource pointing to a sitemap file
*
- * @var resource
+ * @var resource|false
*/
public $file;
}
public function execute() {
- global $wgAllDBsAreLocalhost;
- if ( $wgAllDBsAreLocalhost ) {
+ if ( $this->getConfig()->get( 'AllDBsAreLocalhost' ) ) {
$host = 'localhost';
} elseif ( $this->hasOption( 'group' ) ) {
$db = $this->getDB( DB_REPLICA, $this->getOption( 'group' ) );
public $uploads = false;
protected $uploadCount = 0;
public $imageBasePath = false;
+ /** @var array|false */
public $nsFilter = false;
function __construct() {
}
$this->uploadCount++;
// $this->report();
+ // @phan-suppress-next-line PhanUndeclaredMethod
$this->progress( "upload: " . $revision->getFilename() );
if ( !$this->dryRun ) {
if ( $this->hasOption( 'dry' ) ) {
$this->output( "done.\n" );
+ // @phan-suppress-next-line PhanUndeclaredMethod
} elseif ( $image->recordUpload2(
$archive->value,
$summary,
}
protected function doDBUpdates() {
- global $wgActorTableSchemaMigrationStage;
+ $actorTableSchemaMigrationStage = $this->getConfig()->get( 'ActorTableSchemaMigrationStage' );
- if ( !( $wgActorTableSchemaMigrationStage & SCHEMA_COMPAT_WRITE_NEW ) ) {
+ if ( !( $actorTableSchemaMigrationStage & SCHEMA_COMPAT_WRITE_NEW ) ) {
$this->output(
"...cannot update while \$wgActorTableSchemaMigrationStage lacks SCHEMA_COMPAT_WRITE_NEW\n"
);
protected $bufferSize = 524288; // In bytes. Maximum size to read from the stub in on go.
- protected $php = "php";
+ /** @var array */
+ protected $php = [];
protected $spawn = false;
/**
protected $spawnProc = false;
/**
- * @var bool|resource
+ * @var resource
*/
- protected $spawnWrite = false;
+ protected $spawnWrite;
/**
- * @var bool|resource
+ * @var resource
*/
- protected $spawnRead = false;
+ protected $spawnRead;
/**
* @var bool|resource
protected $firstPageWritten = false;
protected $lastPageWritten = false;
protected $checkpointJustWritten = false;
+ /** @var string[] */
protected $checkpointFiles = [];
/**
* This function resets $this->lb and closes all connections on it.
*
* @throws MWException
+ * @suppress PhanTypeObjectUnsetDeclaredProperty
*/
function rotateDb() {
// Cleaning up old connections
$param = $split[1];
}
$fileURIs = explode( ';', $param );
+ $newFileURIs = [];
foreach ( $fileURIs as $URI ) {
switch ( $val ) {
case "file":
/**
* @throws MWException Failure to parse XML input
- * @param string $input
+ * @param resource $input
* @return bool
*/
function readDump( $input ) {
if ( $this->spawnRead ) {
fclose( $this->spawnRead );
}
- $this->spawnRead = false;
+ $this->spawnRead = null;
if ( $this->spawnWrite ) {
fclose( $this->spawnWrite );
}
- $this->spawnWrite = false;
+ $this->spawnWrite = null;
if ( $this->spawnErr ) {
fclose( $this->spawnErr );
}
require_once RUN_MAINTENANCE_IF_MAIN;
$queue = [];
+'@phan-var string[][] $mmfl';
foreach ( $mmfl['setupFiles'] as $fileName ) {
if ( strval( $fileName ) === '' ) {
continue;
}
protected function doDBUpdates() {
- global $wgDefaultExternalStore;
-
$replaceMissing = $this->hasOption( 'replace-missing' );
+ $defaultExternalStore = $this->getConfig()->get( 'DefaultExternalStore' );
$batchSize = $this->getBatchSize();
$dbr = $this->getDB( DB_REPLICA, [ 'vslow' ] );
if ( $data !== false ) {
$flags = Revision::compressRevisionText( $data );
- if ( $wgDefaultExternalStore ) {
+ if ( $defaultExternalStore ) {
$data = ExternalStore::insertToDefault( $data );
if ( $flags ) {
$flags .= ',';
* @return bool
*/
private function checkAll( $options ) {
- global $wgNamespaceAliases, $wgCapitalLinks;
-
$contLang = MediaWikiServices::getInstance()->getContentLanguage();
$spaces = [];
$spaces[$name] = $ns;
}
}
- foreach ( $wgNamespaceAliases as $name => $ns ) {
+ foreach ( $this->getConfig()->get( 'NamespaceAliases' ) as $name => $ns ) {
$spaces[$name] = $ns;
}
foreach ( $contLang->getNamespaceAliases() as $name => $ns ) {
// We'll need to check for lowercase keys as well,
// since we're doing case-sensitive searches in the db.
+ $capitalLinks = $this->getConfig()->get( 'CapitalLinks' );
foreach ( $spaces as $name => $ns ) {
$moreNames = [];
$moreNames[] = $contLang->uc( $name );
$moreNames[] = $contLang->ucwords( $contLang->lc( $name ) );
$moreNames[] = $contLang->ucwordbreaks( $name );
$moreNames[] = $contLang->ucwordbreaks( $contLang->lc( $name ) );
- if ( !$wgCapitalLinks ) {
+ if ( !$capitalLinks ) {
foreach ( $moreNames as $altName ) {
$moreNames[] = $contLang->lcfirst( $altName );
}
$dbw->query( "DELETE FROM $tbl_pag WHERE page_id = $id" );
$this->commitTransaction( $dbw, __METHOD__ );
// Delete revisions as appropriate
+ /** @var NukePage $child */
$child = $this->runChild( NukePage::class, 'nukePage.php' );
+ '@phan-var NukePage $child';
$child->deleteRevisions( $revs );
$this->purgeRedundantText( true );
$n_deleted++;
$dbw->doAtomicSection( __METHOD__, function ( IDatabase $dbw, $fname ) {
$dbw->insert( 'revision', self::$dummyRev, $fname );
$id = $dbw->insertId();
- $toDelete[] = $id;
+ $toDelete = [ $id ];
$maxId = max(
(int)$dbw->selectField( 'archive', 'MAX(ar_rev_id)', [], $fname ),
}
public function execute() {
- global $wgMultiContentRevisionSchemaMigrationStage;
+ $multiContentRevisionSchemaMigrationStage =
+ $this->getConfig()->get( 'MultiContentRevisionSchemaMigrationStage' );
$t0 = microtime( true );
- if ( ( $wgMultiContentRevisionSchemaMigrationStage & SCHEMA_COMPAT_WRITE_NEW ) === 0 ) {
+ if ( ( $multiContentRevisionSchemaMigrationStage & SCHEMA_COMPAT_WRITE_NEW ) === 0 ) {
$this->writeln(
'...cannot update while \$wgMultiContentRevisionSchemaMigrationStage '
. 'does not have the SCHEMA_COMPAT_WRITE_NEW bit set.'
// with the database write operation, because the writes are queued
// in the pipe buffer. This can improve performance by up to a
// factor of 2.
- global $wgDBuser, $wgDBserver, $wgDBpassword, $wgDBname;
- $cmd = 'mysql -u' . Shell::escape( $wgDBuser ) .
- ' -h' . Shell::escape( $wgDBserver ) .
- ' -p' . Shell::escape( $wgDBpassword, $wgDBname );
+ $config = $this->getConfig();
+ $cmd = 'mysql -u' . Shell::escape( $config->get( 'DBuser' ) ) .
+ ' -h' . Shell::escape( $config->get( 'DBserver' ) ) .
+ ' -p' . Shell::escape( $config->get( 'DBpassword' ), $config->get( 'DBname' ) );
$this->output( "Using pipe method\n" );
$pipe = popen( $cmd, 'w' );
}
}
// Upgrade the old file versions...
foreach ( $file->getHistory() as $oldFile ) {
+ /** @var OldLocalFile $oldFile */
+ '@phan-var OldLocalFile $oldFile';
$sha1 = $oldFile->getRepo()->getFileSha1( $oldFile->getPath() );
if ( strval( $sha1 ) !== '' ) { // file on disk and hashed properly
if ( $isRegen && $oldFile->getSha1() !== $sha1 ) {
}
protected function doDBUpdates() {
- global $wgActorTableSchemaMigrationStage;
-
$batchSize = $this->getBatchSize();
$db = $this->getDB( DB_MASTER );
if ( !$db->tableExists( 'log_search' ) ) {
}
$end = $db->selectField( 'logging', 'MAX(log_id)', '', __FUNCTION__ );
+ // This maintenance script is for updating pre-1.16 to 1.16. The target_author_id and
+ // target_author_ip relations it adds will later be migrated to target_author_actor by
+ // migrateActors.php. If the schema is already 1.34, we should have nothing to do.
+ if ( !$db->fieldExists( 'logging', 'log_user' ) ) {
+ $this->output(
+ "This does not appear to be an upgrade from MediaWiki pre-1.16 "
+ . "(logging.log_user does not exist).\n"
+ );
+ $this->output( "Nothing to do.\n" );
+
+ return true;
+ }
+
# Do remaining chunk
$end += $batchSize - 1;
$blockStart = $start;
'logging', [ 'log_id', 'log_type', 'log_action', 'log_params' ], $cond, __FUNCTION__
);
foreach ( $res as $row ) {
+ // RevisionDelete logs - revisions
if ( LogEventsList::typeAction( $row, $delTypes, 'revision' ) ) {
- // RevisionDelete logs - revisions
$params = LogPage::extractParams( $row->log_params );
// Param format: <urlparam> <item CSV> [<ofield> <nfield>]
if ( count( $params ) < 2 ) {
$log = new LogPage( $row->log_type );
// Add item relations...
$log->addRelations( $field, $items, $row->log_id );
- // Query item author relations...
+ // Determine what table to query...
$prefix = substr( $field, 0, strpos( $field, '_' ) ); // db prefix
if ( !isset( self::$tableMap[$prefix] ) ) {
continue; // bad row?
}
- $tables = [ self::$tableMap[$prefix] ];
- $fields = [];
- $joins = [];
- if ( $wgActorTableSchemaMigrationStage & SCHEMA_COMPAT_WRITE_OLD ) {
- // Read the old fields if we're still writing them regardless of read mode, to handle upgrades
- $fields['userid'] = $prefix . '_user';
- $fields['username'] = $prefix . '_user_text';
- }
- if ( $wgActorTableSchemaMigrationStage & SCHEMA_COMPAT_WRITE_NEW ) {
- // Read the new fields if we're writing them regardless of read mode, to handle upgrades
- if ( $prefix === 'rev' ) {
- $tables[] = 'revision_actor_temp';
- $joins['revision_actor_temp'] = [
- ( $wgActorTableSchemaMigrationStage & SCHEMA_COMPAT_WRITE_OLD ) ? 'LEFT JOIN' : 'JOIN',
- 'rev_id = revactor_rev',
- ];
- $fields['actorid'] = 'revactor_actor';
- } else {
- $fields['actorid'] = $prefix . '_actor';
+ $table = self::$tableMap[$prefix];
+ $userField = $prefix . '_user';
+ $userTextField = $prefix . '_user_text';
+ // Add item author relations...
+ $userIds = $userIPs = [];
+ $sres = $db->select( $table,
+ [ $userField, $userTextField ],
+ [ $field => $items ]
+ );
+ foreach ( $sres as $srow ) {
+ if ( $srow->$userField > 0 ) {
+ $userIds[] = intval( $srow->$userField );
+ } elseif ( $srow->$userTextField != '' ) {
+ $userIPs[] = $srow->$userTextField;
}
}
- $sres = $db->select( $tables, $fields, [ $field => $items ], __METHOD__, [], $joins );
+ // Add item author relations...
+ $log->addRelations( 'target_author_id', $userIds, $row->log_id );
+ $log->addRelations( 'target_author_ip', $userIPs, $row->log_id );
} elseif ( LogEventsList::typeAction( $row, $delTypes, 'event' ) ) {
// RevisionDelete logs - log events
$params = LogPage::extractParams( $row->log_params );
$log = new LogPage( $row->log_type );
// Add item relations...
$log->addRelations( 'log_id', $items, $row->log_id );
- // Query item author relations...
- $fields = [];
- if ( $wgActorTableSchemaMigrationStage & SCHEMA_COMPAT_WRITE_OLD ) {
- // Read the old fields if we're still writing them regardless of read mode, to handle upgrades
- $fields['userid'] = 'log_user';
- $fields['username'] = 'log_user_text';
- }
- if ( $wgActorTableSchemaMigrationStage & SCHEMA_COMPAT_WRITE_NEW ) {
- // Read the new fields if we're writing them regardless of read mode, to handle upgrades
- $fields['actorid'] = 'log_actor';
- }
-
- $sres = $db->select( 'logging', $fields, [ 'log_id' => $items ], __METHOD__ );
- } else {
- continue;
- }
-
- // Add item author relations...
- $userIds = $userIPs = $userActors = [];
- foreach ( $sres as $srow ) {
- if ( $wgActorTableSchemaMigrationStage & SCHEMA_COMPAT_WRITE_OLD ) {
- if ( $srow->userid > 0 ) {
- $userIds[] = intval( $srow->userid );
- } elseif ( $srow->username != '' ) {
- $userIPs[] = $srow->username;
+ // Add item author relations...
+ $userIds = $userIPs = [];
+ $sres = $db->select( 'logging',
+ [ 'log_user', 'log_user_text' ],
+ [ 'log_id' => $items ]
+ );
+ foreach ( $sres as $srow ) {
+ if ( $srow->log_user > 0 ) {
+ $userIds[] = intval( $srow->log_user );
+ } elseif ( IP::isIPAddress( $srow->log_user_text ) ) {
+ $userIPs[] = $srow->log_user_text;
}
}
- if ( $wgActorTableSchemaMigrationStage & SCHEMA_COMPAT_WRITE_NEW ) {
- if ( $srow->actorid ) {
- $userActors[] = intval( $srow->actorid );
- } elseif ( $srow->userid > 0 ) {
- $userActors[] = User::newFromId( $srow->userid )->getActorId( $db );
- } else {
- $userActors[] = User::newFromName( $srow->username, false )->getActorId( $db );
- }
- }
- }
- // Add item author relations...
- if ( $wgActorTableSchemaMigrationStage & SCHEMA_COMPAT_WRITE_OLD ) {
$log->addRelations( 'target_author_id', $userIds, $row->log_id );
$log->addRelations( 'target_author_ip', $userIPs, $row->log_id );
}
- if ( $wgActorTableSchemaMigrationStage & SCHEMA_COMPAT_WRITE_NEW ) {
- $log->addRelations( 'target_author_actor', $userActors, $row->log_id );
- }
}
$blockStart += $batchSize;
$blockEnd += $batchSize;
/**
* @param MediaWiki\Revision\RevisionStore $revStore
- * @param string $emptySha1
* @return int
*/
protected function doSha1LegacyUpdates( $revStore ) {
if ( $content->getModel() !== CONTENT_MODEL_WIKITEXT ) {
return;
}
+ /** @var WikitextContent $content */
+ '@phan-var WikitextContent $content';
try {
$this->mPreprocessor->preprocessToObj( strval( $content->getText() ), 0 );
$passed = 'passed';
} catch ( Exception $e ) {
$testReport = self::$currentTest->getReport();
- $exceptionReport = $e->getText();
+ $exceptionReport = $e instanceof MWException ? $e->getText() : (string)$e;
$hash = md5( $testReport );
file_put_contents( "results/ppft-$hash.in", serialize( self::$currentTest ) );
file_put_contents( "results/ppft-$hash.fail",
* @return int Number of entries changed, or that would be changed
*/
private function doReassignEdits( &$from, &$to, $rc = false, $report = false ) {
- global $wgActorTableSchemaMigrationStage;
+ $actorTableSchemaMigrationStage = $this->getConfig()->get( 'ActorTableSchemaMigrationStage' );
$dbw = $this->getDB( DB_MASTER );
$this->beginTransaction( $dbw, __METHOD__ );
if ( $total ) {
# Reassign edits
$this->output( "\nReassigning current edits..." );
- if ( $wgActorTableSchemaMigrationStage & SCHEMA_COMPAT_WRITE_OLD ) {
+ if ( $actorTableSchemaMigrationStage & SCHEMA_COMPAT_WRITE_OLD ) {
$dbw->update(
'revision',
[
__METHOD__
);
}
- if ( $wgActorTableSchemaMigrationStage & SCHEMA_COMPAT_WRITE_NEW ) {
+ if ( $actorTableSchemaMigrationStage & SCHEMA_COMPAT_WRITE_NEW ) {
$dbw->update(
'revision_actor_temp',
[ 'revactor_actor' => $to->getActorId( $dbw ) ],
* @return array
*/
private function userSpecification( IDatabase $dbw, &$user, $idfield, $utfield, $acfield ) {
- global $wgActorTableSchemaMigrationStage;
+ $actorTableSchemaMigrationStage = $this->getConfig()->get( 'ActorTableSchemaMigrationStage' );
$ret = [];
- if ( $wgActorTableSchemaMigrationStage & SCHEMA_COMPAT_WRITE_OLD ) {
+ if ( $actorTableSchemaMigrationStage & SCHEMA_COMPAT_WRITE_OLD ) {
$ret += [
$idfield => $user->getId(),
$utfield => $user->getName(),
];
}
- if ( $wgActorTableSchemaMigrationStage & SCHEMA_COMPAT_WRITE_NEW ) {
+ if ( $actorTableSchemaMigrationStage & SCHEMA_COMPAT_WRITE_NEW ) {
$ret += [ $acfield => $user->getActorId( $dbw ) ];
}
return $ret;
}
/**
- * @return FileRepo
+ * @return LocalRepo
*/
function getRepo() {
if ( !isset( $this->repo ) ) {
$filename = $altname;
$this->output( "Estimating transcoding... $altname\n" );
} else {
- # @todo FIXME: create renameFile()
+ // @fixme create renameFile()
+ // @phan-suppress-next-line PhanUndeclaredMethod See comment above...
$filename = $this->renameFile( $filename );
}
}
* @ingroup Maintenance
*/
-use MediaWiki\Config\ServiceOptions;
-use MediaWiki\Logger\LoggerFactory;
-use MediaWiki\MediaWikiServices;
-
require_once __DIR__ . '/Maintenance.php';
/**
$conf = $wgLocalisationCacheConf;
$conf['manualRecache'] = false; // Allow fallbacks to create CDB files
- $conf['forceRecache'] = $force || !empty( $conf['forceRecache'] );
+ if ( $force ) {
+ $conf['forceRecache'] = true;
+ }
if ( $this->hasOption( 'outdir' ) ) {
$conf['storeDirectory'] = $this->getOption( 'outdir' );
}
- // XXX Copy-pasted from ServiceWiring.php. Do we need a factory for this one caller?
- $lc = new LocalisationCacheBulkLoad(
- new ServiceOptions(
- LocalisationCache::$constructorOptions,
- $conf,
- MediaWikiServices::getInstance()->getMainConfig()
- ),
- new LCStoreDB( [] ),
- LoggerFactory::getInstance( 'localisation' ),
- [ function () {
- MediaWikiServices::getInstance()->getResourceLoader()
- ->getMessageBlobStore()->clear();
- } ],
- MediaWikiServices::getInstance()->getLanguageNameUtils()
- );
+ $lc = new LocalisationCacheBulkLoad( $conf );
$allCodes = array_keys( Language::fetchLanguageNames( null, 'mwfile' ) );
if ( $this->hasOption( 'lang' ) ) {
<?php
/**
- * Purge all languages from the message cache.
- *
* 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
* @ingroup Maintenance
*/
+use MediaWiki\MediaWikiServices;
+
require_once __DIR__ . '/Maintenance.php';
/**
- * Maintenance script that purges all languages from the message cache.
+ * Maintenance script that purges cache used by MessageCache.
*
* @ingroup Maintenance
*/
class RebuildMessages extends Maintenance {
public function __construct() {
parent::__construct();
- $this->addDescription( 'Purge all language messages from the cache' );
+ $this->addDescription( 'Purge the MessageCache for all interface languages.' );
}
public function execute() {
- global $wgLocalDatabases, $wgDBname, $wgEnableSidebarCache, $messageMemc;
- if ( $wgLocalDatabases ) {
- $databases = $wgLocalDatabases;
- } else {
- $databases = [ $wgDBname ];
- }
-
- foreach ( $databases as $db ) {
- $this->output( "Deleting message cache for {$db}... " );
- $messageMemc->delete( "{$db}:messages" );
- if ( $wgEnableSidebarCache ) {
- $messageMemc->delete( "{$db}:sidebar" );
- }
- $this->output( "Deleted\n" );
- }
+ $this->output( "Purging message cache for all languages on this wiki... " );
+ $messageCache = MediaWikiServices::getInstance()->getMessageCache();
+ $messageCache->clear();
+ $this->output( "Done\n" );
}
}
}
public function execute() {
- global $wgActorTableSchemaMigrationStage;
+ $actorTableSchemaMigrationStage = $this->getConfig()->get( 'ActorTableSchemaMigrationStage' );
$this->output( "Remove unused accounts\n\n" );
$delUser = [];
$delActor = [];
$dbr = $this->getDB( DB_REPLICA );
- if ( $wgActorTableSchemaMigrationStage & SCHEMA_COMPAT_WRITE_NEW ) {
+ if ( $actorTableSchemaMigrationStage & SCHEMA_COMPAT_WRITE_NEW ) {
$res = $dbr->select(
[ 'user', 'actor' ],
[ 'user_id', 'user_name', 'user_touched', 'actor_id' ],
$this->output( "\nDeleting unused accounts..." );
$dbw = $this->getDB( DB_MASTER );
$dbw->delete( 'user', [ 'user_id' => $delUser ], __METHOD__ );
- if ( $wgActorTableSchemaMigrationStage & SCHEMA_COMPAT_WRITE_NEW ) {
+ if ( $actorTableSchemaMigrationStage & SCHEMA_COMPAT_WRITE_NEW ) {
# Keep actor rows referenced from ipblocks
$keep = $dbw->selectFieldValues(
'ipblocks', 'ipb_by_actor', [ 'ipb_by_actor' => $delActor ], __METHOD__
$dbw->delete( 'user_groups', [ 'ug_user' => $delUser ], __METHOD__ );
$dbw->delete( 'user_former_groups', [ 'ufg_user' => $delUser ], __METHOD__ );
$dbw->delete( 'user_properties', [ 'up_user' => $delUser ], __METHOD__ );
- if ( $wgActorTableSchemaMigrationStage & SCHEMA_COMPAT_WRITE_NEW ) {
+ if ( $actorTableSchemaMigrationStage & SCHEMA_COMPAT_WRITE_NEW ) {
$dbw->delete( 'logging', [ 'log_actor' => $delActor ], __METHOD__ );
$dbw->delete( 'recentchanges', [ 'rc_actor' => $delActor ], __METHOD__ );
}
- if ( $wgActorTableSchemaMigrationStage & SCHEMA_COMPAT_WRITE_OLD ) {
+ if ( $actorTableSchemaMigrationStage & SCHEMA_COMPAT_WRITE_OLD ) {
$dbw->delete( 'logging', [ 'log_user' => $delUser ], __METHOD__ );
$dbw->delete( 'recentchanges', [ 'rc_user' => $delUser ], __METHOD__ );
}
return $this->sqlPrintResult( $res, $db );
} catch ( DBQueryError $e ) {
if ( $dieOnError ) {
- $this->fatalError( $e );
+ $this->fatalError( (string)$e );
} else {
- $this->error( $e );
+ $this->error( (string)$e );
}
}
return null;
[],
[ 'content' => [ 'INNER JOIN', [ 'content_id = slot_content_id' ] ] ]
);
+ /** @var \MediaWiki\Storage\SqlBlobStore $blobStore */
$blobStore = MediaWikiServices::getInstance()->getBlobStore();
+ '@phan-var \MediaWiki\Storage\SqlBlobStore $blobStore';
foreach ( $res as $row ) {
$textId = $blobStore->getTextIdFromAddress( $row->content_address );
if ( $textId ) {
* @param string $extdb
* @param bool|int $maxPageId
* @return bool
+ * @suppress PhanTypeInvalidDimOffset
*/
private function compressWithConcat( $startId, $maxChunkSize, $beginDate,
$endDate, $extdb = "", $maxPageId = false
/** @var RecompressTracked */
public $parent;
public $blobClass;
- /** @var ConcatenatedGzipHistoryBlob */
+ /** @var ConcatenatedGzipHistoryBlob|false */
public $cgz;
public $referrers;
-- see https://www.iana.org/assignments/media-types/
img_minor_mime varbinary(100) NOT NULL default "unknown",
- -- Description field as entered by the uploader.
+ -- Foreign key to comment table, which contains the description field as entered by the uploader.
-- This is displayed in image upload history and logs.
img_description_id bigint unsigned NOT NULL,
require_once __DIR__ . '/Maintenance.php';
-use Wikimedia\Rdbms\IMaintainableDatabase;
use Wikimedia\Rdbms\DatabaseSqlite;
/**
$this->output( "MediaWiki {$wgVersion} Updater\n\n" );
- foreach ( SpecialVersion::getSoftwareInformation() as $name => $version ) {
- $this->output( "{$name}: {$version}\n" );
- }
-
wfWaitForSlaves();
if ( !$this->hasOption( 'skip-compat-checks' ) ) {
$dbDomain = WikiMap::getCurrentWikiDbDomain()->getId();
$this->output( "Going to run database updates for $dbDomain\n" );
if ( $db->getType() === 'sqlite' ) {
- /** @var IMaintainableDatabase|DatabaseSqlite $db */
+ /** @var DatabaseSqlite $db */
+ '@phan-var DatabaseSqlite $db';
$this->output( "Using SQLite file: '{$db->getDbFilePath()}'\n" );
}
$this->output( "Depending on the size of your database this may take a while!\n" );
public function __construct() {
parent::__construct();
- global $wgCategoryCollation;
+ $categoryCollation = $this->getConfig()->get( 'CategoryCollation' );
$this->addDescription( <<<TEXT
This script will find all rows in the categorylinks table whose collation is
-out-of-date (cl_collation != '$wgCategoryCollation') and repopulate cl_sortkey
+out-of-date (cl_collation != '$categoryCollation') and repopulate cl_sortkey
using the page title and cl_sortkey_prefix. If all collations are
up-to-date, it will do nothing.
TEXT
}
public function execute() {
- global $wgCategoryCollation;
-
$dbw = $this->getDB( DB_MASTER );
$dbr = $this->getDB( DB_REPLICA );
$force = $this->getOption( 'force' );
$collationName = $this->getOption( 'target-collation' );
$collation = Collation::factory( $collationName );
} else {
- $collationName = $wgCategoryCollation;
+ $collationName = $this->getConfig()->get( 'CategoryCollation' );
$collation = Collation::singleton();
}
'STRAIGHT_JOIN' // per T58041
];
- if ( $force ) {
- $collationConds = [];
- } else {
+ $collationConds = [];
+ if ( !$force ) {
if ( $this->hasOption( 'previous-collation' ) ) {
$collationConds['cl_collation'] = $this->getOption( 'previous-collation' );
} else {
}
$json = FormatJson::decode( file_get_contents( $filename ), true );
- if ( $json === null ) {
+ if ( !is_array( $json ) ) {
$this->fatalError( "Error: Invalid JSON" );
}
while ( $json['manifest_version'] !== ExtensionRegistry::MANIFEST_VERSION ) {
$json['manifest_version'] += 1;
$func = "updateTo{$json['manifest_version']}";
+ // @phan-suppress-next-line PhanUndeclaredMethod
$this->$func( $json );
}
*/
class UserDupes {
/**
- * @var IMaintainableDatabase
+ * @var Database
*/
private $db;
private $reassigned;
$user = User::newFromId( $row->user_id );
/** @var ParameterizedPassword $password */
$password = $passwordFactory->newFromCiphertext( $row->user_password );
+ '@phan-var ParameterizedPassword $password';
/** @var LayeredParameterizedPassword $layeredPassword */
$layeredPassword = $passwordFactory->newFromType( $layeredType );
+ '@phan-var LayeredParameterizedPassword $layeredPassword';
$layeredPassword->partialCrypt( $password );
$updateUsers[] = $user;
}
},
"eslint-utils": {
- "version": "1.3.1",
- "resolved": "https://registry.npmjs.org/eslint-utils/-/eslint-utils-1.3.1.tgz",
- "integrity": "sha512-Z7YjnIldX+2XMcjr7ZkgEsOj/bREONV60qYeB/bjMAqqqZ4zxKyWX+BOUkdmRmA9riiIPVvo5x86m5elviOk0Q==",
- "dev": true
+ "version": "1.4.2",
+ "resolved": "https://registry.npmjs.org/eslint-utils/-/eslint-utils-1.4.2.tgz",
+ "integrity": "sha512-eAZS2sEUMlIeCjBeubdj45dmBHQwPHWyBcT1VSYB7o9x9WRRqKxyUoiXlRjyAwzN7YEzHJlYg0NmzDRWx6GP4Q==",
+ "dev": true,
+ "requires": {
+ "eslint-visitor-keys": "^1.0.0"
+ }
},
"eslint-visitor-keys": {
"version": "1.0.0",
"requires": {
"lodash": "^4.17.11"
}
+ },
+ "lodash": {
+ "version": "4.17.15",
+ "resolved": "https://registry.npmjs.org/lodash/-/lodash-4.17.15.tgz",
+ "integrity": "sha512-8xOcRHvCjnocdS5cpwXQXVzmmh5e5+saE2QGoeQmbKmRS6J3VQppPOIt0MnmE+4xlZoumy0GPG0D0MVIQbNA1A==",
+ "dev": true
}
}
},
}
}
},
- "humanize-duration": {
- "version": "3.15.3",
- "resolved": "https://registry.npmjs.org/humanize-duration/-/humanize-duration-3.15.3.tgz",
- "integrity": "sha512-BMz6w8p3NVa6QP9wDtqUkXfwgBqDaZ5z/np0EYdoWrLqL849Onp6JWMXMhbHtuvO9jUThLN5H1ThRQ8dUWnYkA==",
- "dev": true
- },
"iconv-lite": {
"version": "0.4.24",
"resolved": "https://registry.npmjs.org/iconv-lite/-/iconv-lite-0.4.24.tgz",
}
},
"lodash": {
- "version": "4.17.11",
- "resolved": "https://registry.npmjs.org/lodash/-/lodash-4.17.11.tgz",
- "integrity": "sha512-cQKh8igo5QUhZ7lg38DYWAxMvjSAKG0A8wGSVimP07SIUEK2UO+arSRKbRZWtelMtN5V0Hkwh5ryOto/SshYIg==",
+ "version": "4.17.15",
+ "resolved": "https://registry.npmjs.org/lodash/-/lodash-4.17.15.tgz",
+ "integrity": "sha512-8xOcRHvCjnocdS5cpwXQXVzmmh5e5+saE2QGoeQmbKmRS6J3VQppPOIt0MnmE+4xlZoumy0GPG0D0MVIQbNA1A==",
"dev": true
},
"lodash.get": {
}
},
"mixin-deep": {
- "version": "1.3.1",
- "resolved": "https://registry.npmjs.org/mixin-deep/-/mixin-deep-1.3.1.tgz",
- "integrity": "sha512-8ZItLHeEgaqEvd5lYBXfm4EZSFCX29Jb9K+lAHhDKzReKBQKj3R+7NOF6tjqYi9t4oI8VUfaWITJQm86wnXGNQ==",
+ "version": "1.3.2",
+ "resolved": "https://registry.npmjs.org/mixin-deep/-/mixin-deep-1.3.2.tgz",
+ "integrity": "sha512-WRoDn//mXBiJ1H40rqa3vH0toePwSsGb45iInWlTySa+Uu4k3tYUSxa2v1KqAiLtvlrSzaExqS1gtk96A9zvEA==",
"dev": true,
"requires": {
"for-in": "^1.0.2",
"dev": true
},
"set-value": {
- "version": "2.0.0",
- "resolved": "https://registry.npmjs.org/set-value/-/set-value-2.0.0.tgz",
- "integrity": "sha512-hw0yxk9GT/Hr5yJEYnHNKYXkIA8mVJgd9ditYZCe16ZczcaELYYcfvaXesNACk2O8O0nTiPQcQhGUQj8JLzeeg==",
+ "version": "2.0.1",
+ "resolved": "https://registry.npmjs.org/set-value/-/set-value-2.0.1.tgz",
+ "integrity": "sha512-JxHc1weCN68wRY0fhCoXpyK55m/XPHafOmK4UWD7m2CI14GMcFypt4w/0+NV5f/ZMby2F6S2wwA7fgynh9gWSw==",
"dev": true,
"requires": {
"extend-shallow": "^2.0.1",
}
},
"union-value": {
- "version": "1.0.0",
- "resolved": "https://registry.npmjs.org/union-value/-/union-value-1.0.0.tgz",
- "integrity": "sha1-XHHDTLW61dzr4+oM0IIHulqhrqQ=",
+ "version": "1.0.1",
+ "resolved": "https://registry.npmjs.org/union-value/-/union-value-1.0.1.tgz",
+ "integrity": "sha512-tJfXmxMeWYnczCVs7XAEvIV7ieppALdyepWMkHkwciRpZraG/xwT+s2JN8+pr1+8jCRf80FFzvr+MpQeeoF4Xg==",
"dev": true,
"requires": {
"arr-union": "^3.1.0",
"get-value": "^2.0.6",
"is-extendable": "^0.1.1",
- "set-value": "^0.4.3"
- },
- "dependencies": {
- "extend-shallow": {
- "version": "2.0.1",
- "resolved": "https://registry.npmjs.org/extend-shallow/-/extend-shallow-2.0.1.tgz",
- "integrity": "sha1-Ua99YUrZqfYQ6huvu5idaxxWiQ8=",
- "dev": true,
- "requires": {
- "is-extendable": "^0.1.0"
- }
- },
- "set-value": {
- "version": "0.4.3",
- "resolved": "https://registry.npmjs.org/set-value/-/set-value-0.4.3.tgz",
- "integrity": "sha1-fbCPnT0i3H945Trzw79GZuzfzPE=",
- "dev": true,
- "requires": {
- "extend-shallow": "^2.0.1",
- "is-extendable": "^0.1.1",
- "is-plain-object": "^2.0.1",
- "to-object-path": "^0.3.0"
- }
- }
+ "set-value": "^2.0.1"
}
},
"uniq": {
"sauce-connect-launcher": "~1.2.3"
}
},
- "wdio-spec-reporter": {
- "version": "0.1.5",
- "resolved": "https://registry.npmjs.org/wdio-spec-reporter/-/wdio-spec-reporter-0.1.5.tgz",
- "integrity": "sha512-MqvgTow8hFwhFT47q67JwyJyeynKodGRQCxF7ijKPGfsaG1NLssbXYc0JhiL7SiAyxnQxII0UxzTCd3I6sEdkg==",
- "dev": true,
- "requires": {
- "babel-runtime": "~6.26.0",
- "chalk": "^2.3.0",
- "humanize-duration": "~3.15.0"
- }
- },
"wdio-sync": {
"version": "0.7.3",
"resolved": "https://registry.npmjs.org/wdio-sync/-/wdio-sync-0.7.3.tgz",
"postcss-less": "2.0.0",
"qunit": "2.9.1",
"stylelint-config-wikimedia": "0.6.0",
+ "wdio-dot-reporter": "0.0.10",
"wdio-junit-reporter": "0.4.4",
"wdio-mediawiki": "file:tests/selenium/wdio-mediawiki",
"wdio-mocha-framework": "0.6.4",
"wdio-sauce-service": "0.4.14",
- "wdio-spec-reporter": "0.1.5",
"webdriverio": "4.14.4"
}
}
'mediawiki.pager.tablePager' => [
'styles' => 'resources/src/mediawiki.pager.tablePager/TablePager.less',
],
+ 'mediawiki.pulsatingdot' => [
+ 'styles' => [
+ 'resources/src/mediawiki.pulsatingdot/mediawiki.pulsatingdot.less',
+ ],
+ 'targets' => [ 'desktop', 'mobile' ],
+ ],
'mediawiki.searchSuggest' => [
'targets' => [ 'desktop', 'mobile' ],
'scripts' => 'resources/src/mediawiki.searchSuggest/searchSuggest.js',
'oojs-ui-core',
],
'messages' => [
- // Keep the uses message keys in sync with EditPage#setHeaders
+ // Keep these message keys in sync with EditPage#setHeaders
'creating',
'editconflict',
'editing',
integrity: sha384-RPXhaTf22QktT8KTwZ6bUz/C+7CnccaIw5W/y/t0FW5WSDGj3wc3YtRIJC0w47in
jquery:
- type: file
- src: https://code.jquery.com/jquery-3.3.1.js
- # Integrity from link modals https://code.jquery.com/jquery/
- integrity: sha256-2Kok7MbOyxpgUVvAk/HJ2jigOSYS2auK4Pfzbm7uH60=
- dest: jquery.js
+ type: multi-file
+ files:
+ # Integrities from link modals https://code.jquery.com/jquery/
+ jquery.migrate.js:
+ src: https://code.jquery.com/jquery-migrate-3.0.1.js
+ integrity: sha256-VvnF+Zgpd00LL73P2XULYXEn6ROvoFaa/vbfoiFlZZ4=
+ jquery.js:
+ src: https://code.jquery.com/jquery-3.3.1.js
+ integrity: sha256-2Kok7MbOyxpgUVvAk/HJ2jigOSYS2auK4Pfzbm7uH60=
jquery.chosen:
type: multi-file
---- jquery-3.3.1.js 2019-04-01 08:39:29.000000000 +0200
-+++ jquery-3.3.1.js 2019-04-01 09:02:39.000000000 +0200
-@@ -260,8 +260,9 @@ jQuery.extend = jQuery.fn.extend = function() {
- for ( name in options ) {
- src = target[ name ];
+diff --git a/resources/lib/jquery/jquery.js b/resources/lib/jquery/jquery.js
+index 9b5206bcc6..34a5703d80 100644
+--- a/resources/lib/jquery/jquery.js
++++ b/resources/lib/jquery/jquery.js
+@@ -261,8 +261,9 @@ jQuery.extend = jQuery.fn.extend = function() {
+ src = target[ name ];
copy = options[ name ];
+ // Prevent Object.prototype pollution
--- /dev/null
+diff --git a/resources/lib/jquery/jquery.migrate.js b/resources/lib/jquery/jquery.migrate.js
+index 6ba8af4a42..711e424a39 100644
+--- a/resources/lib/jquery/jquery.migrate.js
++++ b/resources/lib/jquery/jquery.migrate.js
+@@ -1,6 +1,14 @@
+ /*!
+ * jQuery Migrate - v3.0.1 - 2017-09-26
+ * Copyright jQuery Foundation and other contributors
++ *
++ * Patched for MediaWiki:
++ * - Qualify the global lookup for 'jQuery' as 'window.jQuery',
++ * because within mw.loader.implement() for 'jquery', the closure
++ * specifies '$' and 'jQuery', which are undefined.
++ * - Add mw.track instrumentation for statistics.
++ * - Disable jQuery.migrateTrace by default. They are slow and
++ * redundant given console.warn() already provides a trace.
+ */
+ ;( function( factory ) {
+ if ( typeof define === "function" && define.amd ) {
+@@ -15,7 +23,8 @@
+ } else {
+
+ // Browser globals
+- factory( jQuery, window );
++ // PATCH: Qualify jQuery lookup as window.jQuery. --Krinkle
++ factory( window.jQuery, window );
+ }
+ } )( function( jQuery, window ) {
+ "use strict";
+@@ -58,7 +67,8 @@ jQuery.migrateWarnings = [];
+
+ // Set to false to disable traces that appear with warnings
+ if ( jQuery.migrateTrace === undefined ) {
+- jQuery.migrateTrace = true;
++ // PATCH: Disable extra console.trace() call --Krinkle
++ jQuery.migrateTrace = false;
+ }
+
+ // Forget any warnings we've already given; public
+@@ -72,6 +82,10 @@ function migrateWarn( msg ) {
+ if ( !warnedAbout[ msg ] ) {
+ warnedAbout[ msg ] = true;
+ jQuery.migrateWarnings.push( msg );
++ // PATCH: Add instrumentation for statistics --Krinkle
++ if ( window.mw && window.mw.track ) {
++ window.mw.track( "mw.deprecate", "jquery-migrate" );
++ }
+ if ( console && console.warn && !jQuery.migrateMute ) {
+ console.warn( "JQMIGRATE: " + msg );
+ if ( jQuery.migrateTrace && console.trace ) {
+@@ -466,20 +480,6 @@ jQuery.each( [ "load", "unload", "error" ], function( _, name ) {
+
+ } );
+
+-jQuery.each( ( "blur focus focusin focusout resize scroll click dblclick " +
+- "mousedown mouseup mousemove mouseover mouseout mouseenter mouseleave " +
+- "change select submit keydown keypress keyup contextmenu" ).split( " " ),
+- function( i, name ) {
+-
+- // Handle event binding
+- jQuery.fn[ name ] = function( data, fn ) {
+- migrateWarn( "jQuery.fn." + name + "() event shorthand is deprecated" );
+- return arguments.length > 0 ?
+- this.on( name, null, data, fn ) :
+- this.trigger( name );
+- };
+-} );
+-
+ // Trigger "ready" event only once, on document ready
+ jQuery( function() {
+ jQuery( window.document ).triggerHandler( "ready" );
);
},
+ // match prefix plus any combining characters to prevent ugly rendering (see T35242)
+ prefixPlusComboHighlight: function ( node, prefix ) {
+
+ // Equivalent to \p{Mark} (which is not currently available in JavaScript)
+ var comboMarks = '[\u0300-\u036F\u0483-\u0489\u0591-\u05BD\u05BF\u05C1\u05C2\u05C4\u05C5\u05C7\u0610-\u061A\u064B-\u065F\u0670\u06D6-\u06DC\u06DF-\u06E4\u06E7\u06E8\u06EA-\u06ED\u0711\u0730-\u074A\u07A6-\u07B0\u07EB-\u07F3\u07FD\u0816-\u0819\u081B-\u0823\u0825-\u0827\u0829-\u082D\u0859-\u085B\u08D3-\u08E1\u08E3-\u0903\u093A-\u093C\u093E-\u094F\u0951-\u0957\u0962\u0963\u0981-\u0983\u09BC\u09BE-\u09C4\u09C7\u09C8\u09CB-\u09CD\u09D7\u09E2\u09E3\u09FE\u0A01-\u0A03\u0A3C\u0A3E-\u0A42\u0A47\u0A48\u0A4B-\u0A4D\u0A51\u0A70\u0A71\u0A75\u0A81-\u0A83\u0ABC\u0ABE-\u0AC5\u0AC7-\u0AC9\u0ACB-\u0ACD\u0AE2\u0AE3\u0AFA-\u0AFF\u0B01-\u0B03\u0B3C\u0B3E-\u0B44\u0B47\u0B48\u0B4B-\u0B4D\u0B56\u0B57\u0B62\u0B63\u0B82\u0BBE-\u0BC2\u0BC6-\u0BC8\u0BCA-\u0BCD\u0BD7\u0C00-\u0C04\u0C3E-\u0C44\u0C46-\u0C48\u0C4A-\u0C4D\u0C55\u0C56\u0C62\u0C63\u0C81-\u0C83\u0CBC\u0CBE-\u0CC4\u0CC6-\u0CC8\u0CCA-\u0CCD\u0CD5\u0CD6\u0CE2\u0CE3\u0D00-\u0D03\u0D3B\u0D3C\u0D3E-\u0D44\u0D46-\u0D48\u0D4A-\u0D4D\u0D57\u0D62\u0D63\u0D82\u0D83\u0DCA\u0DCF-\u0DD4\u0DD6\u0DD8-\u0DDF\u0DF2\u0DF3\u0E31\u0E34-\u0E3A\u0E47-\u0E4E\u0EB1\u0EB4-\u0EB9\u0EBB\u0EBC\u0EC8-\u0ECD\u0F18\u0F19\u0F35\u0F37\u0F39\u0F3E\u0F3F\u0F71-\u0F84\u0F86\u0F87\u0F8D-\u0F97\u0F99-\u0FBC\u0FC6\u102B-\u103E\u1056-\u1059\u105E-\u1060\u1062-\u1064\u1067-\u106D\u1071-\u1074\u1082-\u108D\u108F\u109A-\u109D\u135D-\u135F\u1712-\u1714\u1732-\u1734\u1752\u1753\u1772\u1773\u17B4-\u17D3\u17DD\u180B-\u180D\u1885\u1886\u18A9\u1920-\u192B\u1930-\u193B\u1A17-\u1A1B\u1A55-\u1A5E\u1A60-\u1A7C\u1A7F\u1AB0-\u1ABE\u1B00-\u1B04\u1B34-\u1B44\u1B6B-\u1B73\u1B80-\u1B82\u1BA1-\u1BAD\u1BE6-\u1BF3\u1C24-\u1C37\u1CD0-\u1CD2\u1CD4-\u1CE8\u1CED\u1CF2-\u1CF4\u1CF7-\u1CF9\u1DC0-\u1DF9\u1DFB-\u1DFF\u20D0-\u20F0\u2CEF-\u2CF1\u2D7F\u2DE0-\u2DFF\u302A-\u302F\u3099\u309A\uA66F-\uA672\uA674-\uA67D\uA69E\uA69F\uA6F0\uA6F1\uA802\uA806\uA80B\uA823-\uA827\uA880\uA881\uA8B4-\uA8C5\uA8E0-\uA8F1\uA8FF\uA926-\uA92D\uA947-\uA953\uA980-\uA983\uA9B3-\uA9C0\uA9E5\uAA29-\uAA36\uAA43\uAA4C\uAA4D\uAA7B-\uAA7D\uAAB0\uAAB2-\uAAB4\uAAB7\uAAB8\uAABE\uAABF\uAAC1\uAAEB-\uAAEF\uAAF5\uAAF6\uABE3-\uABEA\uABEC\uABED\uFB1E\uFE00-\uFE0F\uFE20-\uFE2F]';
+
+ $.highlightText.innerHighlight(
+ node,
+ new RegExp( '(^)' + mw.RegExp.escape( prefix ) + comboMarks + '*', 'i' )
+ );
+ },
+
// scans a node looking for the pattern and wraps a span around each match
innerHighlight: function ( node, pat ) {
var i, match, pos, spannode, middlebit, middleclone;
* @param {string} [options.method='splitAndHighlight'] Method of matching to use, one of:
* - 'splitAndHighlight': Split `matchString` on spaces, then match each word separately.
* - 'prefixHighlight': Match `matchString` at the beginning of text only.
+ * - 'prefixPlusComboHighlight': Match `matchString` plus any combining characters at
+ * the beginning of text only.
* @return {jQuery}
* @chainable
*/
}
if ( context.config.highlightInput ) {
- $result.highlightText( context.data.prevText, { method: 'prefixHighlight' } );
+ $result.highlightText( context.data.prevText, { method: 'prefixPlusComboHighlight' } );
}
// Widen results box if needed (new width is only calculated here, applied later).
* @param {boolean} [options.strictMode=false] Trigger strict mode parsing of the url.
* @param {boolean} [options.overrideKeys=false] Whether to let duplicate query parameters
* override each other (`true`) or automagically convert them to an array (`false`).
+ * @param {boolean} [options.arrayParams=false] Whether to parse array query parameters (e.g.
+ * `&foo[0]=a&foo[1]=b` or `&foo[]=a&foo[]=b`) or leave them alone. Currently this does not
+ * handle associative or multi-dimensional arrays, but that may be improved in the future.
+ * Implies `overrideKeys: true` (query parameters without `[...]` are not parsed as arrays).
* @throws {Error} when the query string or fragment contains an unknown % sequence
*/
function Uri( uri, options ) {
options = typeof options === 'object' ? options : { strictMode: !!options };
options = $.extend( {
strictMode: false,
- overrideKeys: false
+ overrideKeys: false,
+ arrayParams: false
}, options );
+ this.arrayParams = options.arrayParams;
+
if ( uri !== undefined && uri !== null && uri !== '' ) {
if ( typeof uri === 'string' ) {
this.parse( uri, options );
// using replace to iterate over a string
if ( uri.query ) {
uri.query.replace( /(?:^|&)([^&=]*)(?:(=)([^&]*))?/g, function ( match, k, eq, v ) {
+ var arrayKeyMatch, i;
if ( k ) {
k = Uri.decode( k );
v = ( eq === '' || eq === undefined ) ? null : Uri.decode( v );
+ arrayKeyMatch = k.match( /^([^[]+)\[(\d*)\]$/ );
+
+ // If arrayParams and this parameter name contains an array index...
+ if ( options.arrayParams && arrayKeyMatch ) {
+ // Remove the index from parameter name
+ k = arrayKeyMatch[ 1 ];
+
+ // Turn the parameter value into an array (throw away anything else)
+ if ( !Array.isArray( q[ k ] ) ) {
+ q[ k ] = [];
+ }
+
+ i = arrayKeyMatch[ 2 ];
+ if ( i === '' ) {
+ // If no explicit index, append at the end
+ i = q[ k ].length;
+ }
+
+ q[ k ][ i ] = v;
// If overrideKeys, always (re)set top level value.
// If not overrideKeys but this key wasn't set before, then we set it as well.
- if ( options.overrideKeys || !hasOwn.call( q, k ) ) {
+ // arrayParams implies overrideKeys (no array handling for non-array params).
+ } else if ( options.arrayParams || options.overrideKeys || !hasOwn.call( q, k ) ) {
q[ k ] = v;
// Use arrays if overrideKeys is false and key was already seen before
* @return {string}
*/
getQueryString: function () {
- var args = [];
+ var args = [],
+ arrayParams = this.arrayParams;
// eslint-disable-next-line no-jquery/no-each-util
$.each( this.query, function ( key, val ) {
var k = Uri.encode( key ),
- vals = Array.isArray( val ) ? val : [ val ];
- vals.forEach( function ( v ) {
+ isArrayParam = Array.isArray( val ),
+ vals = isArrayParam ? val : [ val ];
+ vals.forEach( function ( v, i ) {
+ var ki = k;
+ if ( arrayParams && isArrayParam ) {
+ ki += Uri.encode( '[' + i + ']' );
+ }
if ( v === null ) {
- args.push( k );
+ args.push( ki );
} else if ( k === 'title' ) {
- args.push( k + '=' + mw.util.wikiUrlencode( v ) );
+ args.push( ki + '=' + mw.util.wikiUrlencode( v ) );
} else {
- args.push( k + '=' + Uri.encode( v ) );
+ args.push( ki + '=' + Uri.encode( v ) );
}
} );
} );
} );
};
+ // Skeleton user object, extended by the 'mediawiki.user' module.
+ /**
+ * @class mw.user
+ * @singleton
+ */
+ mw.user = {
+ /**
+ * @property {mw.Map}
+ */
+ options: new mw.Map(),
+ /**
+ * @property {mw.Map}
+ */
+ tokens: new mw.Map()
+ };
+
// Alias $j to jQuery for backwards compatibility
// @deprecated since 1.23 Use $ or jQuery instead
mw.log.deprecate( window, '$j', $, 'Use $ or jQuery instead.' );
--- /dev/null
+.mw-pulsating-dot {
+ &:before,
+ &:after {
+ content: '';
+ display: block;
+ position: absolute;
+ border-radius: 50%;
+ background-color: #36c;
+ }
+
+ &:before {
+ width: 36px;
+ height: 36px;
+ top: -18px;
+ left: -18px;
+ opacity: 0;
+ -webkit-animation: mw-pulsating-dot-pulse 3s ease-out;
+ -moz-animation: mw-pulsating-dot-pulse 3s ease-out;
+ animation: mw-pulsating-dot-pulse 3s ease-out;
+ -webkit-animation-iteration-count: infinite;
+ -moz-animation-iteration-count: infinite;
+ animation-iteration-count: infinite;
+ }
+
+ &:after {
+ width: 12px;
+ height: 12px;
+ top: -6px;
+ left: -6px;
+ }
+}
+
+.mw-pulsating-dot-pulse-frames() {
+ 0% {
+ transform: scale( 0 );
+ opacity: 0;
+ }
+
+ 25% {
+ transform: scale( 0 );
+ opacity: 0.1;
+ }
+
+ 50% {
+ transform: scale( 0.1 );
+ opacity: 0.3;
+ }
+
+ 75% {
+ transform: scale( 0.5 );
+ opacity: 0.5;
+ }
+
+ 100% {
+ transform: scale( 1 );
+ opacity: 0;
+ }
+}
+
+@-webkit-keyframes mw-pulsating-dot-pulse {
+ .mw-pulsating-dot-pulse-frames;
+}
+
+@-moz-keyframes mw-pulsating-dot-pulse {
+ .mw-pulsating-dot-pulse-frames;
+}
+
+@keyframes mw-pulsating-dot-pulse {
+ .mw-pulsating-dot-pulse-frames;
+}
* @return {boolean}
*/
ItemModel.prototype.isHighlightSupported = function () {
- return !!this.getCssClass();
+ return !!this.getCssClass() && !OO.ui.isMobile();
};
/**
isEmpty = $changesListContent === 'NO_RESULTS',
// For enhanced mode, we have to load these modules, which are
// not loaded for the 'regular' mode in the backend
- loaderPromise = mw.user.options.get( 'usenewrc' ) ?
+ loaderPromise = mw.user.options.get( 'usenewrc' ) && !OO.ui.isMobile() ?
mw.loader.using( [ 'mediawiki.special.changeslist.enhanced', 'mediawiki.icon' ] ) :
$.Deferred().resolve(),
widget = this;
controller, filtersViewModel, invertModel, itemModel, highlightPopup, config
) {
var layout,
+ $widgetRow,
classes = [],
$label = $( '<div>' )
.addClass( 'mw-rcfilters-ui-itemMenuOptionWidget-label' );
// defaults on 'click' as well.
layout.$label.on( 'click', false );
- this.$element
- .addClass( 'mw-rcfilters-ui-itemMenuOptionWidget' )
- .addClass( 'mw-rcfilters-ui-itemMenuOptionWidget-view-' + this.itemModel.getGroupModel().getView() )
+ $widgetRow = $( '<div>' )
+ .addClass( 'mw-rcfilters-ui-table' )
.append(
$( '<div>' )
- .addClass( 'mw-rcfilters-ui-table' )
+ .addClass( 'mw-rcfilters-ui-row' )
.append(
$( '<div>' )
- .addClass( 'mw-rcfilters-ui-row' )
- .append(
- $( '<div>' )
- .addClass( 'mw-rcfilters-ui-cell mw-rcfilters-ui-itemMenuOptionWidget-itemCheckbox' )
- .append( layout.$element ),
- $( '<div>' )
- .addClass( 'mw-rcfilters-ui-cell mw-rcfilters-ui-itemMenuOptionWidget-excludeLabel' )
- .append( this.excludeLabel.$element ),
- $( '<div>' )
- .addClass( 'mw-rcfilters-ui-cell mw-rcfilters-ui-itemMenuOptionWidget-highlightButton' )
- .append( this.highlightButton.$element )
- )
+ .addClass( 'mw-rcfilters-ui-cell mw-rcfilters-ui-itemMenuOptionWidget-itemCheckbox' )
+ .append( layout.$element )
)
);
+ if ( !OO.ui.isMobile() ) {
+ $widgetRow.find( '.mw-rcfilters-ui-row' ).append(
+ $( '<div>' )
+ .addClass( 'mw-rcfilters-ui-cell mw-rcfilters-ui-itemMenuOptionWidget-excludeLabel' )
+ .append( this.excludeLabel.$element ),
+ $( '<div>' )
+ .addClass( 'mw-rcfilters-ui-cell mw-rcfilters-ui-itemMenuOptionWidget-highlightButton' )
+ .append( this.highlightButton.$element )
+ );
+ }
+
+ this.$element
+ .addClass( 'mw-rcfilters-ui-itemMenuOptionWidget' )
+ .addClass( 'mw-rcfilters-ui-itemMenuOptionWidget-view-' + this.itemModel.getGroupModel().getView() )
+ .append( $widgetRow );
+
if ( this.itemModel.getIdentifiers() ) {
this.itemModel.getIdentifiers().forEach( function ( ident ) {
classes.push( 'mw-rcfilters-ui-itemMenuOptionWidget-identifier-' + ident );
// We have no way to display a translated placeholder for custom formats
placeholderDateFormat = '';
} else {
- // Messages: mw-widgets-dateinput-placeholder-day, mw-widgets-dateinput-placeholder-month
+ // The following messages are used here:
+ // * mw-widgets-dateinput-placeholder-day
+ // * mw-widgets-dateinput-placeholder-month
placeholderDateFormat = mw.msg( 'mw-widgets-dateinput-placeholder-' + config.precision );
}
)
);
- if ( this.cache ) {
- this.cache.set( pageData );
- }
-
// Offer the exact text as a suggestion if the page exists
if ( this.addQueryInput && pageExists && !pageExistsExact ) {
titles.unshift( this.getQueryValue() );
+ // Ensure correct page metadata gets used
+ pageData[ this.getQueryValue() ] = pageData[ titleObj.getPrefixedText() ];
+ }
+
+ if ( this.cache ) {
+ this.cache.set( pageData );
}
for ( i = 0, len = titles.length; i < len; i++ ) {
hash ^= str.charCodeAt( i );
}
- hash = ( hash >>> 0 ).toString( 36 );
- while ( hash.length < 7 ) {
+ hash = ( hash >>> 0 ).toString( 36 ).slice( 0, 5 );
+ while ( hash.length < 5 ) {
hash = '0' + hash;
}
/* eslint-enable no-bitwise */
// In addition to currReqBase, doRequest() will also add 'modules' and 'version'.
// > '&modules='.length === 9
- // > '&version=1234567'.length === 16
- // > 9 + 16 = 25
- currReqBaseLength = makeQueryString( currReqBase ).length + 25;
+ // > '&version=12345'.length === 14
+ // > 9 + 14 = 23
+ currReqBaseLength = makeQueryString( currReqBase ).length + 23;
// We may need to split up the request to honor the query string length limit,
// so build it piece by piece.
// Whether the store is in use on this page.
enabled: null,
- // Modules whose string representation exceeds 100 kB are
- // ineligible for storage. See bug T66721.
- MODULE_SIZE_MAX: 100 * 1000,
+ // Modules whose serialised form exceeds 100 kB won't be stored (T66721).
+ MODULE_SIZE_MAX: 1e5,
// The contents of the store, mapping '[name]@[version]' keys
// to module implementations.
* @return {Object} Module store contents.
*/
toJSON: function () {
- return { items: mw.loader.store.items, vary: mw.loader.store.vary };
+ return {
+ items: mw.loader.store.items,
+ vary: mw.loader.store.vary,
+ // Store with 1e7 ms accuracy (1e4 seconds, or ~ 2.7 hours),
+ // which is enough for the purpose of expiring after ~ 30 days.
+ asOf: Math.ceil( Date.now() / 1e7 )
+ };
},
/**
this.enabled = true;
// If null, JSON.parse() will cast to string and re-parse, still null.
data = JSON.parse( raw );
- if ( data && typeof data.items === 'object' && data.vary === this.vary ) {
+ if ( data &&
+ typeof data.items === 'object' &&
+ data.vary === this.vary &&
+ // Only use if it's been less than 30 days since the data was written
+ // 30 days = 2,592,000 s = 2,592,000,000 ms = ± 259e7 ms
+ Date.now() < ( data.asOf * 1e7 ) + 259e7
+ ) {
+ // The data is not corrupt, matches our vary context, and has not expired.
this.items = data.items;
return;
}
}() )
}
};
- }() ),
-
- // Skeleton user object, extended by the 'mediawiki.user' module.
- /**
- * @class mw.user
- * @singleton
- */
- user: {
- /**
- * @property {mw.Map}
- */
- options: new Map(),
- /**
- * @property {mw.Map}
- */
- tokens: new Map()
- }
-
+ }() )
};
// Attach to window and globally alias
//
// Please extend the regex instead of adding new ones!
// And add a test case to startup.test.js
- !ua.match( /MSIE 10|webOS\/1\.[0-4]|SymbianOS|NetFront|Opera Mini|S40OviBrowser|MeeGo|Android.+Glass|^Mozilla\/5\.0 .+ Gecko\/$|googleweblight|PLAYSTATION|PlayStation/ )
+ !ua.match( /MSIE 10|NetFront|Opera Mini|S40OviBrowser|MeeGo|Android.+Glass|^Mozilla\/5\.0 .+ Gecko\/$|googleweblight|PLAYSTATION|PlayStation/ )
);
}
* Common code for test environment initialisation and teardown
*/
class TestSetup {
+ public static $bootstrapGlobals;
+
+ /**
+ * For use in MediaWikiUnitTestCase.
+ *
+ * This should be called before DefaultSettings.php or Setup.php loads.
+ */
+ public static function snapshotGlobals() {
+ self::$bootstrapGlobals = [];
+ foreach ( $GLOBALS as $key => $_ ) {
+ // Support: HHVM (avoid self-ref)
+ if ( $key !== 'GLOBALS' ) {
+ self::$bootstrapGlobals[ $key ] =& $GLOBALS[$key];
+ }
+ }
+ }
+
/**
* This should be called before Setup.php, e.g. from the finalSetup() method
* of a Maintenance subclass
'ApiQueryTestBase' => "$testDir/phpunit/includes/api/query/ApiQueryTestBase.php",
'ApiQueryContinueTestBase' => "$testDir/phpunit/includes/api/query/ApiQueryContinueTestBase.php",
'ApiTestCase' => "$testDir/phpunit/includes/api/ApiTestCase.php",
- 'ApiTestCaseUpload' => "$testDir/phpunit/includes/api/ApiTestCaseUpload.php",
'ApiTestContext' => "$testDir/phpunit/includes/api/ApiTestContext.php",
'ApiUploadTestCase' => "$testDir/phpunit/includes/api/ApiUploadTestCase.php",
'MockApi' => "$testDir/phpunit/includes/api/MockApi.php",
# tests/phpunit/unit/includes
'BadFileLookupTest' => "$testDir/phpunit/unit/includes/BadFileLookupTest.php",
+ # tests/phpunit/unit/includes/filebackend
+ 'FileBackendGroupTestTrait' => "$testDir/phpunit/unit/includes/filebackend/FileBackendGroupTestTrait.php",
+
# tests/phpunit/unit/includes/language
- 'LanguageNameUtilsTestTrait' => "$testDir/phpunit/unit/includes/language/LanguageNameUtilsTestTrait.php",
+ 'LanguageFallbackTestTrait' => "$testDir/phpunit/unit/includes/language/LanguageFallbackTestTrait.php",
# tests/phpunit/unit/includes/libs/filebackend/fsfile
'TempFSFileTestTrait' => "$testDir/phpunit/unit/includes/libs/filebackend/fsfile/TempFSFileTestTrait.php",
'class' => NullLockManager::class,
] ];
$reset = function () {
- LockManagerGroup::destroySingletons();
+ MediaWikiServices::getInstance()->resetServiceForTesting( 'LockManagerGroupFactory' );
};
$setup[] = $reset;
$teardown[] = $reset;
<p><a rel="nofollow" class="external text" href="http://example.com">link</a>
</p>
!! html/parsoid
-<p><a rel="mw:ExtLink" class="external text" href="http://example.com" about="#mwt31" typeof="mw:Transclusion" data-mw='{"parts":[{"template":{"target":{"wt":"echo","href":"./Template:Echo"},"params":{"1":{"wt":"[{{echo|http://example.com}} link]"}},"i":0}}]}'>link</a></p>
+<p><a rel="mw:ExtLink" href="http://example.com" about="#mwt31" typeof="mw:Transclusion" class="external text" data-mw='{"parts":[{"template":{"target":{"wt":"echo","href":"./Template:Echo"},"params":{"1":{"wt":"[{{echo|http://example.com}} link]"}},"i":0}}]}'>link</a></p>
!! end
!! test
<p><a rel="nofollow" class="external free" href="http://foo.com/a%7Cb">http://foo.com/a%7Cb</a>
</p>
!! html/parsoid
-<p><a rel="mw:ExtLink" class="external free" href="http://foo.com/a%7Cb" about="#mwt1" typeof="mw:Transclusion" data-mw='{"parts":[{"template":{"target":{"wt":"echo","href":"./Template:Echo"},"params":{"1":{"wt":"http://foo.com/a&#124;b"}},"i":0}}]}'>http://foo.com/a%7Cb</a></p>
+<p><a rel="mw:ExtLink" href="http://foo.com/a%7Cb" about="#mwt1" typeof="mw:Transclusion" class="external free" data-mw='{"parts":[{"template":{"target":{"wt":"echo","href":"./Template:Echo"},"params":{"1":{"wt":"http://foo.com/a&#124;b"}},"i":0}}]}'>http://foo.com/a%7Cb</a></p>
!! end
!! test
<p><a rel="nofollow" class="external text" href="http://example.org/index.php?title=Parser_test&action=edit">bar</a>
</p>
!! html/parsoid
-<p><a rel="mw:ExtLink" class="external text" href="http://example.org/index.php?title=Parser_test&action=edit" typeof="mw:Transclusion" data-mw='{"parts":[{"template":{"target":{"wt":"echo","href":"./Template:Echo"},"params":{"1":{"wt":"[{{fullurl:{{FULLPAGENAME}}|action=edit}} bar]"}},"i":0}}]}'>bar</a></p>
+<p><a rel="mw:ExtLink" href="http://example.org/index.php?title=Parser_test&action=edit" typeof="mw:Transclusion" class="external text" data-mw='{"parts":[{"template":{"target":{"wt":"echo","href":"./Template:Echo"},"params":{"1":{"wt":"[{{fullurl:{{FULLPAGENAME}}|action=edit}} bar]"}},"i":0}}]}'>bar</a></p>
!! end
!! test
<dl><dt><a rel="nofollow" class="external free" href="news:alt.wikipedia.rox">news:alt.wikipedia.rox</a></dt>
<dd>This isn't even a real newsgroup!</dd></dl>
!! html/parsoid
-<dl><dt><a rel="mw:ExtLink" class="external free" href="news:alt.wikipedia.rox" data-parsoid='{"stx":"url"}'>news:alt.wikipedia.rox</a></dt><dd data-parsoid='{"stx":"row"}'>This isn't even a real newsgroup!</dd></dl>
+<dl><dt><a rel="mw:ExtLink" href="news:alt.wikipedia.rox" class="external free" data-parsoid='{"stx":"url"}'>news:alt.wikipedia.rox</a></dt><dd data-parsoid='{"stx":"row"}'>This isn't even a real newsgroup!</dd></dl>
!! end
!! test
!! end
# FIXME: Maybe get rid of this test?
-# From whitelist:
+# From old whitelist description:
# * The test is wrong, there are two colons where there should be :;
# * The PHP parser is wrong to close the <dl> after the <dt> containing the <ul>.
!! test
Numbered: <a rel="nofollow" class="external autonumber" href="http://example.com">[3]</a>
</p>
!! html/parsoid
-<p>Numbered: <a rel="mw:ExtLink" class="external autonumber" href="http://example.com"></a>
-Numbered: <a rel="mw:ExtLink" class="external autonumber" href="http://example.net"></a>
-Numbered: <a rel="mw:ExtLink" class="external autonumber" href="http://example.com"></a></p>
+<p>Numbered: <a rel="mw:ExtLink" href="http://example.com" class="external autonumber"></a>
+Numbered: <a rel="mw:ExtLink" href="http://example.net" class="external autonumber"></a>
+Numbered: <a rel="mw:ExtLink" href="http://example.com" class="external autonumber"></a></p>
!!end
!! test
<p><a rel="nofollow" class="external autonumber" href="http://example.com/1$2345">[1]</a>
</p>
!! html/parsoid
-<p><a rel="mw:ExtLink" class="external autonumber" href="http://example.com/1$2345"></a></p>
+<p><a rel="mw:ExtLink" href="http://example.com/1$2345" class="external autonumber"></a></p>
!!end
!! test
<p><a rel="nofollow" class="external free" href="http://example.com/1">http://example.com/1</a>[2345
</p>
!! html/parsoid
-<p><a rel="mw:ExtLink" class="external free" href="http://example.com/1">http://example.com/1</a>[2345</p>
+<p><a rel="mw:ExtLink" href="http://example.com/1" class="external free">http://example.com/1</a>[2345</p>
!! end
!! test
<p><a rel="nofollow" class="external text" href="http://example.com/1">[2345</a>
</p>
!! html/parsoid
-<p><a rel="mw:ExtLink" class="external text" href="http://example.com/1">[2345</a></p>
+<p><a rel="mw:ExtLink" href="http://example.com/1" class="external text">[2345</a></p>
!!end
# parsoid adds a space before the link name
<p><a rel="nofollow" class="external autonumber" href="//example.com">[1]</a>
</p>
!! html/parsoid
-<p><a rel="mw:ExtLink" class="external autonumber" href="//example.com"></a></p>
+<p><a rel="mw:ExtLink" href="//example.com" class="external autonumber"></a></p>
!! end
!! test
</p><p><a href="http://en.wikipedia.org/wiki/Foo" class="extiw" title="wikipedia:Foo"><span>Bar</span></a>
</p>
!! html/parsoid
-<p><a rel="mw:ExtLink" class="external autonumber" href="http://en.wikipedia.org/wiki/Foo"></a></p>
+<p><a rel="mw:ExtLink" href="http://en.wikipedia.org/wiki/Foo" class="external autonumber"></a></p>
<p><a rel="mw:WikiLink/Interwiki" href="http://en.wikipedia.org/wiki/Foo" title="wikipedia:Foo">Bar</a></p>
<p><a rel="mw:WikiLink/Interwiki" href="http://en.wikipedia.org/wiki/Foo" title="wikipedia:Foo"><span>Bar</span></a></p>
!! end
<a rel="nofollow" class="external free" href="http://example.com/url_with_entity">http://example.com/url_with_entity</a><
</p>
!! html/parsoid
-<p><a rel="mw:ExtLink" class="external free" href="http://example.com">http://example.com</a>,
-<a rel="mw:ExtLink" class="external free" href="http://example.com">http://example.com</a>;
-<a rel="mw:ExtLink" class="external free" href="http://example.com">http://example.com</a>\
-<a rel="mw:ExtLink" class="external free" href="http://example.com">http://example.com</a>.
-<a rel="mw:ExtLink" class="external free" href="http://example.com">http://example.com</a>:
-<a rel="mw:ExtLink" class="external free" href="http://example.com">http://example.com</a>!
-<a rel="mw:ExtLink" class="external free" href="http://example.com">http://example.com</a>?
-<a rel="mw:ExtLink" class="external free" href="http://example.com">http://example.com</a>)
-<a rel="mw:ExtLink" class="external free" href="http://example.com/url_with_(brackets)">http://example.com/url_with_(brackets)</a>
-(<a rel="mw:ExtLink" class="external free" href="http://example.com/url_without_brackets">http://example.com/url_without_brackets</a>)
-<a rel="mw:ExtLink" class="external free" href="http://example.com/url_with_entity&">http://example.com/url_with_entity&</a>
-<a rel="mw:ExtLink" class="external free" href="http://example.com/url_with_entity&">http://example.com/url_with_entity&</a>
-<a rel="mw:ExtLink" class="external free" href="http://example.com/url_with_entity&">http://example.com/url_with_entity&</a>
-<a rel="mw:ExtLink" class="external free" href="http://example.com/url_with_entity">http://example.com/url_with_entity</a><span typeof="mw:Entity" data-parsoid='{"src":"&nbsp;","srcContent":" "}'> </span>
-<a rel="mw:ExtLink" class="external free" href="http://example.com/url_with_entity">http://example.com/url_with_entity</a><span typeof="mw:Entity" data-parsoid='{"src":"&#xA0;","srcContent":" "}'> </span>
-<a rel="mw:ExtLink" class="external free" href="http://example.com/url_with_entity">http://example.com/url_with_entity</a><span typeof="mw:Entity" data-parsoid='{"src":"&#160;","srcContent":" "}'> </span>
-<a rel="mw:ExtLink" class="external free" href="http://example.com/url_with_entity">http://example.com/url_with_entity</a><span typeof="mw:Entity" data-parsoid='{"src":"&lt;","srcContent":"<"}'><</span>
-<a rel="mw:ExtLink" class="external free" href="http://example.com/url_with_entity">http://example.com/url_with_entity</a><span typeof="mw:Entity" data-parsoid='{"src":"&#x3C;","srcContent":"<"}'><</span>
-<a rel="mw:ExtLink" class="external free" href="http://example.com/url_with_entity">http://example.com/url_with_entity</a><span typeof="mw:Entity" data-parsoid='{"src":"&#60;","srcContent":"<"}'><</span></p>
+<p><a rel="mw:ExtLink" href="http://example.com" class="external free">http://example.com</a>,
+<a rel="mw:ExtLink" href="http://example.com" class="external free">http://example.com</a>;
+<a rel="mw:ExtLink" href="http://example.com" class="external free">http://example.com</a>\
+<a rel="mw:ExtLink" href="http://example.com" class="external free">http://example.com</a>.
+<a rel="mw:ExtLink" href="http://example.com" class="external free">http://example.com</a>:
+<a rel="mw:ExtLink" href="http://example.com" class="external free">http://example.com</a>!
+<a rel="mw:ExtLink" href="http://example.com" class="external free">http://example.com</a>?
+<a rel="mw:ExtLink" href="http://example.com" class="external free">http://example.com</a>)
+<a rel="mw:ExtLink" href="http://example.com/url_with_(brackets)" class="external free">http://example.com/url_with_(brackets)</a>
+(<a rel="mw:ExtLink" href="http://example.com/url_without_brackets" class="external free">http://example.com/url_without_brackets</a>)
+<a rel="mw:ExtLink" href="http://example.com/url_with_entity&" class="external free">http://example.com/url_with_entity&</a>
+<a rel="mw:ExtLink" href="http://example.com/url_with_entity&" class="external free">http://example.com/url_with_entity&</a>
+<a rel="mw:ExtLink" href="http://example.com/url_with_entity&" class="external free">http://example.com/url_with_entity&</a>
+<a rel="mw:ExtLink" href="http://example.com/url_with_entity" class="external free">http://example.com/url_with_entity</a><span typeof="mw:Entity" data-parsoid='{"src":"&nbsp;","srcContent":" "}'> </span>
+<a rel="mw:ExtLink" href="http://example.com/url_with_entity" class="external free">http://example.com/url_with_entity</a><span typeof="mw:Entity" data-parsoid='{"src":"&#xA0;","srcContent":" "}'> </span>
+<a rel="mw:ExtLink" href="http://example.com/url_with_entity" class="external free">http://example.com/url_with_entity</a><span typeof="mw:Entity" data-parsoid='{"src":"&#160;","srcContent":" "}'> </span>
+<a rel="mw:ExtLink" href="http://example.com/url_with_entity" class="external free">http://example.com/url_with_entity</a><span typeof="mw:Entity" data-parsoid='{"src":"&lt;","srcContent":"<"}'><</span>
+<a rel="mw:ExtLink" href="http://example.com/url_with_entity" class="external free">http://example.com/url_with_entity</a><span typeof="mw:Entity" data-parsoid='{"src":"&#x3C;","srcContent":"<"}'><</span>
+<a rel="mw:ExtLink" href="http://example.com/url_with_entity" class="external free">http://example.com/url_with_entity</a><span typeof="mw:Entity" data-parsoid='{"src":"&#60;","srcContent":"<"}'><</span></p>
!! end
!! test
<p><a rel="nofollow" class="external free" href="http://example.com/url_with_entity&amp">http://example.com/url_with_entity&amp</a>;
</p>
!! html/parsoid
-<p><a rel="mw:ExtLink" class="external free" href="http://example.com/url_with_entity&amp">http://example.com/url_with_entity&amp</a>;</p>
+<p><a rel="mw:ExtLink" href="http://example.com/url_with_entity&amp" class="external free">http://example.com/url_with_entity&amp</a>;</p>
!! end
!! test
</p>
!! html/parsoid
<p><b>News:</b> Stuff here</p>
-<p><a rel="mw:ExtLink" class="external free" href="news:'a'b">news:'a'b</a><i>c</i>d e</p>
+<p><a rel="mw:ExtLink" href="news:'a'b" class="external free">news:'a'b</a><i>c</i>d e</p>
!! end
!! test
<p><a rel="nofollow" class="external text" href="http://+www.librarieswithoutborders.org">Libraries without borders</a>
</p>
!! html/parsoid
-<p><a rel="mw:ExtLink" class="external text" href="http://+www.librarieswithoutborders.org" data-parsoid='{"a":{"href":"http://+www.librarieswithoutborders.org"},"sa":{"href":"http://&#x20;www.librarieswithoutborders.org"}}'>Libraries without borders</a></p>
+<p><a rel="mw:ExtLink" href="http://+www.librarieswithoutborders.org" class="external text" data-parsoid='{"a":{"href":"http://+www.librarieswithoutborders.org"},"sa":{"href":"http://&#x20;www.librarieswithoutborders.org"}}'>Libraries without borders</a></p>
!! end
!! test
<p>URL in text: <a rel="nofollow" class="external text" href="http://example.com">http://example.com</a>
</p>
!! html/parsoid
-<p>URL in text: <a rel="mw:ExtLink" class="external text" href="http://example.com">http://example.com</a></p>
+<p>URL in text: <a rel="mw:ExtLink" href="http://example.com" class="external text">http://example.com</a></p>
!! end
!! test
<p>ja-style clickable images: <a rel="nofollow" class="external text" href="http://example.com"><img src="http://meta.wikimedia.org/upload/f/f1/Ncwikicol.png" alt="Ncwikicol.png"/></a>
</p>
!! html/parsoid
-<p>ja-style clickable images: <a rel="mw:ExtLink" class="external text" href="http://example.com"><img src="http://meta.wikimedia.org/upload/f/f1/Ncwikicol.png" alt="Ncwikicol.png" data-parsoid='{"type":"extlink"}'/></a></p>
+<p>ja-style clickable images: <a rel="mw:ExtLink" href="http://example.com" class="external text"><img src="http://meta.wikimedia.org/upload/f/f1/Ncwikicol.png" alt="Ncwikicol.png" data-parsoid='{"type":"extlink"}'/></a></p>
!! end
!! test
<p>Old & use: <a rel="nofollow" class="external free" href="http://x&y">http://x&y</a>
</p>
!! html/parsoid
-<p>Old <span typeof="mw:Entity">&</span> use: <a rel="mw:ExtLink" class="external free" href="http://x&y">http://x&y</a></p>
+<p>Old <span typeof="mw:Entity">&</span> use: <a rel="mw:ExtLink" href="http://x&y" class="external free">http://x&y</a></p>
!! end
!! test
<p><a rel="nofollow" class="external free" href="http://example.com/?foo=bar">http://example.com/?foo=bar</a>
</p>
!! html/parsoid
-<p><a rel="mw:ExtLink" class="external free" href="http://example.com/?foo=bar">http://example.com/?foo=bar</a></p>
+<p><a rel="mw:ExtLink" href="http://example.com/?foo=bar" class="external free">http://example.com/?foo=bar</a></p>
!! end
##
<p>Old & use: <a rel="nofollow" class="external autonumber" href="http://x&y">[1]</a>
</p>
!! html/parsoid
-<p>Old <span typeof="mw:Entity">&</span> use: <a rel="mw:ExtLink" class="external autonumber" href="http://x&y"></a></p>
+<p>Old <span typeof="mw:Entity">&</span> use: <a rel="mw:ExtLink" href="http://x&y" class="external autonumber"></a></p>
!! end
# note that parsoid html is identical to [raw ampersand] case; so html2wt
<p>Old & use: <a rel="nofollow" class="external autonumber" href="http://x&y">[1]</a>
</p>
!! html/parsoid
-<p>Old <span typeof="mw:Entity">&</span> use: <a rel="mw:ExtLink" class="external autonumber" href="http://x&y"></a></p>
+<p>Old <span typeof="mw:Entity">&</span> use: <a rel="mw:ExtLink" href="http://x&y" class="external autonumber"></a></p>
!! end
!! test
<p><a rel="nofollow" class="external autonumber" href="http://example.com/?foo=bar">[1]</a>
</p>
!! html/parsoid
-<p><a rel="mw:ExtLink" class="external autonumber" href="http://example.com/?foo=bar"></a></p>
+<p><a rel="mw:ExtLink" href="http://example.com/?foo=bar" class="external autonumber"></a></p>
!! end
# note that parsoid html is identical to [raw equals] case; so html2wt
<p><a rel="nofollow" class="external autonumber" href="http://example.com/?foo=bar">[1]</a>
</p>
!! html/parsoid
-<p><a rel="mw:ExtLink" class="external autonumber" href="http://example.com/?foo=bar"></a></p>
+<p><a rel="mw:ExtLink" href="http://example.com/?foo=bar" class="external autonumber"></a></p>
!! end
# xxx parsoid strips the IDN character, so the round-trip tests will
<p><a rel="nofollow" class="external autonumber" href="http://example.com/">[1]</a>
</p>
!! html/parsoid
-<p><a rel="mw:ExtLink" class="external autonumber" href="http://example.com/"></a></p>
+<p><a rel="mw:ExtLink" href="http://example.com/" class="external autonumber"></a></p>
!! end
# FIXME: This test (the IDN characters in the text of a link) is an inconsistency.
<p><a rel="nofollow" class="external free" href="http://example.com/">http://example.com/</a>
</p>
!! html/parsoid
-<p><a rel="mw:ExtLink" class="external free" href="http://example.com/">http://example.com/</a></p>
+<p><a rel="mw:ExtLink" href="http://example.com/" class="external free">http://example.com/</a></p>
!! end
!! test
<p><a rel="nofollow" class="external autonumber" href="http://www.unausa.org/newindex.asp?place=http://www.unausa.org/programs/mun.asp">[1]</a>
</p>
!! html/parsoid
-<p><a rel="mw:ExtLink" class="external autonumber" href="http://www.unausa.org/newindex.asp?place=http://www.unausa.org/programs/mun.asp"></a></p>
+<p><a rel="mw:ExtLink" href="http://www.unausa.org/newindex.asp?place=http://www.unausa.org/programs/mun.asp" class="external autonumber"></a></p>
!! end
!! test
<p><a rel="nofollow" class="external free" href="http://www.example.com/">http://www.example.com/</a><b>html</b>
</p>
!! html/parsoid
-<p><a rel="mw:ExtLink" class="external free" href="http://www.example.com/" data-parsoid='{"stx":"url"}'>http://www.example.com/</a><b data-parsoid='{"stx":"html"}'>html</b></p>
+<p><a rel="mw:ExtLink" href="http://www.example.com/" class="external free" data-parsoid='{"stx":"url"}'>http://www.example.com/</a><b data-parsoid='{"stx":"html"}'>html</b></p>
!! end
!! test
</p><p><a rel="nofollow" class="external text" href="http://example.com">test </a><a href="/index.php?title=Wikilink&action=edit&redlink=1" class="new" title="Wikilink (page does not exist)">wikilink</a><a rel="nofollow" class="external text" href="http://example.com"> embedded in ext link</a>
</p>
!! html/parsoid
-<p><a rel="mw:ExtLink" class="external autonumber" href="http://example.com"></a><a rel="mw:WikiLink" href="./Wikilink" title="Wikilink">wikilink</a><span> embedded in ext link</span></p>
-<p><a rel="mw:ExtLink" class="external text" href="http://example.com">test </a><a rel="mw:WikiLink" href="./Wikilink" title="Wikilink">wikilink</a><span> embedded in ext link</span></p>
+<p><a rel="mw:ExtLink" href="http://example.com" class="external autonumber"></a><a rel="mw:WikiLink" href="./Wikilink" title="Wikilink">wikilink</a><span> embedded in ext link</span></p>
+<p><a rel="mw:ExtLink" href="http://example.com" class="external text">test </a><a rel="mw:WikiLink" href="./Wikilink" title="Wikilink">wikilink</a><span> embedded in ext link</span></p>
!! end
!! test
</p><p>{{echo|[[Foo}}
</p>
!! html/parsoid
-<p>[<a rel="mw:ExtLink" class="external free" href="http://example.com">http://example.com</a> x</p>
-<p typeof="mw:Transclusion" data-mw='{"parts":[{"template":{"target":{"wt":"echo","href":"./Template:Echo"},"params":{"1":{"wt":"[http://example.com x"}},"i":0}}]}'>[<a rel="mw:ExtLink" class="external free" href="http://example.com">http://example.com</a> x</p>
+<p>[<a rel="mw:ExtLink" href="http://example.com" class="external free">http://example.com</a> x</p>
+<p typeof="mw:Transclusion" data-mw='{"parts":[{"template":{"target":{"wt":"echo","href":"./Template:Echo"},"params":{"1":{"wt":"[http://example.com x"}},"i":0}}]}'>[<a rel="mw:ExtLink" href="http://example.com" class="external free">http://example.com</a> x</p>
<p>[[Foo</p>
<p>{{echo|[[Foo}}</p>
!! end
<p>[[Foo|<span typeof="mw:Transclusion" data-mw='{"parts":[{"template":{"target":{"wt":"echo","href":"./Template:Echo"},"params":{"1":{"wt":"]]"}},"i":0}}]}'>]]</span></p>
!! end
+!! article
+Template:pipe page
+!! text
+Main|Page
+!! endarticle
+
+## FIXME: Parsoid doesn't support this and may never. See T226523
+!! test
+Template returning pipe used in wikilink target
+!! wikitext
+[[{{pipe page}}]]
+!! html/php+tidy
+<p><a href="/index.php?title=Main&action=edit&redlink=1" class="new" title="Main (page does not exist)">Page</a>
+</p>
+!! html/parsoid
+<p>[[<span about="#mwt1" typeof="mw:Transclusion" data-mw='{"parts":[{"template":{"target":{"wt":"pipe page","href":"./Template:Pipe_page"},"params":{},"i":0}}]}'>Main|Page</span>]]</p>
+!! end
+
+# Italic/link nesting is changed in this test, but the rendered result is the
+# same. Currently the result is actually an improvement over the MediaWiki
+# output.
!! test
T4702: Mismatched <i>, <b> and <a> tags are invalid
!! wikitext
''Something [http://example.com in italic'']
''Something [http://example.com mixed''''', even bold]'''
'''''Now [http://example.com both''''']
-!! html
+!! html/php
<p><a rel="nofollow" class="external text" href="http://example.com"><i>text</i></a>
<a rel="nofollow" class="external text" href="http://example.com"><b>text</b></a>
<i>Something </i><a rel="nofollow" class="external text" href="http://example.com"><i>in italic</i></a>
<i>Something </i><a rel="nofollow" class="external text" href="http://example.com"><i>mixed</i><b>, even bold</b></a>
<i><b>Now </b></i><a rel="nofollow" class="external text" href="http://example.com"><i><b>both</b></i></a>
</p>
+!! html/parsoid
+<p><i data-parsoid='{"autoInsertedEnd":true}'><a rel="mw:ExtLink" href="http://example.com" class="external text">text<i data-parsoid='{"autoInsertedEnd":true}'></i></a></i>
+<a rel="mw:ExtLink" href="http://example.com" class="external text"><b data-parsoid='{"autoInsertedEnd":true}'>text</b></a><b data-parsoid='{"autoInsertedEnd":true}'></b>
+<i data-parsoid='{"autoInsertedEnd":true}'>Something <a rel="mw:ExtLink" href="http://example.com" class="external text">in italic<i data-parsoid='{"autoInsertedEnd":true}'></i></a></i>
+<i>Something <a rel="mw:ExtLink" href="http://example.com" class="external text">mixed<b data-parsoid='{"autoInsertedEnd":true}'><i data-parsoid='{"autoInsertedEnd":true}'>, even bold</i></b></a>'</i>
+<b data-parsoid='{"autoInsertedEnd":true}'><i data-parsoid='{"autoInsertedEnd":true}'>Now <a rel="mw:ExtLink" href="http://example.com" class="external text">both<b data-parsoid='{"autoInsertedEnd":true}'><i data-parsoid='{"autoInsertedEnd":true}'></i></b></a></i></b></p>
!! end
<p><a rel="nofollow" class="external free" href="http://www.example.com/?title=AT%26T">http://www.example.com/?title=AT%26T</a>
</p>
!! html/parsoid
-<p><a rel="mw:ExtLink" class="external free" href="http://www.example.com/?title=AT%26T">http://www.example.com/?title=AT%26T</a></p>
+<p><a rel="mw:ExtLink" href="http://www.example.com/?title=AT%26T" class="external free">http://www.example.com/?title=AT%26T</a></p>
!! end
# According to https://www.w3.org/TR/2011/WD-html5-20110525/Overview.html#parsing-urls a plain
<p><a rel="nofollow" class="external free" href="http://www.example.com/?title=100%25_Bran">http://www.example.com/?title=100%25_Bran</a>
</p>
!! html/parsoid
-<p><a rel="mw:ExtLink" class="external free" href="http://www.example.com/?title=100%25_Bran">http://www.example.com/?title=100%25_Bran</a></p>
+<p><a rel="mw:ExtLink" href="http://www.example.com/?title=100%25_Bran" class="external free">http://www.example.com/?title=100%25_Bran</a></p>
!! end
!! test
<p><a rel="nofollow" class="external free" href="http://www.example.com/?title=Ben-Hur_%281959_film%29">http://www.example.com/?title=Ben-Hur_%281959_film%29</a>
</p>
!! html/parsoid
-<p><a rel="mw:ExtLink" class="external free" href="http://www.example.com/?title=Ben-Hur_%281959_film%29">http://www.example.com/?title=Ben-Hur_%281959_film%29</a></p>
+<p><a rel="mw:ExtLink" href="http://www.example.com/?title=Ben-Hur_%281959_film%29" class="external free">http://www.example.com/?title=Ben-Hur_%281959_film%29</a></p>
!! end
<p><a rel="nofollow" class="external autonumber" href="http://www.example.com/?title=AT%26T">[1]</a>
</p>
!! html/parsoid
-<p><a rel="mw:ExtLink" class="external autonumber" href="http://www.example.com/?title=AT%26T"></a></p>
+<p><a rel="mw:ExtLink" href="http://www.example.com/?title=AT%26T" class="external autonumber"></a></p>
!! end
!! test
<p><a rel="nofollow" class="external autonumber" href="http://www.example.com/?title=100%25_Bran">[1]</a>
</p>
!! html/parsoid
-<p><a rel="mw:ExtLink" class="external autonumber" href="http://www.example.com/?title=100%25_Bran"></a></p>
+<p><a rel="mw:ExtLink" href="http://www.example.com/?title=100%25_Bran" class="external autonumber"></a></p>
!! end
!! test
<p><a rel="nofollow" class="external autonumber" href="http://www.example.com/?title=Ben-Hur_%281959_film%29">[1]</a>
</p>
!! html/parsoid
-<p><a rel="mw:ExtLink" class="external autonumber" href="http://www.example.com/?title=Ben-Hur_%281959_film%29"></a></p>
+<p><a rel="mw:ExtLink" href="http://www.example.com/?title=Ben-Hur_%281959_film%29" class="external autonumber"></a></p>
!! end
<p><a rel="nofollow" class="external text" href="http://www.example.com/?title=AT%26T">link</a>
</p>
!! html/parsoid
-<p><a rel="mw:ExtLink" class="external text" href="http://www.example.com/?title=AT%26T">link</a></p>
+<p><a rel="mw:ExtLink" href="http://www.example.com/?title=AT%26T" class="external text">link</a></p>
!! end
!! test
<p><a rel="nofollow" class="external text" href="http://www.example.com/?title=Ben-Hur_%281959_film%29">link</a>
</p>
!! html/parsoid
-<p><a rel="mw:ExtLink" class="external text" href="http://www.example.com/?title=Ben-Hur_%281959_film%29">link</a></p>
+<p><a rel="mw:ExtLink" href="http://www.example.com/?title=Ben-Hur_%281959_film%29" class="external text">link</a></p>
!! end
!! test
</p><p><a rel="nofollow" class="external text" href="//foo.org/bar.">bang</a>
</p>
!! html/parsoid
-<p><a rel="mw:ExtLink" class="external text" href="//foo.org/bar#baz.">bang</a></p>
-<p><a rel="mw:ExtLink" class="external text" href="//foo.org/bar.">bang</a></p>
+<p><a rel="mw:ExtLink" href="//foo.org/bar#baz." class="external text">bang</a></p>
+<p><a rel="mw:ExtLink" href="//foo.org/bar." class="external text">bang</a></p>
!! end
!! test
</p><p><a rel="nofollow" class="external text" href="//foo.org/bar'baz">bang</a>
</p>
!! html/parsoid
-<p><a rel="mw:ExtLink" class="external autonumber" href="//foo.org/bar'baz"></a></p>
-<p><a rel="mw:ExtLink" class="external text" href="//foo.org/bar'baz">bang</a></p>
+<p><a rel="mw:ExtLink" href="//foo.org/bar'baz" class="external autonumber"></a></p>
+<p><a rel="mw:ExtLink" href="//foo.org/bar'baz" class="external text">bang</a></p>
!! end
!! test
<p><a rel="nofollow" class="external text" href="http://www.musee-picasso.fr/pages/page_id18528_u1l2.htm"><i>La muerte de Casagemas</i> (1901) en el sitio de </a><a href="/index.php?title=Museo_Picasso_(Par%C3%ADs)&action=edit&redlink=1" class="new" title="Museo Picasso (París) (page does not exist)">Museo Picasso</a>.
</p>
!! html/parsoid
-<p><a rel="mw:ExtLink" class="external text" href="http://www.musee-picasso.fr/pages/page_id18528_u1l2.htm"><i>La muerte de Casagemas</i> (1901) en el sitio de </a><a rel="mw:WikiLink" href="./Museo_Picasso_(París)" title="Museo Picasso (París)">Museo Picasso</a><span>.</span></p>
+<p><a rel="mw:ExtLink" href="http://www.musee-picasso.fr/pages/page_id18528_u1l2.htm" class="external text"><i>La muerte de Casagemas</i> (1901) en el sitio de </a><a rel="mw:WikiLink" href="./Museo_Picasso_(París)" title="Museo Picasso (París)">Museo Picasso</a><span>.</span></p>
!! end
!! test
<p><a rel="nofollow" class="external text" href="http://www.google.com">Google </a>
</p>
!! html/parsoid
-<p><a rel="mw:ExtLink" class="external text" href="http://www.google.com">Google <!-- comment --></a></p>
+<p><a rel="mw:ExtLink" href="http://www.google.com" class="external text">Google <!-- comment --></a></p>
!! end
!! test
<p><a rel="nofollow" class="external text" href="http://192.168.0.1">Link</a>
</p>
!! html/parsoid
-<p><a rel="mw:ExtLink" class="external text" href="http://192.168.0.1">Link</a></p>
+<p><a rel="mw:ExtLink" href="http://192.168.0.1" class="external text">Link</a></p>
!! end
!! test
</p><p><a rel="nofollow" class="external free" href="http://example.com/index.php?foozoid%5B%5D=bar">http://example.com/index.php?foozoid%5B%5D=bar</a>
</p>
!! html/parsoid
-<p><a rel="mw:ExtLink" class="external free" href="http://example.com/index.php?foozoid%5B%5D=bar">http://example.com/index.php?foozoid%5B%5D=bar</a></p>
+<p><a rel="mw:ExtLink" href="http://example.com/index.php?foozoid%5B%5D=bar" class="external free">http://example.com/index.php?foozoid%5B%5D=bar</a></p>
-<p><a rel="mw:ExtLink" class="external free" href="http://example.com/index.php?foozoid%5B%5D=bar" data-parsoid='{"stx":"url","a":{"href":"http://example.com/index.php?foozoid%5B%5D=bar"},"sa":{"href":"http://example.com/index.php?foozoid&#x5B;&#x5D;=bar"}}'>http://example.com/index.php?foozoid%5B%5D=bar</a></p>
+<p><a rel="mw:ExtLink" href="http://example.com/index.php?foozoid%5B%5D=bar" class="external free" data-parsoid='{"stx":"url","a":{"href":"http://example.com/index.php?foozoid%5B%5D=bar"},"sa":{"href":"http://example.com/index.php?foozoid&#x5B;&#x5D;=bar"}}'>http://example.com/index.php?foozoid%5B%5D=bar</a></p>
!! end
!! test
<li><a rel="nofollow" class="external free" href="http://[::FFFF:129.144.52.38]:80/index.html">http://[::FFFF:129.144.52.38]:80/index.html</a></li>
<li><a rel="nofollow" class="external free" href="http://[2010:836B:4179::836B:4179]">http://[2010:836B:4179::836B:4179]</a></li></ul>
!! html/parsoid
-<p><a rel="mw:ExtLink" class="external free" href="http://[2404:130:0:1000::187:2]/index.php">http://[2404:130:0:1000::187:2]/index.php</a></p>
+<p><a rel="mw:ExtLink" href="http://[2404:130:0:1000::187:2]/index.php" class="external free">http://[2404:130:0:1000::187:2]/index.php</a></p>
<p>Examples from <a href="https://tools.ietf.org/html/rfc2373" rel="mw:ExtLink" class="external mw-magiclink">RFC 2373</a>, section 2.2:</p>
-<ul><li><a rel="mw:ExtLink" class="external free" href="http://[1080::8:800:200C:417A]/unicast">http://[1080::8:800:200C:417A]/unicast</a></li>
-<li><a rel="mw:ExtLink" class="external free" href="http://[FF01::101]/multicast">http://[FF01::101]/multicast</a></li>
-<li><a rel="mw:ExtLink" class="external free" href="http://[::1]/loopback">http://[::1]/loopback</a></li>
-<li><a rel="mw:ExtLink" class="external free" href="http://[::]/unspecified">http://[::]/unspecified</a></li>
-<li><a rel="mw:ExtLink" class="external free" href="http://[::13.1.68.3]/ipv4compat">http://[::13.1.68.3]/ipv4compat</a></li>
-<li><a rel="mw:ExtLink" class="external free" href="http://[::FFFF:129.144.52.38]/ipv4compat">http://[::FFFF:129.144.52.38]/ipv4compat</a></li></ul>
+<ul><li><a rel="mw:ExtLink" href="http://[1080::8:800:200C:417A]/unicast" class="external free">http://[1080::8:800:200C:417A]/unicast</a></li>
+<li><a rel="mw:ExtLink" href="http://[FF01::101]/multicast" class="external free">http://[FF01::101]/multicast</a></li>
+<li><a rel="mw:ExtLink" href="http://[::1]/loopback" class="external free">http://[::1]/loopback</a></li>
+<li><a rel="mw:ExtLink" href="http://[::]/unspecified" class="external free">http://[::]/unspecified</a></li>
+<li><a rel="mw:ExtLink" href="http://[::13.1.68.3]/ipv4compat" class="external free">http://[::13.1.68.3]/ipv4compat</a></li>
+<li><a rel="mw:ExtLink" href="http://[::FFFF:129.144.52.38]/ipv4compat" class="external free">http://[::FFFF:129.144.52.38]/ipv4compat</a></li></ul>
<p>Examples from <a href="https://tools.ietf.org/html/rfc2732" rel="mw:ExtLink" class="external mw-magiclink">RFC 2732</a>, section 2:</p>
-<ul><li><a rel="mw:ExtLink" class="external free" href="http://[FEDC:BA98:7654:3210:FEDC:BA98:7654:3210]:80/index.html">http://[FEDC:BA98:7654:3210:FEDC:BA98:7654:3210]:80/index.html</a></li>
-<li><a rel="mw:ExtLink" class="external free" href="http://[1080:0:0:0:8:800:200C:417A]/index.html">http://[1080:0:0:0:8:800:200C:417A]/index.html</a></li>
-<li><a rel="mw:ExtLink" class="external free" href="http://[3ffe:2a00:100:7031::1]">http://[3ffe:2a00:100:7031::1]</a></li>
-<li><a rel="mw:ExtLink" class="external free" href="http://[1080::8:800:200C:417A]/foo">http://[1080::8:800:200C:417A]/foo</a></li>
-<li><a rel="mw:ExtLink" class="external free" href="http://[::192.9.5.5]/ipng">http://[::192.9.5.5]/ipng</a></li>
-<li><a rel="mw:ExtLink" class="external free" href="http://[::FFFF:129.144.52.38]:80/index.html">http://[::FFFF:129.144.52.38]:80/index.html</a></li>
-<li><a rel="mw:ExtLink" class="external free" href="http://[2010:836B:4179::836B:4179]">http://[2010:836B:4179::836B:4179]</a></li></ul>
+<ul><li><a rel="mw:ExtLink" href="http://[FEDC:BA98:7654:3210:FEDC:BA98:7654:3210]:80/index.html" class="external free">http://[FEDC:BA98:7654:3210:FEDC:BA98:7654:3210]:80/index.html</a></li>
+<li><a rel="mw:ExtLink" href="http://[1080:0:0:0:8:800:200C:417A]/index.html" class="external free">http://[1080:0:0:0:8:800:200C:417A]/index.html</a></li>
+<li><a rel="mw:ExtLink" href="http://[3ffe:2a00:100:7031::1]" class="external free">http://[3ffe:2a00:100:7031::1]</a></li>
+<li><a rel="mw:ExtLink" href="http://[1080::8:800:200C:417A]/foo" class="external free">http://[1080::8:800:200C:417A]/foo</a></li>
+<li><a rel="mw:ExtLink" href="http://[::192.9.5.5]/ipng" class="external free">http://[::192.9.5.5]/ipng</a></li>
+<li><a rel="mw:ExtLink" href="http://[::FFFF:129.144.52.38]:80/index.html" class="external free">http://[::FFFF:129.144.52.38]:80/index.html</a></li>
+<li><a rel="mw:ExtLink" href="http://[2010:836B:4179::836B:4179]" class="external free">http://[2010:836B:4179::836B:4179]</a></li></ul>
!! end
!! test
<li><a rel="nofollow" class="external text" href="http://[::FFFF:129.144.52.38]:80/index.html">6</a></li>
<li><a rel="nofollow" class="external text" href="http://[2010:836B:4179::836B:4179]">7</a></li></ul>
!! html/parsoid
-<p><a rel="mw:ExtLink" class="external text" href="http://[2404:130:0:1000::187:2]/index.php">test</a></p>
+<p><a rel="mw:ExtLink" href="http://[2404:130:0:1000::187:2]/index.php" class="external text">test</a></p>
<p>Examples from <a href="https://tools.ietf.org/html/rfc2373" rel="mw:ExtLink" class="external mw-magiclink">RFC 2373</a>, section 2.2:</p>
-<ul><li><a rel="mw:ExtLink" class="external text" href="http://[1080::8:800:200C:417A]">unicast</a></li>
-<li><a rel="mw:ExtLink" class="external text" href="http://[FF01::101]">multicast</a></li>
-<li><a rel="mw:ExtLink" class="external text" href="http://[::1]/">loopback</a></li>
-<li><a rel="mw:ExtLink" class="external text" href="http://[::]">unspecified</a></li>
-<li><a rel="mw:ExtLink" class="external text" href="http://[::13.1.68.3]">ipv4compat</a></li>
-<li><a rel="mw:ExtLink" class="external text" href="http://[::FFFF:129.144.52.38]">ipv4compat</a></li></ul>
+<ul><li><a rel="mw:ExtLink" href="http://[1080::8:800:200C:417A]" class="external text">unicast</a></li>
+<li><a rel="mw:ExtLink" href="http://[FF01::101]" class="external text">multicast</a></li>
+<li><a rel="mw:ExtLink" href="http://[::1]/" class="external text">loopback</a></li>
+<li><a rel="mw:ExtLink" href="http://[::]" class="external text">unspecified</a></li>
+<li><a rel="mw:ExtLink" href="http://[::13.1.68.3]" class="external text">ipv4compat</a></li>
+<li><a rel="mw:ExtLink" href="http://[::FFFF:129.144.52.38]" class="external text">ipv4compat</a></li></ul>
<p>Examples from <a href="https://tools.ietf.org/html/rfc2732" rel="mw:ExtLink" class="external mw-magiclink">RFC 2732</a>, section 2:</p>
-<ul><li><a rel="mw:ExtLink" class="external text" href="http://[FEDC:BA98:7654:3210:FEDC:BA98:7654:3210]:80/index.html">1</a></li>
-<li><a rel="mw:ExtLink" class="external text" href="http://[1080:0:0:0:8:800:200C:417A]/index.html">2</a></li>
-<li><a rel="mw:ExtLink" class="external text" href="http://[3ffe:2a00:100:7031::1]">3</a></li>
-<li><a rel="mw:ExtLink" class="external text" href="http://[1080::8:800:200C:417A]/foo">4</a></li>
-<li><a rel="mw:ExtLink" class="external text" href="http://[::192.9.5.5]/ipng">5</a></li>
-<li><a rel="mw:ExtLink" class="external text" href="http://[::FFFF:129.144.52.38]:80/index.html">6</a></li>
-<li><a rel="mw:ExtLink" class="external text" href="http://[2010:836B:4179::836B:4179]">7</a></li></ul>
+<ul><li><a rel="mw:ExtLink" href="http://[FEDC:BA98:7654:3210:FEDC:BA98:7654:3210]:80/index.html" class="external text">1</a></li>
+<li><a rel="mw:ExtLink" href="http://[1080:0:0:0:8:800:200C:417A]/index.html" class="external text">2</a></li>
+<li><a rel="mw:ExtLink" href="http://[3ffe:2a00:100:7031::1]" class="external text">3</a></li>
+<li><a rel="mw:ExtLink" href="http://[1080::8:800:200C:417A]/foo" class="external text">4</a></li>
+<li><a rel="mw:ExtLink" href="http://[::192.9.5.5]/ipng" class="external text">5</a></li>
+<li><a rel="mw:ExtLink" href="http://[::FFFF:129.144.52.38]:80/index.html" class="external text">6</a></li>
+<li><a rel="mw:ExtLink" href="http://[2010:836B:4179::836B:4179]" class="external text">7</a></li></ul>
!! end
!! test
[<span about="#mwt22" typeof="mw:Transclusion" data-mw='{"parts":[{"template":{"target":{"wt":"echo","href":"./Template:Echo"},"params":{"1":{"wt":"foo"}},"i":0}}]}'>foo</span>l's] errand
[<span about="#mwt23" typeof="mw:Transclusion" data-mw='{"parts":[{"template":{"target":{"wt":"echo","href":"./Template:Echo"},"params":{"1":{"wt":"foo"}},"i":0}}]}'>foo</span>l's errand]
[url=<span about="#mwt24" typeof="mw:Transclusion" data-mw='{"parts":[{"template":{"target":{"wt":"echo","href":"./Template:Echo"},"params":{"1":{"wt":"foo"}},"i":0}}]}'>foo</span>]
-[url=<a rel="mw:ExtLink" class="external free" href="http://example.com">http://example.com</a>]
+[url=<a rel="mw:ExtLink" href="http://example.com" class="external free">http://example.com</a>]
[http:// bare protocols don't count]</p>
!! end
<p><a rel="nofollow" class="external text" href="https://github.com/search?l=&q=ResourceLoader+%40wikimedia">Search</a>
</p>
!! html/parsoid
-<p><a rel="mw:ExtLink" class="external text" href="https://github.com/search?l=&q=ResourceLoader+%40wikimedia">Search</a></p>
+<p><a rel="mw:ExtLink" href="https://github.com/search?l=&q=ResourceLoader+%40wikimedia" class="external text">Search</a></p>
!! end
!! test
<p><a rel="nofollow" class="external free" href="http://example.com">http://example.com</a>
</p>
!! html/parsoid
-<p><a rel="mw:ExtLink" class="external free" href="http://example.com">http://example.com</a></p>
+<p><a rel="mw:ExtLink" href="http://example.com" class="external free">http://example.com</a></p>
!! end
!! test
</p><p><a rel="nofollow" class="external text" href="http://example.com)">foo</a>
</p>
!! html/parsoid
-<p><a rel="mw:ExtLink" class="external free" href="http://example.com">http://example.com</a>)</p>
-<p><a rel="mw:ExtLink" class="external free" href="http://example.com/test">http://example.com/test</a>)</p>
-<p><a rel="mw:ExtLink" class="external free" href="http://example.com/(test)">http://example.com/(test)</a></p>
-<p><a rel="mw:ExtLink" class="external free" href="http://example.com/((test)">http://example.com/((test)</a></p>
-<p>(<a rel="mw:ExtLink" class="external free" href="http://example.com/(test))">http://example.com/(test))</a></p>
-<p>(<a rel="mw:ExtLink" class="external free" href="http://example.com/(test)))))">http://example.com/(test)))))</a></p>
-<p><a rel="mw:ExtLink" class="external free" href="http://example.com/a)b">http://example.com/a)b</a></p>
-<p><a rel="mw:ExtLink" class="external text" href="http://example.com)">foo</a></p>
+<p><a rel="mw:ExtLink" href="http://example.com" class="external free">http://example.com</a>)</p>
+<p><a rel="mw:ExtLink" href="http://example.com/test" class="external free">http://example.com/test</a>)</p>
+<p><a rel="mw:ExtLink" href="http://example.com/(test)" class="external free">http://example.com/(test)</a></p>
+<p><a rel="mw:ExtLink" href="http://example.com/((test)" class="external free">http://example.com/((test)</a></p>
+<p>(<a rel="mw:ExtLink" href="http://example.com/(test))" class="external free">http://example.com/(test))</a></p>
+<p>(<a rel="mw:ExtLink" href="http://example.com/(test)))))" class="external free">http://example.com/(test)))))</a></p>
+<p><a rel="mw:ExtLink" href="http://example.com/a)b" class="external free">http://example.com/a)b</a></p>
+<p><a rel="mw:ExtLink" href="http://example.com)" class="external text">foo</a></p>
!! end
!! test
</p><p>(<a rel="nofollow" class="external free" href="http://example.com">http://example.com</a>)
</p>
!! html/parsoid
-<p>(<a typeof="mw:ExpandedAttrs" about="#mwt2" rel="mw:ExtLink" class="external free" href="http://example.com/hi" data-parsoid='{"stx":"url","a":{"href":"http://example.com/hi"},"sa":{"href":"http://example.com/{{echo|hi}}"}}' data-mw='{"attribs":[[{"txt":"href"},{"html":"http://example.com/<span about=\"#mwt1\" typeof=\"mw:Transclusion\" data-parsoid='{\"pi\":[[{\"k\":\"1\"}]],\"dsr\":[20,31,null,null]}' data-mw='{\"parts\":[{\"template\":{\"target\":{\"wt\":\"echo\",\"href\":\"./Template:Echo\"},\"params\":{\"1\":{\"wt\":\"hi\"}},\"i\":0}}]}'>hi</span>"}]]}'>http://example.com/hi</a>)</p>
+<p>(<a typeof="mw:ExpandedAttrs" about="#mwt2" rel="mw:ExtLink" href="http://example.com/hi" class="external free" data-parsoid='{"stx":"url","a":{"href":"http://example.com/hi"},"sa":{"href":"http://example.com/{{echo|hi}}"}}' data-mw='{"attribs":[[{"txt":"href"},{"html":"http://example.com/<span about=\"#mwt1\" typeof=\"mw:Transclusion\" data-parsoid='{\"pi\":[[{\"k\":\"1\"}]],\"dsr\":[20,31,null,null]}' data-mw='{\"parts\":[{\"template\":{\"target\":{\"wt\":\"echo\",\"href\":\"./Template:Echo\"},\"params\":{\"1\":{\"wt\":\"hi\"}},\"i\":0}}]}'>hi</span>"}]]}'>http://example.com/hi</a>)</p>
-<p>(<a rel="mw:ExtLink" class="external free" href="http://example.com" data-parsoid='{"stx":"url","a":{"href":"http://example.com"},"sa":{"href":"http://example.com<!-- hi -->"}}'>http://example.com</a>)</p>
+<p>(<a rel="mw:ExtLink" href="http://example.com" class="external free" data-parsoid='{"stx":"url","a":{"href":"http://example.com"},"sa":{"href":"http://example.com<!-- hi -->"}}'>http://example.com</a>)</p>
!! end
!! test
</td></tr></table>
!!end
+# Differences between Parsoid and PHP re: trailing whitespace in a
+# table cell.
!! test
Table rowspan
!! wikitext
|Cell 1, row 2
|Cell 3, row 2
|}
-!! html
+!! html/php
<table border="1">
<tr>
<td>Cell 1, row 1
</td>
<td>Cell 3, row 2
</td></tr></table>
+!! html/parsoid
+<table border="1">
+<tbody><tr data-parsoid='{"autoInsertedStart":true}'><td>Cell 1, row 1</td>
+<td rowspan="2">Cell 2, row 1 (and 2)</td>
+<td>Cell 3, row 1</td></tr>
+<tr data-parsoid='{"startTagSrc":"|-"}'>
+<td>Cell 1, row 2</td>
+<td>Cell 3, row 2</td></tr>
+</tbody></table>
!! end
!! test
!! html/parsoid
<table><tbody>
<tr>
-<td data-parsoid='{"startTagSrc":"| ","attrSepSrc":"|","autoInsertedEnd":true}'>[<a rel="mw:ExtLink" class="external free" href="ftp://%7Cx" data-parsoid='{"stx":"url","a":{"href":"ftp://%7Cx"},"sa":{"href":"ftp://|x"}}'>ftp://%7Cx</a></td><td data-parsoid='{"stx":"row","autoInsertedEnd":true}'>]" onmouseover="alert(document.cookie)">test</td></tr></tbody></table>
+<td data-parsoid='{"startTagSrc":"| ","attrSepSrc":"|","autoInsertedEnd":true}'>[<a rel="mw:ExtLink" href="ftp://%7Cx" class="external free" data-parsoid='{"stx":"url","a":{"href":"ftp://%7Cx"},"sa":{"href":"ftp://|x"}}'>ftp://%7Cx</a></td><td data-parsoid='{"stx":"row","autoInsertedEnd":true}'>]" onmouseover="alert(document.cookie)">test</td></tr></tbody></table>
!! end
!! test
</p>
!! end
+# The PHP parser strips the hash fragment for non-existent pages, but
+# Parsoid does not. (T227693)
!! test
Broken link with fragment
!! wikitext
[[Zigzagzogzagzig#zug]]
-!! html
+!! html/php
<p><a href="/index.php?title=Zigzagzogzagzig&action=edit&redlink=1" class="new" title="Zigzagzogzagzig (page does not exist)">Zigzagzogzagzig#zug</a>
</p>
+!! html/parsoid
+<p><a rel="mw:WikiLink" href="./Zigzagzogzagzig#zug" title="Zigzagzogzagzig" data-parsoid="{"tsr":[0,23],"src":"[[Zigzagzogzagzig#zug]]","bsp":[0,23],"stx":"simple"}">Zigzagzogzagzig#zug</a></p>
!! end
!! test
</p>
!! end
+# Parsoid does not strip fragment from red links: T227693
!! test
Nonexistent special page link with fragment
!! wikitext
[[Special:ThisNameWillHopefullyNeverBeUsed#anchor]]
-!! html
+!! html/php
<p><a href="/wiki/Special:ThisNameWillHopefullyNeverBeUsed" class="new" title="Special:ThisNameWillHopefullyNeverBeUsed (page does not exist)">Special:ThisNameWillHopefullyNeverBeUsed#anchor</a>
</p>
+!! html/parsoid
+<p><a rel="mw:WikiLink" href="./Special:ThisNameWillHopefullyNeverBeUsed#anchor" title="Special:ThisNameWillHopefullyNeverBeUsed">Special:ThisNameWillHopefullyNeverBeUsed#anchor</a></p>
!! end
!! test
!! wikitext
[[File:Cool "Gator".png]]
!! html/php+tidy
-<p><a href="/index.php?title=Special:Upload&wpDestFile=Cool_%22Gator%22.png" class="new" title="File:Cool "Gator".png">File:Cool "Gator".png</a>
+<p><a href="/index.php?title=Special:Upload&wpDestFile=Cool_%22Gator%22.png" class="new" title="File:Cool "Gator".png">File:Cool "Gator".png</a>
</p>
!! html/parsoid
<p><figure-inline class="mw-default-size" typeof="mw:Error mw:Image" data-mw='{"errors":[{"key":"apierror-filedoesnotexist","message":"This image does not exist."}]}'><a href="./Special:FilePath/Cool_%22Gator%22.png"><span resource='./File:Cool_"Gator".png' data-parsoid='{"a":{"resource":"./File:Cool_\"Gator\".png"},"sa":{"resource":"File:Cool \"Gator\".png"}}'>File:Cool "Gator".png</span></a></figure-inline></p>
!! end
+!! test
+File containing single quotes
+!! wikitext
+[[File:Foo's ''italic'' bar.jpg]]
+[[File:Foo's ''italic'' bar.jpg|Foo's ''italic'' bar]]
+!! html/php+tidy
+<p><a href="/index.php?title=Special:Upload&wpDestFile=Foo%27s_%27%27italic%27%27_bar.jpg" class="new" title="File:Foo's ''italic'' bar.jpg">File:Foo's <i>italic</i> bar.jpg</a>
+<a href="/index.php?title=Special:Upload&wpDestFile=Foo%27s_%27%27italic%27%27_bar.jpg" class="new" title="File:Foo's ''italic'' bar.jpg">Foo's italic bar</a>
+</p>
+!! end
+
!! test
Redirect containing double quotes and spaces
!! wikitext
[[File:Nonexistent|<]]
[[File:Nonexistent|a<i>b</i>c]]
!! html/php
-<p><a href="/index.php?title=Special:Upload&wpDestFile=Nonexistent" class="new" title="File:Nonexistent"><script></script></a>
-<a href="/index.php?title=Special:Upload&wpDestFile=Nonexistent" class="new" title="File:Nonexistent"><script></script></a>
+<p><a href="/index.php?title=Special:Upload&wpDestFile=Nonexistent" class="new" title="File:Nonexistent"><script></script></a>
+<a href="/index.php?title=Special:Upload&wpDestFile=Nonexistent" class="new" title="File:Nonexistent"><script></script></a>
<a href="/index.php?title=Special:Upload&wpDestFile=Nonexistent" class="new" title="File:Nonexistent"><</a>
<a href="/index.php?title=Special:Upload&wpDestFile=Nonexistent" class="new" title="File:Nonexistent">abc</a>
</p>
<p>[<a rel="nofollow" class="external autonumber" href="http://www.example.com">[1]</a>]
</p>
!! html/parsoid
-<p>[<a rel="mw:ExtLink" class="external autonumber" href="http://www.example.com"></a>]</p>
+<p>[<a rel="mw:ExtLink" href="http://www.example.com" class="external autonumber"></a>]</p>
!! end
!! test
<p>[<a rel="nofollow" class="external autonumber" href="//www.example.com">[1]</a>]
</p>
!! html/parsoid
-<p>[<a rel="mw:ExtLink" class="external autonumber" href="//www.example.com"></a>]</p>
+<p>[<a rel="mw:ExtLink" href="//www.example.com" class="external autonumber"></a>]</p>
!! end
!! test
<p>Piped link to URL: [<a rel="nofollow" class="external text" href="http://www.example.com%7Can">example URL</a>]
</p>
!! html/parsoid
-<p>Piped link to URL: [<a rel="mw:ExtLink" class="external text" href="http://www.example.com%7Can" data-parsoid='{"a":{"href":"http://www.example.com%7Can"},"sa":{"href":"http://www.example.com|an"}}'>example URL</a>]</p>
+<p>Piped link to URL: [<a rel="mw:ExtLink" href="http://www.example.com%7Can" class="external text" data-parsoid='{"a":{"href":"http://www.example.com%7Can"},"sa":{"href":"http://www.example.com|an"}}'>example URL</a>]</p>
!! end
!! test
</p><p>[<a rel="nofollow" class="external free" href="http://www.example.com">http://www.example.com</a>
</p>
!! html/parsoid
-<p about="#mwt1" typeof="mw:Transclusion" data-mw='{"parts":[{"template":{"target":{"wt":"echo","href":"./Template:Echo"},"params":{"1":{"wt":"[http://www.example.com "},"2":{"wt":"123]"}},"i":0}}]}'>[<a rel="mw:ExtLink" class="external free" href="http://www.example.com">http://www.example.com</a> </p>
+<p about="#mwt1" typeof="mw:Transclusion" data-mw='{"parts":[{"template":{"target":{"wt":"echo","href":"./Template:Echo"},"params":{"1":{"wt":"[http://www.example.com "},"2":{"wt":"123]"}},"i":0}}]}'>[<a rel="mw:ExtLink" href="http://www.example.com" class="external free">http://www.example.com</a> </p>
-<p about="#mwt2" typeof="mw:Transclusion" data-mw='{"parts":[{"template":{"target":{"wt":"echo","href":"./Template:Echo"},"params":{"1":{"wt":"[[http://www.example.com |123]]"}},"i":0}}]}'>[<a rel="mw:ExtLink" class="external text" href="http://www.example.com">|123</a>]</p>
+<p about="#mwt2" typeof="mw:Transclusion" data-mw='{"parts":[{"template":{"target":{"wt":"echo","href":"./Template:Echo"},"params":{"1":{"wt":"[[http://www.example.com |123]]"}},"i":0}}]}'>[<a rel="mw:ExtLink" href="http://www.example.com" class="external text">|123</a>]</p>
-<p>{{echo|[<a rel="mw:ExtLink" class="external text" href="http://www.example.com" data-parsoid='{"targetOff":114,"contentOffsets":[114,118],"dsr":[90,119,24,1]}'>|123</a>}}</p>
+<p>{{echo|[<a rel="mw:ExtLink" href="http://www.example.com" class="external text" data-parsoid='{"targetOff":114,"contentOffsets":[114,118],"dsr":[90,119,24,1]}'>|123</a>}}</p>
-<p about="#mwt3" typeof="mw:Transclusion" data-mw='{"parts":[{"template":{"target":{"wt":"echo","href":"./Template:Echo"},"params":{"1":{"wt":"[http://www.example.com "},"2":{"wt":"123]]"}},"i":0}}]}'>[<a rel="mw:ExtLink" class="external free" href="http://www.example.com">http://www.example.com</a> </p>
+<p about="#mwt3" typeof="mw:Transclusion" data-mw='{"parts":[{"template":{"target":{"wt":"echo","href":"./Template:Echo"},"params":{"1":{"wt":"[http://www.example.com "},"2":{"wt":"123]]"}},"i":0}}]}'>[<a rel="mw:ExtLink" href="http://www.example.com" class="external free">http://www.example.com</a> </p>
!! end
!! test
<p><a rel="mw:WikiLink/Interwiki" href="http://www.usemod.com/cgi-bin/mb.pl?ok" title="meatball:ok">meatball:ok</a>
<a rel="mw:WikiLink/Interwiki" href="http://www.usemod.com/cgi-bin/mb.pl?ok#foo" title="meatball:ok">ok with fragment</a>
<a rel="mw:WikiLink/Interwiki" href="http://www.usemod.com/cgi-bin/mb.pl?ok_as_well%3F" title="meatball:ok as well?">ok ending with ? mark</a>
-<a rel="mw:ExtLink" class="external text" href="http://de.wikipedia.org/wiki/Foo?action=history">has query</a>
-<a rel="mw:ExtLink" class="external text" href="http://de.wikipedia.org/wiki/#foo">is just fragment</a></p>
+<a rel="mw:ExtLink" href="http://de.wikipedia.org/wiki/Foo?action=history" class="external text">has query</a>
+<a rel="mw:ExtLink" href="http://de.wikipedia.org/wiki/#foo" class="external text">is just fragment</a></p>
!! end
!! test
</p>
!! html/parsoid
<p>X<a rel="mw:WikiLink" href="./Special:BookSources/0978739256" title="Special:BookSources/0978739256">foo</a></p>
-<p>X<a rel="mw:ExtLink" class="external text" href="https://tools.ietf.org/html/rfc1234">foo</a></p>
+<p>X<a rel="mw:ExtLink" href="https://tools.ietf.org/html/rfc1234" class="external text">foo</a></p>
!! end
!! test
<p><span typeof="mw:Transclusion" about="#mwt1" data-mw='{"parts":[{"template":{"target":{"wt":"[[Main Page]]"},"params":{},"i":0}}]}'>{{</span><a rel="mw:WikiLink" href="./Main_Page" about="#mwt1">Main Page</a><span about="#mwt1">}}</span></p>
!! end
+# The html2html output of this test is currently failing
+# because the html2wt output is broken; see
+# https://phabricator.wikimedia.org/T220018#5123777 for a discussion.
+# Not (yet) including html2wt as a test mode because there are
+# a couple of different correct ways this could be <nowiki>'ed.
!! test
Template with just whitespace in it, T70421
!! wikitext
{{echo|{{ }}}}
+!! options
+parsoid=wt2html,html2html
+!! html/php+tidy
+<p>{{ }}
+</p>
!! html/parsoid
<p about="#mwt1" typeof="mw:Transclusion" data-parsoid='{"pi":[[{"k":"1"}]]}' data-mw='{"parts":[{"template":{"target":{"wt":"echo","href":"./Template:Echo"},"params":{"1":{"wt":"{{ }}"}},"i":0}}]}'>{{ }}</p>
!! end
+# This is currently the wikitext output of html2wt on the above test
+# case; note that it is broken! Adding a <nowiki> around the closing
+# brace changes how the open braces associate, breaking the outer
+# {{echo}} template invocation. *However* this "broken" wikitext
+# exposed a useful tokenizer bug (T221384) in how the broken_template
+# rule was being backtracked into, so it's a useful test case even
+# if/when the above test case gets its html2wt output fixed.
+!! test
+Template with just whitespace (bad template brace matching)
+!! options
+parsoid=wt2html
+!! wikitext
+{{echo|{{ }<nowiki>}</nowiki>}}
+!! html/php+tidy
+<p>{{echo|{{ }}}}
+</p>
+!! html/parsoid
+<p>{{echo|{{ }<span typeof="mw:Nowiki">}</span>}}</p>
+!! end
+
!! article
Template:test
!! text
Template infinite loop
!! wikitext
{{loop1}}
-!! html
+!! html/php
<p><span class="error">Template loop detected: <a href="/wiki/Template:Loop1" title="Template:Loop1">Template:Loop1</a></span>
</p>
+!! html/parsoid
+<p><span class="error" typeof="mw:Transclusion" data-mw='{"parts":[{"template":{"target":{"wt":"loop1","href":"./Template:Loop1"},"params":{},"i":0}}]}'>Template loop detected: <a rel="mw:WikiLink" href="./Template:Loop1" title="Template:Loop1">Template:Loop1</a></span></p>
!! end
!! test
<td>hi
</td></tr></tbody></table>
!! html/parsoid
-<p about="#mwt1" typeof="mw:Transclusion" data-parsoid='{"stx":"html","autoInsertedEnd":true,"pi":[[{"k":"1"}],[{"k":"1"}],[{"k":"1"}]],"firstWikitextNode":"table"}' data-mw='{"parts":["{|",{"template":{"target":{"wt":"echo","href":"./Template:Echo"},"params":{"1":{"wt":"\n<p>ha</p>"}},"i":0}},"\n","{|",{"template":{"target":{"wt":"echo","href":"./Template:Echo"},"params":{"1":{"wt":"\n<p>ho</p>"}},"i":1}},"\n",{"template":{"target":{"wt":"echo","href":"./Template:Echo"},"params":{"1":{"wt":"{{!}}hi"}},"i":2}},"\n|}"]}'>ha</p><table about="#mwt1" typeof="mw:ExpandedAttrs" data-mw='{"attribs":[[{"txt":"","html":""},{"html":""}]]}'>
+<p about="#mwt1" typeof="mw:Transclusion" data-parsoid='{"stx":"html","autoInsertedEnd":true,"pi":[[{"k":"1"}],[{"k":"1"}],[{"k":"1"}]],"firstWikitextNode":"TABLE"}' data-mw='{"parts":["{|",{"template":{"target":{"wt":"echo","href":"./Template:Echo"},"params":{"1":{"wt":"\n<p>ha</p>"}},"i":0}},"\n","{|",{"template":{"target":{"wt":"echo","href":"./Template:Echo"},"params":{"1":{"wt":"\n<p>ho</p>"}},"i":1}},"\n",{"template":{"target":{"wt":"echo","href":"./Template:Echo"},"params":{"1":{"wt":"{{!}}hi"}},"i":2}},"\n|}"]}'>ha</p><table about="#mwt1" typeof="mw:ExpandedAttrs" data-mw='{"attribs":[[{"txt":"","html":""},{"html":""}]]}'>
</table><p about="#mwt1">ho</p><table about="#mwt1" typeof="mw:ExpandedAttrs" data-mw='{"attribs":[[{"txt":"","html":""},{"html":""}]]}'>
<onlyinclude> being included
!! wikitext
{{Includes2}}
-!! html
+!! html/php+tidy
<p>Foo
</p>
+!! html/parsoid
+<p><meta typeof="mw:Transclusion mw:Includes/OnlyInclude" about="#mwt1" data-mw='{"parts":[{"template":{"target":{"wt":"Includes2","href":"./Template:Includes2"},"params":{},"i":0}}]}'/><span about="#mwt1">Foo</span><meta typeof="mw:Includes/OnlyInclude/End" about="#mwt1"/></p>
!! end
<onlyinclude> and <includeonly> being included
!! wikitext
{{Includes3}}
-!! html
+!! html/php+tidy
<p>Foo
</p>
+!! html/parsoid
+<p><meta typeof="mw:Transclusion mw:Includes/OnlyInclude" about="#mwt1" data-mw='{"parts":[{"template":{"target":{"wt":"Includes3","href":"./Template:Includes3"},"params":{},"i":0}}]}'/><span about="#mwt1">Foo</span><meta typeof="mw:Includes/OnlyInclude/End" about="#mwt1"/></p>
!! end
# FIXME: Parsoid's markup for this is quite ugly.
Un-closed <noinclude>
!! wikitext
<noinclude>
-!! html
+!! html/php+tidy
+!! html/parsoid
+<meta typeof="mw:Includes/NoInclude" data-parsoid='{"src":"<noinclude>"}'/>
+!! end
+
+!! test
+Empty <noinclude>
+!! wikitext
+Hello<noinclude></noinclude>!
+!! html/php+tidy
+<p>Hello!
+</p>
+!! html/parsoid
+<p>Hello<meta typeof="mw:Includes/NoInclude" data-parsoid='{"src":"<noinclude>"}'/><meta typeof="mw:Includes/NoInclude/End" data-parsoid='{"src":"</noinclude>"}'/>!</p>
!! end
!! test
## will normalize the include directives to serialize on their own line.
## Selser will take care of preserving formatting in scenarios where they
## intermingled with other wikitext.
+## This test also triggered T223411 during Parsoid-PHP porting.
!! test
Includes and comments at SOL
!! options
<li>{{echo|<a rel="nofollow" class="external text" href="http://example.com/-{foo">Breaks template, however</a>}}</li></ul>
!! html/parsoid
<ul>
-<li><a rel="mw:ExtLink" class="external text" href="http://example.com/-{foo">Example in URL</a></li>
-<li><a rel="mw:ExtLink" class="external text" href="http://example.com">Example in -{link} description</a></li>
-<li>{{echo|<a rel="mw:ExtLink" class="external text" href="http://example.com/-{foo">Breaks template, however</a>}}</li>
+<li><a rel="mw:ExtLink" href="http://example.com/-{foo" class="external text">Example in URL</a></li>
+<li><a rel="mw:ExtLink" href="http://example.com" class="external text">Example in -{link} description</a></li>
+<li>{{echo|<a rel="mw:ExtLink" href="http://example.com/-{foo" class="external text">Breaks template, however</a>}}</li>
</ul>
!! end
<p><span about="#mwt2" typeof="mw:Transclusion" data-mw='{"parts":[{"template":{"target":{"wt":"echo","href":"./Template:Echo"},"params":{"1":{"wt":"hi<ref>[[ho|{{echo|hi}}]]</ref>"}},"i":0}}]}'>hi</span><sup about="#mwt2" class="mw-ref" id="cite_ref-1" rel="dc:references" typeof="mw:Extension/ref" data-mw='{"name":"ref","attrs":{},"body":{"id":"mw-reference-text-cite_note-1"}}'><a href="./Main_Page#cite_note-1" style="counter-reset: mw-Ref 1;"><span class="mw-reflink-text">[1]</span></a></sup>
<span about="#mwt8" typeof="mw:Transclusion" data-mw='{"parts":[{"template":{"target":{"wt":"echo","href":"./Template:Echo"},"params":{"1":{"wt":"hi<ref>[http://test.com?q={{echo|ho}}]</ref>"}},"i":0}}]}'>hi</span><sup about="#mwt8" class="mw-ref" id="cite_ref-2" rel="dc:references" typeof="mw:Extension/ref" data-mw='{"name":"ref","attrs":{},"body":{"id":"mw-reference-text-cite_note-2"}}'><a href="./Main_Page#cite_note-2" style="counter-reset: mw-Ref 2;"><span class="mw-reflink-text">[2]</span></a></sup>
<span about="#mwt13" typeof="mw:Transclusion" data-mw='{"parts":[{"template":{"target":{"wt":"echo","href":"./Template:Echo"},"params":{"1":{"wt":"hi<ref>-{ho|{{echo|hi}}}-</ref>"}},"i":0}}]}'>hi</span><sup about="#mwt13" class="mw-ref" id="cite_ref-3" rel="dc:references" typeof="mw:Extension/ref" data-mw='{"name":"ref","attrs":{},"body":{"id":"mw-reference-text-cite_note-3"}}'><a href="./Main_Page#cite_note-3" style="counter-reset: mw-Ref 3;"><span class="mw-reflink-text">[3]</span></a></sup></p>
-<ol class="mw-references references" typeof="mw:Extension/references" about="#mwt17" data-mw='{"name":"references","attrs":{}}'><li about="#cite_note-1" id="cite_note-1"><a href="./Main_Page#cite_ref-1" rel="mw:referencedBy"><span class="mw-linkback-text">↑ </span></a> <span id="mw-reference-text-cite_note-1" class="mw-reference-text"><a rel="mw:WikiLink" href="./Ho" title="Ho">hi</a></span></li><li about="#cite_note-2" id="cite_note-2"><a href="./Main_Page#cite_ref-2" rel="mw:referencedBy"><span class="mw-linkback-text">↑ </span></a> <span id="mw-reference-text-cite_note-2" class="mw-reference-text"><a rel="mw:ExtLink" class="external autonumber" href="http://test.com?q=ho"></a></span></li><li about="#cite_note-3" id="cite_note-3"><a href="./Main_Page#cite_ref-3" rel="mw:referencedBy"><span class="mw-linkback-text">↑ </span></a> <span id="mw-reference-text-cite_note-3" class="mw-reference-text"><span typeof="mw:LanguageVariant" data-mw-variant='{"filter":{"l":["ho"],"t":"hi"}}'></span></span></li></ol>
+<ol class="mw-references references" typeof="mw:Extension/references" about="#mwt17" data-mw='{"name":"references","attrs":{}}'><li about="#cite_note-1" id="cite_note-1"><a href="./Main_Page#cite_ref-1" rel="mw:referencedBy"><span class="mw-linkback-text">↑ </span></a> <span id="mw-reference-text-cite_note-1" class="mw-reference-text"><a rel="mw:WikiLink" href="./Ho" title="Ho">hi</a></span></li><li about="#cite_note-2" id="cite_note-2"><a href="./Main_Page#cite_ref-2" rel="mw:referencedBy"><span class="mw-linkback-text">↑ </span></a> <span id="mw-reference-text-cite_note-2" class="mw-reference-text"><a rel="mw:ExtLink" href="http://test.com?q=ho" class="external autonumber"></a></span></li><li about="#cite_note-3" id="cite_note-3"><a href="./Main_Page#cite_ref-3" rel="mw:referencedBy"><span class="mw-linkback-text">↑ </span></a> <span id="mw-reference-text-cite_note-3" class="mw-reference-text"><span typeof="mw:LanguageVariant" data-mw-variant='{"filter":{"l":["ho"],"t":"hi"}}'></span></span></li></ol>
!! end
###
!! html/php
<div class="thumb tright"><div class="thumbinner" style="width:222px;"><a href="/wiki/File:Foobar.jpg" class="image"><img alt="" src="http://example.com/images/thumb/3/3a/Foobar.jpg/220px-Foobar.jpg" decoding="async" width="220" height="25" class="thumbimage" srcset="http://example.com/images/thumb/3/3a/Foobar.jpg/330px-Foobar.jpg 1.5x, http://example.com/images/thumb/3/3a/Foobar.jpg/440px-Foobar.jpg 2x" /></a> <div class="thumbcaption"><div class="magnify"><a href="/wiki/File:Foobar.jpg" class="internal" title="Enlarge"></a></div><a rel="nofollow" class="external free" href="http://example.com">http://example.com</a></div></div></div>
!! html/parsoid
-<figure class="mw-default-size" typeof="mw:Image/Thumb"><a href="./File:Foobar.jpg"><img resource="./File:Foobar.jpg" src="//example.com/images/thumb/3/3a/Foobar.jpg/220px-Foobar.jpg" data-file-width="1941" data-file-height="220" data-file-type="bitmap" height="25" width="220"/></a><figcaption><a rel="mw:ExtLink" class="external free" href="http://example.com">http://example.com</a></figcaption></figure>
+<figure class="mw-default-size" typeof="mw:Image/Thumb"><a href="./File:Foobar.jpg"><img resource="./File:Foobar.jpg" src="//example.com/images/thumb/3/3a/Foobar.jpg/220px-Foobar.jpg" data-file-width="1941" data-file-height="220" data-file-type="bitmap" height="25" width="220"/></a><figcaption><a rel="mw:ExtLink" href="http://example.com" class="external free">http://example.com</a></figcaption></figure>
!! end
!! test
!! html/php
<div class="thumb tright"><div class="thumbinner" style="width:222px;"><a href="/wiki/File:Foobar.jpg" class="image"><img alt="Alteration" src="http://example.com/images/thumb/3/3a/Foobar.jpg/220px-Foobar.jpg" decoding="async" width="220" height="25" class="thumbimage" srcset="http://example.com/images/thumb/3/3a/Foobar.jpg/330px-Foobar.jpg 1.5x, http://example.com/images/thumb/3/3a/Foobar.jpg/440px-Foobar.jpg 2x" /></a> <div class="thumbcaption"><div class="magnify"><a href="/wiki/File:Foobar.jpg" class="internal" title="Enlarge"></a></div><a rel="nofollow" class="external free" href="http://example.com">http://example.com</a></div></div></div>
!! html/parsoid
-<figure class="mw-default-size" typeof="mw:Image/Thumb"><a href="./File:Foobar.jpg"><img alt="Alteration" resource="./File:Foobar.jpg" src="//example.com/images/thumb/3/3a/Foobar.jpg/220px-Foobar.jpg" data-file-width="1941" data-file-height="220" data-file-type="bitmap" height="25" width="220"/></a><figcaption><a rel="mw:ExtLink" class="external free" href="http://example.com">http://example.com</a></figcaption></figure>
+<figure class="mw-default-size" typeof="mw:Image/Thumb"><a href="./File:Foobar.jpg"><img alt="Alteration" resource="./File:Foobar.jpg" src="//example.com/images/thumb/3/3a/Foobar.jpg/220px-Foobar.jpg" data-file-width="1941" data-file-height="220" data-file-type="bitmap" height="25" width="220"/></a><figcaption><a rel="mw:ExtLink" href="http://example.com" class="external free">http://example.com</a></figcaption></figure>
!! end
!! test
!! html/php
<div class="thumb tright"><div class="thumbinner" style="width:182px;"><a href="/wiki/File:Foobar.jpg" class="image"><img alt="" src="http://example.com/images/thumb/3/3a/Foobar.jpg/180px-Foobar.jpg" decoding="async" width="180" height="20" class="thumbimage" srcset="http://example.com/images/thumb/3/3a/Foobar.jpg/270px-Foobar.jpg 1.5x, http://example.com/images/thumb/3/3a/Foobar.jpg/360px-Foobar.jpg 2x" /></a> <div class="thumbcaption"><div class="magnify"><a href="/wiki/File:Foobar.jpg" class="internal" title="Enlarge"></a></div>Please <a rel="nofollow" class="external free" href="mailto:nobody@example.com">mailto:nobody@example.com</a></div></div></div>
!! html/parsoid
-<figure class="mw-default-size" typeof="mw:Image/Thumb"><a href="./File:Foobar.jpg"><img resource="./File:Foobar.jpg" src="//example.com/images/thumb/3/3a/Foobar.jpg/220px-Foobar.jpg" data-file-width="1941" data-file-height="220" data-file-type="bitmap" height="25" width="220"/></a><figcaption>Please <a rel="mw:ExtLink" class="external free" href="mailto:nobody@example.com">mailto:nobody@example.com</a></figcaption></figure>
+<figure class="mw-default-size" typeof="mw:Image/Thumb"><a href="./File:Foobar.jpg"><img resource="./File:Foobar.jpg" src="//example.com/images/thumb/3/3a/Foobar.jpg/220px-Foobar.jpg" data-file-width="1941" data-file-height="220" data-file-type="bitmap" height="25" width="220"/></a><figcaption>Please <a rel="mw:ExtLink" href="mailto:nobody@example.com" class="external free">mailto:nobody@example.com</a></figcaption></figure>
!! end
# Pending resolution to T2368
!! html/php
<div class="thumb tright"><div class="thumbinner" style="width:202px;"><a href="/wiki/File:Foobar.jpg" class="image"><img alt="" src="http://example.com/images/thumb/3/3a/Foobar.jpg/200px-Foobar.jpg" decoding="async" width="200" height="23" class="thumbimage" srcset="http://example.com/images/thumb/3/3a/Foobar.jpg/300px-Foobar.jpg 1.5x, http://example.com/images/thumb/3/3a/Foobar.jpg/400px-Foobar.jpg 2x" /></a> <div class="thumbcaption"><div class="magnify"><a href="/wiki/File:Foobar.jpg" class="internal" title="Enlarge"></a></div>This caption has <a rel="nofollow" class="external text" href="irc://example.net">irc</a> and <a rel="nofollow" class="external text" href="https://example.com">Secure</a> ext links in it.</div></div></div>
!! html/parsoid
-<figure typeof="mw:Image/Thumb"><a href="./File:Foobar.jpg"><img resource="./File:Foobar.jpg" src="//example.com/images/thumb/3/3a/Foobar.jpg/200px-Foobar.jpg" data-file-width="1941" data-file-height="220" data-file-type="bitmap" height="23" width="200"/></a><figcaption>This caption has <a rel="mw:ExtLink" class="external text" href="irc://example.net">irc</a> and <a rel="mw:ExtLink" class="external text" href="https://example.com">Secure</a> ext links in it.</figcaption></figure>
+<figure typeof="mw:Image/Thumb"><a href="./File:Foobar.jpg"><img resource="./File:Foobar.jpg" src="//example.com/images/thumb/3/3a/Foobar.jpg/200px-Foobar.jpg" data-file-width="1941" data-file-height="220" data-file-type="bitmap" height="23" width="200"/></a><figcaption>This caption has <a rel="mw:ExtLink" href="irc://example.net" class="external text">irc</a> and <a rel="mw:ExtLink" href="https://example.com" class="external text">Secure</a> ext links in it.</figcaption></figure>
!! end
!! test
[[.]]
[[..]]
[[foo././bar]]
-[[foo<a rel="mw:ExtLink" class="external autonumber" href="http://example.com"></a>xyz]]</p>
+[[foo<a rel="mw:ExtLink" href="http://example.com" class="external autonumber"></a>xyz]]</p>
<p>[[<span typeof="mw:Transclusion" data-mw='{"parts":[{"template":{"target":{"wt":"echo","href":"./Template:Echo"},"params":{"1":{"wt":"./../foo"}},"i":0}}]}'>./../foo</span>|bar]]
[[<span typeof="mw:Transclusion" data-mw='{"parts":[{"template":{"target":{"wt":"echo","href":"./Template:Echo"},"params":{"1":{"wt":"foo/."}},"i":0}}]}'>foo/.</span>|bar]]
<link rel="mw:PageProp/Category" href="./Category:MediaWiki_User's_Guide#MediaWiki%20User's%20Guide" data-parsoid='{"stx":"piped","a":{"href":"./Category:MediaWiki_User's_Guide"},"sa":{"href":"Category:MediaWiki User's Guide"}}'/>
!! end
+!! test
+Category with template-generated sort key
+!! options
+cat
+!! wikitext
+[[Category:MediaWiki User's Guide|MediaWiki {{echo|Foo}} Guide]]
+!! html/php
+cat=MediaWiki_User's_Guide sort=MediaWiki Foo Guide
+!! html/parsoid
+<link rel="mw:PageProp/Category" href="./Category:MediaWiki_User's_Guide#MediaWiki%20Foo%20Guide" typeof="mw:ExpandedAttrs" data-mw='{"attribs":[[{"txt":"mw:sortKey"},{"html":"MediaWiki <span typeof=\"mw:Transclusion\" data-mw='{\"parts\":[{\"template\":{\"target\":{\"wt\":\"echo\",\"href\":\"./Template:Echo\"},\"params\":{\"1\":{\"wt\":\"Foo\"}},\"i\":0}}]}'>Foo</span> Guide"}]]}'/>
+!! end
+
!! test
Category with empty sort key
!! options
<p><a rel="nofollow" class="external free" href="http://example.com">http://example.com</a> <a href="/wiki/File:Foobar.jpg" class="image"><img alt="Foobar.jpg" src="http://example.com/images/3/3a/Foobar.jpg" decoding="async" width="1941" height="220" /></a>
</p>
!! html/parsoid
-<p><a rel="mw:ExtLink" class="external free" href="http://example.com">http://example.com</a> <figure-inline class="mw-default-size" typeof="mw:Image"><a href="./File:Foobar.jpg"><img resource="./File:Foobar.jpg" src="//example.com/images/3/3a/Foobar.jpg" data-file-width="1941" data-file-height="220" data-file-type="bitmap" height="220" width="1941"/></a></figure-inline></p>
+<p><a rel="mw:ExtLink" href="http://example.com" class="external free">http://example.com</a> <figure-inline class="mw-default-size" typeof="mw:Image"><a href="./File:Foobar.jpg"><img resource="./File:Foobar.jpg" src="//example.com/images/3/3a/Foobar.jpg" data-file-width="1941" data-file-height="220" data-file-type="bitmap" height="220" width="1941"/></a></figure-inline></p>
!!end
# Parsoid doesn't wt2wt this cleanly because it adds <nowiki>s.
<p><a rel="nofollow" class="external free" href="http://example.com">http://example.com</a><a href="/wiki/File:Foobar.jpg" class="image"><img alt="Foobar.jpg" src="http://example.com/images/3/3a/Foobar.jpg" decoding="async" width="1941" height="220" /></a>
</p>
!! html/parsoid
-<p><a rel="mw:ExtLink" class="external free" href="http://example.com">http://example.com</a><figure-inline class="mw-default-size" typeof="mw:Image"><a href="./File:Foobar.jpg"><img resource="./File:Foobar.jpg" src="//example.com/images/3/3a/Foobar.jpg" data-file-width="1941" data-file-height="220" data-file-type="bitmap" height="220" width="1941"/></a></figure-inline></p>
+<p><a rel="mw:ExtLink" href="http://example.com" class="external free">http://example.com</a><figure-inline class="mw-default-size" typeof="mw:Image"><a href="./File:Foobar.jpg"><img resource="./File:Foobar.jpg" src="//example.com/images/3/3a/Foobar.jpg" data-file-width="1941" data-file-height="220" data-file-type="bitmap" height="220" width="1941"/></a></figure-inline></p>
!!end
!! test
</p>
!! end
+!! test
+Text with HTML5 semicolon-less entity (should not decode)
+!! wikitext
+&amp;
+!! html/php+tidy
+<p>&ampamp;
+</p>
+!! html/parsoid
+<p>&ampamp;</p>
+!! end
+
!! test
HTML5 tags
!! wikitext
</p><p><a rel="nofollow" class="external free" href="mailto:inline@mail.tld">mailto:inline@mail.tld</a>
</p>
!! html/parsoid
-<p><a rel="mw:ExtLink" class="external autonumber" href="http://first/"></a> <a rel="mw:ExtLink" class="external autonumber" href="http://second"></a> <a rel="mw:ExtLink" class="external autonumber" href="ftp://ftp"></a></p>
-<p><a rel="mw:ExtLink" class="external free" href="ftp://inlineftp">ftp://inlineftp</a></p>
-<p><a rel="mw:ExtLink" class="external text" href="mailto:enclosed@mail.tld">With target</a></p>
-<p><a rel="mw:ExtLink" class="external autonumber" href="mailto:enclosed@mail.tld"></a></p>
-<p><a rel="mw:ExtLink" class="external free" href="mailto:inline@mail.tld">mailto:inline@mail.tld</a></p>
+<p><a rel="mw:ExtLink" href="http://first/" class="external autonumber"></a> <a rel="mw:ExtLink" href="http://second" class="external autonumber"></a> <a rel="mw:ExtLink" href="ftp://ftp" class="external autonumber"></a></p>
+<p><a rel="mw:ExtLink" href="ftp://inlineftp" class="external free">ftp://inlineftp</a></p>
+<p><a rel="mw:ExtLink" href="mailto:enclosed@mail.tld" class="external text">With target</a></p>
+<p><a rel="mw:ExtLink" href="mailto:enclosed@mail.tld" class="external autonumber"></a></p>
+<p><a rel="mw:ExtLink" href="mailto:inline@mail.tld" class="external free">mailto:inline@mail.tld</a></p>
!! end
</div>
!! html/parsoid
<h2 id="onmouseover="><span id="onmouseover.3D" typeof="mw:FallbackId"></span>onmouseover=</h2>
-<p><a rel="mw:ExtLink" class="external free" href="http://__TOC__" data-parsoid='{"stx":"url"}'>http://__TOC__</a></p>
+<p><a rel="mw:ExtLink" href="http://__TOC__" class="external free" data-parsoid='{"stx":"url"}'>http://__TOC__</a></p>
!! end
!! test
http://===r:::https://b
{|
-!! html
+!! html/php
<p><a rel="nofollow" class="external free" href="http://===r:::https://b">http://===r:::https://b</a>
</p>
<table>
<tr><td></td></tr>
</table>
+!! html/parsoid
+<p><a rel="mw:ExtLink" href="http://===r:::https://b" class="external free" data-parsoid='{"stx":"url"}'>http://===r:::https://b</a></p>
+
+<table data-parsoid='{"autoInsertedEnd":true}'></table>
+!! end
+
+# The above 'Parser24' fuzz test exposed a tokenizer bug (T221384);
+# this is a minimized version of the above test to catch regressions.
+!! test
+Fuzz testing: Parser24 (minimized)
+!! options
+parsoid=wt2html
+!! wikitext
+{{<u {{{{[[Sx-->}}
+!! html/php+tidy
+<p>{{<u>}}
+</u></p>
+!! html/parsoid
+<p>{{<u data-parsoid='{"stx":"html","a":{"{{{{[[Sx--":null},"sa":{"{{{{[[Sx--":""},"autoInsertedEnd":true}'>}}</u></p>
!! end
## Remex doesn't account for fostered content.
<p><a rel="nofollow" class="external free" href="http://example.com">http://example.com</a> junk
</p>
!! html/parsoid
-<p><a rel="mw:ExtLink" class="external free" href="http://example.com" data-parsoid='{"stx":"url"}'>http://example.com</a> <span typeof="mw:Nowiki">junk</span></p>
+<p><a rel="mw:ExtLink" href="http://example.com" class="external free" data-parsoid='{"stx":"url"}'>http://example.com</a> <span typeof="mw:Nowiki">junk</span></p>
!! end
!!test
<p><a rel="nofollow" class="external free" href="http://example.com">http://example.com</a>junk
</p>
!! html/parsoid
-<p><a rel="mw:ExtLink" class="external free" href="http://example.com" data-parsoid='{"stx":"url"}'>http://example.com</a><span typeof="mw:Nowiki">junk</span></p>
+<p><a rel="mw:ExtLink" href="http://example.com" class="external free" data-parsoid='{"stx":"url"}'>http://example.com</a><span typeof="mw:Nowiki">junk</span></p>
!! end
!! test
!! html/php+tidy
<p><a rel="nofollow" class="external free" href="http://example.com">http://example.com</a></p><pre>junk</pre>
!! html/parsoid
-<p><a rel="mw:ExtLink" class="external free" href="http://example.com" data-parsoid='{"stx":"url"}'>http://example.com</a></p><pre typeof="mw:Extension/pre" about="#mwt2" data-mw='{"name":"pre","attrs":{},"body":{"extsrc":"junk"}}'>junk</pre>
+<p><a rel="mw:ExtLink" href="http://example.com" class="external free" data-parsoid='{"stx":"url"}'>http://example.com</a></p><pre typeof="mw:Extension/pre" about="#mwt2" data-mw='{"name":"pre","attrs":{},"body":{"extsrc":"junk"}}'>junk</pre>
!! end
!! test
<pre dir=" "></pre>
!! html/parsoid
<pre dir="
-" typeof="mw:Extension/pre" about="#mwt2"data-mw='{"name":"pre","attrs":{"dir":"\n"},"body":{"extsrc":""}}'></pre>
+" typeof="mw:Extension/pre" about="#mwt2" data-mw='{"name":"pre","attrs":{"dir":""},"body":{"extsrc":""}}'></pre>
!! end
!! test
!! html/php
<ul><li><a rel="nofollow" class="external free" href="irc://%0Aa">irc://%0Aa</a></li></ul>
!! html/parsoid
-<ul><li><a rel="mw:ExtLink" class="external free" href="irc://%0Aa" data-parsoid='{"stx":"url","a":{"href":"irc://%0Aa"},"sa":{"href":"irc://&#x0A;a"}}'>irc://%0Aa</a></li></ul>
+<ul><li><a rel="mw:ExtLink" href="irc://%0Aa" class="external free" data-parsoid='{"stx":"url","a":{"href":"irc://%0Aa"},"sa":{"href":"irc://&#x0A;a"}}'>irc://%0Aa</a></li></ul>
!! end
!! test
!! html/php
<ul><li><a rel="nofollow" class="external free" href="irc://%0Aa">irc://%0Aa</a></li></ul>
!! html/parsoid
-<ul><li><a rel="mw:ExtLink" class="external free" href="irc://%0Aa">irc://%0Aa</a></li></ul>
+<ul><li><a rel="mw:ExtLink" href="irc://%0Aa" class="external free">irc://%0Aa</a></li></ul>
!! end
# The PHP parser strips the empty tags out for giggles; parsoid doesn't.
<li class="gallerybox" style="width: 155px;"><div class="thumb" style="width: 150px; height: 150px;"><figure-inline typeof="mw:Error mw:Image" data-mw='{"errors":[{"key":"apierror-filedoesnotexist","message":"This image does not exist."}]}'><a href="./Special:FilePath/Image2.gif"><span resource="./File:Image2.gif" data-width="120" data-height="120">File:Image2.gif</span></a></figure-inline></div><div class="gallerytext"></div></li>
<li class="gallerybox" style="width: 155px;"><div class="thumb" style="width: 150px; height: 150px;"><figure-inline typeof="mw:Error mw:Image" data-mw='{"errors":[{"key":"apierror-filedoesnotexist","message":"This image does not exist."}]}'><a href="./Special:FilePath/Image3"><span resource="./File:Image3" data-width="120" data-height="120">File:Image3</span></a></figure-inline></div><div class="gallerytext"></div></li>
<li class="gallerybox" style="width: 155px;"><div class="thumb" style="width: 150px; height: 150px;"><figure-inline typeof="mw:Error mw:Image" data-mw='{"errors":[{"key":"apierror-filedoesnotexist","message":"This image does not exist."}]}'><a href="./Special:FilePath/Image4"><span resource="./File:Image4" data-width="300">File:Image4</span></a></figure-inline></div><div class="gallerytext"></div></li>
-<li class="gallerybox" style="width: 155px;"><div class="thumb" style="width: 150px; height: 150px;"><figure-inline typeof="mw:Error mw:Image" data-mw='{"errors":[{"key":"apierror-filedoesnotexist","message":"This image does not exist."}]}'><a href="./Special:FilePath/Image5.svg"><span resource="./File:Image5.svg" data-width="120" data-height="120">File:Image5.svg</span></a></figure-inline></div><div class="gallerytext"> <a rel="mw:ExtLink" class="external free" href="http://///////">http://///////</a></div></li>
+<li class="gallerybox" style="width: 155px;"><div class="thumb" style="width: 150px; height: 150px;"><figure-inline typeof="mw:Error mw:Image" data-mw='{"errors":[{"key":"apierror-filedoesnotexist","message":"This image does not exist."}]}'><a href="./Special:FilePath/Image5.svg"><span resource="./File:Image5.svg" data-width="120" data-height="120">File:Image5.svg</span></a></figure-inline></div><div class="gallerytext"> <a rel="mw:ExtLink" href="http://///////" class="external free">http://///////</a></div></li>
<li class="gallerybox" style="width: 155px;"><div class="thumb" style="width: 150px; height: 150px;"><figure-inline typeof="mw:Error mw:Image" data-mw='{"errors":[{"key":"apierror-filedoesnotexist","message":"This image does not exist."}]}'><a href="./Special:FilePath/*_image6"><span resource="./File:*_image6" data-width="120" data-height="120">File:* image6</span></a></figure-inline></div><div class="gallerytext"></div></li>
</ul>
!! end
</ul>
!! end
+!! test
+Gallery in nolines mode
+!! wikitext
+<gallery mode="nolines" showfilenames="yes" caption="No Lines!">
+File:Foobar.jpg|foo
+</gallery>
+!! html/php
+<ul class="gallery mw-gallery-nolines">
+ <li class='gallerycaption'>No Lines!</li>
+ <li class="gallerybox" style="width: 125px"><div style="width: 125px">
+ <div class="thumb" style="width: 120px;"><div style="margin:0px auto;"><a href="/wiki/File:Foobar.jpg" class="image"><img alt="" src="http://example.com/images/thumb/3/3a/Foobar.jpg/120px-Foobar.jpg" decoding="async" width="120" height="14" srcset="http://example.com/images/thumb/3/3a/Foobar.jpg/180px-Foobar.jpg 1.5x, http://example.com/images/thumb/3/3a/Foobar.jpg/240px-Foobar.jpg 2x" /></a></div></div>
+ <div class="gallerytext">
+<p>foo
+</p>
+ </div>
+ </div></li>
+</ul>
+!! html/parsoid
+<ul class="gallery mw-gallery-nolines" typeof="mw:Extension/gallery" about="#mwt3" data-mw='{"name":"gallery","attrs":{"mode":"nolines","showfilenames":"yes"},"body":{}}'>
+<li class="gallerycaption">No Lines!</li>
+<li class="gallerybox" style="width: 125px;"><div class="thumb" style="width: 120px;"><figure-inline typeof="mw:Image"><a href="./File:Foobar.jpg"><img resource="./File:Foobar.jpg" src="//example.com/images/thumb/3/3a/Foobar.jpg/120px-Foobar.jpg" data-file-width="1941" data-file-height="220" data-file-type="bitmap" height="14" width="120"/></a></figure-inline></div><div class="gallerytext">foo</div></li>
+</ul>
+!! end
+
!! test
Gallery in slideshow mode
!! wikitext
</ul>
!! html/parsoid
<ul class="gallery mw-gallery-packed" typeof="mw:Extension/gallery" about="#mwt3" data-parsoid='{"dsr":[0,50,23,10]}' data-mw='{"name":"gallery","attrs":{"mode":"packed"},"body":{}}'>
-<li class="gallerybox" style="width: 1061px;"><div class="thumb" style="width: 1059px;"><figure-inline typeof="mw:Image"><a href="./File:Foobar.jpg"><img resource="./File:Foobar.jpg" src="//example.com/images/thumb/3/3a/Foobar.jpg/1589px-Foobar.jpg" data-file-width="1941" data-file-height="220" data-file-type="bitmap" height="120" width="1059"/></a></figure-inline></div><div class="gallerytext"></div></li>
+<li class="gallerybox" style="width: 1061.3333333333333px;"><div class="thumb" style="width: 1059.3333333333333px;"><figure-inline typeof="mw:Image"><a href="./File:Foobar.jpg"><img resource="./File:Foobar.jpg" src="//example.com/images/thumb/3/3a/Foobar.jpg/1589px-Foobar.jpg" data-file-width="1941" data-file-height="220" data-file-type="bitmap" height="120" width="1060"/></a></figure-inline></div><div class="gallerytext"></div></li>
+</ul>
+!! end
+
+!! test
+Gallery in packed-overlay mode
+!! wikitext
+<gallery mode="packed-overlay" showfilenames="yes" caption="Packed Overlay!">
+File:Foobar.jpg|foo
+</gallery>
+!! html/php
+<ul class="gallery mw-gallery-packed-overlay">
+ <li class='gallerycaption'>Packed Overlay!</li>
+ <li class="gallerybox" style="width: 1061.3333333333px"><div style="width: 1061.3333333333px">
+ <div class="thumb" style="width: 1059.3333333333px;"><div style="margin:0px auto;"><a href="/wiki/File:Foobar.jpg" class="image"><img alt="" src="http://example.com/images/thumb/3/3a/Foobar.jpg/1589px-Foobar.jpg" decoding="async" width="1060" height="120" srcset="http://example.com/images/3/3a/Foobar.jpg 1.5x" /></a></div></div>
+ <div class="gallerytextwrapper" style="width: 1040px"><div class="gallerytext">
+<p>foo
+</p>
+ </div></div>
+ </div></li>
+</ul>
+!! html/parsoid
+<ul class="gallery mw-gallery-packed-overlay" typeof="mw:Extension/gallery" about="#mwt3" data-mw='{"name":"gallery","attrs":{"mode":"packed-overlay","showfilenames":"yes"},"body":{}}'>
+<li class="gallerycaption">Packed Overlay!</li>
+<li class="gallerybox" style="width: 1061.3333333333333px;"><div class="thumb" style="width: 1059.3333333333333px;"><figure-inline typeof="mw:Image"><a href="./File:Foobar.jpg"><img resource="./File:Foobar.jpg" src="//example.com/images/thumb/3/3a/Foobar.jpg/1589px-Foobar.jpg" data-file-width="1941" data-file-height="220" data-file-type="bitmap" height="120" width="1060"/></a></figure-inline></div><div class="gallerytextwrapper" style="width: 1040px;"><div class="gallerytext">foo</div></div></li>
+</ul>
+!! end
+
+!! test
+Gallery in packed-hover mode
+!! wikitext
+<gallery mode="packed-hover" showfilenames="yes" caption="Packed Hover!">
+File:Foobar.jpg|foo
+</gallery>
+!! html/php
+<ul class="gallery mw-gallery-packed-hover">
+ <li class='gallerycaption'>Packed Hover!</li>
+ <li class="gallerybox" style="width: 1061.3333333333px"><div style="width: 1061.3333333333px">
+ <div class="thumb" style="width: 1059.3333333333px;"><div style="margin:0px auto;"><a href="/wiki/File:Foobar.jpg" class="image"><img alt="" src="http://example.com/images/thumb/3/3a/Foobar.jpg/1589px-Foobar.jpg" decoding="async" width="1060" height="120" srcset="http://example.com/images/3/3a/Foobar.jpg 1.5x" /></a></div></div>
+ <div class="gallerytextwrapper" style="width: 1040px"><div class="gallerytext">
+<p>foo
+</p>
+ </div></div>
+ </div></li>
+</ul>
+!! html/parsoid
+<ul class="gallery mw-gallery-packed-hover" typeof="mw:Extension/gallery" about="#mwt3" data-mw='{"name":"gallery","attrs":{"mode":"packed-hover","showfilenames":"yes"},"body":{}}'>
+<li class="gallerycaption">Packed Hover!</li>
+<li class="gallerybox" style="width: 1061.3333333333333px;"><div class="thumb" style="width: 1059.3333333333333px;"><figure-inline typeof="mw:Image"><a href="./File:Foobar.jpg"><img resource="./File:Foobar.jpg" src="//example.com/images/thumb/3/3a/Foobar.jpg/1589px-Foobar.jpg" data-file-width="1941" data-file-height="220" data-file-type="bitmap" height="120" width="1060"/></a></figure-inline></div><div class="gallerytextwrapper" style="width: 1040px;"><div class="gallerytext">foo</div></div></li>
</ul>
!! end
# See: https://www.w3.org/TR/html5/syntax.html#character-references
# Note that U+000C (form feed) is not a valid XML character, so
# it is banned even though allowed in HTML5.
+# Note there are also weird legacy numeric entities which are mapped
+# elsewhere; see T113194
!! test
-Illegal character references (T106578)
+Illegal character references (T106578, T113194)
+!! options
+parsoid={ "modes": ["wt2html","html2html"], "normalizePhp": true }
!! wikitext
; Null: �
; FF: 
; CR: 
; Control (low): 
; Control (high):  Ÿ
+; Unsupported legacy: € ‚ ƒ – Ÿ
; Surrogate: ��
; This is an okay astral character: 💩
!! html+tidy
<dd>&#8;</dd>
<dt>Control (high)</dt>
<dd>&#x7F; &#x9F;</dd>
+<dt>Unsupported legacy</dt>
+<dd>&#128; &#130; &#131; &#150; &#159;</dd>
<dt>Surrogate</dt>
<dd>&#xD83D;&#xDCA9;</dd>
<dt>This is an okay astral character</dt>
<p><abbr>(fr)</abbr> <a href="/wiki/Special:BookSources/2753300917" class="internal mw-magiclink-isbn">ISBN 2753300917</a> <a rel="nofollow" class="external text" href="http://www.example.com">example.com</a>
</p>
!! html/parsoid
-<p><abbr data-parsoid='{"stx":"html"}'>(fr)</abbr> <a href="./Special:BookSources/2753300917" rel="mw:WikiLink" data-parsoid='{"stx":"magiclink"}'>ISBN 2753300917</a> <a rel="mw:ExtLink" class="external text" href="http://www.example.com">example.com</a></p>
+<p><abbr data-parsoid='{"stx":"html"}'>(fr)</abbr> <a href="./Special:BookSources/2753300917" rel="mw:WikiLink" data-parsoid='{"stx":"magiclink"}'>ISBN 2753300917</a> <a rel="mw:ExtLink" href="http://www.example.com" class="external text">example.com</a></p>
!! end
!! test
!! html/php
<div class="thumb tright"><div class="thumbinner" style="width:182px;"><a href="/wiki/File:Foobar.jpg" class="image"><img alt="" src="http://example.com/images/thumb/3/3a/Foobar.jpg/180px-Foobar.jpg" decoding="async" width="180" height="20" class="thumbimage" srcset="http://example.com/images/thumb/3/3a/Foobar.jpg/270px-Foobar.jpg 1.5x, http://example.com/images/thumb/3/3a/Foobar.jpg/360px-Foobar.jpg 2x" /></a> <div class="thumbcaption"><div class="magnify"><a href="/wiki/File:Foobar.jpg" class="internal" title="Enlarge"></a></div>An <a rel="nofollow" class="external text" href="http://test/?param1=%7Cleft%7C&param2=%7Cx">external</a> URL</div></div></div>
!! html/parsoid
-<figure class="mw-default-size" typeof="mw:Image/Thumb"><a href="./File:Foobar.jpg"><img resource="./File:Foobar.jpg" src="//example.com/images/thumb/3/3a/Foobar.jpg/220px-Foobar.jpg" data-file-width="1941" data-file-height="220" data-file-type="bitmap" height="25" width="220"/></a><figcaption>An <a rel="mw:ExtLink" class="external text" href="http://test/?param1=%7Cleft%7C&param2=%7Cx" data-parsoid='{"a":{"href":"http://test/?param1=%7Cleft%7C&param2=%7Cx"},"sa":{"href":"http://test/?param1=|left|&param2=|x"}}'>external</a> URL</figcaption></figure>
+<figure class="mw-default-size" typeof="mw:Image/Thumb"><a href="./File:Foobar.jpg"><img resource="./File:Foobar.jpg" src="//example.com/images/thumb/3/3a/Foobar.jpg/220px-Foobar.jpg" data-file-width="1941" data-file-height="220" data-file-type="bitmap" height="25" width="220"/></a><figcaption>An <a rel="mw:ExtLink" href="http://test/?param1=%7Cleft%7C&param2=%7Cx" class="external text" data-parsoid='{"a":{"href":"http://test/?param1=%7Cleft%7C&param2=%7Cx"},"sa":{"href":"http://test/?param1=|left|&param2=|x"}}'>external</a> URL</figcaption></figure>
!! end
!! test
<p>Nested: Hello Hong Kong!
</p>
!! html/parsoid
-<p>Nested: <span typeof="mw:LanguageVariant" data-parsoid='{"tSp":[7]}' data-mw-variant='{"twoway":[{"l":"zh-hans","t":"Hi <span typeof=\"mw:LanguageVariant\" data-mw-variant='{\"twoway\":[{\"l\":\"zh-cn\",\"t\":\"China\"},{\"l\":\"zh-sg\",\"t\":\"Singapore\"}]}' data-parsoid='{\"fl\":[],\"tSp\":[7],\"dsr\":[21,53,null,2]}'></span>"},{"l":"zh-hant","t":"Hello <span typeof=\"mw:LanguageVariant\" data-mw-variant='{\"twoway\":[{\"l\":\"zh-tw\",\"t\":\"Taiwan\"},{\"l\":\"zh-hk\",\"t\":\"H&lt;span typeof=\\\"mw:LanguageVariant\\\" data-mw-variant=&apos;{\\\"disabled\\\":{\\\"t\\\":\\\"ong\\\"}}&apos; data-parsoid=&apos;{\\\"fl\\\":[],\\\"dsr\\\":[90,97,null,2]}&apos;>&lt;/span> K&lt;span typeof=\\\"mw:LanguageVariant\\\" data-mw-variant=&apos;{\\\"disabled\\\":{\\\"t\\\":\\\"\\\"}}&apos; data-parsoid=&apos;{\\\"fl\\\":[],\\\"dsr\\\":[99,103,null,2]}&apos;>&lt;/span>ong\"}]}' data-parsoid='{\"fl\":[],\"tSp\":[7],\"dsr\":[68,109,null,2]}'></span>"}]}'></span>!</p>
+<p>Nested: <span typeof="mw:LanguageVariant" data-parsoid='{"tSp":[7]}' data-mw-variant='{"twoway":[{"l":"zh-hans","t":"Hi <span typeof=\"mw:LanguageVariant\" data-mw-variant='{\"twoway\":[{\"l\":\"zh-cn\",\"t\":\"China\"},{\"l\":\"zh-sg\",\"t\":\"Singapore\"}]}' data-parsoid='{\"fl\":[],\"tSp\":[7],\"dsr\":[21,53,2,2]}'></span>"},{"l":"zh-hant","t":"Hello <span typeof=\"mw:LanguageVariant\" data-mw-variant='{\"twoway\":[{\"l\":\"zh-tw\",\"t\":\"Taiwan\"},{\"l\":\"zh-hk\",\"t\":\"H&lt;span typeof=\\\"mw:LanguageVariant\\\" data-mw-variant=&apos;{\\\"disabled\\\":{\\\"t\\\":\\\"ong\\\"}}&apos; data-parsoid=&apos;{\\\"fl\\\":[],\\\"dsr\\\":[90,97,2,2]}&apos;>&lt;/span> K&lt;span typeof=\\\"mw:LanguageVariant\\\" data-mw-variant=&apos;{\\\"disabled\\\":{\\\"t\\\":\\\"\\\"}}&apos; data-parsoid=&apos;{\\\"fl\\\":[],\\\"dsr\\\":[99,103,2,2]}&apos;>&lt;/span>ong\"}]}' data-parsoid='{\"fl\":[],\"tSp\":[7],\"dsr\":[68,109,2,2]}'></span>"}]}'></span>!</p>
!! end
!! test
<p><span title="X">A</span>
</p>
!! html/parsoid
-<p><span typeof="mw:LanguageVariant" data-mw-variant='{"filter":{"l":["zh","zh-hans","zh-hant"],"t":"<span title=\"\" about=\"#mwt1\" typeof=\"mw:ExpandedAttrs\" data-parsoid='{\"stx\":\"html\",\"a\":{\"title\":\"\"},\"sa\":{\"title\":\"-{X}-\"},\"dsr\":[21,49,20,7]}' data-mw='{\"attribs\":[[{\"txt\":\"title\"},{\"html\":\"&lt;span typeof=\\\"mw:LanguageVariant\\\" data-mw-variant=&apos;{\\\"disabled\\\":{\\\"t\\\":\\\"X\\\"}}&apos; data-parsoid=&apos;{\\\"fl\\\":[],\\\"dsr\\\":[34,39,null,2]}&apos;>&lt;/span>\"}]]}'>A</span>"}}'></span></p>
+<p><span typeof="mw:LanguageVariant" data-mw-variant='{"filter":{"l":["zh","zh-hans","zh-hant"],"t":"<span title=\"\" about=\"#mwt1\" typeof=\"mw:ExpandedAttrs\" data-parsoid='{\"stx\":\"html\",\"a\":{\"title\":\"\"},\"sa\":{\"title\":\"-{X}-\"},\"dsr\":[21,49,20,7]}' data-mw='{\"attribs\":[[{\"txt\":\"title\"},{\"html\":\"&lt;span typeof=\\\"mw:LanguageVariant\\\" data-mw-variant=&apos;{\\\"disabled\\\":{\\\"t\\\":\\\"X\\\"}}&apos; data-parsoid=&apos;{\\\"fl\\\":[],\\\"dsr\\\":[34,39,2,2]}&apos;>&lt;/span>\"}]]}'>A</span>"}}'></span></p>
!! end
!! test
<p><span title="X">A</span>
</p>
!! html/parsoid
-<p><span typeof="mw:LanguageVariant" data-mw-variant='{"disabled":{"t":"<span title=\"\" about=\"#mwt1\" typeof=\"mw:ExpandedAttrs\" data-parsoid='{\"stx\":\"html\",\"a\":{\"title\":\"\"},\"sa\":{\"title\":\"-{X}-\"},\"dsr\":[2,30,20,7]}' data-mw='{\"attribs\":[[{\"txt\":\"title\"},{\"html\":\"&lt;span typeof=\\\"mw:LanguageVariant\\\" data-mw-variant=&apos;{\\\"disabled\\\":{\\\"t\\\":\\\"X\\\"}}&apos; data-parsoid=&apos;{\\\"fl\\\":[],\\\"dsr\\\":[15,20,null,2]}&apos;>&lt;/span>\"}]]}'>A</span>"}}'></span></p>
+<p><span typeof="mw:LanguageVariant" data-mw-variant='{"disabled":{"t":"<span title=\"\" about=\"#mwt1\" typeof=\"mw:ExpandedAttrs\" data-parsoid='{\"stx\":\"html\",\"a\":{\"title\":\"\"},\"sa\":{\"title\":\"-{X}-\"},\"dsr\":[2,30,20,7]}' data-mw='{\"attribs\":[[{\"txt\":\"title\"},{\"html\":\"&lt;span typeof=\\\"mw:LanguageVariant\\\" data-mw-variant=&apos;{\\\"disabled\\\":{\\\"t\\\":\\\"X\\\"}}&apos; data-parsoid=&apos;{\\\"fl\\\":[],\\\"dsr\\\":[15,20,2,2]}&apos;>&lt;/span>\"}]]}'>A</span>"}}'></span></p>
!! end
# Parsoid and PHP disagree on how to parse this example: Parsoid
<a rel="nofollow" class="external text" href="//www.google.com">www.гоогле.цом</a>
</p>
!! html/parsoid
-<p><a rel="mw:ExtLink" class="external free" href="http://www.google.com">http://www.google.com</a>
-<a rel="mw:ExtLink" class="external free" href="gopher://www.google.com">gopher://www.google.com</a>
-<a rel="mw:ExtLink" class="external text" href="http://www.google.com">http://www.google.com</a>
-<a rel="mw:ExtLink" class="external text" href="gopher://www.google.com">gopher://www.google.com</a>
-<a rel="mw:ExtLink" class="external text" href="https://www.google.com">irc://www.google.com</a>
-<a rel="mw:ExtLink" class="external text" href="ftp://www.google.com">www.google.com/ftp://dir</a>
-<a rel="mw:ExtLink" class="external text" href="//www.google.com">www.google.com</a></p>
+<p><a rel="mw:ExtLink" href="http://www.google.com" class="external free">http://www.google.com</a>
+<a rel="mw:ExtLink" href="gopher://www.google.com" class="external free">gopher://www.google.com</a>
+<a rel="mw:ExtLink" href="http://www.google.com" class="external text">http://www.google.com</a>
+<a rel="mw:ExtLink" href="gopher://www.google.com" class="external text">gopher://www.google.com</a>
+<a rel="mw:ExtLink" href="https://www.google.com" class="external text">irc://www.google.com</a>
+<a rel="mw:ExtLink" href="ftp://www.google.com" class="external text">www.google.com/ftp://dir</a>
+<a rel="mw:ExtLink" href="//www.google.com" class="external text">www.google.com</a></p>
!! end
!! test
<p><a rel="nofollow" class="external autonumber" href="http://en.wikipedia.org/">[۱]</a>
</p>
!! html/parsoid
-<p><a rel="mw:ExtLink" class="external autonumber" href="http://en.wikipedia.org/"></a></p>
+<p><a rel="mw:ExtLink" href="http://en.wikipedia.org/" class="external autonumber"></a></p>
!! end
!! test
<p><a rel="nofollow" class="external autonumber" href="HttP://MediaWiki.Org/">[1]</a>
</p>
!! html/parsoid
-<p><a rel="mw:ExtLink" class="external autonumber" href="HttP://MediaWiki.Org/"></a></p>
+<p><a rel="mw:ExtLink" href="HttP://MediaWiki.Org/" class="external autonumber"></a></p>
!! end
!!test
<p><a rel="nofollow" class="external free" href="HttP://MediaWiki.Org/">HttP://MediaWiki.Org/</a>
</p>
!! html/parsoid
-<p><a rel="mw:ExtLink" class="external free" href="HttP://MediaWiki.Org/">HttP://MediaWiki.Org/</a></p>
+<p><a rel="mw:ExtLink" href="HttP://MediaWiki.Org/" class="external free">HttP://MediaWiki.Org/</a></p>
!! end
!!test
<b><small><figure class="mw-halign-right" typeof="mw:Image"><a href="./File:Foobar.jpg"><img resource="./File:Foobar.jpg" src="//example.com/images/thumb/3/3a/Foobar.jpg/300px-Foobar.jpg" data-file-width="1941" data-file-height="220" data-file-type="bitmap" height="34" width="300"/></a><figcaption></figcaption></figure></small></b>
!! end
+## Just a regression test
+!! test
+Wikilink with only closing tag in target
+!! options
+parsoid=wt2html
+!! wikitext
+[[Test|</span>]]
+!! html/parsoid
+<p><a rel="mw:WikiLink" href="./Test" title="Test"></a></p>
+!! end
+
#### ----------------------------------------------------------------
#### Parsoid-only testing of Parsoid's impl of LST
#### Not implemented yet, see
!!end
!! test
-Don't block XML namespace declaration
+T72867: Don't block XML namespace declaration
!! wikitext
<span xmlns:dct="http://purl.org/dc/terms/" property="dct:title">MediaWiki</span>
!! html/php
[[es:Toxine_bactérienne]]
!! end
+# Regression test for T219023
+!! test
+Emit simple non-piped link where possible
+!! options
+parsoid=html2wt
+!! html/parsoid
+<a rel='mw:WikiLink' href='./VisualEditor'>VisualEditor</a>
+<a rel='mw:WikiLink' href='./VisualEditor'>visualEditor</a>
+<a rel='mw:WikiLink' href='./VisualEditor link'>VisualEditor link</a>
+<a rel='mw:WikiLink' href='./VisualEditor link'>visualEditor link</a>
+!! wikitext
+[[VisualEditor]]
+[[visualEditor]]
+[[VisualEditor link]]
+[[visualEditor link]]
+!! end
+
!! test
Image: Modifying size of an image (1)
!! options
!! wikitext
x<nowiki/>http://cscott.net<nowiki/>x
!! html/parsoid
-<p>x<a rel="mw:ExtLink" class="external free" href="http://cscott.net">http://cscott.net</a>x</p>
+<p>x<a rel="mw:ExtLink" href="http://cscott.net" class="external free">http://cscott.net</a>x</p>
!! end
# this is the "easy" test because it leaves in place all the
http://example.com <nowiki>http://example.com</nowiki> is not a link.
!! end
+!! test
+WTS of an autolink surrounded by square brackets (T220018)
+!! options
+parsoid=html2wt
+!! html/parsoid
+<p>[<a rel="mw:ExtLink" href="http://example.com">http://example.com</a>]</p>
+!! wikitext
+<nowiki>[</nowiki>http://example.com]
+!! end
+
+!! test
+WTS of edited autolink surrounded by square brackets (T220018)
+!! options
+parsoid={
+ "modes": ["wt2wt"],
+ "changes": [
+ [ "a", "before", "[" ],
+ [ "a", "after", "]" ]
+ ]
+}
+!! wikitext
+http://example.com
+!! wikitext/edited
+<nowiki>[</nowiki>http://example.com]
+!! end
+
+!! test
+WTS of an external link surrounded by square brackets (T220018)
+!! options
+parsoid=html2wt
+!! html/parsoid
+<p>[<a rel="mw:ExtLink" href="http://example.com">foo</a>]</p>
+!! wikitext
+<nowiki>[</nowiki>[http://example.com foo]]
+!! end
+
+!! test
+WTS of edited external link surrounded by square brackets (T220018)
+!! options
+parsoid={
+ "modes": ["wt2wt"],
+ "changes": [
+ [ "a", "before", "[" ],
+ [ "a", "after", "]" ]
+ ]
+}
+!! wikitext
+[http://example.com foo]
+!! wikitext/edited
+<nowiki>[</nowiki>[http://example.com foo]]
+!! end
+
!! test
Magic links inside links (not autolinked)
!! wikitext
<a rel="mw:WikiLink" href="./Foo" title="Foo">PMID 1234</a>
<a rel="mw:WikiLink" href="./Foo" title="Foo">ISBN 123456789x</a></p>
-<p><a rel="mw:ExtLink" class="external text" href="http://foo.com">http://example.com</a>
-<a rel="mw:ExtLink" class="external text" href="http://foo.com">RFC 1234</a>
-<a rel="mw:ExtLink" class="external text" href="http://foo.com">PMID 1234</a>
-<a rel="mw:ExtLink" class="external text" href="http://foo.com">ISBN 123456789x</a></p>
+<p><a rel="mw:ExtLink" href="http://foo.com" class="external text">http://example.com</a>
+<a rel="mw:ExtLink" href="http://foo.com" class="external text">RFC 1234</a>
+<a rel="mw:ExtLink" href="http://foo.com" class="external text">PMID 1234</a>
+<a rel="mw:ExtLink" href="http://foo.com" class="external text">ISBN 123456789x</a></p>
!! end
!! test
<div class="thumb tright"><div class="thumbinner" style="width:182px;"><a href="/wiki/File:Foobar.jpg" class="image"><img alt="" src="http://example.com/images/thumb/3/3a/Foobar.jpg/180px-Foobar.jpg" decoding="async" width="180" height="20" class="thumbimage" srcset="http://example.com/images/thumb/3/3a/Foobar.jpg/270px-Foobar.jpg 1.5x, http://example.com/images/thumb/3/3a/Foobar.jpg/360px-Foobar.jpg 2x" /></a> <div class="thumbcaption"><div class="magnify"><a href="/wiki/File:Foobar.jpg" class="internal" title="Enlarge"></a></div><a class="external mw-magiclink-pmid" rel="nofollow" href="//www.ncbi.nlm.nih.gov/pubmed/1234?dopt=Abstract">PMID 1234</a></div></div></div>
<div class="thumb tright"><div class="thumbinner" style="width:182px;"><a href="/wiki/File:Foobar.jpg" class="image"><img alt="" src="http://example.com/images/thumb/3/3a/Foobar.jpg/180px-Foobar.jpg" decoding="async" width="180" height="20" class="thumbimage" srcset="http://example.com/images/thumb/3/3a/Foobar.jpg/270px-Foobar.jpg 1.5x, http://example.com/images/thumb/3/3a/Foobar.jpg/360px-Foobar.jpg 2x" /></a> <div class="thumbcaption"><div class="magnify"><a href="/wiki/File:Foobar.jpg" class="internal" title="Enlarge"></a></div><a href="/wiki/Special:BookSources/123456789X" class="internal mw-magiclink-isbn">ISBN 123456789x</a></div></div></div>
!! html/parsoid
-<figure class="mw-default-size" typeof="mw:Image/Thumb"><a href="./File:Foobar.jpg"><img resource="./File:Foobar.jpg" src="//example.com/images/thumb/3/3a/Foobar.jpg/220px-Foobar.jpg" data-file-width="1941" data-file-height="220" data-file-type="bitmap" height="25" width="220"/></a><figcaption><a rel="mw:ExtLink" class="external free" href="http://example.com">http://example.com</a></figcaption></figure>
+<figure class="mw-default-size" typeof="mw:Image/Thumb"><a href="./File:Foobar.jpg"><img resource="./File:Foobar.jpg" src="//example.com/images/thumb/3/3a/Foobar.jpg/220px-Foobar.jpg" data-file-width="1941" data-file-height="220" data-file-type="bitmap" height="25" width="220"/></a><figcaption><a rel="mw:ExtLink" href="http://example.com" class="external free">http://example.com</a></figcaption></figure>
<figure class="mw-default-size" typeof="mw:Image/Thumb"><a href="./File:Foobar.jpg"><img resource="./File:Foobar.jpg" src="//example.com/images/thumb/3/3a/Foobar.jpg/220px-Foobar.jpg" data-file-width="1941" data-file-height="220" data-file-type="bitmap" height="25" width="220"/></a><figcaption><a href="https://tools.ietf.org/html/rfc1234" rel="mw:ExtLink" class="external mw-magiclink">RFC 1234</a></figcaption></figure>
<figure class="mw-default-size" typeof="mw:Image/Thumb"><a href="./File:Foobar.jpg"><img resource="./File:Foobar.jpg" src="//example.com/images/thumb/3/3a/Foobar.jpg/220px-Foobar.jpg" data-file-width="1941" data-file-height="220" data-file-type="bitmap" height="25" width="220"/></a><figcaption><a href="//www.ncbi.nlm.nih.gov/pubmed/1234?dopt=Abstract" rel="mw:ExtLink" class="external mw-magiclink">PMID 1234</a></figcaption></figure>
<figure class="mw-default-size" typeof="mw:Image/Thumb"><a href="./File:Foobar.jpg"><img resource="./File:Foobar.jpg" src="//example.com/images/thumb/3/3a/Foobar.jpg/220px-Foobar.jpg" data-file-width="1941" data-file-height="220" data-file-type="bitmap" height="25" width="220"/></a><figcaption><a href="./Special:BookSources/123456789X" rel="mw:WikiLink">ISBN 123456789x</a></figcaption></figure>
!! wikitext
{{echo|hi}}[http://example.com [[ho]]]
!! html/parsoid
-<p><span about="#mwt1" typeof="mw:Transclusion" data-mw='{"parts":[{"template":{"target":{"wt":"echo","href":"./Template:Echo"},"params":{"1":{"wt":"hi"}},"i":0}}]}'>hi</span><a rel="mw:ExtLink" class="external autonumber" href="http://example.com"></a><a rel="mw:WikiLink" href="./Ho" title="Ho" data-parsoid='{"misnested":true}'>ho</a></p>
+<p><span about="#mwt1" typeof="mw:Transclusion" data-mw='{"parts":[{"template":{"target":{"wt":"echo","href":"./Template:Echo"},"params":{"1":{"wt":"hi"}},"i":0}}]}'>hi</span><a rel="mw:ExtLink" href="http://example.com" class="external autonumber"></a><a rel="mw:WikiLink" href="./Ho" title="Ho" data-parsoid='{"misnested":true}'>ho</a></p>
!! end
!! test
!! options
parsoid=html2wt
!! html/parsoid
-<span about="#mwt1" typeof="mw:Transclusion" data-parsoid='{"pi":[[{"k":"1"}]]}' data-mw='{"parts":[{"template":{"target":{"wt":"echo","href":"./Template:Echo"},"params":{"1":{"wt":"a"}},"i":0}}]}'>a</span><table about="#mwt2" typeof="mw:Transclusion mw:ExpandedAttrs" data-parsoid='{"a":{"{{echo|c\n{{!}}d\n}}":null},"sa":{"{{echo|c\n{{!}}d\n}}":""},"firstWikitextNode":"table","pi":[[{"k":"1"}]]}' data-mw='{"parts":["{|",{"template":{"target":{"wt":"echo","href":"./Template:Echo"},"params":{"1":{"wt":"c\n{{!}}d\n"}},"i":0}},"\n|}"]}'>
+<span about="#mwt1" typeof="mw:Transclusion" data-parsoid='{"pi":[[{"k":"1"}]]}' data-mw='{"parts":[{"template":{"target":{"wt":"echo","href":"./Template:Echo"},"params":{"1":{"wt":"a"}},"i":0}}]}'>a</span><table about="#mwt2" typeof="mw:Transclusion mw:ExpandedAttrs" data-parsoid='{"a":{"{{echo|c\n{{!}}d\n}}":null},"sa":{"{{echo|c\n{{!}}d\n}}":""},"firstWikitextNode":"TABLE","pi":[[{"k":"1"}]]}' data-mw='{"parts":["{|",{"template":{"target":{"wt":"echo","href":"./Template:Echo"},"params":{"1":{"wt":"c\n{{!}}d\n"}},"i":0}},"\n|}"]}'>
<tbody><tr><td>d
</td></tr>
</tbody></table>
</p>
<a rel="nofollow" class="external text" href="http://www.google.com"></a><div class="thumb tright"><a rel="nofollow" class="external text" href="http://www.google.com"></a><div class="thumbinner" style="width:182px;"><a rel="nofollow" class="external text" href="http://www.google.com"></a><a href="/wiki/File:Foobar.jpg" class="image"><img alt="" src="http://example.com/images/thumb/3/3a/Foobar.jpg/180px-Foobar.jpg" decoding="async" width="180" height="20" class="thumbimage" srcset="http://example.com/images/thumb/3/3a/Foobar.jpg/270px-Foobar.jpg 1.5x, http://example.com/images/thumb/3/3a/Foobar.jpg/360px-Foobar.jpg 2x" /></a> <div class="thumbcaption"><div class="magnify"><a href="/wiki/File:Foobar.jpg" class="internal" title="Enlarge"></a></div>123</div></div></div>
!! html/parsoid
-<p><a rel="mw:ExtLink" class="external text" href="http://www.google.com" data-parsoid='{"targetOff":23,"contentOffsets":[23,46]}'><figure-inline class="mw-default-size" typeof="mw:Image" data-parsoid='{"optList":[{"ck":"caption","ak":"123"}]}' data-mw='{"caption":"123"}'></figure-inline></a><a href="./File:Foobar.jpg" data-parsoid='{"misnested":true}'><img resource="./File:Foobar.jpg" src="//example.com/images/3/3a/Foobar.jpg" data-file-width="1941" data-file-height="220" data-file-type="bitmap" height="220" width="1941" data-parsoid='{"a":{"resource":"./File:Foobar.jpg","height":"220","width":"1941"},"sa":{"resource":"File:Foobar.jpg"},"misnested":true}'/></a></p>
+<p><a rel="mw:ExtLink" href="http://www.google.com" class="external text" data-parsoid='{"targetOff":23,"contentOffsets":[23,46]}'><figure-inline class="mw-default-size" typeof="mw:Image" data-parsoid='{"optList":[{"ck":"caption","ak":"123"}]}' data-mw='{"caption":"123"}'></figure-inline></a><a href="./File:Foobar.jpg" data-parsoid='{"misnested":true}'><img resource="./File:Foobar.jpg" src="//example.com/images/3/3a/Foobar.jpg" data-file-width="1941" data-file-height="220" data-file-type="bitmap" height="220" width="1941" data-parsoid='{"a":{"resource":"./File:Foobar.jpg","height":"220","width":"1941"},"sa":{"resource":"File:Foobar.jpg"},"misnested":true}'/></a></p>
-<a rel="mw:ExtLink" class="external autonumber" href="http://www.google.com" data-parsoid='{"targetOff":72,"contentOffsets":[72,101]}'></a><figure class="mw-default-size" typeof="mw:Image/Thumb" data-parsoid='{"optList":[{"ck":"thumbnail","ak":"thumb"},{"ck":"caption","ak":"123"}]}'><a rel="mw:ExtLink" class="external autonumber" href="http://www.google.com" data-parsoid='{"targetOff":72,"contentOffsets":[72,101]}'></a><a href="./File:Foobar.jpg" data-parsoid='{"misnested":true}'><img resource="./File:Foobar.jpg" src="//example.com/images/thumb/3/3a/Foobar.jpg/220px-Foobar.jpg" data-file-width="1941" data-file-height="220" data-file-type="bitmap" height="25" width="220" data-parsoid='{"a":{"resource":"./File:Foobar.jpg","height":"25","width":"220"},"sa":{"resource":"File:Foobar.jpg"},"misnested":true}'/></a><figcaption data-parsoid='{"misnested":true}'>123</figcaption></figure>
+<a rel="mw:ExtLink" href="http://www.google.com" class="external autonumber" data-parsoid='{"targetOff":72,"contentOffsets":[72,101]}'></a><figure class="mw-default-size" typeof="mw:Image/Thumb" data-parsoid='{"optList":[{"ck":"thumbnail","ak":"thumb"},{"ck":"caption","ak":"123"}]}'><a rel="mw:ExtLink" href="http://www.google.com" class="external autonumber" data-parsoid='{"targetOff":72,"contentOffsets":[72,101]}'></a><a href="./File:Foobar.jpg" data-parsoid='{"misnested":true}'><img resource="./File:Foobar.jpg" src="//example.com/images/thumb/3/3a/Foobar.jpg/220px-Foobar.jpg" data-file-width="1941" data-file-height="220" data-file-type="bitmap" height="25" width="220" data-parsoid='{"a":{"resource":"./File:Foobar.jpg","height":"25","width":"220"},"sa":{"resource":"File:Foobar.jpg"},"misnested":true}'/></a><figcaption data-parsoid='{"misnested":true}'>123</figcaption></figure>
!! end
# --------------------------------------------
{{echo|foo}}
!! end
+!! test
+Only html p-tag is strong indent pre suppressing
+!! options
+parsoid=html2wt
+!! html/parsoid
+<p>test2<span>
+ test3
+</span></p>
+!! wikitext
+test2<span>
+<nowiki> </nowiki>test3
+</span>
+!! end
+
# -----------------------------------------------------------------
# End of section for Parsoid-only html2wt tests for serialization
# of new content
<a rel="nofollow" class="external text" href="http://example.com/">link <span title="title with [brackets]">span</span></a>
</p>
!! html/parsoid
-<p><a rel="mw:ExtLink" class="external text" href="http://example.com/">link <span title="title with [brackets]">span</span></a>
-<a rel="mw:ExtLink" class="external text" href="http://example.com/">link <span title="title with [brackets]" data-parsoid='{"stx":"html","a":{"title":"title with [brackets]"},"sa":{"title":"title with &#91;brackets&#93;"}}'>span</span></a></p>
+<p><a rel="mw:ExtLink" href="http://example.com/" class="external text">link <span title="title with [brackets]">span</span></a>
+<a rel="mw:ExtLink" href="http://example.com/" class="external text">link <span title="title with [brackets]" data-parsoid='{"stx":"html","a":{"title":"title with [brackets]"},"sa":{"title":"title with &#91;brackets&#93;"}}'>span</span></a></p>
!! end
!! test
*foo
footer
!! end
+
+!! test
+Ensure disambiguation links are marked properly
+!! options
+parsoid=wt2html
+!! wikitext
+[[Disambiguation]]
+!! html/parsoid
+<p><a rel="mw:WikiLink" href="./Disambiguation" title="Disambiguation" class="mw-disambig">Disambiguation</a></p>
+!! end
use Wikimedia\Rdbms\IMaintainableDatabase;
use Wikimedia\Rdbms\Database;
use Wikimedia\TestingAccessWrapper;
+use Wikimedia\Timestamp\ConvertibleTimestamp;
/**
* @since 1.18
global $IP;
parent::setUpBeforeClass();
if ( !file_exists( "$IP/LocalSettings.php" ) ) {
- echo 'A working MediaWiki installation with a configured LocalSettings.php file is'
- . ' required for tests that extend ' . self::class;
+ echo "File \"$IP/LocalSettings.php\" could not be found. "
+ . "Test case " . static::class . " extends " . self::class . " "
+ . "which requires a working MediaWiki installation.\n"
+ . ( new RuntimeException() )->getTraceAsString();
die();
}
self::initializeForStandardPhpunitEntrypointIfNeeded();
$wgRequest = new FauxRequest();
MediaWiki\Session\SessionManager::resetCache();
- Language::clearCaches();
}
public function run( PHPUnit_Framework_TestResult $result = null ) {
$this->tmpFiles = array_merge( $this->tmpFiles, (array)$files );
}
- // @todo Make const when we no longer support HHVM (T192166)
- private static $namespaceAffectingSettings = [
- 'wgAllowImageMoving',
- 'wgCanonicalNamespaceNames',
- 'wgCapitalLinkOverrides',
- 'wgCapitalLinks',
- 'wgContentNamespaces',
- 'wgExtensionMessagesFiles',
- 'wgExtensionNamespaces',
- 'wgExtraNamespaces',
- 'wgExtraSignatureNamespaces',
- 'wgNamespaceContentModels',
- 'wgNamespaceProtection',
- 'wgNamespacesWithSubpages',
- 'wgNonincludableNamespaces',
- 'wgRestrictionLevels',
- ];
+ private static function formatErrorLevel( $errorLevel ) {
+ switch ( gettype( $errorLevel ) ) {
+ case 'integer':
+ return '0x' . strtoupper( dechex( $errorLevel ) );
+ case 'NULL':
+ return 'null';
+ default:
+ throw new MWException( 'Unexpected error level type ' . gettype( $errorLevel ) );
+ }
+ }
protected function tearDown() {
global $wgRequest, $wgSQLMode;
foreach ( $this->iniSettings as $name => $value ) {
ini_set( $name, $value );
}
- if (
- array_intersect( self::$namespaceAffectingSettings, array_keys( $this->mwGlobals ) ) ||
- array_intersect( self::$namespaceAffectingSettings, $this->mwGlobalsToUnset )
- ) {
- $this->resetNamespaces();
- }
$this->mwGlobals = [];
$this->mwGlobalsToUnset = [];
$this->restoreLoggers();
if ( $phpErrorLevel !== $this->phpErrorLevel ) {
ini_set( 'error_reporting', $this->phpErrorLevel );
- $oldHex = strtoupper( dechex( $this->phpErrorLevel ) );
- $newHex = strtoupper( dechex( $phpErrorLevel ) );
+ $oldVal = self::formatErrorLevel( $this->phpErrorLevel );
+ $newVal = self::formatErrorLevel( $phpErrorLevel );
$message = "PHP error_reporting setting was left dirty: "
- . "was 0x$oldHex before test, 0x$newHex after test!";
+ . "was $oldVal before test, $newVal after test!";
$this->fail( $message );
}
+ // If anything faked the time, reset it
+ ConvertibleTimestamp::setFakeTime( false );
+
parent::tearDown();
}
);
if ( $name === 'ContentLanguage' ) {
- $this->doSetMwGlobals( [ 'wgContLang' => $this->localServices->getContentLanguage() ] );
+ $this->setMwGlobals( [ 'wgContLang' => $this->localServices->getContentLanguage() ] );
}
}
* The key is added to the array of globals that will be reset afterwards
* in the tearDown().
*
- * It may be necessary to call resetServices() to allow any changed configuration variables
- * to take effect on services that get initialized based on these variables.
- *
* @par Example
* @code
* protected function setUp() {
* @param mixed|null $value Value to set the global to (ignored
* if an array is given as first argument).
*
- * @note To allow changes to global variables to take effect on global service instances,
- * call resetServices().
+ * @note This will call resetServices().
*
* @since 1.21
*/
$pairs = [ $pairs => $value ];
}
- if ( isset( $pairs['wgContLang'] ) ) {
- throw new MWException(
- 'No setting $wgContLang, use setContentLang() or setService( \'ContentLanguage\' )'
- );
- }
-
- $this->doSetMwGlobals( $pairs, $value );
- }
-
- /**
- * An internal method that allows setService() to set globals that tests are not supposed to
- * touch.
- */
- private function doSetMwGlobals( $pairs, $value = null ) {
$this->doStashMwGlobals( array_keys( $pairs ) );
foreach ( $pairs as $key => $value ) {
$GLOBALS[$key] = $value;
}
- if ( array_intersect( self::$namespaceAffectingSettings, array_keys( $pairs ) ) ) {
- $this->resetNamespaces();
- }
+ $this->resetServices();
}
/**
ini_set( $name, $value );
}
- /**
- * Must be called whenever namespaces are changed, e.g., $wgExtraNamespaces is altered.
- * Otherwise old namespace data will lurk and cause bugs.
- */
- private function resetNamespaces() {
- if ( !$this->localServices ) {
- throw new Exception( __METHOD__ . ' must be called after MediaWikiTestCase::run()' );
- }
-
- if ( $this->localServices !== MediaWikiServices::getInstance() ) {
- throw new Exception( __METHOD__ . ' will not work because the global MediaWikiServices '
- . 'instance has been replaced by test code.' );
- }
-
- Language::clearCaches();
- }
-
/**
* Check if we can back up a value by performing a shallow copy.
* Values which fail this test are copied recursively.
* Useful for setting some entries in a configuration array, instead of
* setting the entire array.
*
- * It may be necessary to call resetServices() to allow any changed configuration variables
- * to take effect on services that get initialized based on these variables.
- *
* @param string $name The name of the global, as in wgFooBar
* @param array $values The array containing the entries to set in that global
*
* @throws MWException If the designated global is not an array.
*
- * @note To allow changes to global variables to take effect on global service instances,
- * call resetServices().
+ * @note This will call resetServices().
*
* @since 1.21
*/
}
self::resetGlobalParser();
+ Language::clearCaches();
}
/**
*/
public function setContentLang( $lang ) {
if ( $lang instanceof Language ) {
- $this->setMwGlobals( 'wgLanguageCode', $lang->getCode() );
// Set to the exact object requested
$this->setService( 'ContentLanguage', $lang );
+ $this->setMwGlobals( 'wgLanguageCode', $lang->getCode() );
} else {
- $this->setMwGlobals( 'wgLanguageCode', $lang );
- // Let the service handler make up the object. Avoid calling setService(), because if
- // we do, overrideMwServices() will complain if it's called later on.
- $services = MediaWikiServices::getInstance();
- $services->resetServiceForTesting( 'ContentLanguage' );
- $this->doSetMwGlobals( [ 'wgContLang' => $services->getContentLanguage() ] );
+ $this->setMwGlobals( [
+ 'wgLanguageCode' => $lang,
+ 'wgContLang' => Language::factory( $lang ),
+ ] );
}
}
* or three values to set a single permission, like
* $this->setGroupPermissions( '*', 'read', false );
*
+ * @note This will call resetServices().
+ *
* @since 1.31
* @param array|string $newPerms Either an array of permissions to change,
* in which case the next two parameters are ignored; or a single string
}
$this->setMwGlobals( 'wgGroupPermissions', $newPermissions );
-
- // Reset services so they pick up the new permissions.
- // Resetting just PermissionManager is not sufficient, since other services may
- // have the old instance of PermissionManager injected.
- $this->resetServices();
}
/**
if ( !isset( $db->_originalTablePrefix ) ) {
$oldPrefix = $db->tablePrefix();
-
if ( $oldPrefix === $prefix ) {
// table already has the correct prefix, but presumably no cloned tables
$oldPrefix = self::$oldTablePrefix;
$tablesCloned = self::listTables( $db );
$dbClone = new CloneDatabase( $db, $tablesCloned, $prefix, $oldPrefix );
$dbClone->useTemporaryTables( self::$useTemporaryTables );
-
$dbClone->cloneTableStructure();
$db->tablePrefix( $prefix );
$db->_originalTablePrefix = $oldPrefix;
+
+ $lb = MediaWikiServices::getInstance()->getDBLoadBalancer();
+ $lb->setTempTablesOnlyMode( self::$useTemporaryTables, $lb->getLocalDomainID() );
}
return true;
$dbClone = new CloneDatabase( $db, $tables, $db->tablePrefix(), $db->_originalTablePrefix );
$dbClone->useTemporaryTables( self::$useTemporaryTables );
-
$dbClone->cloneTableStructure();
+
+ $lb = MediaWikiServices::getInstance()->getDBLoadBalancer();
+ $lb->setTempTablesOnlyMode( self::$useTemporaryTables, $lb->getLocalDomainID() );
}
/**
/**
* Create a temporary hook handler which will be reset by tearDown.
* This replaces other handlers for the same hook.
+ *
+ * @note This will call resetServices().
+ *
* @param string $hookName Hook name
* @param mixed $handler Value suitable for a hook handler
* @since 1.28
...array_map( [ $this, 'matches' ], $values )
) );
}
+
+ /**
+ * Return a PHPUnit mock that is expected to never have any methods called on it.
+ *
+ * @param string $type
+ * @return object
+ */
+ protected function createNoOpMock( $type ) {
+ $mock = $this->createMock( $type );
+ $mock->expects( $this->never() )->method( $this->anythingBut( '__destruct' ) );
+ return $mock;
+ }
}
use MediaWikiCoversValidator;
use MediaWikiTestCaseTrait;
- private $unitGlobals = [];
+ private static $originalGlobals;
+ private static $unitGlobals;
- protected function setUp() {
- parent::setUp();
- $reflection = new ReflectionClass( $this );
+ public static function setUpBeforeClass() {
+ parent::setUpBeforeClass();
+
+ $reflection = new ReflectionClass( static::class );
$dirSeparator = DIRECTORY_SEPARATOR;
- if ( strpos( $reflection->getFilename(), "${dirSeparator}unit${dirSeparator}" ) === false ) {
- $this->fail( 'This unit test needs to be in "tests/phpunit/unit"!' );
+ if ( stripos( $reflection->getFilename(), "${dirSeparator}unit${dirSeparator}" ) === false ) {
+ self::fail( 'This unit test needs to be in "tests/phpunit/unit"!' );
+ }
+
+ if ( defined( 'HHVM_VERSION' ) ) {
+ // There are a number of issues we encountered in trying to make this
+ // work on HHVM. Specifically, once an MediaWikiIntegrationTestCase executes
+ // before us, the original globals go missing. This might have to do with
+ // one of the non-unit tests passing GLOBALS somewhere and causing HHVM
+ // to get confused somehow.
+ return;
}
- $this->unitGlobals = $GLOBALS;
- unset( $GLOBALS );
- $GLOBALS = [];
- // Add back the minimal set of globals needed for unit tests to run for core +
- // extensions/skins.
- foreach ( $this->unitGlobals['wgPhpUnitBootstrapGlobals'] ?? [] as $key => $value ) {
- $GLOBALS[ $key ] = $this->unitGlobals[ $key ];
+
+ self::$unitGlobals =& TestSetup::$bootstrapGlobals;
+ // The autoloader may change between bootstrap and the first test,
+ // so (lazily) capture these here instead.
+ self::$unitGlobals['wgAutoloadClasses'] =& $GLOBALS['wgAutoloadClasses'];
+ self::$unitGlobals['wgAutoloadLocalClasses'] =& $GLOBALS['wgAutoloadLocalClasses'];
+ // This value should always be true.
+ self::$unitGlobals['wgAutoloadAttemptLowercase'] = true;
+
+ // Would be nice if we coud simply replace $GLOBALS as a whole,
+ // but unsetting or re-assigning that breaks the reference of this magic
+ // variable. Thus we have to modify it in place.
+ self::$originalGlobals = [];
+ foreach ( $GLOBALS as $key => $_ ) {
+ // Stash current values
+ self::$originalGlobals[$key] =& $GLOBALS[$key];
+
+ // Remove globals not part of the snapshot (see bootstrap.php, phpunit.php).
+ // Support: HHVM (avoid self-ref)
+ if ( $key !== 'GLOBALS' && !array_key_exists( $key, self::$unitGlobals ) ) {
+ unset( $GLOBALS[$key] );
+ }
+ }
+ // Restore values from the early snapshot
+ // Not by ref because tests must not be able to modify the snapshot.
+ foreach ( self::$unitGlobals as $key => $value ) {
+ $GLOBALS[ $key ] = $value;
}
}
protected function tearDown() {
- $GLOBALS = $this->unitGlobals;
+ if ( !defined( 'HHVM_VERSION' ) ) {
+ // Quick reset between tests
+ foreach ( $GLOBALS as $key => $_ ) {
+ if ( $key !== 'GLOBALS' && !array_key_exists( $key, self::$unitGlobals ) ) {
+ unset( $GLOBALS[$key] );
+ }
+ }
+ foreach ( self::$unitGlobals as $key => $value ) {
+ $GLOBALS[ $key ] = $value;
+ }
+ }
+
parent::tearDown();
}
+ public static function tearDownAfterClass() {
+ if ( !defined( 'HHVM_VERSION' ) ) {
+ // Remove globals created by the test
+ foreach ( $GLOBALS as $key => $_ ) {
+ if ( $key !== 'GLOBALS' && !array_key_exists( $key, self::$originalGlobals ) ) {
+ unset( $GLOBALS[$key] );
+ }
+ }
+ // Restore values (including reference!)
+ foreach ( self::$originalGlobals as $key => &$value ) {
+ $GLOBALS[ $key ] =& $value;
+ }
+ }
+
+ parent::tearDownAfterClass();
+ }
+
/**
* Create a temporary hook handler which will be reset by tearDown.
* This replaces other handlers for the same hook.
global $wgHooks;
$wgHooks[$hookName] = [ $handler ];
}
+
+ protected function getMockMessage( $text, ...$params ) {
+ if ( isset( $params[0] ) && is_array( $params[0] ) ) {
+ $params = $params[0];
+ }
+
+ $msg = $this->getMockBuilder( Message::class )
+ ->disableOriginalConstructor()
+ ->setMethods( [] )
+ ->getMock();
+
+ $msg->method( 'toString' )->willReturn( $text );
+ $msg->method( '__toString' )->willReturn( $text );
+ $msg->method( 'text' )->willReturn( $text );
+ $msg->method( 'parse' )->willReturn( $text );
+ $msg->method( 'plain' )->willReturn( $text );
+ $msg->method( 'parseAsBlock' )->willReturn( $text );
+ $msg->method( 'escaped' )->willReturn( $text );
+
+ $msg->method( 'title' )->willReturn( $msg );
+ $msg->method( 'inLanguage' )->willReturn( $msg );
+ $msg->method( 'inContentLanguage' )->willReturn( $msg );
+ $msg->method( 'useDatabase' )->willReturn( $msg );
+ $msg->method( 'setContext' )->willReturn( $msg );
+
+ $msg->method( 'exists' )->willReturn( true );
+ $msg->method( 'content' )->willReturn( new MessageContent( $msg ) );
+
+ return $msg;
+ }
}
// Version hash for a blank file module.
// Result of ResourceLoader::makeHash(), ResourceLoaderTestModule
// and ResourceLoaderFileModule::getDefinitionSummary().
- const BLANK_VERSION = '09p30q0';
+ const BLANK_VERSION = '9p30q';
+ // Result of ResoureLoader::makeVersionQuery() for a blank file module.
+ // In other words, result of ResourceLoader::makeHash( BLANK_VERSION );
+ const BLANK_COMBI = 'rbml8';
/**
* @param array|string $options Language code or options array
// these variables must be defined before setup runs
$GLOBALS['IP'] = $IP;
-// Set bootstrap globals to reuse in MediaWikiUnitTestCase
-$bootstrapGlobals = [];
-foreach ( $GLOBALS as $key => $value ) {
- $bootstrapGlobals[ $key ] = $value;
-}
-$GLOBALS['wgPhpUnitBootstrapGlobals'] = $bootstrapGlobals;
-// Faking for Setup.php
+
+require_once "$IP/tests/common/TestSetup.php";
+TestSetup::snapshotGlobals();
+
+// Faking in lieu of Setup.php
$GLOBALS['wgScopeTest'] = 'MediaWiki Setup.php scope test';
$GLOBALS['wgCommandLineMode'] = true;
$GLOBALS['wgAutoloadClasses'] = [];
-require_once "$IP/tests/common/TestSetup.php";
-
wfRequireOnceInGlobalScope( "$IP/includes/AutoLoader.php" );
wfRequireOnceInGlobalScope( "$IP/tests/common/TestsAutoLoader.php" );
wfRequireOnceInGlobalScope( "$IP/includes/Defines.php" );
wfRequireOnceInGlobalScope( "$IP/includes/DefaultSettings.php" );
wfRequireOnceInGlobalScope( "$IP/includes/GlobalFunctions.php" );
-// Load extensions/skins present in filesystem so that classes can be discovered.
+// Populate classes and namespaces from extensions and skins present in filesystem.
$directoryToJsonMap = [
- 'extensions' => [ 'extension.json', 'extension-wip.json' ],
- 'skins' => [ 'skin.json', 'skin-wip.json' ]
+ $GLOBALS['wgExtensionDirectory'] => [ 'extension.json', 'extension-wip.json' ],
+ $GLOBALS['wgStyleDirectory'] => [ 'skin.json', 'skin-wip.json' ]
];
foreach ( $directoryToJsonMap as $directory => $jsonFile ) {
- foreach ( new DirectoryIterator( __DIR__ . '/../../' . $directory ) as $iterator ) {
+ foreach ( new DirectoryIterator( $directory ) as $iterator ) {
foreach ( $jsonFile as $file ) {
+
$jsonPath = $iterator->getPathname() . '/' . $file;
if ( file_exists( $jsonPath ) ) {
+ // ExtensionRegistry->readFromQueue is not used as it checks extension/skin
+ // dependencies, which we don't need or want for unit tests.
$json = file_get_contents( $jsonPath );
$info = json_decode( $json, true );
$dir = dirname( $jsonPath );
DELETE {
?category ?x ?y
} WHERE {
+ ?category ?x ?y
VALUES ?category {
<http://acme.test/wiki/Category:Test> <http://acme.test/wiki/Category:Test_2>
}
DELETE {
?category ?x ?y
} WHERE {
+ ?category ?x ?y
VALUES ?category {
<http://acme.test/wiki/Category:Changed_category>
}
DELETE {
?category ?x ?y
} WHERE {
+ ?category ?x ?y
VALUES ?category {
<http://acme.test/wiki/Category:Test> <http://acme.test/wiki/Category:MovedTo> <http://acme.test/wiki/Category:Test_2> <http://acme.test/wiki/Category:Test_3> <http://acme.test/wiki/Category:Test_4>
}
// for User::getActorId()
'wgActorTableSchemaMigrationStage' => $stage
] );
- $this->overrideMwServices();
$user = $this->getMutableTestUser()->getUser();
$userIdentity = $this->getMock( UserIdentity::class );
// Note, there are some obscure globals which
// could affect the results which aren't included above.
- $this->overrideMwServices();
$context = RequestContext::getMain();
$resp = $context->getRequest()->response();
$conf = $context->getConfig();
fwrite( $f, 'Message' );
fclose( $f );
- // Reset the service to avoid cached results
- $this->overrideMwServices();
-
$this->assertTrue( wfReadOnly() );
$this->assertTrue( wfReadOnly() ); # Check cached
}
$this->setMwGlobals( [
'wgReadOnly' => 'reason'
] );
- $this->overrideMwServices();
$this->assertSame( 'reason', wfReadOnlyReason() );
}
] );
$this->setLogger( 'wfDebug', new LegacyLogger( 'wfDebug' ) );
+ unlink( $debugLogFile );
wfDebug( "This is a normal string" );
$this->assertEquals( "This is a normal string\n", file_get_contents( $debugLogFile ) );
- unlink( $debugLogFile );
+ unlink( $debugLogFile );
wfDebug( "This is nöt an ASCII string" );
$this->assertEquals( "This is nöt an ASCII string\n", file_get_contents( $debugLogFile ) );
- unlink( $debugLogFile );
+ unlink( $debugLogFile );
wfDebug( "\00305This has böth UTF and control chars\003" );
$this->assertEquals(
" 05This has böth UTF and control chars \n",
file_get_contents( $debugLogFile )
);
- unlink( $debugLogFile );
+ unlink( $debugLogFile );
wfDebugMem();
$this->assertGreaterThan(
1000,
preg_replace( '/\D/', '', file_get_contents( $debugLogFile ) )
);
- unlink( $debugLogFile );
+ unlink( $debugLogFile );
wfDebugMem( true );
$this->assertGreaterThan(
1000000,
preg_replace( '/\D/', '', file_get_contents( $debugLogFile ) )
);
+
unlink( $debugLogFile );
}
// Don't try to fetch the files from Commons or anything, please
$this->setMwGlobals( 'wgForeignFileRepos', [] );
- // We need to reset services immediately so that editPage() doesn't use the old RepoGroup
- // and hit the network
- $this->resetServices();
// XXX How do we get file redirects to work?
$this->editPage( 'File:Redirect to bad.jpg', '#REDIRECT [[Bad.jpg]]' );
--- /dev/null
+<?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";
+ }
+}
*/
public function testRawHtmlInMsg() {
$this->setMwGlobals( 'wgRawHtml', true );
- // We have to reset the core hook registration.
- // to register the html hook
- $this->overrideMwServices();
$msg = new RawMessage( '<html><script>alert("xss")</script></html>' );
$txt = '<span class="error"><html> tags cannot be' .
* @group Database
*/
class MovePageTest extends MediaWikiTestCase {
- /**
- * @param string $class
- * @return object A mock that throws on any method call
- */
- private function getNoOpMock( $class ) {
- $mock = $this->createMock( $class );
- $mock->expects( $this->never() )->method( $this->anythingBut( '__destruct' ) );
- return $mock;
- }
-
/**
* The only files that exist are 'File:Existent.jpg', 'File:Existent2.jpg', and
* 'File:Existent-file-no-page.jpg'. Calling unexpected methods causes a test failure.
private function newMovePage( $old, $new, array $params = [] ) : MovePage {
$mockLB = $this->createMock( LoadBalancer::class );
$mockLB->method( 'getConnection' )
- ->willReturn( $params['db'] ?? $this->getNoOpMock( IDatabase::class ) );
+ ->willReturn( $params['db'] ?? $this->createNoOpMock( IDatabase::class ) );
$mockLB->expects( $this->never() )
->method( $this->anythingBut( 'getConnection', '__destruct' ) );
),
$mockLB,
$params['nsInfo'] ?? $mockNsInfo,
- $params['wiStore'] ?? $this->getNoOpMock( WatchedItemStore::class ),
- $params['permMgr'] ?? $this->getNoOpMock( PermissionManager::class ),
+ $params['wiStore'] ?? $this->createNoOpMock( WatchedItemStore::class ),
+ $params['permMgr'] ?? $this->createNoOpMock( PermissionManager::class ),
$params['repoGroup'] ?? $this->getMockRepoGroup()
);
}
foreach ( $extraOptions as $key => $val ) {
$this->setMwGlobals( "wg$key", $val );
}
- $this->overrideMwServices();
$this->setService( 'RepoGroup', $this->getMockRepoGroup() );
// This returns true instead of an array if there are no errors
$this->hideDeprecated( 'Title::isValidMoveOperation' );
[
[ 'test.quux', ResourceLoaderModule::TYPE_COMBINED ],
"<script nonce=\"secret\">(RLQ=window.RLQ||[]).push(function(){"
- . "mw.loader.implement(\"test.quux@1ev0ijv\",function($,jQuery,require,module){"
+ . "mw.loader.implement(\"test.quux@1ev0i\",function($,jQuery,require,module){"
. "mw.test.baz({token:123});},{\"css\":[\".mw-icon{transition:none}"
. "\"]});});</script>"
],
$op = TestingAccessWrapper::newFromObject( $op );
$op->rlExemptStyleModules = $exemptStyleModules;
+ $expect = strtr( $expect, [
+ '{blankCombi}' => ResourceLoaderTestCase::BLANK_COMBI,
+ ] );
$this->assertEquals(
$expect,
strval( $op->buildExemptModules() )
'exemptStyleModules' => [ 'site' => [ 'site.styles' ], 'user' => [ 'user.styles' ] ],
'<meta name="ResourceLoaderDynamicStyles" content=""/>' . "\n" .
'<link rel="stylesheet" href="/w/load.php?lang=en&modules=site.styles&only=styles"/>' . "\n" .
- '<link rel="stylesheet" href="/w/load.php?lang=en&modules=user.styles&only=styles&version=1ai9g6t"/>',
+ '<link rel="stylesheet" href="/w/load.php?lang=en&modules=user.styles&only=styles&version=15pue"/>',
],
'custom modules' => [
'exemptStyleModules' => [
'<meta name="ResourceLoaderDynamicStyles" content=""/>' . "\n" .
'<link rel="stylesheet" href="/w/load.php?lang=en&modules=example.site.a%2Cb&only=styles"/>' . "\n" .
'<link rel="stylesheet" href="/w/load.php?lang=en&modules=site.styles&only=styles"/>' . "\n" .
- '<link rel="stylesheet" href="/w/load.php?lang=en&modules=example.user&only=styles&version=0a56zyi"/>' . "\n" .
- '<link rel="stylesheet" href="/w/load.php?lang=en&modules=user.styles&only=styles&version=1ai9g6t"/>',
+ '<link rel="stylesheet" href="/w/load.php?lang=en&modules=example.user&only=styles&version={blankCombi}"/>' . "\n" .
+ '<link rel="stylesheet" href="/w/load.php?lang=en&modules=user.styles&only=styles&version=15pue"/>',
],
];
// phpcs:enable
$this->user = $this->userUser;
}
-
- $this->resetServices();
}
public function tearDown() {
} else {
$this->user = $this->altUser;
}
- $this->resetServices();
}
/**
global $wgGroupPermissions;
$old = $wgGroupPermissions;
- $wgGroupPermissions = [];
- $this->resetServices();
+ $this->setMwGlobals( 'wgGroupPermissions', [] );
$this->assertEquals( $check[$action][1],
MediaWikiServices::getInstance()->getPermissionManager()
$this->assertEquals( $check[$action][1],
MediaWikiServices::getInstance()->getPermissionManager()
->getPermissionErrors( $action, $this->user, $this->title, 'secure' ) );
- $wgGroupPermissions = $old;
- $this->resetServices();
+ $this->setMwGlobals( 'wgGroupPermissions', $old );
$this->overrideUserPermissions( $this->user, $action );
$this->assertEquals( $check[$action][2],
->userCan( $action, $this->user, $this->title, true ) );
$this->assertEquals( $check[$action][3],
MediaWikiServices::getInstance()->getPermissionManager()
- ->userCan( $action, $this->user, $this->title,
- PermissionManager::RIGOR_QUICK ) );
+ ->quickUserCan( $action, $this->user, $this->title ) );
# count( User::getGroupsWithPermissions( $action ) ) < 1
}
}
protected function runGroupPermissions( $perm, $action, $result, $result2 = null ) {
- global $wgGroupPermissions;
-
if ( $result2 === null ) {
$result2 = $result;
}
- $wgGroupPermissions['autoconfirmed']['move'] = false;
- $wgGroupPermissions['user']['move'] = false;
- $this->resetServices();
+ $this->setGroupPermissions( 'autoconfirmed', 'move', false );
+ $this->setGroupPermissions( 'user', 'move', false );
$this->overrideUserPermissions( $this->user, $perm );
$res = MediaWikiServices::getInstance()->getPermissionManager()
->getPermissionErrors( $action, $this->user, $this->title );
$this->assertEquals( $result, $res );
- $wgGroupPermissions['autoconfirmed']['move'] = true;
- $wgGroupPermissions['user']['move'] = false;
- $this->resetServices();
+ $this->setGroupPermissions( 'autoconfirmed', 'move', true );
+ $this->setGroupPermissions( 'user', 'move', false );
$this->overrideUserPermissions( $this->user, $perm );
$res = MediaWikiServices::getInstance()->getPermissionManager()
->getPermissionErrors( $action, $this->user, $this->title );
$this->assertEquals( $result2, $res );
- $wgGroupPermissions['autoconfirmed']['move'] = true;
- $wgGroupPermissions['user']['move'] = true;
- $this->resetServices();
+ $this->setGroupPermissions( 'autoconfirmed', 'move', true );
+ $this->setGroupPermissions( 'user', 'move', true );
$this->overrideUserPermissions( $this->user, $perm );
$res = MediaWikiServices::getInstance()->getPermissionManager()
->getPermissionErrors( $action, $this->user, $this->title );
$this->assertEquals( $result2, $res );
- $wgGroupPermissions['autoconfirmed']['move'] = false;
- $wgGroupPermissions['user']['move'] = true;
- $this->resetServices();
+ $this->setGroupPermissions( 'autoconfirmed', 'move', false );
+ $this->setGroupPermissions( 'user', 'move', true );
$this->overrideUserPermissions( $this->user, $perm );
$res = MediaWikiServices::getInstance()->getPermissionManager()
->getPermissionErrors( $action, $this->user, $this->title );
* @covers MediaWiki\Permissions\PermissionManager::checkSpecialsAndNSPermissions
*/
public function testSpecialsAndNSPermissions() {
- global $wgNamespaceProtection;
$this->setUser( $this->userName );
$this->setTitle( NS_SPECIAL );
MediaWikiServices::getInstance()->getPermissionManager()
->getPermissionErrors( 'bogus', $this->user, $this->title ) );
- $wgNamespaceProtection[NS_USER] = [ 'bogus' ];
+ $this->mergeMwGlobalArrayValue( 'wgNamespaceProtection', [
+ NS_USER => [ 'bogus' ]
+ ] );
+ $this->resetServices();
+ $this->overrideUserPermissions( $this->user, '' );
$this->setTitle( NS_USER );
- $this->overrideUserPermissions( $this->user, '' );
$this->assertEquals( [ [ 'badaccess-group0' ],
[ 'namespaceprotected', 'User', 'bogus' ] ],
MediaWikiServices::getInstance()->getPermissionManager()
MediaWikiServices::getInstance()->getPermissionManager()
->getPermissionErrors( 'bogus', $this->user, $this->title ) );
- $wgNamespaceProtection = null;
-
+ $this->setMwGlobals( 'wgNamespaceProtection', null );
+ $this->resetServices();
$this->overrideUserPermissions( $this->user, 'bogus' );
+
$this->assertEquals( [],
MediaWikiServices::getInstance()->getPermissionManager()
->getPermissionErrors( 'bogus', $this->user, $this->title ) );
$this->assertEquals( true,
MediaWikiServices::getInstance()->getPermissionManager()
- ->userCan( 'edit', $this->user, $this->title, PermissionManager::RIGOR_QUICK ) );
+ ->quickUserCan( 'edit', $this->user, $this->title ) );
$this->title->mRestrictions = [ "edit" => [ 'bogus', "sysop", "protect", "" ],
"bogus" => [ 'bogus', "sysop", "protect", "" ] ];
$this->assertEquals( false,
MediaWikiServices::getInstance()->getPermissionManager()
- ->userCan( 'bogus', $this->user, $this->title, PermissionManager::RIGOR_QUICK ) );
+ ->quickUserCan( 'bogus', $this->user, $this->title ) );
$this->assertEquals( false,
- MediaWikiServices::getInstance()->getPermissionManager()->userCan(
- 'edit', $this->user, $this->title, PermissionManager::RIGOR_QUICK ) );
+ MediaWikiServices::getInstance()->getPermissionManager()->quickUserCan(
+ 'edit', $this->user, $this->title ) );
$this->assertEquals( [ [ 'badaccess-group0' ],
[ 'protectedpagetext', 'bogus', 'bogus' ],
$this->overrideUserPermissions( $this->user, [ "edit", "editprotected" ] );
$this->assertEquals( false,
- MediaWikiServices::getInstance()->getPermissionManager()->userCan(
- 'bogus', $this->user, $this->title, PermissionManager::RIGOR_QUICK ) );
+ MediaWikiServices::getInstance()->getPermissionManager()->quickUserCan(
+ 'bogus', $this->user, $this->title ) );
$this->assertEquals( false,
- MediaWikiServices::getInstance()->getPermissionManager()->userCan(
- 'edit', $this->user, $this->title, PermissionManager::RIGOR_QUICK ) );
+ MediaWikiServices::getInstance()->getPermissionManager()->quickUserCan(
+ 'edit', $this->user, $this->title ) );
$this->assertEquals( [ [ 'badaccess-group0' ],
[ 'protectedpagetext', 'bogus', 'bogus' ],
->getPermissionErrors( 'edit', $this->user, $this->title ) );
$this->setMwGlobals( 'wgEmailConfirmToEdit', false );
- $this->resetServices();
$this->overrideUserPermissions( $this->user, [
'createpage',
'edit',
->userCan( 'move-target', $this->user, $this->title ) );
// quickUserCan should ignore user blocks
$this->assertEquals( true, MediaWikiServices::getInstance()->getPermissionManager()
- ->userCan( 'move-target', $this->user, $this->title,
- PermissionManager::RIGOR_QUICK ) );
+ ->quickUserCan( 'move-target', $this->user, $this->title ) );
global $wgLocalTZoffset;
$wgLocalTZoffset = -60;
$rights = array_diff( $rights, [ 'writetest' ] );
} );
- $this->resetServices();
$rights = MediaWikiServices::getInstance()
->getPermissionManager()
->getUserPermissions( $user );
'wgRestrictionLevels' => [ '', 'autoconfirmed', 'sysop' ],
'wgAutopromote' => []
] );
- $this->resetServices();
$user = is_null( $userGroups ) ? null : $this->getTestUser( $userGroups )->getUser();
$this->assertSame( $expected, MediaWikiServices::getInstance()
->getPermissionManager()
->getNamespaceRestrictionLevels( $ns, $user ) );
}
+
+ /**
+ * @covers \MediaWiki\Permissions\PermissionManager::getAllPermissions
+ */
+ public function testGetAllPermissions() {
+ $this->setMwGlobals( [
+ 'wgAvailableRights' => [ 'test_right' ]
+ ] );
+ $this->resetServices();
+ $this->assertContains(
+ 'test_right',
+ MediaWikiServices::getInstance()
+ ->getPermissionManager()
+ ->getAllPermissions()
+ );
+ }
+
+ /**
+ * @covers \MediaWiki\Permissions\PermissionManager::getRightsCacheKey
+ * @throws \Exception
+ */
+ public function testAnonPermissionsNotClash() {
+ $user1 = User::newFromName( 'User1' );
+ $user2 = User::newFromName( 'User2' );
+ $pm = MediaWikiServices::getInstance()->getPermissionManager();
+ $pm->overrideUserRightsForTesting( $user2, [] );
+ $this->assertNotSame( $pm->getUserPermissions( $user1 ), $pm->getUserPermissions( $user2 ) );
+ }
+
+ /**
+ * @covers \MediaWiki\Permissions\PermissionManager::getRightsCacheKey
+ */
+ public function testAnonPermissionsNotClashOneRegistered() {
+ $user1 = User::newFromName( 'User1' );
+ $user2 = $this->getTestSysop()->getUser();
+ $pm = MediaWikiServices::getInstance()->getPermissionManager();
+ $this->assertNotSame( $pm->getUserPermissions( $user1 ), $pm->getUserPermissions( $user2 ) );
+ }
}
$this->originalHandlers = TestingAccessWrapper::newFromClass( Hooks::class )->handlers;
TestingAccessWrapper::newFromClass( Hooks::class )->handlers = [];
-
- $this->overrideMwServices();
}
public function tearDown() {
$user = User::newFromName( 'Test user' );
// Don't allow the rights to everybody so that user rights kick in.
$this->mergeMwGlobalArrayValue( 'wgGroupPermissions', [ '*' => $userRights ] );
- $this->resetServices();
$this->overrideUserPermissions(
$user,
array_keys( array_filter( $userRights ), function ( $value ) {
--- /dev/null
+<?php
+
+namespace MediaWiki\Tests\Rest;
+
+use EmptyBagOStuff;
+use GuzzleHttp\Psr7\Uri;
+use GuzzleHttp\Psr7\Stream;
+use MediaWiki\Rest\BasicAccess\StaticBasicAuthorizer;
+use MediaWiki\Rest\Handler;
+use MediaWiki\Rest\EntryPoint;
+use MediaWiki\Rest\RequestData;
+use MediaWiki\Rest\ResponseFactory;
+use MediaWiki\Rest\Router;
+use RequestContext;
+use WebResponse;
+
+/**
+ * @covers \MediaWiki\Rest\EntryPoint
+ * @covers \MediaWiki\Rest\Router
+ */
+class EntryPointTest extends \MediaWikiTestCase {
+ private static $mockHandler;
+
+ private function createRouter() {
+ global $IP;
+
+ return new Router(
+ [ "$IP/tests/phpunit/unit/includes/Rest/testRoutes.json" ],
+ [],
+ '/rest',
+ new EmptyBagOStuff(),
+ new ResponseFactory(),
+ new StaticBasicAuthorizer() );
+ }
+
+ private function createWebResponse() {
+ return $this->getMockBuilder( WebResponse::class )
+ ->setMethods( [ 'header' ] )
+ ->getMock();
+ }
+
+ public static function mockHandlerHeader() {
+ return new class extends Handler {
+ public function execute() {
+ $response = $this->getResponseFactory()->create();
+ $response->setHeader( 'Foo', 'Bar' );
+ return $response;
+ }
+ };
+ }
+
+ public function testHeader() {
+ $webResponse = $this->createWebResponse();
+ $webResponse->expects( $this->any() )
+ ->method( 'header' )
+ ->withConsecutive(
+ [ 'HTTP/1.1 200 OK', true, null ],
+ [ 'Foo: Bar', true, null ]
+ );
+
+ $entryPoint = new EntryPoint(
+ RequestContext::getMain(),
+ new RequestData( [ 'uri' => new Uri( '/rest/mock/EntryPoint/header' ) ] ),
+ $webResponse,
+ $this->createRouter() );
+ $entryPoint->execute();
+ $this->assertTrue( true );
+ }
+
+ public static function mockHandlerBodyRewind() {
+ return new class extends Handler {
+ public function execute() {
+ $response = $this->getResponseFactory()->create();
+ $stream = new Stream( fopen( 'php://memory', 'w+' ) );
+ $stream->write( 'hello' );
+ $response->setBody( $stream );
+ return $response;
+ }
+ };
+ }
+
+ /**
+ * Make sure EntryPoint rewinds a seekable body stream before reading.
+ */
+ public function testBodyRewind() {
+ $entryPoint = new EntryPoint(
+ RequestContext::getMain(),
+ new RequestData( [ 'uri' => new Uri( '/rest/mock/EntryPoint/bodyRewind' ) ] ),
+ $this->createWebResponse(),
+ $this->createRouter() );
+ ob_start();
+ $entryPoint->execute();
+ $this->assertSame( 'hello', ob_get_clean() );
+ }
+
+}
--- /dev/null
+<?php
+
+namespace MediaWiki\Tests\Revision;
+
+use MediaWiki\Revision\MainSlotRoleHandler;
+use PHPUnit\Framework\MockObject\MockObject;
+use Title;
+
+/**
+ * @covers \MediaWiki\Revision\MainSlotRoleHandler
+ */
+class MainSlotRoleHandlerTest extends \MediaWikiIntegrationTestCase {
+
+ private function makeTitleObject( $ns ) {
+ /** @var Title|MockObject $title */
+ $title = $this->getMockBuilder( Title::class )
+ ->disableOriginalConstructor()
+ ->getMock();
+
+ $title->method( 'getNamespace' )
+ ->willReturn( $ns );
+
+ return $title;
+ }
+
+ /**
+ * @covers \MediaWiki\Revision\MainSlotRoleHandler::__construct
+ * @covers \MediaWiki\Revision\MainSlotRoleHandler::getRole()
+ * @covers \MediaWiki\Revision\MainSlotRoleHandler::getNameMessageKey()
+ * @covers \MediaWiki\Revision\MainSlotRoleHandler::getOutputLayoutHints()
+ */
+ public function testConstruction() {
+ $handler = new MainSlotRoleHandler( [] );
+ $this->assertSame( 'main', $handler->getRole() );
+ $this->assertSame( 'slot-name-main', $handler->getNameMessageKey() );
+
+ $hints = $handler->getOutputLayoutHints();
+ $this->assertArrayHasKey( 'display', $hints );
+ $this->assertArrayHasKey( 'region', $hints );
+ $this->assertArrayHasKey( 'placement', $hints );
+ }
+
+ /**
+ * @covers \MediaWiki\Revision\MainSlotRoleHandler::getDefaultModel()
+ */
+ public function testFetDefaultModel() {
+ $handler = new MainSlotRoleHandler( [ 100 => CONTENT_MODEL_TEXT ] );
+
+ // For the main handler, the namespace determins the default model
+ $titleMain = $this->makeTitleObject( NS_MAIN );
+ $this->assertSame( CONTENT_MODEL_WIKITEXT, $handler->getDefaultModel( $titleMain ) );
+
+ $title100 = $this->makeTitleObject( 100 );
+ $this->assertSame( CONTENT_MODEL_TEXT, $handler->getDefaultModel( $title100 ) );
+ }
+
+ /**
+ * @covers \MediaWiki\Revision\MainSlotRoleHandler::isAllowedModel()
+ */
+ public function testIsAllowedModel() {
+ $handler = new MainSlotRoleHandler( [] );
+
+ // For the main handler, (nearly) all models are allowed
+ $title = $this->makeTitleObject( NS_MAIN );
+ $this->assertTrue( $handler->isAllowedModel( CONTENT_MODEL_WIKITEXT, $title ) );
+ $this->assertTrue( $handler->isAllowedModel( CONTENT_MODEL_TEXT, $title ) );
+ }
+
+ /**
+ * @covers \MediaWiki\Revision\MainSlotRoleHandler::supportsArticleCount()
+ */
+ public function testSupportsArticleCount() {
+ $handler = new MainSlotRoleHandler( [] );
+
+ $this->assertTrue( $handler->supportsArticleCount() );
+ }
+
+}
*/
public function testRevisionSelectFields( $migrationStageSettings, $expected ) {
$this->setMwGlobals( $migrationStageSettings );
- $this->overrideMwServices();
$this->hideDeprecated( 'Revision::selectFields' );
$this->assertArrayEqualsIgnoringIntKeyOrder( $expected, Revision::selectFields() );
*/
public function testRevisionSelectArchiveFields( $migrationStageSettings, $expected ) {
$this->setMwGlobals( $migrationStageSettings );
- $this->overrideMwServices();
$this->hideDeprecated( 'Revision::selectArchiveFields' );
$this->assertArrayEqualsIgnoringIntKeyOrder( $expected, Revision::selectArchiveFields() );
public function testRevisionUserJoinCond() {
$this->hideDeprecated( 'Revision::userJoinCond' );
$this->setMwGlobals( 'wgActorTableSchemaMigrationStage', SCHEMA_COMPAT_OLD );
- $this->overrideMwServices();
$this->assertEquals(
[ 'LEFT JOIN', [ 'rev_user != 0', 'user_id = rev_user' ] ],
Revision::userJoinCond()
*/
public function testRevisionGetArchiveQueryInfo( $migrationStageSettings, $expected ) {
$this->setMwGlobals( $migrationStageSettings );
- $this->overrideMwServices();
$queryInfo = Revision::getArchiveQueryInfo();
$this->assertQueryInfoEquals( $expected, $queryInfo );
*/
public function testRevisionGetQueryInfo( $migrationStageSettings, $options, $expected ) {
$this->setMwGlobals( $migrationStageSettings );
- $this->overrideMwServices();
$queryInfo = Revision::getQueryInfo( $options );
$this->assertQueryInfoEquals( $expected, $queryInfo );
*/
public function testRevisionStoreGetQueryInfo( $migrationStageSettings, $options, $expected ) {
$this->setMwGlobals( $migrationStageSettings );
- $this->overrideMwServices();
$store = MediaWikiServices::getInstance()->getRevisionStore();
$expected
) {
$this->setMwGlobals( $migrationStageSettings );
- $this->overrideMwServices();
$store = MediaWikiServices::getInstance()->getRevisionStore();
*/
public function testRevisionStoreGetArchiveQueryInfo( $migrationStageSettings, $expected ) {
$this->setMwGlobals( $migrationStageSettings );
- $this->overrideMwServices();
$store = MediaWikiServices::getInstance()->getRevisionStore();
use MediaWiki\User\UserIdentityValue;
use MediaWikiTestCase;
use PHPUnit_Framework_MockObject_MockObject;
-use Psr\Log\NullLogger;
use Revision;
use TestUserRegistry;
use Title;
'wgContentHandlerUseDB' => $this->getContentHandlerUseDB(),
'wgActorTableSchemaMigrationStage' => SCHEMA_COMPAT_NEW,
] );
-
- $this->overrideMwServices();
}
protected function addCoreDBData() {
->getMock();
$lb->method( 'reallyOpenConnection' )->willReturnCallback(
- function () use ( $server ) {
+ function ( array $server, $dbNameOverride ) {
return $this->getDatabaseMock( $server );
}
);
'cliMode' => true,
'agent' => '',
'load' => 100,
- 'srvCache' => new HashBagOStuff(),
'profiler' => null,
'trxProfiler' => new TransactionProfiler(),
- 'connLogger' => new NullLogger(),
- 'queryLogger' => new NullLogger(),
+ 'connLogger' => new \Psr\Log\NullLogger(),
+ 'queryLogger' => new \Psr\Log\NullLogger(),
'errorLogger' => function () {
},
'deprecationLogger' => function () {
$title = $this->getTestPageTitle();
$rev = $this->getRevisionRecordFromDetailsArray( $revDetails );
- $this->overrideMwServices();
$store = MediaWikiServices::getInstance()->getRevisionStore();
$return = $store->insertRevisionOn( $rev, wfGetDB( DB_MASTER ) );
'user' => true,
];
- $this->overrideMwServices();
$store = MediaWikiServices::getInstance()->getRevisionStore();
// Insert the first revision
* @covers \MediaWiki\Revision\RevisionStore::findSlotContentId
*/
public function testNewNullRevision( Title $title, $revDetails, $comment, $minor = false ) {
- $this->overrideMwServices();
-
$user = TestUserRegistry::getMutableTestUser( __METHOD__ )->getUser();
$page = WikiPage::factory( $title );
*/
public function testNewRevisionFromRow_anonEdit_legacyEncoding() {
$this->setMwGlobals( 'wgLegacyEncoding', 'windows-1252' );
- $this->overrideMwServices();
$page = $this->getTestPage();
$text = __METHOD__ . 'a-ä';
/** @var Revision $rev */
*/
public function testNewRevisionFromArchiveRow_legacyEncoding() {
$this->setMwGlobals( 'wgLegacyEncoding', 'windows-1252' );
- $this->overrideMwServices();
$store = MediaWikiServices::getInstance()->getRevisionStore();
$title = Title::newFromText( __METHOD__ );
$text = __METHOD__ . '-bä';
public function testGetKnownCurrentRevision_userNameChange() {
global $wgActorTableSchemaMigrationStage;
- $this->overrideMwServices();
$cache = new WANObjectCache( [ 'cache' => new HashBagOStuff() ] );
$this->setService( 'MainWANObjectCache', $cache );
* @covers \MediaWiki\Revision\RevisionStore::getKnownCurrentRevision
*/
public function testGetKnownCurrentRevision_revDelete() {
- $this->overrideMwServices();
$cache = new WANObjectCache( [ 'cache' => new HashBagOStuff() ] );
$this->setService( 'MainWANObjectCache', $cache );
--- /dev/null
+<?php
+
+namespace MediaWiki\Tests\Revision;
+
+use InvalidArgumentException;
+use LogicException;
+use MediaWiki\Revision\IncompleteRevisionException;
+use MediaWiki\Revision\SlotRecord;
+use MediaWiki\Revision\SuppressedDataException;
+use WikitextContent;
+
+/**
+ * @covers \MediaWiki\Revision\SlotRecord
+ */
+class SlotRecordTest extends \MediaWikiIntegrationTestCase {
+
+ private function makeRow( $data = [] ) {
+ $data = $data + [
+ 'slot_id' => 1234,
+ 'slot_content_id' => 33,
+ 'content_size' => '5',
+ 'content_sha1' => 'someHash',
+ 'content_address' => 'tt:456',
+ 'model_name' => CONTENT_MODEL_WIKITEXT,
+ 'format_name' => CONTENT_FORMAT_WIKITEXT,
+ 'slot_revision_id' => '2',
+ 'slot_origin' => '1',
+ 'role_name' => 'myRole',
+ ];
+ return (object)$data;
+ }
+
+ public function testCompleteConstruction() {
+ $row = $this->makeRow();
+ $record = new SlotRecord( $row, new WikitextContent( 'A' ) );
+
+ $this->assertTrue( $record->hasAddress() );
+ $this->assertTrue( $record->hasContentId() );
+ $this->assertTrue( $record->hasRevision() );
+ $this->assertTrue( $record->isInherited() );
+ $this->assertSame( 'A', $record->getContent()->getText() );
+ $this->assertSame( 5, $record->getSize() );
+ $this->assertSame( 'someHash', $record->getSha1() );
+ $this->assertSame( CONTENT_MODEL_WIKITEXT, $record->getModel() );
+ $this->assertSame( 2, $record->getRevision() );
+ $this->assertSame( 1, $record->getOrigin() );
+ $this->assertSame( 'tt:456', $record->getAddress() );
+ $this->assertSame( 33, $record->getContentId() );
+ $this->assertSame( CONTENT_FORMAT_WIKITEXT, $record->getFormat() );
+ $this->assertSame( 'myRole', $record->getRole() );
+ }
+
+ public function testConstructionDeferred() {
+ $row = $this->makeRow( [
+ 'content_size' => null, // to be computed
+ 'content_sha1' => null, // to be computed
+ 'format_name' => function () {
+ return CONTENT_FORMAT_WIKITEXT;
+ },
+ 'slot_revision_id' => '2',
+ 'slot_origin' => '2',
+ 'slot_content_id' => function () {
+ return null;
+ },
+ ] );
+
+ $content = function () {
+ return new WikitextContent( 'A' );
+ };
+
+ $record = new SlotRecord( $row, $content );
+
+ $this->assertTrue( $record->hasAddress() );
+ $this->assertTrue( $record->hasRevision() );
+ $this->assertFalse( $record->hasContentId() );
+ $this->assertFalse( $record->isInherited() );
+ $this->assertSame( 'A', $record->getContent()->getText() );
+ $this->assertSame( 1, $record->getSize() );
+ $this->assertNotEmpty( $record->getSha1() );
+ $this->assertSame( CONTENT_MODEL_WIKITEXT, $record->getModel() );
+ $this->assertSame( 2, $record->getRevision() );
+ $this->assertSame( 2, $record->getRevision() );
+ $this->assertSame( 'tt:456', $record->getAddress() );
+ $this->assertSame( CONTENT_FORMAT_WIKITEXT, $record->getFormat() );
+ $this->assertSame( 'myRole', $record->getRole() );
+ }
+
+ public function testNewUnsaved() {
+ $record = SlotRecord::newUnsaved( 'myRole', new WikitextContent( 'A' ) );
+
+ $this->assertFalse( $record->hasAddress() );
+ $this->assertFalse( $record->hasContentId() );
+ $this->assertFalse( $record->hasRevision() );
+ $this->assertFalse( $record->isInherited() );
+ $this->assertFalse( $record->hasOrigin() );
+ $this->assertSame( 'A', $record->getContent()->getText() );
+ $this->assertSame( 1, $record->getSize() );
+ $this->assertNotEmpty( $record->getSha1() );
+ $this->assertSame( CONTENT_MODEL_WIKITEXT, $record->getModel() );
+ $this->assertSame( 'myRole', $record->getRole() );
+ }
+
+ public function provideInvalidConstruction() {
+ yield 'both null' => [ null, null ];
+ yield 'null row' => [ null, new WikitextContent( 'A' ) ];
+ yield 'array row' => [ [], new WikitextContent( 'A' ) ];
+ yield 'empty row' => [ (object)[], new WikitextContent( 'A' ) ];
+ yield 'null content' => [ (object)[], null ];
+ }
+
+ /**
+ * @dataProvider provideInvalidConstruction
+ */
+ public function testInvalidConstruction( $row, $content ) {
+ $this->setExpectedException( InvalidArgumentException::class );
+ new SlotRecord( $row, $content );
+ }
+
+ public function testGetContentId_fails() {
+ $record = SlotRecord::newUnsaved( SlotRecord::MAIN, new WikitextContent( 'A' ) );
+ $this->setExpectedException( IncompleteRevisionException::class );
+
+ $record->getContentId();
+ }
+
+ public function testGetAddress_fails() {
+ $record = SlotRecord::newUnsaved( SlotRecord::MAIN, new WikitextContent( 'A' ) );
+ $this->setExpectedException( IncompleteRevisionException::class );
+
+ $record->getAddress();
+ }
+
+ public function provideIncomplete() {
+ $unsaved = SlotRecord::newUnsaved( SlotRecord::MAIN, new WikitextContent( 'A' ) );
+ yield 'unsaved' => [ $unsaved ];
+
+ $parent = new SlotRecord( $this->makeRow(), new WikitextContent( 'A' ) );
+ $inherited = SlotRecord::newInherited( $parent );
+ yield 'inherited' => [ $inherited ];
+ }
+
+ /**
+ * @dataProvider provideIncomplete
+ */
+ public function testGetRevision_fails( SlotRecord $record ) {
+ $record = SlotRecord::newUnsaved( SlotRecord::MAIN, new WikitextContent( 'A' ) );
+ $this->setExpectedException( IncompleteRevisionException::class );
+
+ $record->getRevision();
+ }
+
+ /**
+ * @dataProvider provideIncomplete
+ */
+ public function testGetOrigin_fails( SlotRecord $record ) {
+ $record = SlotRecord::newUnsaved( SlotRecord::MAIN, new WikitextContent( 'A' ) );
+ $this->setExpectedException( IncompleteRevisionException::class );
+
+ $record->getOrigin();
+ }
+
+ public function provideHashStability() {
+ yield [ '', 'phoiac9h4m842xq45sp7s6u21eteeq1' ];
+ yield [ 'Lorem ipsum', 'hcr5u40uxr81d3nx89nvwzclfz6r9c5' ];
+ }
+
+ /**
+ * @dataProvider provideHashStability
+ */
+ public function testHashStability( $text, $hash ) {
+ // Changing the output of the hash function will break things horribly!
+
+ $this->assertSame( $hash, SlotRecord::base36Sha1( $text ) );
+
+ $record = SlotRecord::newUnsaved( SlotRecord::MAIN, new WikitextContent( $text ) );
+ $this->assertSame( $hash, $record->getSha1() );
+ }
+
+ public function testHashComputed() {
+ $row = $this->makeRow();
+ $row->content_sha1 = '';
+
+ $rec = new SlotRecord( $row, new WikitextContent( 'A' ) );
+ $this->assertNotEmpty( $rec->getSha1() );
+ }
+
+ public function testNewWithSuppressedContent() {
+ $input = new SlotRecord( $this->makeRow(), new WikitextContent( 'A' ) );
+ $output = SlotRecord::newWithSuppressedContent( $input );
+
+ $this->setExpectedException( SuppressedDataException::class );
+ $output->getContent();
+ }
+
+ public function testNewInherited() {
+ $row = $this->makeRow( [ 'slot_revision_id' => 7, 'slot_origin' => 7 ] );
+ $parent = new SlotRecord( $row, new WikitextContent( 'A' ) );
+
+ // This would happen while doing an edit, before saving revision meta-data.
+ $inherited = SlotRecord::newInherited( $parent );
+
+ $this->assertSame( $parent->getContentId(), $inherited->getContentId() );
+ $this->assertSame( $parent->getAddress(), $inherited->getAddress() );
+ $this->assertSame( $parent->getContent(), $inherited->getContent() );
+ $this->assertTrue( $inherited->isInherited() );
+ $this->assertTrue( $inherited->hasOrigin() );
+ $this->assertFalse( $inherited->hasRevision() );
+
+ // make sure we didn't mess with the internal state of $parent
+ $this->assertFalse( $parent->isInherited() );
+ $this->assertSame( 7, $parent->getRevision() );
+
+ // This would happen while doing an edit, after saving the revision meta-data
+ // and content meta-data.
+ $saved = SlotRecord::newSaved(
+ 10,
+ $inherited->getContentId(),
+ $inherited->getAddress(),
+ $inherited
+ );
+ $this->assertSame( $parent->getContentId(), $saved->getContentId() );
+ $this->assertSame( $parent->getAddress(), $saved->getAddress() );
+ $this->assertSame( $parent->getContent(), $saved->getContent() );
+ $this->assertTrue( $saved->isInherited() );
+ $this->assertTrue( $saved->hasRevision() );
+ $this->assertSame( 10, $saved->getRevision() );
+
+ // make sure we didn't mess with the internal state of $parent or $inherited
+ $this->assertSame( 7, $parent->getRevision() );
+ $this->assertFalse( $inherited->hasRevision() );
+ }
+
+ public function testNewSaved() {
+ // This would happen while doing an edit, before saving revision meta-data.
+ $unsaved = SlotRecord::newUnsaved( SlotRecord::MAIN, new WikitextContent( 'A' ) );
+
+ // This would happen while doing an edit, after saving the revision meta-data
+ // and content meta-data.
+ $saved = SlotRecord::newSaved( 10, 20, 'theNewAddress', $unsaved );
+ $this->assertFalse( $saved->isInherited() );
+ $this->assertTrue( $saved->hasOrigin() );
+ $this->assertTrue( $saved->hasRevision() );
+ $this->assertTrue( $saved->hasAddress() );
+ $this->assertTrue( $saved->hasContentId() );
+ $this->assertSame( 'theNewAddress', $saved->getAddress() );
+ $this->assertSame( 20, $saved->getContentId() );
+ $this->assertSame( 'A', $saved->getContent()->getText() );
+ $this->assertSame( 10, $saved->getRevision() );
+ $this->assertSame( 10, $saved->getOrigin() );
+
+ // make sure we didn't mess with the internal state of $unsaved
+ $this->assertFalse( $unsaved->hasAddress() );
+ $this->assertFalse( $unsaved->hasContentId() );
+ $this->assertFalse( $unsaved->hasRevision() );
+ }
+
+ public function provideNewSaved_LogicException() {
+ $freshRow = $this->makeRow( [
+ 'content_id' => 10,
+ 'content_address' => 'address:1',
+ 'slot_origin' => 1,
+ 'slot_revision_id' => 1,
+ ] );
+
+ $freshSlot = new SlotRecord( $freshRow, new WikitextContent( 'A' ) );
+ yield 'mismatching address' => [ 1, 10, 'address:BAD', $freshSlot ];
+ yield 'mismatching revision' => [ 5, 10, 'address:1', $freshSlot ];
+ yield 'mismatching content ID' => [ 1, 17, 'address:1', $freshSlot ];
+
+ $inheritedRow = $this->makeRow( [
+ 'content_id' => null,
+ 'content_address' => null,
+ 'slot_origin' => 0,
+ 'slot_revision_id' => 1,
+ ] );
+
+ $inheritedSlot = new SlotRecord( $inheritedRow, new WikitextContent( 'A' ) );
+ yield 'inherited, but no address' => [ 1, 10, 'address:2', $inheritedSlot ];
+ }
+
+ /**
+ * @dataProvider provideNewSaved_LogicException
+ */
+ public function testNewSaved_LogicException(
+ $revisionId,
+ $contentId,
+ $contentAddress,
+ SlotRecord $protoSlot
+ ) {
+ $this->setExpectedException( LogicException::class );
+ SlotRecord::newSaved( $revisionId, $contentId, $contentAddress, $protoSlot );
+ }
+
+ public function provideNewSaved_InvalidArgumentException() {
+ $unsaved = SlotRecord::newUnsaved( SlotRecord::MAIN, new WikitextContent( 'A' ) );
+
+ yield 'bad revision id' => [ 'xyzzy', 5, 'address', $unsaved ];
+ yield 'bad content id' => [ 7, 'xyzzy', 'address', $unsaved ];
+ yield 'bad content address' => [ 7, 5, 77, $unsaved ];
+ }
+
+ /**
+ * @dataProvider provideNewSaved_InvalidArgumentException
+ */
+ public function testNewSaved_InvalidArgumentException(
+ $revisionId,
+ $contentId,
+ $contentAddress,
+ SlotRecord $protoSlot
+ ) {
+ $this->setExpectedException( InvalidArgumentException::class );
+ SlotRecord::newSaved( $revisionId, $contentId, $contentAddress, $protoSlot );
+ }
+
+ public function provideHasSameContent() {
+ $fail = function () {
+ self::fail( 'There should be no need to actually load the content.' );
+ };
+
+ $a100a1 = new SlotRecord(
+ $this->makeRow(
+ [
+ 'model_name' => 'A',
+ 'content_size' => 100,
+ 'content_sha1' => 'hash-a',
+ 'content_address' => 'xxx:a1',
+ ]
+ ),
+ $fail
+ );
+ $a100a1b = new SlotRecord(
+ $this->makeRow(
+ [
+ 'model_name' => 'A',
+ 'content_size' => 100,
+ 'content_sha1' => 'hash-a',
+ 'content_address' => 'xxx:a1',
+ ]
+ ),
+ $fail
+ );
+ $a100null = new SlotRecord(
+ $this->makeRow(
+ [
+ 'model_name' => 'A',
+ 'content_size' => 100,
+ 'content_sha1' => 'hash-a',
+ 'content_address' => null,
+ ]
+ ),
+ $fail
+ );
+ $a100a2 = new SlotRecord(
+ $this->makeRow(
+ [
+ 'model_name' => 'A',
+ 'content_size' => 100,
+ 'content_sha1' => 'hash-a',
+ 'content_address' => 'xxx:a2',
+ ]
+ ),
+ $fail
+ );
+ $b100a1 = new SlotRecord(
+ $this->makeRow(
+ [
+ 'model_name' => 'B',
+ 'content_size' => 100,
+ 'content_sha1' => 'hash-a',
+ 'content_address' => 'xxx:a1',
+ ]
+ ),
+ $fail
+ );
+ $a200a1 = new SlotRecord(
+ $this->makeRow(
+ [
+ 'model_name' => 'A',
+ 'content_size' => 200,
+ 'content_sha1' => 'hash-a',
+ 'content_address' => 'xxx:a2',
+ ]
+ ),
+ $fail
+ );
+ $a100x1 = new SlotRecord(
+ $this->makeRow(
+ [
+ 'model_name' => 'A',
+ 'content_size' => 100,
+ 'content_sha1' => 'hash-x',
+ 'content_address' => 'xxx:x1',
+ ]
+ ),
+ $fail
+ );
+
+ yield 'same instance' => [ $a100a1, $a100a1, true ];
+ yield 'no address' => [ $a100a1, $a100null, true ];
+ yield 'same address' => [ $a100a1, $a100a1b, true ];
+ yield 'different address' => [ $a100a1, $a100a2, true ];
+ yield 'different model' => [ $a100a1, $b100a1, false ];
+ yield 'different size' => [ $a100a1, $a200a1, false ];
+ yield 'different hash' => [ $a100a1, $a100x1, false ];
+ }
+
+ /**
+ * @dataProvider provideHasSameContent
+ */
+ public function testHasSameContent( SlotRecord $a, SlotRecord $b, $sameContent ) {
+ $this->assertSame( $sameContent, $a->hasSameContent( $b ) );
+ $this->assertSame( $sameContent, $b->hasSameContent( $a ) );
+ }
+
+}
'wgActorTableSchemaMigrationStage' => SCHEMA_COMPAT_NEW,
] );
- $this->overrideMwServices();
-
if ( !$this->testPage ) {
/**
* We have to create a new page for each subclass as the page creation may result
* @covers \MediaWiki\Revision\RevisionStore::newMutableRevisionFromArray
*/
public function testConstructFromRowWithBadPageId() {
- $this->overrideMwServices();
Wikimedia\suppressWarnings();
$rev = new Revision( (object)[
'rev_page' => 77777777,
*/
public function testLoadFromTitle() {
$this->setMwGlobals( 'wgActorTableSchemaMigrationStage', SCHEMA_COMPAT_NEW );
- $this->overrideMwServices();
$title = $this->getMockTitle();
$conditions = [
use WANObjectCache;
use Wikimedia\Rdbms\IDatabase;
use Wikimedia\Rdbms\LoadBalancer;
+use Wikimedia\Rdbms\MaintainableDBConnRef;
use Wikimedia\TestingAccessWrapper;
/**
->disableOriginalConstructor()
->getMock();
$mock->expects( $this->any() )
- ->method( 'getConnection' )
- ->willReturn( $db );
+ ->method( 'getConnectionRef' )
+ ->willReturnCallback( function ( $i ) use ( $mock, $db ) {
+ return new MaintainableDBConnRef( $mock, $db, $i );
+ } );
return $mock;
}
use InvalidArgumentException;
use Language;
use MediaWiki\MediaWikiServices;
+use MediaWiki\Storage\BlobAccessException;
use MediaWiki\Storage\SqlBlobStore;
use MediaWikiTestCase;
use stdClass;
}
/**
+ * @param string $blob
* @dataProvider provideBlobs
* @covers \MediaWiki\Storage\SqlBlobStore::storeBlob
* @covers \MediaWiki\Storage\SqlBlobStore::getBlob
$this->assertSame( $blob, $store->getBlob( $address ) );
}
+ /**
+ * @covers \MediaWiki\Storage\SqlBlobStore::storeBlob
+ * @covers \MediaWiki\Storage\SqlBlobStore::getBlobBatch
+ */
+ public function testSimpleStorageGetBlobBatchSimpleEmpty() {
+ $store = $this->getBlobStore();
+ $this->assertArrayEquals(
+ [],
+ $store->getBlobBatch( [] )->getValue()
+ );
+ }
+
+ /**
+ * @param string $blob
+ * @dataProvider provideBlobs
+ * @covers \MediaWiki\Storage\SqlBlobStore::storeBlob
+ * @covers \MediaWiki\Storage\SqlBlobStore::getBlobBatch
+ */
+ public function testSimpleStorageGetBlobBatchSimpleRoundtrip( $blob ) {
+ $store = $this->getBlobStore();
+ $addresses = [
+ $store->storeBlob( $blob ),
+ $store->storeBlob( $blob . '1' )
+ ];
+ $this->assertArrayEquals(
+ array_combine( $addresses, [ $blob, $blob . '1' ] ),
+ $store->getBlobBatch( $addresses )->getValue()
+ );
+ }
+
+ /**
+ * @covers \MediaWiki\Storage\SqlBlobStore::getBlob
+ */
+ public function testSimpleStorageNonExistentBlob() {
+ $this->setExpectedException( BlobAccessException::class );
+ $store = $this->getBlobStore();
+ $store->getBlob( 'tt:this_will_not_exist' );
+ }
+
+ /**
+ * @covers \MediaWiki\Storage\SqlBlobStore::getBlobBatch
+ */
+ public function testSimpleStorageNonExistentBlobBatch() {
+ $store = $this->getBlobStore();
+ $result = $store->getBlobBatch( [ 'tt:this_will_not_exist', 'tt:1000', 'bla:1001' ] );
+ $this->assertSame(
+ [
+ 'tt:this_will_not_exist' => null,
+ 'tt:1000' => null,
+ 'bla:1001' => null
+ ],
+ $result->getValue()
+ );
+ $this->assertSame( [
+ [
+ 'type' => 'warning',
+ 'message' => 'internalerror',
+ 'params' => [
+ 'Bad blob address: tt:this_will_not_exist'
+ ]
+ ],
+ [
+ 'type' => 'warning',
+ 'message' => 'internalerror',
+ 'params' => [
+ 'Unknown blob address schema: bla'
+ ]
+ ],
+ [
+ 'type' => 'warning',
+ 'message' => 'internalerror',
+ 'params' => [
+ 'Unable to fetch blob at tt:1000'
+ ]
+ ]
+ ], $result->getErrors() );
+ }
+
+ /**
+ * @covers \MediaWiki\Storage\SqlBlobStore::getBlobBatch
+ */
+ public function testSimpleStoragePartialNonExistentBlobBatch() {
+ $store = $this->getBlobStore();
+ $address = $store->storeBlob( 'test_data' );
+ $result = $store->getBlobBatch( [ $address, 'tt:this_will_not_exist_too' ] );
+ $this->assertSame(
+ [
+ $address => 'test_data',
+ 'tt:this_will_not_exist_too' => null
+ ],
+ $result->getValue()
+ );
+ $this->assertSame( [
+ [
+ 'type' => 'warning',
+ 'message' => 'internalerror',
+ 'params' => [
+ 'Bad blob address: tt:this_will_not_exist_too'
+ ]
+ ],
+ ], $result->getErrors() );
+ }
+
/**
* @dataProvider provideBlobs
* @covers \MediaWiki\Storage\SqlBlobStore::storeBlob
$this->user = $this->userUser;
}
- $this->resetServices();
}
protected function setTitle( $ns, $title = "Main_Page" ) {
global $wgGroupPermissions;
$old = $wgGroupPermissions;
- $wgGroupPermissions = [];
-
- $this->resetServices();
+ $this->setMwGlobals( 'wgGroupPermissions', [] );
$this->assertEquals( $check[$action][1],
$this->title->getUserPermissionsErrors( $action, $this->user, true ) );
$this->assertEquals( $check[$action][1],
$this->title->getUserPermissionsErrors( $action, $this->user, 'secure' ) );
- $wgGroupPermissions = $old;
- $this->resetServices();
+ $this->setMwGlobals( 'wgGroupPermissions', $old );
$this->overrideUserPermissions( $this->user, $action );
$this->assertEquals( $check[$action][2],
}
protected function runGroupPermissions( $action, $result, $result2 = null ) {
- global $wgGroupPermissions;
-
if ( $result2 === null ) {
$result2 = $result;
}
$userPermsOverrides = MediaWikiServices::getInstance()->getPermissionManager()
->getUserPermissions( $this->user );
- $wgGroupPermissions['autoconfirmed']['move'] = false;
- $wgGroupPermissions['user']['move'] = false;
- $this->resetServices();
+ $this->setGroupPermissions( 'autoconfirmed', 'move', false );
+ $this->setGroupPermissions( 'user', 'move', false );
$this->overrideUserPermissions( $this->user, $userPermsOverrides );
$res = $this->title->getUserPermissionsErrors( $action, $this->user );
$this->assertEquals( $result, $res );
- $wgGroupPermissions['autoconfirmed']['move'] = true;
- $wgGroupPermissions['user']['move'] = false;
- $this->resetServices();
+ $this->setGroupPermissions( 'autoconfirmed', 'move', true );
+ $this->setGroupPermissions( 'user', 'move', false );
$this->overrideUserPermissions( $this->user, $userPermsOverrides );
$res = $this->title->getUserPermissionsErrors( $action, $this->user );
$this->assertEquals( $result2, $res );
- $wgGroupPermissions['autoconfirmed']['move'] = true;
- $wgGroupPermissions['user']['move'] = true;
- $this->resetServices();
+ $this->setGroupPermissions( 'autoconfirmed', 'move', true );
+ $this->setGroupPermissions( 'user', 'move', true );
$this->overrideUserPermissions( $this->user, $userPermsOverrides );
$res = $this->title->getUserPermissionsErrors( $action, $this->user );
$this->assertEquals( $result2, $res );
- $wgGroupPermissions['autoconfirmed']['move'] = false;
- $wgGroupPermissions['user']['move'] = true;
- $this->resetServices();
+ $this->setGroupPermissions( 'autoconfirmed', 'move', false );
+ $this->setGroupPermissions( 'user', 'move', true );
$this->overrideUserPermissions( $this->user, $userPermsOverrides );
$res = $this->title->getUserPermissionsErrors( $action, $this->user );
$this->assertEquals( $result2, $res );
* @covers \MediaWiki\Permissions\PermissionManager::checkSpecialsAndNSPermissions
*/
public function testSpecialsAndNSPermissions() {
- global $wgNamespaceProtection;
$this->setUser( $this->userName );
$this->setTitle( NS_SPECIAL );
$this->assertEquals( [ [ 'badaccess-group0' ] ],
$this->title->getUserPermissionsErrors( 'bogus', $this->user ) );
- $wgNamespaceProtection[NS_USER] = [ 'bogus' ];
-
+ $this->mergeMwGlobalArrayValue( 'wgNamespaceProtection', [
+ NS_USER => [ 'bogus' ]
+ ] );
+ $this->resetServices();
$this->setTitle( NS_USER );
$this->overrideUserPermissions( $this->user );
$this->assertEquals( [ [ 'badaccess-group0' ],
$this->assertEquals( [ [ 'protectedinterface', 'bogus' ] ],
$this->title->getUserPermissionsErrors( 'bogus', $this->user ) );
- $wgNamespaceProtection = null;
-
+ $this->setMwGlobals( 'wgNamespaceProtection', null );
+ $this->resetServices();
$this->overrideUserPermissions( $this->user, 'bogus' );
$this->assertEquals( [],
$this->title->getUserPermissionsErrors( 'bogus', $this->user ) );
'wgEmailAuthentication' => true,
'wgBlockDisablesLogin' => false,
] );
- $this->resetServices();
$this->overrideUserPermissions(
$this->user,
$this->title->getUserPermissionsErrors( 'edit', $this->user ) );
$this->setMwGlobals( 'wgEmailConfirmToEdit', false );
- $this->resetServices();
$this->overrideUserPermissions(
$this->user,
[ 'createpage', 'edit', 'move', 'rollback', 'patrol', 'upload', 'purge' ]
'address' => '127.0.8.1',
'by' => $this->user->getId(),
'reason' => 'no reason given',
- 'timestamp' => $prev + 3600,
+ 'timestamp' => $prev,
'auto' => true,
'expiry' => 0
] );
- $this->user->mBlock->setTimestamp( 0 );
$this->assertEquals( [ [ 'autoblockedtext',
"[[User:Useruser|\u{202A}Useruser\u{202C}]]", 'no reason given', '127.0.0.1',
"\u{202A}Useruser\u{202C}", null, 'infinite', '127.0.8.1',
],
],
] );
- $this->resetServices();
$now = time();
$this->user->mBlockedby = $this->user->getName();
]
]
] );
-
- // Reset services since we modified $wgLocalInterwikis
- $this->overrideMwServices();
}
/**
--- /dev/null
+<?php
+
+/**
+ * @covers WikiReference
+ */
+class WikiReferenceTest extends MediaWikiIntegrationTestCase {
+
+ public function provideGetDisplayName() {
+ return [
+ 'http' => [ 'foo.bar', 'http://foo.bar' ],
+ 'https' => [ 'foo.bar', 'http://foo.bar' ],
+
+ // apparently, this is the expected behavior
+ 'invalid' => [ 'purple kittens', 'purple kittens' ],
+ ];
+ }
+
+ /**
+ * @dataProvider provideGetDisplayName
+ */
+ public function testGetDisplayName( $expected, $canonicalServer ) {
+ $reference = new WikiReference( $canonicalServer, '/wiki/$1' );
+ $this->assertEquals( $expected, $reference->getDisplayName() );
+ }
+
+ public function testGetCanonicalServer() {
+ $reference = new WikiReference( 'https://acme.com', '/wiki/$1', '//acme.com' );
+ $this->assertEquals( 'https://acme.com', $reference->getCanonicalServer() );
+ }
+
+ public function provideGetCanonicalUrl() {
+ return [
+ 'no fragment' => [
+ 'https://acme.com/wiki/Foo',
+ 'https://acme.com',
+ '//acme.com',
+ '/wiki/$1',
+ 'Foo',
+ null
+ ],
+ 'empty fragment' => [
+ 'https://acme.com/wiki/Foo',
+ 'https://acme.com',
+ '//acme.com',
+ '/wiki/$1',
+ 'Foo',
+ ''
+ ],
+ 'fragment' => [
+ 'https://acme.com/wiki/Foo#Bar',
+ 'https://acme.com',
+ '//acme.com',
+ '/wiki/$1',
+ 'Foo',
+ 'Bar'
+ ],
+ 'double fragment' => [
+ 'https://acme.com/wiki/Foo#Bar%23Xus',
+ 'https://acme.com',
+ '//acme.com',
+ '/wiki/$1',
+ 'Foo',
+ 'Bar#Xus'
+ ],
+ 'escaped fragment' => [
+ 'https://acme.com/wiki/Foo%23Bar',
+ 'https://acme.com',
+ '//acme.com',
+ '/wiki/$1',
+ 'Foo#Bar',
+ null
+ ],
+ 'empty path' => [
+ 'https://acme.com/Foo',
+ 'https://acme.com',
+ '//acme.com',
+ '/$1',
+ 'Foo',
+ null
+ ],
+ ];
+ }
+
+ /**
+ * @dataProvider provideGetCanonicalUrl
+ */
+ public function testGetCanonicalUrl(
+ $expected, $canonicalServer, $server, $path, $page, $fragmentId
+ ) {
+ $reference = new WikiReference( $canonicalServer, $path, $server );
+ $this->assertEquals( $expected, $reference->getCanonicalUrl( $page, $fragmentId ) );
+ }
+
+ /**
+ * @dataProvider provideGetCanonicalUrl
+ * @note getUrl is an alias for getCanonicalUrl
+ */
+ public function testGetUrl( $expected, $canonicalServer, $server, $path, $page, $fragmentId ) {
+ $reference = new WikiReference( $canonicalServer, $path, $server );
+ $this->assertEquals( $expected, $reference->getUrl( $page, $fragmentId ) );
+ }
+
+ public function provideGetFullUrl() {
+ return [
+ 'no fragment' => [
+ '//acme.com/wiki/Foo',
+ 'https://acme.com',
+ '//acme.com',
+ '/wiki/$1',
+ 'Foo',
+ null
+ ],
+ 'empty fragment' => [
+ '//acme.com/wiki/Foo',
+ 'https://acme.com',
+ '//acme.com',
+ '/wiki/$1',
+ 'Foo',
+ ''
+ ],
+ 'fragment' => [
+ '//acme.com/wiki/Foo#Bar',
+ 'https://acme.com',
+ '//acme.com',
+ '/wiki/$1',
+ 'Foo',
+ 'Bar'
+ ],
+ 'double fragment' => [
+ '//acme.com/wiki/Foo#Bar%23Xus',
+ 'https://acme.com',
+ '//acme.com',
+ '/wiki/$1',
+ 'Foo',
+ 'Bar#Xus'
+ ],
+ 'escaped fragment' => [
+ '//acme.com/wiki/Foo%23Bar',
+ 'https://acme.com',
+ '//acme.com',
+ '/wiki/$1',
+ 'Foo#Bar',
+ null
+ ],
+ 'empty path' => [
+ '//acme.com/Foo',
+ 'https://acme.com',
+ '//acme.com',
+ '/$1',
+ 'Foo',
+ null
+ ],
+ ];
+ }
+
+ /**
+ * @dataProvider provideGetFullUrl
+ */
+ public function testGetFullUrl( $expected, $canonicalServer, $server, $path, $page, $fragmentId ) {
+ $reference = new WikiReference( $canonicalServer, $path, $server );
+ $this->assertEquals( $expected, $reference->getFullUrl( $page, $fragmentId ) );
+ }
+
+}
}
$status = StatusValue::newGood();
- $status->setOk( false );
+ $status->setOK( false );
try {
$mock->dieStatus( $status );
$this->fail( 'Expected exception not thrown' );
$this->setMwGlobals( 'wgRevokePermissions',
[ 'user' => [ 'applychangetags' => true ] ] );
- $this->resetServices();
-
$this->doBlock( [ 'tags' => 'custom tag' ] );
}
$this->mergeMwGlobalArrayValue( 'wgGroupPermissions',
[ 'sysop' => $newPermissions ] );
- $this->resetServices();
$res = $this->doBlock( [ 'hidename' => '' ] );
$dbw = wfGetDB( DB_MASTER );
$this->setMwGlobals( 'wgRevokePermissions',
[ 'sysop' => [ 'blockemail' => true ] ] );
- $this->resetServices();
-
$this->doBlock( [ 'noemail' => '' ] );
}
ChangeTags::defineTag( 'custom tag' );
$this->setMwGlobals( 'wgRevokePermissions',
[ 'user' => [ 'applychangetags' => true ] ] );
- $this->resetServices();
$this->editPage( $name, 'Some text' );
$this->tablesUsed,
[ 'change_tag', 'change_tag_def', 'logging' ]
);
- $this->resetServices();
}
public function testEdit() {
ChangeTags::defineTag( 'custom tag' );
$this->setMwGlobals( 'wgRevokePermissions',
[ 'user' => [ 'applychangetags' => true ] ] );
- // Supply services with updated globals
- $this->resetServices();
try {
$this->doApiRequestWithToken( [
$this->setMwGlobals( 'wgRevokePermissions',
[ 'user' => [ 'upload' => true ] ] );
- // Supply services with updated globals
- $this->resetServices();
$this->doApiRequestWithToken( [
'action' => 'edit',
'The content you supplied exceeds the article size limit of 1 kilobyte.' );
$this->setMwGlobals( 'wgMaxArticleSize', 1 );
- // Supply services with updated globals
- $this->resetServices();
$text = str_repeat( '!', 1025 );
'The action you have requested is limited to users in the group: ' );
$this->setMwGlobals( 'wgRevokePermissions', [ '*' => [ 'edit' => true ] ] );
- // Supply services with updated globals
- $this->resetServices();
$this->doApiRequestWithToken( [
'action' => 'edit',
$this->setMwGlobals( 'wgRevokePermissions',
[ 'user' => [ 'editcontentmodel' => true ] ] );
- // Supply services with updated globals
- $this->resetServices();
$this->doApiRequestWithToken( [
'action' => 'edit',
public function testSetCacheModeUnrecognized() {
$api = new ApiMain();
$api->setCacheMode( 'unrecognized' );
- $this->resetServices();
$this->assertSame(
'private',
TestingAccessWrapper::newFromObject( $api )->mCacheMode,
$name = ucfirst( __FUNCTION__ );
$this->mergeMwGlobalArrayValue( 'wgNamespacesWithSubpages', [ NS_MAIN => true ] );
- $this->resetServices();
$pages = [ $name, "$name/1", "$name/2", "Talk:$name", "Talk:$name/1", "Talk:$name/3" ];
$ids = [];
$this->mUserMock->method( 'getOptions' )
->willReturn( [] );
+ // DefaultPreferencesFactory calls a ton of user methods, but we still want to list all of
+ // them in case bugs are caused by unexpected things returning null that shouldn't.
+ $this->mUserMock->expects( $this->never() )->method( $this->anythingBut(
+ 'getEffectiveGroups', 'getOptionKinds', 'getInstanceForUpdate', 'getOptions', 'getId',
+ 'isAnon', 'getRequest', 'isLoggedIn', 'getName', 'getGroupMemberships', 'getEditCount',
+ 'getRegistration', 'isAllowed', 'getRealName', 'getOption', 'getStubThreshold',
+ 'getBoolOption', 'getEmail', 'getDatePreference', 'useRCPatrol', 'useNPPatrol',
+ 'setOption', 'saveSettings', 'resetOptions', 'isRegistered'
+ ) );
+
// Create a new context
$this->mContext = new DerivativeContext( new RequestContext() );
$this->mContext->getContext()->setTitle( Title::newFromText( 'Test' ) );
private function executeQuery( $request ) {
$this->mContext->setRequest( new FauxRequest( $request, true, $this->mSession ) );
+ $this->mUserMock->method( 'getRequest' )->willReturn( $this->mContext->getRequest() );
+
$this->mTested->execute();
return $this->mTested->getResult()->getResultData( null, [ 'Strip' => 'all' ] );
$this->setMwGlobals( 'wgExtraInterlanguageLinkPrefixes', [ 'madeuplanguage' ] );
$this->tablesUsed[] = 'interwiki';
- $this->resetServices();
}
/**
*/
private function mockResultClosure( $title, $setters = [] ) {
return function () use ( $title, $setters ){
- $result = MockSearchResult::newFromTitle( Title::newFromText( $title ) );
+ $result = new MockSearchResult( Title::newFromText( $title ) );
foreach ( $setters as $method => $param ) {
$result->$method( $param );
'wgExtraInterlanguageLinkPrefixes' => [ 'self' ],
'wgExtraLanguageNames' => [ 'self' => 'Recursion' ],
] );
- $this->resetServices();
MessageCache::singleton()->enable();
$this->setExpectedApiException( 'apierror-siteinfo-includealldenied' );
}
- $mockLB = $this->getMockBuilder( LoadBalancer::class )
- ->disableOriginalConstructor()
- ->setMethods( [ 'getMaxLag', 'getLagTimes', 'getServerName', '__destruct' ] )
- ->getMock();
+ $mockLB = $this->createMock( LoadBalancer::class );
$mockLB->method( 'getMaxLag' )->willReturn( [ null, 7, 1 ] );
$mockLB->method( 'getLagTimes' )->willReturn( [ 5, 7 ] );
$mockLB->method( 'getServerName' )->will( $this->returnValueMap( [
[ 0, 'apple' ], [ 1, 'carrot' ]
] ) );
+ $mockLB->method( 'getLocalDomainID' )->willReturn( 'testdomain' );
+ $mockLB->expects( $this->never() )->method( $this->anythingBut(
+ 'getMaxLag', 'getLagTimes', 'getServerName', 'getLocalDomainID', '__destruct'
+ ) );
$this->setService( 'DBLoadBalancer', $mockLB );
$this->setMwGlobals( 'wgShowHostnames', $showHostnames );
+++ /dev/null
-<?php
-
-/**
- * For backward compatibility since 1.31
- */
-abstract class ApiTestCaseUpload extends ApiUploadTestCase {
-}
<?php
+
/**
- * n.b. Ensure that you can write to the images/ directory as the
- * user that will run tests.
- *
- * Note for reviewers: this intentionally duplicates functionality already in
- * "ApiSetup" and so on. This framework works better IMO and has less
- * strangeness (such as test cases inheriting from "ApiSetup"...) (and in the
- * case of the other Upload tests, this flat out just actually works... )
- *
- * @todo Port the other Upload tests, and other API tests to this framework
- *
- * @todo Broken test, reports false errors from time to time.
- * See https://phabricator.wikimedia.org/T28169
- *
- * @todo This is pretty sucky... needs to be prettified.
- *
* @group API
* @group Database
* @group medium
- * @group Broken
*
* @covers ApiUpload
*/
class ApiUploadTest extends ApiUploadTestCase {
- /**
- * Testing login
- * XXX this is a funny way of getting session context
- */
- public function testLogin() {
- $user = self::$users['uploader'];
- $userName = $user->getUser()->getName();
- $password = $user->getPassword();
-
- $params = [
- 'action' => 'login',
- 'lgname' => $userName,
- 'lgpassword' => $password
- ];
- list( $result, , $session ) = $this->doApiRequest( $params );
- $this->assertArrayHasKey( "login", $result );
- $this->assertArrayHasKey( "result", $result['login'] );
- $this->assertEquals( "NeedToken", $result['login']['result'] );
- $token = $result['login']['token'];
-
- $params = [
- 'action' => 'login',
- 'lgtoken' => $token,
- 'lgname' => $userName,
- 'lgpassword' => $password
- ];
- list( $result, , $session ) = $this->doApiRequest( $params, $session );
- $this->assertArrayHasKey( "login", $result );
- $this->assertArrayHasKey( "result", $result['login'] );
- $this->assertEquals( "Success", $result['login']['result'] );
-
- $this->assertNotEmpty( $session, 'API Login must return a session' );
-
- return $session;
+ private function filePath( $fileName ) {
+ return __DIR__ . '/../../data/media/' . $fileName;
}
- /**
- * @depends testLogin
- */
- public function testUploadRequiresToken( $session ) {
- $exception = false;
- try {
- $this->doApiRequest( [
- 'action' => 'upload'
- ] );
- } catch ( ApiUsageException $e ) {
- $exception = true;
- $this->assertContains( 'The "token" parameter must be set', $e->getMessage() );
- }
- $this->assertTrue( $exception, "Got exception" );
+ public function setUp() {
+ parent::setUp();
+ $this->tablesUsed[] = 'watchlist'; // This test might interfere with watchlists test.
+ $this->tablesUsed = array_merge( $this->tablesUsed, LocalFile::getQueryInfo()['tables'] );
+ $this->setService( 'RepoGroup', new RepoGroup(
+ [
+ 'class' => LocalRepo::class,
+ 'name' => 'temp',
+ 'backend' => new FSFileBackend( [
+ 'name' => 'temp-backend',
+ 'wikiId' => wfWikiID(),
+ 'basePath' => $this->getNewTempDirectory()
+ ] )
+ ],
+ [],
+ null
+ ) );
+ $this->resetServices();
}
- /**
- * @depends testLogin
- */
- public function testUploadMissingParams( $session ) {
- $exception = false;
- try {
- $this->doApiRequestWithToken( [
- 'action' => 'upload',
- ], $session, self::$users['uploader']->getUser() );
- } catch ( ApiUsageException $e ) {
- $exception = true;
- $this->assertEquals(
- 'One of the parameters "filekey", "file" and "url" is required.',
- $e->getMessage()
- );
- }
- $this->assertTrue( $exception, "Got exception" );
+ public function testUploadRequiresToken() {
+ $this->setExpectedException(
+ ApiUsageException::class,
+ 'The "token" parameter must be set'
+ );
+ $this->doApiRequest( [
+ 'action' => 'upload'
+ ] );
}
- /**
- * @depends testLogin
- */
- public function testUpload( $session ) {
- $extension = 'png';
- $mimeType = 'image/png';
-
- try {
- $randomImageGenerator = new RandomImageGenerator();
- $filePaths = $randomImageGenerator->writeImages( 1, $extension, $this->getNewTempDirectory() );
- } catch ( Exception $e ) {
- $this->markTestIncomplete( $e->getMessage() );
- }
-
- /** @var array $filePaths */
- $filePath = $filePaths[0];
- $fileSize = filesize( $filePath );
- $fileName = basename( $filePath );
-
- $this->deleteFileByFileName( $fileName );
- $this->deleteFileByContent( $filePath );
+ public function testUploadMissingParams() {
+ $this->setExpectedException(
+ ApiUsageException::class,
+ 'One of the parameters "filekey", "file" and "url" is required'
+ );
+ $this->doApiRequestWithToken( [
+ 'action' => 'upload',
+ ], null, self::$users['uploader']->getUser() );
+ }
- if ( !$this->fakeUploadFile( 'file', $fileName, $mimeType, $filePath ) ) {
- $this->markTestIncomplete( "Couldn't upload file!\n" );
- }
+ public function testUpload() {
+ $fileName = 'TestUpload.jpg';
+ $mimeType = 'image/jpeg';
+ $filePath = $this->filePath( 'yuv420.jpg' );
- $params = [
+ $this->fakeUploadFile( 'file', $fileName, $mimeType, $filePath );
+ list( $result ) = $this->doApiRequestWithToken( [
'action' => 'upload',
'filename' => $fileName,
'file' => 'dummy content',
'comment' => 'dummy comment',
'text' => "This is the page text for $fileName",
- ];
+ ], null, self::$users['uploader']->getUser() );
- $exception = false;
- try {
- list( $result, , ) = $this->doApiRequestWithToken( $params, $session,
- self::$users['uploader']->getUser() );
- } catch ( ApiUsageException $e ) {
- $exception = true;
- }
- $this->assertTrue( isset( $result['upload'] ) );
+ $this->assertArrayHasKey( 'upload', $result );
$this->assertEquals( 'Success', $result['upload']['result'] );
- $this->assertEquals( $fileSize, (int)$result['upload']['imageinfo']['size'] );
+ $this->assertSame( filesize( $filePath ), (int)$result['upload']['imageinfo']['size'] );
$this->assertEquals( $mimeType, $result['upload']['imageinfo']['mime'] );
- $this->assertFalse( $exception );
-
- // clean up
- $this->deleteFileByFileName( $fileName );
}
- /**
- * @depends testLogin
- */
- public function testUploadZeroLength( $session ) {
- $mimeType = 'image/png';
-
+ public function testUploadZeroLength() {
$filePath = $this->getNewTempFile();
- $fileName = "apiTestUploadZeroLength.png";
-
- $this->deleteFileByFileName( $fileName );
+ $mimeType = 'image/jpeg';
+ $fileName = "ApiTestUploadZeroLength.jpg";
- if ( !$this->fakeUploadFile( 'file', $fileName, $mimeType, $filePath ) ) {
- $this->markTestIncomplete( "Couldn't upload file!\n" );
- }
+ $this->fakeUploadFile( 'file', $fileName, $mimeType, $filePath );
- $params = [
+ $this->setExpectedException(
+ ApiUsageException::class,
+ 'The file you submitted was empty'
+ );
+ $this->doApiRequestWithToken( [
'action' => 'upload',
'filename' => $fileName,
'file' => 'dummy content',
'comment' => 'dummy comment',
'text' => "This is the page text for $fileName",
- ];
-
- $exception = false;
- try {
- $this->doApiRequestWithToken( $params, $session, self::$users['uploader']->getUser() );
- } catch ( ApiUsageException $e ) {
- $this->assertContains( 'The file you submitted was empty', $e->getMessage() );
- $exception = true;
- }
- $this->assertTrue( $exception );
-
- // clean up
- $this->deleteFileByFileName( $fileName );
+ ], null, self::$users['uploader']->getUser() );
}
- /**
- * @depends testLogin
- */
- public function testUploadSameFileName( $session ) {
- $extension = 'png';
- $mimeType = 'image/png';
-
- try {
- $randomImageGenerator = new RandomImageGenerator();
- $filePaths = $randomImageGenerator->writeImages( 2, $extension, $this->getNewTempDirectory() );
- } catch ( Exception $e ) {
- $this->markTestIncomplete( $e->getMessage() );
- }
-
- // we'll reuse this filename
- /** @var array $filePaths */
- $fileName = basename( $filePaths[0] );
-
- // clear any other files with the same name
- $this->deleteFileByFileName( $fileName );
+ public function testUploadSameFileName() {
+ $fileName = 'TestUploadSameFileName.jpg';
+ $mimeType = 'image/jpeg';
+ $filePaths = [
+ $this->filePath( 'yuv420.jpg' ),
+ $this->filePath( 'yuv444.jpg' )
+ ];
// we reuse these params
$params = [
// first upload .... should succeed
- if ( !$this->fakeUploadFile( 'file', $fileName, $mimeType, $filePaths[0] ) ) {
- $this->markTestIncomplete( "Couldn't upload file!\n" );
- }
-
- $exception = false;
- try {
- list( $result, , $session ) = $this->doApiRequestWithToken( $params, $session,
- self::$users['uploader']->getUser() );
- } catch ( ApiUsageException $e ) {
- $exception = true;
- }
- $this->assertTrue( isset( $result['upload'] ) );
+ $this->fakeUploadFile( 'file', $fileName, $mimeType, $filePaths[0] );
+ list( $result ) = $this->doApiRequestWithToken( $params, null,
+ self::$users['uploader']->getUser() );
+ $this->assertArrayHasKey( 'upload', $result );
$this->assertEquals( 'Success', $result['upload']['result'] );
- $this->assertFalse( $exception );
// second upload with the same name (but different content)
- if ( !$this->fakeUploadFile( 'file', $fileName, $mimeType, $filePaths[1] ) ) {
- $this->markTestIncomplete( "Couldn't upload file!\n" );
- }
-
- $exception = false;
- try {
- list( $result, , ) = $this->doApiRequestWithToken( $params, $session,
- self::$users['uploader']->getUser() ); // FIXME: leaks a temporary file
- } catch ( ApiUsageException $e ) {
- $exception = true;
- }
- $this->assertTrue( isset( $result['upload'] ) );
+ $this->fakeUploadFile( 'file', $fileName, $mimeType, $filePaths[1] );
+ list( $result ) = $this->doApiRequestWithToken( $params, null,
+ self::$users['uploader']->getUser() );
+ $this->assertArrayHasKey( 'upload', $result );
$this->assertEquals( 'Warning', $result['upload']['result'] );
- $this->assertTrue( isset( $result['upload']['warnings'] ) );
- $this->assertTrue( isset( $result['upload']['warnings']['exists'] ) );
- $this->assertFalse( $exception );
-
- // clean up
- $this->deleteFileByFileName( $fileName );
+ $this->assertArrayHasKey( 'warnings', $result['upload'] );
+ $this->assertArrayHasKey( 'exists', $result['upload']['warnings'] );
}
- /**
- * @depends testLogin
- */
- public function testUploadSameContent( $session ) {
- $extension = 'png';
- $mimeType = 'image/png';
-
- try {
- $randomImageGenerator = new RandomImageGenerator();
- $filePaths = $randomImageGenerator->writeImages( 1, $extension, $this->getNewTempDirectory() );
- } catch ( Exception $e ) {
- $this->markTestIncomplete( $e->getMessage() );
- }
-
- /** @var array $filePaths */
- $fileNames[0] = basename( $filePaths[0] );
- $fileNames[1] = "SameContentAs" . $fileNames[0];
-
- // clear any other files with the same name or content
- $this->deleteFileByContent( $filePaths[0] );
- $this->deleteFileByFileName( $fileNames[0] );
- $this->deleteFileByFileName( $fileNames[1] );
+ public function testUploadSameContent() {
+ $fileNames = [ 'TestUploadSameContent_1.jpg', 'TestUploadSameContent_2.jpg' ];
+ $mimeType = 'image/jpeg';
+ $filePath = $this->filePath( 'yuv420.jpg' );
// first upload .... should succeed
-
- $params = [
+ $this->fakeUploadFile( 'file', $fileNames[0], $mimeType, $filePath );
+ list( $result ) = $this->doApiRequestWithToken( [
'action' => 'upload',
'filename' => $fileNames[0],
'file' => 'dummy content',
'comment' => 'dummy comment',
- 'text' => "This is the page text for " . $fileNames[0],
- ];
-
- if ( !$this->fakeUploadFile( 'file', $fileNames[0], $mimeType, $filePaths[0] ) ) {
- $this->markTestIncomplete( "Couldn't upload file!\n" );
- }
-
- $exception = false;
- try {
- list( $result, , $session ) = $this->doApiRequestWithToken( $params, $session,
- self::$users['uploader']->getUser() );
- } catch ( ApiUsageException $e ) {
- $exception = true;
- }
- $this->assertTrue( isset( $result['upload'] ) );
+ 'text' => "This is the page text for {$fileNames[0]}",
+ ], null, self::$users['uploader']->getUser() );
+ $this->assertArrayHasKey( 'upload', $result );
$this->assertEquals( 'Success', $result['upload']['result'] );
- $this->assertFalse( $exception );
// second upload with the same content (but different name)
+ $this->fakeUploadFile( 'file', $fileNames[1], $mimeType, $filePath );
+ list( $result ) = $this->doApiRequestWithToken( [
+ 'action' => 'upload',
+ 'filename' => $fileNames[1],
+ 'file' => 'dummy content',
+ 'comment' => 'dummy comment',
+ 'text' => "This is the page text for {$fileNames[1]}",
+ ], null, self::$users['uploader']->getUser() );
- if ( !$this->fakeUploadFile( 'file', $fileNames[1], $mimeType, $filePaths[0] ) ) {
- $this->markTestIncomplete( "Couldn't upload file!\n" );
- }
-
- $params = [
- 'action' => 'upload',
- 'filename' => $fileNames[1],
- 'file' => 'dummy content',
- 'comment' => 'dummy comment',
- 'text' => "This is the page text for " . $fileNames[1],
- ];
-
- $exception = false;
- try {
- list( $result ) = $this->doApiRequestWithToken( $params, $session,
- self::$users['uploader']->getUser() ); // FIXME: leaks a temporary file
- } catch ( ApiUsageException $e ) {
- $exception = true;
- }
- $this->assertTrue( isset( $result['upload'] ) );
+ $this->assertArrayHasKey( 'upload', $result );
$this->assertEquals( 'Warning', $result['upload']['result'] );
- $this->assertTrue( isset( $result['upload']['warnings'] ) );
- $this->assertTrue( isset( $result['upload']['warnings']['duplicate'] ) );
- $this->assertFalse( $exception );
-
- // clean up
- $this->deleteFileByFileName( $fileNames[0] );
- $this->deleteFileByFileName( $fileNames[1] );
+ $this->assertArrayHasKey( 'warnings', $result['upload'] );
+ $this->assertArrayHasKey( 'duplicate', $result['upload']['warnings'] );
+ $this->assertArrayEquals( [ $fileNames[0] ], $result['upload']['warnings']['duplicate'] );
+ $this->assertArrayNotHasKey( 'exists', $result['upload']['warnings'] );
}
- /**
- * @depends testLogin
- */
- public function testUploadStash( $session ) {
- $this->setMwGlobals( [
- 'wgUser' => self::$users['uploader']->getUser(), // @todo FIXME: still used somewhere
- ] );
-
- $extension = 'png';
- $mimeType = 'image/png';
-
- try {
- $randomImageGenerator = new RandomImageGenerator();
- $filePaths = $randomImageGenerator->writeImages( 1, $extension, $this->getNewTempDirectory() );
- } catch ( Exception $e ) {
- $this->markTestIncomplete( $e->getMessage() );
- }
-
- /** @var array $filePaths */
- $filePath = $filePaths[0];
- $fileSize = filesize( $filePath );
- $fileName = basename( $filePath );
-
- $this->deleteFileByFileName( $fileName );
- $this->deleteFileByContent( $filePath );
-
- if ( !$this->fakeUploadFile( 'file', $fileName, $mimeType, $filePath ) ) {
- $this->markTestIncomplete( "Couldn't upload file!\n" );
- }
+ public function testUploadStash() {
+ $fileName = 'TestUploadStash.jpg';
+ $mimeType = 'image/jpeg';
+ $filePath = $this->filePath( 'yuv420.jpg' );
- $params = [
+ $this->fakeUploadFile( 'file', $fileName, $mimeType, $filePath );
+ list( $result ) = $this->doApiRequestWithToken( [
'action' => 'upload',
'stash' => 1,
'filename' => $fileName,
'file' => 'dummy content',
'comment' => 'dummy comment',
'text' => "This is the page text for $fileName",
- ];
+ ], null, self::$users['uploader']->getUser() );
- $exception = false;
- try {
- list( $result, , $session ) = $this->doApiRequestWithToken( $params, $session,
- self::$users['uploader']->getUser() ); // FIXME: leaks a temporary file
- } catch ( ApiUsageException $e ) {
- $exception = true;
- }
- $this->assertFalse( $exception );
- $this->assertTrue( isset( $result['upload'] ) );
+ $this->assertArrayHasKey( 'upload', $result );
$this->assertEquals( 'Success', $result['upload']['result'] );
- $this->assertEquals( $fileSize, (int)$result['upload']['imageinfo']['size'] );
+ $this->assertSame( filesize( $filePath ), (int)$result['upload']['imageinfo']['size'] );
$this->assertEquals( $mimeType, $result['upload']['imageinfo']['mime'] );
- $this->assertTrue( isset( $result['upload']['filekey'] ) );
+ $this->assertArrayHasKey( 'filekey', $result['upload'] );
$this->assertEquals( $result['upload']['sessionkey'], $result['upload']['filekey'] );
$filekey = $result['upload']['filekey'];
// XXX ...but how to test this, with a fake WebRequest with the session?
// now we should try to release the file from stash
- $params = [
+ $this->clearFakeUploads();
+ list( $result ) = $this->doApiRequestWithToken( [
'action' => 'upload',
'filekey' => $filekey,
'filename' => $fileName,
'comment' => 'dummy comment',
'text' => "This is the page text for $fileName, altered",
- ];
-
- $this->clearFakeUploads();
- $exception = false;
- try {
- list( $result ) = $this->doApiRequestWithToken( $params, $session,
- self::$users['uploader']->getUser() );
- } catch ( ApiUsageException $e ) {
- $exception = true;
- }
- $this->assertTrue( isset( $result['upload'] ) );
+ ], null, self::$users['uploader']->getUser() );
+ $this->assertArrayHasKey( 'upload', $result );
$this->assertEquals( 'Success', $result['upload']['result'] );
- $this->assertFalse( $exception, "No ApiUsageException exception." );
-
- // clean up
- $this->deleteFileByFileName( $fileName );
}
- /**
- * @depends testLogin
- */
- public function testUploadChunks( $session ) {
- $this->setMwGlobals( [
- // @todo FIXME: still used somewhere
- 'wgUser' => self::$users['uploader']->getUser(),
- ] );
-
- $chunkSize = 1048576;
- // Download a large image file
- // (using RandomImageGenerator for large files is not stable)
- // @todo Don't download files from wikimedia.org
+ public function testUploadChunks() {
+ $fileName = 'TestUploadChunks.jpg';
$mimeType = 'image/jpeg';
- $url = 'http://upload.wikimedia.org/wikipedia/commons/'
- . 'e/ed/Oberaargletscher_from_Oberaar%2C_2010_07.JPG';
- $filePath = $this->getNewTempDirectory() . '/Oberaargletscher_from_Oberaar.jpg';
- try {
- copy( $url, $filePath );
- } catch ( Exception $e ) {
- $this->markTestIncomplete( $e->getMessage() );
- }
-
+ $filePath = $this->filePath( 'yuv420.jpg' );
$fileSize = filesize( $filePath );
- $fileName = basename( $filePath );
+ $chunkSize = 20 * 1024; // The file is ~60kB, use 20kB chunks
- $this->deleteFileByFileName( $fileName );
- $this->deleteFileByContent( $filePath );
+ $this->setMwGlobals( [
+ 'wgMinUploadChunkSize' => $chunkSize
+ ] );
// Base upload params:
$params = [
];
// Upload chunks
- $chunkSessionKey = false;
- $resultOffset = 0;
- // Open the file:
- Wikimedia\suppressWarnings();
$handle = fopen( $filePath, "r" );
- Wikimedia\restoreWarnings();
-
- if ( $handle === false ) {
- $this->markTestIncomplete( "could not open file: $filePath" );
- }
-
+ $resultOffset = 0;
+ $filekey = false;
while ( !feof( $handle ) ) {
- // Get the current chunk
- Wikimedia\suppressWarnings();
$chunkData = fread( $handle, $chunkSize );
- Wikimedia\restoreWarnings();
// Upload the current chunk into the $_FILE object:
$this->fakeUploadChunk( 'chunk', 'blob', $mimeType, $chunkData );
-
- // Check for chunkSessionKey
- if ( !$chunkSessionKey ) {
- // Upload fist chunk ( and get the session key )
- try {
- list( $result, , $session ) = $this->doApiRequestWithToken( $params, $session,
- self::$users['uploader']->getUser() );
- } catch ( ApiUsageException $e ) {
- $this->markTestIncomplete( $e->getMessage() );
- }
+ if ( !$filekey ) {
+ list( $result ) = $this->doApiRequestWithToken( $params, null,
+ self::$users['uploader']->getUser() );
// Make sure we got a valid chunk continue:
- $this->assertTrue( isset( $result['upload'] ) );
- $this->assertTrue( isset( $result['upload']['filekey'] ) );
- // If we don't get a session key mark test incomplete.
- if ( !isset( $result['upload']['filekey'] ) ) {
- $this->markTestIncomplete( "no filekey provided" );
- }
- $chunkSessionKey = $result['upload']['filekey'];
+ $this->assertArrayHasKey( 'upload', $result );
+ $this->assertArrayHasKey( 'filekey', $result['upload'] );
$this->assertEquals( 'Continue', $result['upload']['result'] );
- // First chunk should have chunkSize == offset
$this->assertEquals( $chunkSize, $result['upload']['offset'] );
+
+ $filekey = $result['upload']['filekey'];
$resultOffset = $result['upload']['offset'];
- continue;
- }
- // Filekey set to chunk session
- $params['filekey'] = $chunkSessionKey;
- // Update the offset ( always add chunkSize for subquent chunks
- // should be in-sync with $result['upload']['offset'] )
- $params['offset'] += $chunkSize;
- // Make sure param offset is insync with resultOffset:
- $this->assertEquals( $resultOffset, $params['offset'] );
- // Upload current chunk
- try {
- list( $result, , $session ) = $this->doApiRequestWithToken( $params, $session,
- self::$users['uploader']->getUser() );
- } catch ( ApiUsageException $e ) {
- $this->markTestIncomplete( $e->getMessage() );
- }
- // Make sure we got a valid chunk continue:
- $this->assertTrue( isset( $result['upload'] ) );
- $this->assertTrue( isset( $result['upload']['filekey'] ) );
-
- // Check if we were on the last chunk:
- if ( $params['offset'] + $chunkSize >= $fileSize ) {
- $this->assertEquals( 'Success', $result['upload']['result'] );
- break;
} else {
- $this->assertEquals( 'Continue', $result['upload']['result'] );
- // update $resultOffset
- $resultOffset = $result['upload']['offset'];
+ // Filekey set to chunk session
+ $params['filekey'] = $filekey;
+ // Update the offset ( always add chunkSize for subquent chunks
+ // should be in-sync with $result['upload']['offset'] )
+ $params['offset'] += $chunkSize;
+ // Make sure param offset is insync with resultOffset:
+ $this->assertEquals( $resultOffset, $params['offset'] );
+ // Upload current chunk
+ list( $result ) = $this->doApiRequestWithToken( $params, null,
+ self::$users['uploader']->getUser() );
+ // Make sure we got a valid chunk continue:
+ $this->assertArrayHasKey( 'upload', $result );
+ $this->assertArrayHasKey( 'filekey', $result['upload'] );
+
+ // Check if we were on the last chunk:
+ if ( $params['offset'] + $chunkSize >= $fileSize ) {
+ $this->assertEquals( 'Success', $result['upload']['result'] );
+ break;
+ } else {
+ $this->assertEquals( 'Continue', $result['upload']['result'] );
+ $resultOffset = $result['upload']['offset'];
+ }
}
}
fclose( $handle );
// Check that we got a valid file result:
- wfDebug( __METHOD__
- . " hohoh filesize {$fileSize} info {$result['upload']['imageinfo']['size']}\n\n" );
$this->assertEquals( $fileSize, $result['upload']['imageinfo']['size'] );
$this->assertEquals( $mimeType, $result['upload']['imageinfo']['mime'] );
- $this->assertTrue( isset( $result['upload']['filekey'] ) );
+ $this->assertArrayHasKey( 'filekey', $result['upload'] );
$filekey = $result['upload']['filekey'];
// Now we should try to release the file from stash
- $params = [
+ $this->clearFakeUploads();
+ list( $result ) = $this->doApiRequestWithToken( [
'action' => 'upload',
'filekey' => $filekey,
'filename' => $fileName,
'comment' => 'dummy comment',
'text' => "This is the page text for $fileName, altered",
- ];
- $this->clearFakeUploads();
- $exception = false;
- try {
- list( $result ) = $this->doApiRequestWithToken( $params, $session,
- self::$users['uploader']->getUser() );
- } catch ( ApiUsageException $e ) {
- $exception = true;
- }
- $this->assertTrue( isset( $result['upload'] ) );
+ ], null, self::$users['uploader']->getUser() );
+ $this->assertArrayHasKey( 'upload', $result );
$this->assertEquals( 'Success', $result['upload']['result'] );
- $this->assertFalse( $exception );
-
- // clean up
- $this->deleteFileByFileName( $fileName );
}
}
if ( $remove ) {
$this->mergeMwGlobalArrayValue( 'wgRemoveGroups', [ 'bureaucrat' => $remove ] );
}
-
- $this->resetServices();
}
/**
ChangeTags::defineTag( 'custom tag' );
$this->setGroupPermissions( 'user', 'applychangetags', false );
- $this->resetServices();
$this->doFailedRightsChange(
'You do not have permission to apply change tags along with your changes.',
global $wgActorTableSchemaMigrationStage;
$reset = new \Wikimedia\ScopedCallback( function ( $v ) {
- global $wgActorTableSchemaMigrationStage;
- $wgActorTableSchemaMigrationStage = $v;
- $this->overrideMwServices();
+ $this->setMwGlobals( 'wgActorTableSchemaMigrationStage', $v );
}, [ $wgActorTableSchemaMigrationStage ] );
// Needs to WRITE_BOTH so READ_OLD tests below work. READ mode here doesn't really matter.
- $wgActorTableSchemaMigrationStage = SCHEMA_COMPAT_WRITE_BOTH | SCHEMA_COMPAT_READ_NEW;
- $this->overrideMwServices();
+ $this->setMwGlobals( 'wgActorTableSchemaMigrationStage',
+ SCHEMA_COMPAT_WRITE_BOTH | SCHEMA_COMPAT_READ_NEW );
$users = [
User::newFromName( '192.168.2.2', false ),
$this->markTestSkippedIfDbType( 'sqlite' );
$this->setMwGlobals( 'wgActorTableSchemaMigrationStage', $stage );
- $this->overrideMwServices();
if ( isset( $params['ucuserids'] ) ) {
$params['ucuserids'] = implode( '|', array_map( 'User::idFromName', $params['ucuserids'] ) );
*/
public function testInterwikiUser( $stage ) {
$this->setMwGlobals( 'wgActorTableSchemaMigrationStage', $stage );
- $this->overrideMwServices();
$params = [
'action' => 'query',
],
'wgProxyWhitelist' => [],
] );
- $this->resetServices();
$status = $this->manager->checkAccountCreatePermissions( new \User );
$this->assertFalse( $status->isOK() );
$this->assertTrue( $status->hasMessage( 'sorbs_create_account_reason' ) );
$this->setMwGlobals( 'wgProxyWhitelist', [ '127.0.0.1' ] );
- $this->resetServices();
$status = $this->manager->checkAccountCreatePermissions( new \User );
$this->assertTrue( $status->isGood() );
}
$this->assertSame( AuthenticationResponse::FAIL, $ret->status );
$this->assertSame( 'noname', $ret->message->getKey() );
+ $this->hook( 'LocalUserCreated', $this->never() );
$readOnlyMode = \MediaWiki\MediaWikiServices::getInstance()->getReadOnlyMode();
$readOnlyMode->setReason( 'Because' );
- $this->hook( 'LocalUserCreated', $this->never() );
$userReq->username = self::usernameForCreation();
$ret = $this->manager->beginAccountCreation( $creator, [ $userReq ], 'http://localhost/' );
$this->unhook( 'LocalUserCreated' );
$session, $this->request->getSession()->getSecret( 'AuthManager::accountCreationState' )
);
+ $this->hook( 'LocalUserCreated', $this->never() );
$this->request->getSession()->setSecret( 'AuthManager::accountCreationState',
[ 'username' => $creator->getName() ] + $session );
$readOnlyMode = \MediaWiki\MediaWikiServices::getInstance()->getReadOnlyMode();
$readOnlyMode->setReason( 'Because' );
- $this->hook( 'LocalUserCreated', $this->never() );
$ret = $this->manager->continueAccountCreation( [] );
$this->unhook( 'LocalUserCreated' );
$this->assertSame( AuthenticationResponse::FAIL, $ret->status );
$this->mergeMwGlobalArrayValue( 'wgObjectCaches',
[ __METHOD__ => [ 'class' => 'HashBagOStuff' ] ] );
$this->setMwGlobals( [ 'wgMainCacheType' => __METHOD__ ] );
- // Supply services with updated globals
- $this->resetServices();
// Set up lots of mocks...
$mocks = [];
// Wiki is read-only
$session->clear();
+ $this->hook( 'LocalUserCreated', $this->never() );
$readOnlyMode = \MediaWiki\MediaWikiServices::getInstance()->getReadOnlyMode();
$readOnlyMode->setReason( 'Because' );
$user = \User::newFromName( $username );
- $this->hook( 'LocalUserCreated', $this->never() );
$ret = $this->manager->autoCreateUser( $user, AuthManager::AUTOCREATE_SOURCE_SESSION, true );
$this->unhook( 'LocalUserCreated' );
$this->assertEquals( \Status::newFatal( wfMessage( 'readonlytext', 'Because' ) ), $ret );
$req->email = $email;
$req->realname = $realname;
$this->assertEquals( $expect, $req->populateUser( $user ) );
- if ( $expect->isOk() ) {
+ if ( $expect->isOK() ) {
$this->assertSame( $email ?: 'default@example.com', $user->getEmail() );
$this->assertSame( $realname ?: 'Fake Name', $user->getRealName() );
}
private function getBlockManagerConstructorArgs( $overrideConfig ) {
$blockManagerConfig = array_merge( $this->blockManagerConfig, $overrideConfig );
$this->setMwGlobals( $blockManagerConfig );
- $this->overrideMwServices();
return [
new LoggedServiceOptions(
self::$serviceOptionsAccessLog,
use MediaWiki\Block\BlockRestrictionStore;
use MediaWiki\Block\CompositeBlock;
+use MediaWiki\Block\DatabaseBlock;
use MediaWiki\Block\Restriction\PageRestriction;
use MediaWiki\Block\Restriction\NamespaceRestriction;
use MediaWiki\Block\SystemBlock;
private function getPartialBlocks() {
$sysopId = $this->getTestSysop()->getUser()->getId();
- $userBlock = new Block( [
+ $userBlock = new DatabaseBlock( [
'address' => $this->getTestUser()->getUser(),
'by' => $sysopId,
'sitewide' => false,
] );
- $ipBlock = new Block( [
+ $ipBlock = new DatabaseBlock( [
'address' => '127.0.0.1',
'by' => $sysopId,
'sitewide' => false,
return [
'Sitewide block and partial block' => [
[
- new Block( [
+ new DatabaseBlock( [
'sitewide' => false,
'blockEmail' => true,
'allowUsertalk' => true,
] ),
- new Block( [
+ new DatabaseBlock( [
'sitewide' => true,
'blockEmail' => false,
'allowUsertalk' => false,
],
'Partial block and system block' => [
[
- new Block( [
+ new DatabaseBlock( [
'sitewide' => false,
'blockEmail' => true,
'allowUsertalk' => false,
],
'System block and user name hiding block' => [
[
- new Block( [
+ new DatabaseBlock( [
'hideName' => true,
'sitewide' => true,
'blockEmail' => true,
],
'Two lenient partial blocks' => [
[
- new Block( [
+ new DatabaseBlock( [
'sitewide' => false,
'blockEmail' => false,
'allowUsertalk' => true,
] ),
- new Block( [
+ new DatabaseBlock( [
'sitewide' => false,
'blockEmail' => false,
'allowUsertalk' => true,
* @covers ::appliesToRight
* @dataProvider provideTestBlockAppliesToRight
*/
- public function testBlockAppliesToRight( $blocks, $right, $expected ) {
+ public function testBlockAppliesToRight( $applies, $expected ) {
$this->setMwGlobals( [
'wgBlockDisablesLogin' => false,
] );
$block = new CompositeBlock( [
- 'originalBlocks' => $blocks,
+ 'originalBlocks' => [
+ $this->getMockBlockForTestAppliesToRight( $applies[ 0 ] ),
+ $this->getMockBlockForTestAppliesToRight( $applies[ 1 ] ),
+ ],
] );
- $this->assertSame( $block->appliesToRight( $right ), $expected );
+ $this->assertSame( $block->appliesToRight( 'right' ), $expected );
+ }
+
+ private function getMockBlockForTestAppliesToRight( $applies ) {
+ $mockBlock = $this->getMockBuilder( DatabaseBlock::class )
+ ->setMethods( [ 'appliesToRight' ] )
+ ->getMock();
+ $mockBlock->method( 'appliesToRight' )
+ ->willReturn( $applies );
+ return $mockBlock;
}
- public static function provideTestBlockAppliesToRight() {
+ public function provideTestBlockAppliesToRight() {
return [
- 'Read is not blocked' => [
- [
- new Block(),
- new Block(),
- ],
- 'read',
+ 'Block does not apply if no original blocks apply' => [
+ [ false, false ],
false,
],
- 'Email is blocked if blocked by any blocks' => [
- [
- new Block( [
- 'blockEmail' => true,
- ] ),
- new Block( [
- 'blockEmail' => false,
- ] ),
- ],
- 'sendemail',
+ 'Block applies if any original block applies (second block doesn\'t apply)' => [
+ [ true, false ],
+ true,
+ ],
+ 'Block applies if any original block applies (second block unsure)' => [
+ [ true, null ],
true,
],
+ 'Block is unsure if all original blocks are unsure' => [
+ [ null, null ],
+ null,
+ ],
+ 'Block is unsure if any original block is unsure, and no others apply' => [
+ [ null, false ],
+ null,
+ ],
];
}
<?php
-
-use MediaWiki\Config\ServiceOptions;
-use MediaWiki\Languages\LanguageNameUtils;
-use Psr\Log\NullLogger;
-
/**
* @group Database
* @group Cache
*/
protected function getMockLocalisationCache() {
global $IP;
-
- $mockLangNameUtils = $this->createMock( LanguageNameUtils::class );
- $mockLangNameUtils->method( 'isValidBuiltInCode' )->will( $this->returnCallback(
- function ( $code ) {
- // Copy-paste, but it's only one line
- return (bool)preg_match( '/^[a-z0-9-]{2,}$/', $code );
- }
- ) );
- $mockLangNameUtils->method( 'isSupportedLanguage' )->will( $this->returnCallback(
- function ( $code ) {
- return in_array( $code, [
- 'ar',
- 'arz',
- 'ba',
- 'de',
- 'en',
- 'ksh',
- 'ru',
- ] );
- }
- ) );
- $mockLangNameUtils->method( 'getMessagesFileName' )->will( $this->returnCallback(
- function ( $code ) {
- global $IP;
- $code = str_replace( '-', '_', ucfirst( $code ) );
- return "$IP/languages/messages/Messages$code.php";
- }
- ) );
- $mockLangNameUtils->expects( $this->never() )->method( $this->anythingBut(
- 'isValidBuiltInCode', 'isSupportedLanguage', 'getMessagesFileName'
- ) );
-
- $lc = $this->getMockBuilder( LocalisationCache::class )
- ->setConstructorArgs( [
- new ServiceOptions( LocalisationCache::$constructorOptions, [
- 'forceRecache' => false,
- 'manualRecache' => false,
- 'ExtensionMessagesFiles' => [],
- 'MessagesDirs' => [],
- ] ),
- new LCStoreDB( [] ),
- new NullLogger,
- [],
- $mockLangNameUtils
- ] )
+ $lc = $this->getMockBuilder( \LocalisationCache::class )
+ ->setConstructorArgs( [ [ 'store' => 'detect' ] ] )
->setMethods( [ 'getMessagesDirs' ] )
->getMock();
$lc->expects( $this->any() )->method( 'getMessagesDirs' )
return $lc;
}
- public function testPluralRulesFallback() {
+ public function testPuralRulesFallback() {
$cache = $this->getMockLocalisationCache();
$this->assertEquals(
// let's choose e.g. German (de)
$this->setUserLang( 'de' );
$this->setContentLang( 'de' );
- $this->resetServices();
}
function addDBDataOnce() {
]
]
] );
- $this->overrideMwServices();
$messageCache = MessageCache::singleton();
$messageCache->enable();
--- /dev/null
+<?php
+
+use MediaWiki\Revision\SlotRecord;
+use MediaWiki\Revision\SlotRenderingProvider;
+
+/**
+ * @group ContentHandler
+ */
+class UnknownContentHandlerTest extends MediaWikiLangTestCase {
+ /**
+ * @covers UnknownContentHandler::supportsDirectEditing
+ */
+ public function testSupportsDirectEditing() {
+ $handler = new UnknownContentHandler( 'horkyporky' );
+ $this->assertFalse( $handler->supportsDirectEditing(), 'direct editing supported' );
+ }
+
+ /**
+ * @covers UnknownContentHandler::serializeContent
+ */
+ public function testSerializeContent() {
+ $handler = new UnknownContentHandler( 'horkyporky' );
+ $content = new UnknownContent( 'hello world', 'horkyporky' );
+
+ $this->assertEquals( 'hello world', $handler->serializeContent( $content ) );
+ $this->assertEquals(
+ 'hello world',
+ $handler->serializeContent( $content, 'application/horkyporky' )
+ );
+ }
+
+ /**
+ * @covers UnknownContentHandler::unserializeContent
+ */
+ public function testUnserializeContent() {
+ $handler = new UnknownContentHandler( 'horkyporky' );
+ $content = $handler->unserializeContent( 'hello world' );
+ $this->assertEquals( 'hello world', $content->getData() );
+
+ $content = $handler->unserializeContent( 'hello world', 'application/horkyporky' );
+ $this->assertEquals( 'hello world', $content->getData() );
+ }
+
+ /**
+ * @covers UnknownContentHandler::makeEmptyContent
+ */
+ public function testMakeEmptyContent() {
+ $handler = new UnknownContentHandler( 'horkyporky' );
+ $content = $handler->makeEmptyContent();
+
+ $this->assertTrue( $content->isEmpty() );
+ $this->assertEquals( '', $content->getData() );
+ }
+
+ public static function dataIsSupportedFormat() {
+ return [
+ [ null, true ],
+ [ 'application/octet-stream', true ],
+ [ 'unknown/unknown', true ],
+ [ 'text/plain', false ],
+ [ 99887766, false ],
+ ];
+ }
+
+ /**
+ * @dataProvider dataIsSupportedFormat
+ * @covers UnknownContentHandler::isSupportedFormat
+ */
+ public function testIsSupportedFormat( $format, $supported ) {
+ $handler = new UnknownContentHandler( 'horkyporky' );
+ $this->assertEquals( $supported, $handler->isSupportedFormat( $format ) );
+ }
+
+ /**
+ * @covers ContentHandler::getSecondaryDataUpdates
+ */
+ public function testGetSecondaryDataUpdates() {
+ $title = Title::newFromText( 'Somefile.jpg', NS_FILE );
+ $content = new UnknownContent( '', 'horkyporky' );
+
+ /** @var SlotRenderingProvider $srp */
+ $srp = $this->getMock( SlotRenderingProvider::class );
+
+ $handler = new UnknownContentHandler( 'horkyporky' );
+ $updates = $handler->getSecondaryDataUpdates( $title, $content, SlotRecord::MAIN, $srp );
+
+ $this->assertEquals( [], $updates );
+ }
+
+ /**
+ * @covers ContentHandler::getDeletionUpdates
+ */
+ public function testGetDeletionUpdates() {
+ $title = Title::newFromText( 'Somefile.jpg', NS_FILE );
+
+ $handler = new UnknownContentHandler( 'horkyporky' );
+ $updates = $handler->getDeletionUpdates( $title, SlotRecord::MAIN );
+
+ $this->assertEquals( [], $updates );
+ }
+
+ /**
+ * @covers ContentHandler::getDeletionUpdates
+ */
+ public function testGetSlotDiffRenderer() {
+ $context = new RequestContext();
+ $context->setRequest( new FauxRequest() );
+
+ $handler = new UnknownContentHandler( 'horkyporky' );
+ $slotDiffRenderer = $handler->getSlotDiffRenderer( $context );
+
+ $oldContent = $handler->unserializeContent( 'Foo' );
+ $newContent = $handler->unserializeContent( 'Foo bar' );
+
+ $diff = $slotDiffRenderer->getDiff( $oldContent, $newContent );
+ $this->assertNotEmpty( $diff );
+ }
+
+}
--- /dev/null
+<?php
+
+/**
+ * @group ContentHandler
+ */
+class UnknownContentTest extends MediaWikiLangTestCase {
+
+ /**
+ * @param string $data
+ * @return UnknownContent
+ */
+ public function newContent( $data, $type = 'xyzzy' ) {
+ return new UnknownContent( $data, $type );
+ }
+
+ /**
+ * @covers UnknownContent::getParserOutput
+ */
+ public function testGetParserOutput() {
+ $this->setUserLang( 'en' );
+ $this->setContentLang( 'qqx' );
+
+ $title = Title::newFromText( 'Test' );
+ $content = $this->newContent( 'Horkyporky' );
+
+ $po = $content->getParserOutput( $title );
+ $html = $po->getText();
+ $html = preg_replace( '#<!--.*?-->#sm', '', $html ); // strip comments
+
+ $this->assertNotContains( 'Horkyporky', $html );
+ $this->assertNotContains( '(unsupported-content-model)', $html );
+ }
+
+ /**
+ * @covers UnknownContent::preSaveTransform
+ */
+ public function testPreSaveTransform() {
+ $title = Title::newFromText( 'Test' );
+ $user = $this->getTestUser()->getUser();
+ $content = $this->newContent( 'Horkyporky ~~~' );
+
+ $options = new ParserOptions();
+
+ $this->assertSame( $content, $content->preSaveTransform( $title, $user, $options ) );
+ }
+
+ /**
+ * @covers UnknownContent::preloadTransform
+ */
+ public function testPreloadTransform() {
+ $title = Title::newFromText( 'Test' );
+ $content = $this->newContent( 'Horkyporky ~~~' );
+
+ $options = new ParserOptions();
+
+ $this->assertSame( $content, $content->preloadTransform( $title, $options ) );
+ }
+
+ /**
+ * @covers UnknownContent::getRedirectTarget
+ */
+ public function testGetRedirectTarget() {
+ $content = $this->newContent( '#REDIRECT [[Horkyporky]]' );
+ $this->assertNull( $content->getRedirectTarget() );
+ }
+
+ /**
+ * @covers UnknownContent::isRedirect
+ */
+ public function testIsRedirect() {
+ $content = $this->newContent( '#REDIRECT [[Horkyporky]]' );
+ $this->assertFalse( $content->isRedirect() );
+ }
+
+ /**
+ * @covers UnknownContent::isCountable
+ */
+ public function testIsCountable() {
+ $content = $this->newContent( '[[Horkyporky]]' );
+ $this->assertFalse( $content->isCountable( true ) );
+ }
+
+ /**
+ * @covers UnknownContent::getTextForSummary
+ */
+ public function testGetTextForSummary() {
+ $content = $this->newContent( 'Horkyporky' );
+ $this->assertSame( '', $content->getTextForSummary() );
+ }
+
+ /**
+ * @covers UnknownContent::getTextForSearchIndex
+ */
+ public function testGetTextForSearchIndex() {
+ $content = $this->newContent( 'Horkyporky' );
+ $this->assertSame( '', $content->getTextForSearchIndex() );
+ }
+
+ /**
+ * @covers UnknownContent::copy
+ */
+ public function testCopy() {
+ $content = $this->newContent( 'hello world.' );
+ $copy = $content->copy();
+
+ $this->assertSame( $content, $copy );
+ }
+
+ /**
+ * @covers UnknownContent::getSize
+ */
+ public function testGetSize() {
+ $content = $this->newContent( 'hello world.' );
+
+ $this->assertEquals( 12, $content->getSize() );
+ }
+
+ /**
+ * @covers UnknownContent::getData
+ */
+ public function testGetData() {
+ $content = $this->newContent( 'hello world.' );
+
+ $this->assertEquals( 'hello world.', $content->getData() );
+ }
+
+ /**
+ * @covers UnknownContent::getNativeData
+ */
+ public function testGetNativeData() {
+ $content = $this->newContent( 'hello world.' );
+
+ $this->assertEquals( 'hello world.', $content->getNativeData() );
+ }
+
+ /**
+ * @covers UnknownContent::getWikitextForTransclusion
+ */
+ public function testGetWikitextForTransclusion() {
+ $content = $this->newContent( 'hello world.' );
+
+ $this->assertEquals( '', $content->getWikitextForTransclusion() );
+ }
+
+ /**
+ * @covers UnknownContent::getModel
+ */
+ public function testGetModel() {
+ $content = $this->newContent( "hello world.", 'horkyporky' );
+
+ $this->assertEquals( 'horkyporky', $content->getModel() );
+ }
+
+ /**
+ * @covers UnknownContent::getContentHandler
+ */
+ public function testGetContentHandler() {
+ $this->mergeMwGlobalArrayValue(
+ 'wgContentHandlers',
+ [ 'horkyporky' => 'UnknownContentHandler' ]
+ );
+
+ $content = $this->newContent( "hello world.", 'horkyporky' );
+
+ $this->assertInstanceOf( UnknownContentHandler::class, $content->getContentHandler() );
+ $this->assertEquals( 'horkyporky', $content->getContentHandler()->getModelID() );
+ }
+
+ public static function dataIsEmpty() {
+ return [
+ [ '', true ],
+ [ ' ', false ],
+ [ '0', false ],
+ [ 'hallo welt.', false ],
+ ];
+ }
+
+ /**
+ * @dataProvider dataIsEmpty
+ * @covers UnknownContent::isEmpty
+ */
+ public function testIsEmpty( $text, $empty ) {
+ $content = $this->newContent( $text );
+
+ $this->assertEquals( $empty, $content->isEmpty() );
+ }
+
+ public function provideEquals() {
+ return [
+ [ new UnknownContent( "hallo", 'horky' ), null, false ],
+ [ new UnknownContent( "hallo", 'horky' ), new UnknownContent( "hallo", 'horky' ), true ],
+ [ new UnknownContent( "hallo", 'horky' ), new UnknownContent( "hallo", 'xyzzy' ), false ],
+ [ new UnknownContent( "hallo", 'horky' ), new JavaScriptContent( "hallo" ), false ],
+ [ new UnknownContent( "hallo", 'horky' ), new WikitextContent( "hallo" ), false ],
+ ];
+ }
+
+ /**
+ * @dataProvider provideEquals
+ * @covers UnknownContent::equals
+ */
+ public function testEquals( Content $a, Content $b = null, $equal = false ) {
+ $this->assertEquals( $equal, $a->equals( $b ) );
+ }
+
+ public static function provideConvert() {
+ return [
+ [ // #0
+ 'Hallo Welt',
+ CONTENT_MODEL_WIKITEXT,
+ 'lossless',
+ 'Hallo Welt'
+ ],
+ [ // #1
+ 'Hallo Welt',
+ CONTENT_MODEL_WIKITEXT,
+ 'lossless',
+ 'Hallo Welt'
+ ],
+ [ // #1
+ 'Hallo Welt',
+ CONTENT_MODEL_CSS,
+ 'lossless',
+ 'Hallo Welt'
+ ],
+ [ // #1
+ 'Hallo Welt',
+ CONTENT_MODEL_JAVASCRIPT,
+ 'lossless',
+ 'Hallo Welt'
+ ],
+ ];
+ }
+
+ /**
+ * @covers UnknownContent::convert
+ */
+ public function testConvert() {
+ $content = $this->newContent( 'More horkyporky?' );
+
+ $this->assertFalse( $content->convert( CONTENT_MODEL_TEXT ) );
+ }
+
+ /**
+ * @covers UnknownContent::__construct
+ * @covers UnknownContentHandler::serializeContent
+ */
+ public function testSerialize() {
+ $this->mergeMwGlobalArrayValue(
+ 'wgContentHandlers',
+ [ 'horkyporky' => 'UnknownContentHandler' ]
+ );
+
+ $content = $this->newContent( 'Hörkypörky', 'horkyporky' );
+
+ $this->assertSame( 'Hörkypörky', $content->serialize() );
+ }
+
+}
* @covers \Wikimedia\Rdbms\DatabasePostgres::getAttributes
*/
public function testAttributes() {
- $this->assertTrue(
- Database::attributesFromType( 'postgres' )[Database::ATTR_SCHEMAS_AS_TABLE_GROUPS]
- );
+ $this->assertTrue( DatabasePostgres::getAttributes()[Database::ATTR_SCHEMAS_AS_TABLE_GROUPS] );
}
}
* @copyright © 2013 Wikimedia Foundation Inc.
*/
-use Wikimedia\AtEase\AtEase;
use Wikimedia\Rdbms\IDatabase;
use Wikimedia\Rdbms\IMaintainableDatabase;
use Wikimedia\Rdbms\LBFactory;
unset( $db );
/** @var IMaintainableDatabase $db */
- $db = $lb->getConnection( DB_MASTER, [], $lb::DOMAIN_ANY );
+ $db = $lb->getConnection( DB_MASTER, [], '' );
$this->assertEquals(
'',
);
$lb = $factory->getMainLB();
/** @var IMaintainableDatabase $db */
- $db = $lb->getConnection( DB_MASTER, [], $lb::DOMAIN_ANY );
+ $db = $lb->getConnection( DB_MASTER, [], '' );
$this->assertEquals( '', $db->getDomainID(), "Null domain used" );
);
$lb = $factory->getMainLB();
/** @var IDatabase $db */
- $db = $lb->getConnection( DB_MASTER, [], $lb::DOMAIN_ANY );
+ $db = $lb->getConnection( DB_MASTER, [], '' );
- AtEase::suppressWarnings();
+ \Wikimedia\suppressWarnings();
try {
- $this->assertFalse( $db->selectDomain( 'garbagedb' ) );
+ $this->assertFalse( $db->selectDB( 'garbage-db' ) );
$this->fail( "No error thrown." );
} catch ( \Wikimedia\Rdbms\DBQueryError $e ) {
- $this->assertRegExp( '/[\'"]garbagedb[\'"]/', $e->getMessage() );
+ $this->assertRegExp( '/[\'"]garbage-db[\'"]/', $e->getMessage() );
}
- AtEase::restoreWarnings();
+ \Wikimedia\restoreWarnings();
}
/**
);
$lb = $factory->getMainLB();
- if ( !$factory->getMainLB()->getServerAttributes( 0 )[Database::ATTR_DB_IS_FILE] ) {
- $this->markTestSkipped( "Not applicable per ATTR_DB_IS_FILE" );
+ if ( !$lb->getConnection( DB_MASTER )->databasesAreIndependent() ) {
+ $this->markTestSkipped( "Not applicable per databasesAreIndependent()" );
}
/** @var IDatabase $db */
- $this->assertNotNull( $lb->getConnection( DB_MASTER, [], $lb::DOMAIN_ANY ) );
+ $lb->getConnection( DB_MASTER, [], '' );
}
/**
}
$db = $lb->getConnection( DB_MASTER );
- $db->selectDomain( 'garbage-db' );
+ $db->selectDB( 'garbage-db' );
}
/**
--- /dev/null
+<?php
+
+/**
+ * @covers DifferenceEngineSlotDiffRenderer
+ */
+class DifferenceEngineSlotDiffRendererTest extends MediaWikiIntegrationTestCase {
+
+ public function testGetDiff() {
+ $differenceEngine = new CustomDifferenceEngine();
+ $slotDiffRenderer = new DifferenceEngineSlotDiffRenderer( $differenceEngine );
+ $oldContent = ContentHandler::makeContent( 'xxx', null, CONTENT_MODEL_TEXT );
+ $newContent = ContentHandler::makeContent( 'yyy', null, CONTENT_MODEL_TEXT );
+
+ $diff = $slotDiffRenderer->getDiff( $oldContent, $newContent );
+ $this->assertEquals( 'xxx|yyy', $diff );
+
+ $diff = $slotDiffRenderer->getDiff( null, $newContent );
+ $this->assertEquals( '|yyy', $diff );
+
+ $diff = $slotDiffRenderer->getDiff( $oldContent, null );
+ $this->assertEquals( 'xxx|', $diff );
+ }
+
+ public function testAddModules() {
+ $output = $this->getMockBuilder( OutputPage::class )
+ ->disableOriginalConstructor()
+ ->setMethods( [ 'addModules' ] )
+ ->getMock();
+ $output->expects( $this->once() )
+ ->method( 'addModules' )
+ ->with( 'foo' );
+ $differenceEngine = new CustomDifferenceEngine();
+ $slotDiffRenderer = new DifferenceEngineSlotDiffRenderer( $differenceEngine );
+ $slotDiffRenderer->addModules( $output );
+ }
+
+ public function testGetExtraCacheKeys() {
+ $differenceEngine = new CustomDifferenceEngine();
+ $slotDiffRenderer = new DifferenceEngineSlotDiffRenderer( $differenceEngine );
+ $extraCacheKeys = $slotDiffRenderer->getExtraCacheKeys();
+ $this->assertSame( [ 'foo' ], $extraCacheKeys );
+ }
+
+}
* @dataProvider provideGenerateContentDiffBody
*/
public function testGenerateContentDiffBody(
- Content $oldContent, Content $newContent, $expectedDiff
+ array $oldContentArgs, array $newContentArgs, $expectedDiff
) {
+ $this->mergeMwGlobalArrayValue( 'wgContentHandlers', [
+ 'testing-nontext' => DummyNonTextContentHandler::class,
+ ] );
+ $oldContent = ContentHandler::makeContent( ...$oldContentArgs );
+ $newContent = ContentHandler::makeContent( ...$newContentArgs );
+
// Set $wgExternalDiffEngine to something bogus to try to force use of
// the PHP engine rather than wikidiff2.
$this->setMwGlobals( [
$this->assertSame( $expectedDiff, $this->getPlainDiff( $diff ) );
}
- public function provideGenerateContentDiffBody() {
- $this->mergeMwGlobalArrayValue( 'wgContentHandlers', [
- 'testing-nontext' => DummyNonTextContentHandler::class,
- ] );
- $content1 = ContentHandler::makeContent( 'xxx', null, CONTENT_MODEL_TEXT );
- $content2 = ContentHandler::makeContent( 'yyy', null, CONTENT_MODEL_TEXT );
+ public static function provideGenerateContentDiffBody() {
+ $content1 = [ 'xxx', null, CONTENT_MODEL_TEXT ];
+ $content2 = [ 'yyy', null, CONTENT_MODEL_TEXT ];
return [
'self-diff' => [ $content1, $content1, '' ],
--- /dev/null
+<?php
+
+use Wikimedia\Assert\ParameterTypeException;
+use Wikimedia\TestingAccessWrapper;
+
+/**
+ * @covers SlotDiffRenderer
+ */
+class SlotDiffRendererTest extends \MediaWikiIntegrationTestCase {
+
+ /**
+ * @dataProvider provideNormalizeContents
+ */
+ public function testNormalizeContents(
+ $oldContent, $newContent, $allowedClasses,
+ $expectedOldContent, $expectedNewContent, $expectedExceptionClass
+ ) {
+ $slotDiffRenderer = $this->getMockBuilder( SlotDiffRenderer::class )
+ ->getMock();
+ try {
+ // __call needs help deciding which parameter to take by reference
+ call_user_func_array( [ TestingAccessWrapper::newFromObject( $slotDiffRenderer ),
+ 'normalizeContents' ], [ &$oldContent, &$newContent, $allowedClasses ] );
+ $this->assertEquals( $expectedOldContent, $oldContent );
+ $this->assertEquals( $expectedNewContent, $newContent );
+ } catch ( Exception $e ) {
+ if ( !$expectedExceptionClass ) {
+ throw $e;
+ }
+ $this->assertInstanceOf( $expectedExceptionClass, $e );
+ }
+ }
+
+ public function provideNormalizeContents() {
+ return [
+ 'both null' => [ null, null, null, null, null, InvalidArgumentException::class ],
+ 'left null' => [
+ null, new WikitextContent( 'abc' ), null,
+ new WikitextContent( '' ), new WikitextContent( 'abc' ), null,
+ ],
+ 'right null' => [
+ new WikitextContent( 'def' ), null, null,
+ new WikitextContent( 'def' ), new WikitextContent( '' ), null,
+ ],
+ 'type filter' => [
+ new WikitextContent( 'abc' ), new WikitextContent( 'def' ), WikitextContent::class,
+ new WikitextContent( 'abc' ), new WikitextContent( 'def' ), null,
+ ],
+ 'type filter (subclass)' => [
+ new WikitextContent( 'abc' ), new WikitextContent( 'def' ), TextContent::class,
+ new WikitextContent( 'abc' ), new WikitextContent( 'def' ), null,
+ ],
+ 'type filter (null)' => [
+ new WikitextContent( 'abc' ), null, TextContent::class,
+ new WikitextContent( 'abc' ), new WikitextContent( '' ), null,
+ ],
+ 'type filter failure (left)' => [
+ new TextContent( 'abc' ), new WikitextContent( 'def' ), WikitextContent::class,
+ null, null, ParameterTypeException::class,
+ ],
+ 'type filter failure (right)' => [
+ new WikitextContent( 'abc' ), new TextContent( 'def' ), WikitextContent::class,
+ null, null, ParameterTypeException::class,
+ ],
+ 'type filter (array syntax)' => [
+ new WikitextContent( 'abc' ), new JsonContent( 'def' ),
+ [ JsonContent::class, WikitextContent::class ],
+ new WikitextContent( 'abc' ), new JsonContent( 'def' ), null,
+ ],
+ 'type filter failure (array syntax)' => [
+ new WikitextContent( 'abc' ), new CssContent( 'def' ),
+ [ JsonContent::class, WikitextContent::class ],
+ null, null, ParameterTypeException::class,
+ ],
+ ];
+ }
+
+}
/**
* @dataProvider provideGetDiff
- * @param Content|null $oldContent
- * @param Content|null $newContent
+ * @param array|null $oldContentArgs To pass to makeContent() (if not null)
+ * @param array|null $newContentArgs
* @param string|Exception $expectedResult
* @throws Exception
*/
public function testGetDiff(
- Content $oldContent = null, Content $newContent = null, $expectedResult
+ array $oldContentArgs = null, array $newContentArgs = null, $expectedResult
) {
+ $this->mergeMwGlobalArrayValue( 'wgContentHandlers', [
+ 'testing' => DummyContentHandlerForTesting::class,
+ 'testing-nontext' => DummyNonTextContentHandler::class,
+ ] );
+
+ $oldContent = $oldContentArgs ? self::makeContent( ...$oldContentArgs ) : null;
+ $newContent = $newContentArgs ? self::makeContent( ...$newContentArgs ) : null;
+
if ( $expectedResult instanceof Exception ) {
$this->setExpectedException( get_class( $expectedResult ), $expectedResult->getMessage() );
}
$this->assertSame( $expectedResult, $plainDiff );
}
- public function provideGetDiff() {
- $this->mergeMwGlobalArrayValue( 'wgContentHandlers', [
- 'testing' => DummyContentHandlerForTesting::class,
- 'testing-nontext' => DummyNonTextContentHandler::class,
- ] );
-
+ public static function provideGetDiff() {
return [
'same text' => [
- $this->makeContent( "aaa\nbbb\nccc" ),
- $this->makeContent( "aaa\nbbb\nccc" ),
+ [ "aaa\nbbb\nccc" ],
+ [ "aaa\nbbb\nccc" ],
"",
],
'different text' => [
- $this->makeContent( "aaa\nbbb\nccc" ),
- $this->makeContent( "aaa\nxxx\nccc" ),
+ [ "aaa\nbbb\nccc" ],
+ [ "aaa\nxxx\nccc" ],
" aaa aaa\n-bbb+xxx\n ccc ccc",
],
'no right content' => [
- $this->makeContent( "aaa\nbbb\nccc" ),
+ [ "aaa\nbbb\nccc" ],
null,
"-aaa+ \n-bbb \n-ccc ",
],
'no left content' => [
null,
- $this->makeContent( "aaa\nbbb\nccc" ),
+ [ "aaa\nbbb\nccc" ],
"- +aaa\n +bbb\n +ccc",
],
'no content' => [
new InvalidArgumentException( '$oldContent and $newContent cannot both be null' ),
],
'non-text left content' => [
- $this->makeContent( '', 'testing-nontext' ),
- $this->makeContent( "aaa\nbbb\nccc" ),
+ [ '', 'testing-nontext' ],
+ [ "aaa\nbbb\nccc" ],
new ParameterTypeException( '$oldContent', 'TextContent|null' ),
],
'non-text right content' => [
- $this->makeContent( "aaa\nbbb\nccc" ),
- $this->makeContent( '', 'testing-nontext' ),
+ [ "aaa\nbbb\nccc" ],
+ [ '', 'testing-nontext' ],
new ParameterTypeException( '$newContent', 'TextContent|null' ),
],
];
* @param string $model
* @return null|TextContent
*/
- private function makeContent( $str, $model = CONTENT_MODEL_TEXT ) {
+ private static function makeContent( $str, $model = CONTENT_MODEL_TEXT ) {
return ContentHandler::makeContent( $str, null, $model );
}
--- /dev/null
+<?php
+
+/**
+ * @covers UnsupportedSlotDiffRenderer
+ */
+class UnsupportedSlotDiffRendererTest extends MediaWikiTestCase {
+
+ public function provideDiff() {
+ $oldContent = new TextContent( 'Kittens' );
+ $newContent = new TextContent( 'Goats' );
+ $badContent = new UnknownContent( 'Dragons', 'xyzzy' );
+
+ yield [ '(unsupported-content-diff)', $oldContent, null ];
+ yield [ '(unsupported-content-diff)', null, $newContent ];
+ yield [ '(unsupported-content-diff)', $oldContent, $newContent ];
+ yield [ '(unsupported-content-diff2)', $badContent, $newContent ];
+ yield [ '(unsupported-content-diff2)', $oldContent, $badContent ];
+ yield [ '(unsupported-content-diff)', null, $badContent ];
+ yield [ '(unsupported-content-diff)', $badContent, null ];
+ }
+
+ /**
+ * @dataProvider provideDiff
+ */
+ public function testDiff( $expected, $oldContent, $newContent ) {
+ $this->mergeMwGlobalArrayValue(
+ 'wgContentHandlers',
+ [ 'xyzzy' => 'UnknownContentHandler' ]
+ );
+
+ $localizer = $this->getMock( MessageLocalizer::class );
+
+ $localizer->method( 'msg' )
+ ->willReturnCallback( function ( $key, ...$params ) {
+ return new RawMessage( "($key)", $params );
+ } );
+
+ $sdr = new UnsupportedSlotDiffRenderer( $localizer );
+ $this->assertContains( $expected, $sdr->getDiff( $oldContent, $newContent ) );
+ }
+
+}
--- /dev/null
+<?php
+
+use MediaWiki\MediaWikiServices;
+
+/**
+ * @coversDefaultClass FileBackendGroup
+ * @covers ::singleton
+ * @covers ::destroySingleton
+ */
+class FileBackendGroupIntegrationTest extends MediaWikiIntegrationTestCase {
+ use FileBackendGroupTestTrait;
+
+ private static function getWikiID() {
+ return wfWikiID();
+ }
+
+ private function getLockManagerGroupFactory() {
+ return MediaWikiServices::getInstance()->getLockManagerGroupFactory();
+ }
+
+ private function newObj( array $options = [] ) : FileBackendGroup {
+ $globals = [ 'DirectoryMode', 'FileBackends', 'ForeignFileRepos', 'LocalFileRepo' ];
+ foreach ( $globals as $global ) {
+ $this->setMwGlobals(
+ "wg$global", $options[$global] ?? self::getDefaultOptions()[$global] );
+ }
+
+ $serviceMembers = [
+ 'configuredROMode' => 'ConfiguredReadOnlyMode',
+ 'srvCache' => 'LocalServerObjectCache',
+ 'wanCache' => 'MainWANObjectCache',
+ 'mimeAnalyzer' => 'MimeAnalyzer',
+ 'lmgFactory' => 'LockManagerGroupFactory',
+ 'tmpFileFactory' => 'TempFSFileFactory',
+ ];
+
+ foreach ( $serviceMembers as $key => $name ) {
+ if ( isset( $options[$key] ) ) {
+ $this->setService( $name, $options[$key] );
+ }
+ }
+
+ $this->assertEmpty(
+ array_diff( array_keys( $options ), $globals, array_keys( $serviceMembers ) ) );
+
+ $this->resetServices();
+ FileBackendGroup::destroySingleton();
+
+ $services = MediaWikiServices::getInstance();
+
+ foreach ( $serviceMembers as $key => $name ) {
+ if ( $key === 'srvCache' ) {
+ $this->$key = ObjectCache::getLocalServerInstance( 'hash' );
+ } else {
+ $this->$key = $services->getService( $name );
+ }
+ }
+
+ return FileBackendGroup::singleton();
+ }
+}
* @covers FileBackendStoreShardDirIterator
* @covers FileBackendStoreShardFileIterator
* @covers FileBackendStoreShardListIterator
- * @covers FileJournal
* @covers FileOp
* @covers FileOpBatch
* @covers HTTPFileStreamer
* @covers MemoryFileBackend
* @covers MoveFileOp
* @covers MySqlLockManager
- * @covers NullFileJournal
* @covers NullFileOp
* @covers StoreFileOp
* @covers TempFSFile
--- /dev/null
+<?php
+
+use MediaWiki\MediaWikiServices;
+use Wikimedia\Timestamp\ConvertibleTimestamp;
+
+/**
+ * @coversDefaultClass DBFileJournal
+ * @covers ::__construct
+ * @covers ::getMasterDB
+ * @group Database
+ */
+class DBFileJournalIntegrationTest extends MediaWikiIntegrationTestCase {
+ public function addDBDataOnce() {
+ global $IP;
+ $db = MediaWikiServices::getInstance()->getDBLoadBalancer()->getConnection( DB_MASTER );
+ if ( $db->getType() !== 'mysql' ) {
+ return;
+ }
+ if ( !$db->tableExists( 'filejournal' ) ) {
+ $db->sourceFile( "$IP/maintenance/archives/patch-filejournal.sql" );
+ }
+ }
+
+ protected function setUp() {
+ parent::setUp();
+
+ $db = MediaWikiServices::getInstance()->getDBLoadBalancer()->getConnection( DB_MASTER );
+ if ( $db->getType() !== 'mysql' ) {
+ $this->markTestSkipped( 'No filejournal schema available for this database type' );
+ }
+
+ $this->tablesUsed[] = 'filejournal';
+ }
+
+ private function getJournal( $options = [] ) {
+ return FileJournal::factory(
+ $options + [ 'class' => DBFileJournal::class, 'domain' => wfWikiID() ],
+ 'local-backend' );
+ }
+
+ /**
+ * @covers ::doLogChangeBatch
+ */
+ public function testDoLogChangeBatch_exceptionDbConnect() {
+ $journal = $this->getJournal( [ 'domain' => 'no-such-domain' ] );
+
+ $this->assertEquals(
+ StatusValue::newFatal( 'filejournal-fail-dbconnect', 'local-backend' ),
+ $journal->logChangeBatch( [ [] ], 'batch' ) );
+ }
+
+ /**
+ * @covers ::doLogChangeBatch
+ */
+ public function testDoLogChangeBatch_exceptionDbQuery() {
+ MediaWikiServices::getInstance()->getConfiguredReadOnlyMode()->setReason( 'testing' );
+
+ $journal = $this->getJournal();
+
+ $this->assertEquals(
+ StatusValue::newFatal( 'filejournal-fail-dbquery', 'local-backend' ),
+ $journal->logChangeBatch(
+ [ [ 'op' => null, 'path' => '', 'newSha1' => false ] ], 'batch' ) );
+ }
+
+ /**
+ * @covers ::doLogChangeBatch
+ * @covers ::doGetCurrentPosition
+ */
+ public function testDoGetCurrentPosition() {
+ $journal = $this->getJournal();
+
+ $this->assertNull( $journal->getCurrentPosition() );
+
+ $journal->logChangeBatch(
+ [ [ 'op' => 'create', 'path' => '/path', 'newSha1' => false ] ], 'batch1' );
+
+ $this->assertSame( '1', $journal->getCurrentPosition() );
+
+ $journal->logChangeBatch(
+ [ [ 'op' => 'create', 'path' => '/path', 'newSha1' => false ] ], 'batch2' );
+
+ $this->assertSame( '2', $journal->getCurrentPosition() );
+ }
+
+ /**
+ * @covers ::doLogChangeBatch
+ * @covers ::doGetPositionAtTime
+ */
+ public function testDoGetPositionAtTime() {
+ $journal = $this->getJournal();
+
+ $now = time();
+
+ $this->assertFalse( $journal->getPositionAtTime( $now ) );
+
+ ConvertibleTimestamp::setFakeTime( $now - 86400 );
+
+ $journal->logChangeBatch(
+ [ [ 'op' => 'create', 'path' => '/path', 'newSha1' => false ] ], 'batch1' );
+
+ ConvertibleTimestamp::setFakeTime( $now - 3600 );
+
+ $journal->logChangeBatch(
+ [ [ 'op' => 'create', 'path' => '/path', 'newSha1' => false ] ], 'batch2' );
+
+ $this->assertFalse( $journal->getPositionAtTime( $now - 86401 ) );
+ $this->assertSame( '1', $journal->getPositionAtTime( $now - 86400 ) );
+ $this->assertSame( '1', $journal->getPositionAtTime( $now - 3601 ) );
+ $this->assertSame( '2', $journal->getPositionAtTime( $now - 3600 ) );
+ }
+
+ /**
+ * @param int $expectedStart First index expected to be returned (0-based)
+ * @param int|null $expectedCount Number of entries expected to be returned (null for all)
+ * @param string|null|false $expectedNext Expected value of $next, or false not to pass
+ * @param array $args If any third argument is present, $next will also be tested
+ * @dataProvider provideDoGetChangeEntries
+ * @covers ::doLogChangeBatch
+ * @covers ::doGetChangeEntries
+ */
+ public function testDoGetChangeEntries(
+ $expectedStart, $expectedCount, $expectedNext, array $args
+ ) {
+ $journal = $this->getJournal();
+
+ $i = 0;
+ $makeExpectedEntry = function ( $op, $path, $newSha1, $batch, $time ) use ( &$i ) {
+ $i++;
+ return [
+ 'id' => (string)$i,
+ 'batch_uuid' => $batch,
+ 'backend' => 'local-backend',
+ 'path' => $path,
+ 'op' => $op ?? '',
+ 'new_sha1' => $newSha1 !== false ? $newSha1 : '0',
+ 'timestamp' => ConvertibleTimestamp::convert( TS_MW, $time ),
+ ];
+ };
+
+ $expectedEntries = [];
+
+ $now = time();
+
+ ConvertibleTimestamp::setFakeTime( $now - 3600 );
+ $changes = [
+ [ 'op' => 'create', 'path' => '/path1',
+ 'newSha1' => base_convert( sha1( 'a' ), 16, 36 ) ],
+ [ 'op' => 'delete', 'path' => '/path2', 'newSha1' => false ],
+ [ 'op' => 'null', 'path' => '', 'newSha1' => false ],
+ ];
+ $this->assertEquals( StatusValue::newGood(),
+ $journal->logChangeBatch( $changes, 'batch1' ) );
+ foreach ( $changes as $change ) {
+ $expectedEntries[] = $makeExpectedEntry(
+ ...array_merge( array_values( $change ), [ 'batch1', $now - 3600 ] ) );
+ }
+
+ ConvertibleTimestamp::setFakeTime( $now - 60 );
+ $change = [ 'op' => 'update', 'path' => '/path1',
+ 'newSha1' => base_convert( sha1( 'b' ), 16, 36 ) ];
+ $this->assertEquals(
+ StatusValue::newGood(), $journal->logChangeBatch( [ $change ], 'batch2' ) );
+ $expectedEntries[] = $makeExpectedEntry(
+ ...array_merge( array_values( $change ), [ 'batch2', $now - 60 ] ) );
+
+ if ( $expectedNext === false ) {
+ $this->assertSame(
+ array_slice( $expectedEntries, $expectedStart, $expectedCount ),
+ $journal->getChangeEntries( ...$args )
+ );
+ } else {
+ $next = false;
+ $this->assertSame(
+ array_slice( $expectedEntries, $expectedStart, $expectedCount ),
+ $journal->getChangeEntries( $args[0], $args[1], $next )
+ );
+ $this->assertSame( $expectedNext, $next );
+ }
+ }
+
+ public static function provideDoGetChangeEntries() {
+ return [
+ 'No args' => [ 0, 4, false, [] ],
+ 'null' => [ 0, 4, false, [ null ] ],
+ '1' => [ 0, 4, false, [ 1 ] ],
+ '2' => [ 1, 3, false, [ 2 ] ],
+ '4' => [ 3, 1, false, [ 4 ] ],
+ '5' => [ 0, 0, false, [ 5 ] ],
+ 'null, 0' => [ 0, 4, null, [ null, 0 ] ],
+ '1, 0' => [ 0, 4, null, [ 1, 0 ] ],
+ '2, 0' => [ 1, 3, null, [ 2, 0 ] ],
+ '4, 0' => [ 3, 1, null, [ 4, 0 ] ],
+ '5, 0' => [ 0, 0, null, [ 5, 0 ] ],
+ '1, 1' => [ 0, 1, '2', [ 1, 1 ] ],
+ '1, 2' => [ 0, 2, '3', [ 1, 2 ] ],
+ '1, 4' => [ 0, 4, null, [ 1, 4 ] ],
+ '1, 5' => [ 0, 4, null, [ 1, 5 ] ],
+ '2, 2' => [ 1, 2, '4', [ 2, 2 ] ],
+ '1, 2 with no $next' => [ 0, 2, false, [ 1, 2 ] ],
+ ];
+ }
+
+ /**
+ * @covers ::doPurgeOldLogs
+ */
+ public function testDoPurgeOldLogs_noop() {
+ // If we tried to access the database, it would throw, because the domain doesn't exist
+ $journal = $this->getJournal( [ 'domain' => 'no-such-domain' ] );
+ $this->assertEquals( StatusValue::newGood(), $journal->purgeOldLogs() );
+ }
+
+ /**
+ * @covers ::doPurgeOldLogs
+ * @covers ::doLogChangeBatch
+ * @covers ::doGetChangeEntries
+ */
+ public function testDoPurgeOldLogs() {
+ $journal = $this->getJournal( [ 'ttlDays' => 1 ] );
+ $now = time();
+
+ // One day and one second ago
+ ConvertibleTimestamp::setFakeTime( $now - 86401 );
+ $this->assertEquals( StatusValue::newGood(), $journal->logChangeBatch(
+ [ [ 'op' => 'null', 'path' => '', 'newSha1' => false ] ], 'batch1' ) );
+
+ // One day ago exactly, won't get purged
+ ConvertibleTimestamp::setFakeTime( $now - 86400 );
+ $this->assertEquals( StatusValue::newGood(), $journal->logChangeBatch(
+ [ [ 'op' => 'null', 'path' => '', 'newSha1' => false ] ], 'batch2' ) );
+
+ ConvertibleTimestamp::setFakeTime( $now );
+ $this->assertCount( 2, $journal->getChangeEntries() );
+ $journal->purgeOldLogs();
+ $this->assertCount( 1, $journal->getChangeEntries() );
+ }
+}
LockManagerGroup::destroySingletons();
$this->assertSame(
- null,
+ WikiMap::getCurrentWikiDbDomain()->getId(),
LockManagerGroup::singleton( null )->config( 'a' )['domain']
);
}
--- /dev/null
+<?php
+
+class FileBackendDBRepoWrapperTest extends MediaWikiIntegrationTestCase {
+ protected $backendName = 'foo-backend';
+ protected $repoName = 'pureTestRepo';
+
+ /**
+ * @dataProvider getBackendPathsProvider
+ * @covers FileBackendDBRepoWrapper::getBackendPaths
+ */
+ public function testGetBackendPaths(
+ $mocks,
+ $latest,
+ $dbReadsExpected,
+ $dbReturnValue,
+ $originalPath,
+ $expectedBackendPath,
+ $message ) {
+ list( $dbMock, $backendMock, $wrapperMock ) = $mocks;
+
+ $dbMock->expects( $dbReadsExpected )
+ ->method( 'selectField' )
+ ->will( $this->returnValue( $dbReturnValue ) );
+
+ $newPaths = $wrapperMock->getBackendPaths( [ $originalPath ], $latest );
+
+ $this->assertEquals(
+ $expectedBackendPath,
+ $newPaths[0],
+ $message );
+ }
+
+ public function getBackendPathsProvider() {
+ $prefix = 'mwstore://' . $this->backendName . '/' . $this->repoName;
+ $mocksForCaching = $this->getMocks();
+
+ return [
+ [
+ $mocksForCaching,
+ false,
+ $this->once(),
+ '96246614d75ba1703bdfd5d7660bb57407aaf5d9',
+ $prefix . '-public/f/o/foobar.jpg',
+ $prefix . '-original/9/6/2/96246614d75ba1703bdfd5d7660bb57407aaf5d9',
+ 'Public path translated correctly',
+ ],
+ [
+ $mocksForCaching,
+ false,
+ $this->never(),
+ '96246614d75ba1703bdfd5d7660bb57407aaf5d9',
+ $prefix . '-public/f/o/foobar.jpg',
+ $prefix . '-original/9/6/2/96246614d75ba1703bdfd5d7660bb57407aaf5d9',
+ 'LRU cache leveraged',
+ ],
+ [
+ $this->getMocks(),
+ true,
+ $this->once(),
+ '96246614d75ba1703bdfd5d7660bb57407aaf5d9',
+ $prefix . '-public/f/o/foobar.jpg',
+ $prefix . '-original/9/6/2/96246614d75ba1703bdfd5d7660bb57407aaf5d9',
+ 'Latest obtained',
+ ],
+ [
+ $this->getMocks(),
+ true,
+ $this->never(),
+ '96246614d75ba1703bdfd5d7660bb57407aaf5d9',
+ $prefix . '-deleted/f/o/foobar.jpg',
+ $prefix . '-original/f/o/o/foobar',
+ 'Deleted path translated correctly',
+ ],
+ [
+ $this->getMocks(),
+ true,
+ $this->once(),
+ null,
+ $prefix . '-public/b/a/baz.jpg',
+ $prefix . '-public/b/a/baz.jpg',
+ 'Path left untouched if no sha1 can be found',
+ ],
+ ];
+ }
+
+ /**
+ * @covers FileBackendDBRepoWrapper::getFileContentsMulti
+ */
+ public function testGetFileContentsMulti() {
+ list( $dbMock, $backendMock, $wrapperMock ) = $this->getMocks();
+
+ $sha1Path = 'mwstore://' . $this->backendName . '/' . $this->repoName
+ . '-original/9/6/2/96246614d75ba1703bdfd5d7660bb57407aaf5d9';
+ $filenamePath = 'mwstore://' . $this->backendName . '/' . $this->repoName
+ . '-public/f/o/foobar.jpg';
+
+ $dbMock->expects( $this->once() )
+ ->method( 'selectField' )
+ ->will( $this->returnValue( '96246614d75ba1703bdfd5d7660bb57407aaf5d9' ) );
+
+ $backendMock->expects( $this->once() )
+ ->method( 'getFileContentsMulti' )
+ ->will( $this->returnValue( [ $sha1Path => 'foo' ] ) );
+
+ $result = $wrapperMock->getFileContentsMulti( [ 'srcs' => [ $filenamePath ] ] );
+
+ $this->assertEquals(
+ [ $filenamePath => 'foo' ],
+ $result,
+ 'File contents paths translated properly'
+ );
+ }
+
+ protected function getMocks() {
+ $dbMock = $this->getMockBuilder( Wikimedia\Rdbms\IDatabase::class )
+ ->disableOriginalClone()
+ ->disableOriginalConstructor()
+ ->getMock();
+
+ $backendMock = $this->getMockBuilder( FSFileBackend::class )
+ ->setConstructorArgs( [ [
+ 'name' => $this->backendName,
+ 'wikiId' => wfWikiID()
+ ] ] )
+ ->getMock();
+
+ $wrapperMock = $this->getMockBuilder( FileBackendDBRepoWrapper::class )
+ ->setMethods( [ 'getDB' ] )
+ ->setConstructorArgs( [ [
+ 'backend' => $backendMock,
+ 'repoName' => $this->repoName,
+ 'dbHandleFactory' => null
+ ] ] )
+ ->getMock();
+
+ $wrapperMock->expects( $this->any() )->method( 'getDB' )->will( $this->returnValue( $dbMock ) );
+
+ return [ $dbMock, $backendMock, $wrapperMock ];
+ }
+}
--- /dev/null
+<?php
+
+use MediaWiki\MediaWikiServices;
+
+/**
+ * @coversDefaultClass LocalRepo
+ * @group Database
+ */
+class LocalRepoTest extends MediaWikiIntegrationTestCase {
+ /**
+ * @param array $extraInfo To pass to LocalRepo constructor
+ */
+ private function newRepo( array $extraInfo = [] ) {
+ return new LocalRepo( $extraInfo + [
+ 'name' => 'local',
+ 'backend' => 'local-backend',
+ ] );
+ }
+
+ /**
+ * @param array $extraInfo To pass to constructor
+ * @param bool $expected
+ * @dataProvider provideHasSha1Storage
+ * @covers ::__construct
+ */
+ public function testHasSha1Storage( array $extraInfo, $expected ) {
+ $this->assertSame( $expected, $this->newRepo( $extraInfo )->hasSha1Storage() );
+ }
+
+ public static function provideHasSha1Storage() {
+ return [
+ [ [], false ],
+ [ [ 'storageLayout' => 'sha256' ], false ],
+ [ [ 'storageLayout' => 'sha1' ], true ],
+ ];
+ }
+
+ /**
+ * @param string $prefix 'img' or 'oi'
+ * @param string $expectedClass 'LocalFile' or 'OldLocalFile'
+ * @dataProvider provideNewFileFromRow
+ * @covers ::newFileFromRow
+ */
+ public function testNewFileFromRow( $prefix, $expectedClass ) {
+ $this->editPage( 'File:Test_file', 'Some description' );
+
+ $row = (object)[
+ "{$prefix}_name" => 'Test_file',
+ // We cheat and include this for img_ too, it will be ignored
+ "{$prefix}_archive_name" => 'Archive_name',
+ "{$prefix}_user" => '1',
+ "{$prefix}_timestamp" => '12345678910111',
+ "{$prefix}_metadata" => '',
+ "{$prefix}_sha1" => sha1( '' ),
+ "{$prefix}_size" => '0',
+ "{$prefix}_height" => '0',
+ "{$prefix}_width" => '0',
+ "{$prefix}_bits" => '0',
+ "{$prefix}_description_text" => '',
+ "{$prefix}_description_data" => null,
+ ];
+ $file = $this->newRepo()->newFileFromRow( $row );
+ $this->assertInstanceOf( $expectedClass, $file );
+ $this->assertSame( 'Test_file', $file->getName() );
+ $this->assertSame( 1, $file->getUser( 'id' ) );
+ }
+
+ public static function provideNewFileFromRow() {
+ return [
+ 'img' => [ 'img', LocalFile::class ],
+ 'oi' => [ 'oi', OldLocalFile::class ],
+ ];
+ }
+
+ /**
+ * @covers ::__construct
+ * @covers ::newFileFromRow
+ */
+ public function testNewFileFromRow_invalid() {
+ $this->setExpectedException( 'MWException', 'LocalRepo::newFileFromRow: invalid row' );
+
+ $row = (object)[
+ "img_user" => '1',
+ "img_timestamp" => '12345678910111',
+ "img_metadata" => '',
+ "img_sha1" => sha1( '' ),
+ "img_size" => '0',
+ "img_height" => '0',
+ "img_width" => '0',
+ "img_bits" => '0',
+ ];
+ $file = $this->newRepo()->newFileFromRow( $row );
+ }
+
+ /**
+ * @covers ::__construct
+ * @covers ::newFromArchiveName
+ */
+ public function testNewFromArchiveName() {
+ $this->editPage( 'File:Test_file', 'Some description' );
+
+ $file = $this->newRepo()->newFromArchiveName( 'Test_file', 'b' );
+ $this->assertInstanceOf( OldLocalFile::class, $file );
+ $this->assertSame( 'Test_file', $file->getName() );
+ }
+
+ // TODO cleanupDeletedBatch, deletedFileHasKey, hiddenFileHasKey
+
+ /**
+ * @covers ::__construct
+ * @covers ::cleanupDeletedBatch
+ */
+ public function testCleanupDeletedBatch_sha1Storage() {
+ $this->assertEquals( Status::newGood(),
+ $this->newRepo( [ 'storageLayout' => 'sha1' ] )->cleanupDeletedBatch( [] ) );
+ }
+
+ /**
+ * @param string $input
+ * @param string $expected
+ * @dataProvider provideGetHashFromKey
+ * @covers ::getHashFromKey
+ */
+ public function testGetHashFromKey( $input, $expected ) {
+ $this->assertSame( $expected, LocalRepo::getHashFromKey( $input ) );
+ }
+
+ public static function provideGetHashFromKey() {
+ return [
+ [ '', false ],
+ [ '.', false ],
+ [ 'a.', 'a' ],
+ [ '.b', 'b' ],
+ [ '..c', 'c' ],
+ [ 'd.x', 'd' ],
+ [ '.e.x', 'e' ],
+ [ '..f.x', 'f' ],
+ [ 'g..x', 'g' ],
+ [ '01234567890123456789012345678901.x', '1234567890123456789012345678901' ],
+ ];
+ }
+
+ /**
+ * @covers ::__construct
+ * @covers ::checkRedirect
+ */
+ public function testCheckRedirect_nonRedirect() {
+ $this->editPage( 'File:Not a redirect', 'Not a redirect' );
+ $this->assertFalse(
+ $this->newRepo()->checkRedirect( Title::makeTitle( NS_FILE, 'Not a redirect' ) ) );
+ }
+
+ /**
+ * @covers ::__construct
+ * @covers ::checkRedirect
+ * @covers ::getSharedCacheKey
+ */
+ public function testCheckRedirect_redirect() {
+ $this->editPage( 'File:Redirect', '#REDIRECT [[File:Target]]' );
+ $this->assertEquals( 'File:Target',
+ $this->newRepo()->checkRedirect( Title::makeTitle( NS_FILE, 'Redirect' ) )
+ ->getPrefixedText() );
+ }
+
+ /**
+ * @covers ::__construct
+ * @covers ::checkRedirect
+ * @covers ::getSharedCacheKey
+ * @covers ::getLocalCacheKey
+ */
+ public function testCheckRedirect_redirect_noWANCache() {
+ $this->markTestIncomplete( 'WANObjectCache::makeKey is final' );
+
+ $mockWan = $this->getMockBuilder( WANObjectCache::class )
+ ->setConstructorArgs( [ [ 'cache' => new EmptyBagOStuff ] ] )
+ ->setMethods( [ 'makeKey' ] )
+ ->getMock();
+ $mockWan->expects( $this->exactly( 2 ) )->method( 'makeKey' )->withConsecutive(
+ [ 'image_redirect', md5( 'Redirect' ) ],
+ [ 'filerepo', 'local', 'image_redirect', md5( 'Redirect' ) ]
+ )->will( $this->onConsecutiveCalls( false, 'somekey' ) );
+
+ $repo = $this->newRepo( [ 'wanCache' => $mockWan ] );
+
+ $this->editPage( 'File:Redirect', '#REDIRECT [[File:Target]]' );
+ $this->assertEquals( 'File:Target',
+ $repo->checkRedirect( Title::makeTitle( NS_FILE, 'Redirect' ) )->getPrefixedText() );
+ }
+
+ /**
+ * @covers ::__construct
+ * @covers ::checkRedirect
+ */
+ public function testCheckRedirect_invalidFile() {
+ $this->setExpectedException( MWException::class, '`Notafile` is not a valid file title.' );
+ $this->newRepo()->checkRedirect( Title::makeTitle( NS_MAIN, 'Notafile' ) );
+ }
+
+ /**
+ * @covers ::__construct
+ * @covers ::findBySha1
+ */
+ public function testFindBySha1() {
+ $this->markTestIncomplete( "Haven't figured out how to upload files yet" );
+
+ $repo = $this->newRepo();
+
+ $tmpFileFactory = MediaWikiServices::getInstance()->getTempFSFileFactory();
+ foreach ( [ 'File1', 'File2', 'File3' ] as $name ) {
+ $fsFile = $tmpFileFactory->newTempFSFile( '' );
+ file_put_contents( $fsFile->getPath(), "$name contents" );
+ $localFile = $repo->newFile( $name );
+ $localFile->upload( $fsFile, 'Uploaded', "$name desc" );
+ }
+ }
+
+ /**
+ * @covers ::__construct
+ * @covers ::getSharedCacheKey
+ * @covers ::checkRedirect
+ * @covers ::invalidateImageRedirect
+ */
+ public function testInvalidateImageRedirect() {
+ global $wgTestMe;
+ $wgTestMe = true;
+ $repo = $this->newRepo(
+ [ 'wanCache' => new WANObjectCache( [ 'cache' => new HashBagOStuff ] ) ] );
+
+ $title = Title::makeTitle( NS_FILE, 'Redirect' );
+
+ $this->editPage( 'File:Redirect', '#REDIRECT [[File:Target]]' );
+
+ $this->assertSame( 'File:Target',
+ $repo->checkRedirect( $title )->getPrefixedText() );
+
+ $this->editPage( 'File:Redirect', 'No longer a redirect' );
+
+ $this->assertSame( 'File:Target',
+ $repo->checkRedirect( $title )->getPrefixedText() );
+
+ $repo->invalidateImageRedirect( $title );
+ $repo->getMasterDB()->commit();
+
+ $this->markTestIncomplete(
+ "Can't figure out how to get image redirect validation to take effect" );
+
+ $this->assertSame( false, $repo->checkRedirect( $title ) );
+ }
+
+ /**
+ * @covers ::getInfo
+ */
+ public function testGetInfo() {
+ $this->setMwGlobals( [
+ 'wgFavicon' => '//example.com/favicon.ico',
+ 'wgSitename' => 'Test my site',
+ ] );
+
+ $repo = $this->newRepo( [ 'favicon' => 'Hey, this option is ignored in LocalRepo!' ] );
+
+ $this->assertSame( [
+ 'name' => 'local',
+ 'displayname' => 'Test my site',
+ 'rootUrl' => false,
+ 'local' => true,
+ 'url' => false,
+ 'thumbUrl' => false,
+ 'initialCapital' => true,
+ // XXX This assumes protocol-relative will get expanded to http instead of https
+ 'favicon' => 'http://example.com/favicon.ico',
+ ], $repo->getInfo() );
+ }
+
+ // XXX The following getInfo tests are really testing FileRepo, not LocalRepo, but we want to
+ // make sure they're true for LocalRepo too. How should we do this? A trait?
+
+ /**
+ * @covers ::getInfo
+ */
+ public function testGetInfo_name() {
+ $this->assertSame( 'some-name',
+ $this->newRepo( [ 'name' => 'some-name' ] )->getInfo()['name'] );
+ }
+
+ /**
+ * @covers ::getInfo
+ */
+ public function testGetInfo_displayName() {
+ $this->assertSame( wfMessage( 'shared-repo' )->text(),
+ $this->newRepo( [ 'name' => 'not-local' ] )->getInfo()['displayname'] );
+ }
+
+ /**
+ * @covers ::getInfo
+ */
+ public function testGetInfo_displayNameCustomMsg() {
+ $this->editPage( 'MediaWiki:Shared-repo-name-not-local', 'Name to display please' );
+ // Allow the message to take effect
+ MediaWikiServices::getInstance()->getMessageCache()->enable();
+
+ $this->assertSame( 'Name to display please',
+ $this->newRepo( [ 'name' => 'not-local' ] )->getInfo()['displayname'] );
+ }
+
+ /**
+ * @covers ::getInfo
+ */
+ public function testGetInfo_rootUrl() {
+ $this->assertSame( 'https://my.url',
+ $this->newRepo( [ 'url' => 'https://my.url' ] )->getInfo()['rootUrl'] );
+ }
+
+ /**
+ * @covers ::getInfo
+ */
+ public function testGetInfo_rootUrlCustomized() {
+ $this->assertSame(
+ 'https://my.url/some/sub/dir',
+ $this->newRepo( [
+ 'url' => 'https://my.url',
+ 'zones' => [ 'public' => [ 'url' => 'https://my.url/some/sub/dir' ] ],
+ ] )->getInfo()['rootUrl']
+ );
+ }
+
+ /**
+ * @covers ::getInfo
+ */
+ public function testGetInfo_local() {
+ $this->assertFalse( $this->newRepo( [ 'name' => 'not-local' ] )->getInfo()['local'] );
+ }
+
+ /**
+ * @param string $setting
+ * @dataProvider provideGetInfo_optionalSettings
+ * @covers ::getInfo
+ */
+ public function testGetInfo_optionalSettings( $setting ) {
+ $this->assertSame( 'dummy test value',
+ $this->newRepo( [ $setting => 'dummy test value' ] )->getInfo()[$setting] );
+ }
+
+ public static function provideGetInfo_optionalSettings() {
+ return [
+ [ 'url' ],
+ [ 'thumbUrl' ],
+ [ 'initialCapital' ],
+ [ 'descBaseUrl' ],
+ [ 'scriptDirUrl' ],
+ [ 'articleUrl' ],
+ [ 'fetchDescription' ],
+ [ 'descriptionCacheExpiry' ],
+ ];
+ }
+
+ /**
+ * @param string $method
+ * @param mixed ...$args
+ * @dataProvider provideSkipWriteOperationIfSha1
+ * @covers ::store
+ * @covers ::storeBatch
+ * @covers ::cleanupBatch
+ * @covers ::publish
+ * @covers ::publishBatch
+ * @covers ::delete
+ * @covers ::deleteBatch
+ * @covers ::skipWriteOperationIfSha1
+ */
+ public function testSkipWriteOperationIfSha1( $method, ...$args ) {
+ $repo = $this->newRepo( [ 'storageLayout' => 'sha1' ] );
+ $this->assertEquals( Status::newGood(), $repo->$method( ...$args ) );
+ }
+
+ public static function provideSkipWriteOperationIfSha1() {
+ return [
+ [ 'store', '', '', '' ],
+ [ 'storeBatch', [ '' ] ],
+ [ 'cleanupBatch', [ '' ] ],
+ [ 'publish', '', '', '' ],
+ [ 'publishBatch', [ '' ] ],
+ [ 'delete', '', '' ],
+ [ 'deleteBatch', [ '' ] ],
+ ];
+ }
+}
function testHasForeignRepoNegative() {
$this->setMwGlobals( 'wgForeignFileRepos', [] );
- $this->overrideMwServices();
FileBackendGroup::destroySingleton();
$this->assertFalse( RepoGroup::singleton()->hasForeignRepos() );
}
function testForEachForeignRepoNone() {
$this->setMwGlobals( 'wgForeignFileRepos', [] );
- $this->overrideMwServices();
FileBackendGroup::destroySingleton();
$fakeCallback = $this->createMock( RepoGroupTestHelper::class );
$fakeCallback->expects( $this->never() )->method( 'callback' );
'apiThumbCacheExpiry' => 86400,
'directory' => $wgUploadDirectory
] ] );
- $this->overrideMwServices();
FileBackendGroup::destroySingleton();
}
}
}
private function setWgInterwikiCache( $interwikiCache ) {
- $this->overrideMwServices();
MediaWikiServices::getInstance()->resetServiceForTesting( 'InterwikiLookup' );
$this->setMwGlobals( 'wgInterwikiCache', $interwikiCache );
}
--- /dev/null
+<?php
+
+/**
+ * @covers ConverterRule
+ */
+class ConverterRuleTest extends MediaWikiTestCase {
+
+ public function setUp() {
+ parent::setUp();
+ $this->setMwGlobals( 'wgUser', new User );
+ }
+
+ public function testParseEmpty() {
+ $converter = new LanguageConverter( new Language(), 'en' );
+ $rule = new ConverterRule( '', $converter );
+ $rule->parse();
+
+ $this->assertSame( false, $rule->getTitle(), 'title' );
+ $this->assertSame( [], $rule->getConvTable(), 'conversion table' );
+ $this->assertSame( 'none', $rule->getRulesAction(), 'rules action' );
+ }
+
+}
}
}
+ public function testHashRingSingleLocation() {
+ // SHA-1 based and weighted
+ $ring = new HashRing( [ 's1' => 1 ], 'sha1' );
+
+ $this->assertEquals(
+ [ 's1' => 1 ],
+ $ring->getLocationWeights(),
+ 'Normalized location weights'
+ );
+
+ for ( $i = 0; $i < 5; $i++ ) {
+ $this->assertEquals(
+ 's1',
+ $ring->getLocation( "hello$i" ),
+ 'Items placed at proper locations'
+ );
+ $this->assertEquals(
+ [ 's1' ],
+ $ring->getLocations( "hello$i", 2 ),
+ 'Items placed at proper locations'
+ );
+ }
+
+ $this->assertEquals( [], $ring->getLocations( "helloX", 0 ), "Limit of 0" );
+ }
+
public function testHashRingMapping() {
// SHA-1 based and weighted
$ring = new HashRing(
--- /dev/null
+<?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 );
+ }
+}
$db->method( 'getMasterServerInfo' )
->willReturn( [ 'serverId' => 172, 'asOf' => time() ] );
- $db->setLBInfo( 'replica', true );
-
// Fake the current time.
list( $nowSecFrac, $nowSec ) = explode( ' ', microtime() );
$now = (float)$nowSec + (float)$nowSecFrac;
global $wgExtensionMessagesFiles;
self::$oldExtMsgFiles = $wgExtensionMessagesFiles;
$wgExtensionMessagesFiles['LogTests'] = __DIR__ . '/LogTests.i18n.php';
- Language::clearCaches();
+ Language::getLocalisationCache()->recache( 'en' );
}
public static function tearDownAfterClass() {
global $wgExtensionMessagesFiles;
$wgExtensionMessagesFiles = self::$oldExtMsgFiles;
- Language::clearCaches();
+ Language::getLocalisationCache()->recache( 'en' );
parent::tearDownAfterClass();
}
--- /dev/null
+<?php
+/**
+ * @todo Could use a test of extended XMP segments. Hard to find programs that
+ * create example files, and creating my own in vim propbably wouldn't
+ * serve as a very good "test". (Adobe photoshop probably creates such files
+ * but it costs money). The implementation of it currently in MediaWiki is based
+ * solely on reading the standard, without any real world test files.
+ *
+ * @group Media
+ * @covers JpegMetadataExtractor
+ */
+class JpegMetadataExtractorTest extends MediaWikiIntegrationTestCase {
+
+ protected $filePath;
+
+ protected function setUp() {
+ parent::setUp();
+
+ $this->filePath = __DIR__ . '/../../data/media/';
+ }
+
+ /**
+ * We also use this test to test padding bytes don't
+ * screw stuff up
+ *
+ * @param string $file Filename
+ *
+ * @dataProvider provideUtf8Comment
+ */
+ public function testUtf8Comment( $file ) {
+ $res = JpegMetadataExtractor::segmentSplitter( $this->filePath . $file );
+ $this->assertEquals( [ 'UTF-8 JPEG Comment — ¼' ], $res['COM'] );
+ }
+
+ public static function provideUtf8Comment() {
+ return [
+ [ 'jpeg-comment-utf.jpg' ],
+ [ 'jpeg-padding-even.jpg' ],
+ [ 'jpeg-padding-odd.jpg' ],
+ ];
+ }
+
+ /** The file is iso-8859-1, but it should get auto converted */
+ public function testIso88591Comment() {
+ $res = JpegMetadataExtractor::segmentSplitter( $this->filePath . 'jpeg-comment-iso8859-1.jpg' );
+ $this->assertEquals( [ 'ISO-8859-1 JPEG Comment - ¼' ], $res['COM'] );
+ }
+
+ /** Comment values that are non-textual (random binary junk) should not be shown.
+ * The example test file has a comment with a 0x5 byte in it which is a control character
+ * and considered binary junk for our purposes.
+ */
+ public function testBinaryCommentStripped() {
+ $res = JpegMetadataExtractor::segmentSplitter( $this->filePath . 'jpeg-comment-binary.jpg' );
+ $this->assertEmpty( $res['COM'] );
+ }
+
+ /* Very rarely a file can have multiple comments.
+ * Order of comments is based on order inside the file.
+ */
+ public function testMultipleComment() {
+ $res = JpegMetadataExtractor::segmentSplitter( $this->filePath . 'jpeg-comment-multiple.jpg' );
+ $this->assertEquals( [ 'foo', 'bar' ], $res['COM'] );
+ }
+
+ public function testXMPExtraction() {
+ $res = JpegMetadataExtractor::segmentSplitter( $this->filePath . 'jpeg-xmp-psir.jpg' );
+ $expected = file_get_contents( $this->filePath . 'jpeg-xmp-psir.xmp' );
+ $this->assertEquals( $expected, $res['XMP'] );
+ }
+
+ public function testPSIRExtraction() {
+ $res = JpegMetadataExtractor::segmentSplitter( $this->filePath . 'jpeg-xmp-psir.jpg' );
+ $expected = '50686f746f73686f7020332e30003842494d04040000000'
+ . '000181c02190004746573741c02190003666f6f1c020000020004';
+ $this->assertEquals( $expected, bin2hex( $res['PSIR'][0] ) );
+ }
+
+ public function testXMPExtractionAltAppId() {
+ $res = JpegMetadataExtractor::segmentSplitter( $this->filePath . 'jpeg-xmp-alt.jpg' );
+ $expected = file_get_contents( $this->filePath . 'jpeg-xmp-psir.xmp' );
+ $this->assertEquals( $expected, $res['XMP'] );
+ }
+
+ public function testIPTCHashComparisionNoHash() {
+ $segments = JpegMetadataExtractor::segmentSplitter( $this->filePath . 'jpeg-xmp-psir.jpg' );
+ $res = JpegMetadataExtractor::doPSIR( $segments['PSIR'][0] );
+
+ $this->assertEquals( 'iptc-no-hash', $res );
+ }
+
+ public function testIPTCHashComparisionBadHash() {
+ $segments = JpegMetadataExtractor::segmentSplitter( $this->filePath . 'jpeg-iptc-bad-hash.jpg' );
+ $res = JpegMetadataExtractor::doPSIR( $segments['PSIR'][0] );
+
+ $this->assertEquals( 'iptc-bad-hash', $res );
+ }
+
+ public function testIPTCHashComparisionGoodHash() {
+ $segments = JpegMetadataExtractor::segmentSplitter( $this->filePath . 'jpeg-iptc-good-hash.jpg' );
+ $res = JpegMetadataExtractor::doPSIR( $segments['PSIR'][0] );
+
+ $this->assertEquals( 'iptc-good-hash', $res );
+ }
+
+ public function testExifByteOrder() {
+ $res = JpegMetadataExtractor::segmentSplitter( $this->filePath . 'exif-user-comment.jpg' );
+ $expected = 'BE';
+ $this->assertEquals( $expected, $res['byteOrder'] );
+ }
+
+ public function testInfiniteRead() {
+ // test file truncated right after a segment, which previously
+ // caused an infinite loop looking for the next segment byte.
+ // Should get past infinite loop and throw in wfUnpack()
+ $this->setExpectedException( 'MWException' );
+ $res = JpegMetadataExtractor::segmentSplitter( $this->filePath . 'jpeg-segment-loop1.jpg' );
+ }
+
+ public function testInfiniteRead2() {
+ // test file truncated after a segment's marker and size, which
+ // would cause a seek past end of file. Seek past end of file
+ // doesn't actually fail, but prevents further reading and was
+ // devolving into the previous case (testInfiniteRead).
+ $this->setExpectedException( 'MWException' );
+ $res = JpegMetadataExtractor::segmentSplitter( $this->filePath . 'jpeg-segment-loop2.jpg' );
+ }
+}
/** @covers ObjectCache::newAnything */
public function testNewAnythingNoAccelNoDb() {
- $this->overrideMwServices(); // Ensures restore on tear down
- MediaWiki\MediaWikiServices::disableStorageBackend();
-
$this->setMwGlobals( [
'wgMainCacheType' => CACHE_ACCEL
] );
CACHE_ACCEL => [ 'class' => EmptyBagOStuff::class ]
] );
+ MediaWiki\MediaWikiServices::disableStorageBackend();
+
$this->assertInstanceOf(
EmptyBagOStuff::class,
ObjectCache::newAnything( [] ),
/** @covers ObjectCache::newAnything */
public function testNewAnythingNothingNoDb() {
- $this->overrideMwServices();
MediaWiki\MediaWikiServices::disableStorageBackend();
$this->assertInstanceOf(
$this->tablesUsed += $this->getMcrTablesToReset();
- $this->setMwGlobals( 'wgActorTableSchemaMigrationStage', SCHEMA_COMPAT_NEW );
- $this->setMwGlobals( 'wgContentHandlerUseDB', $this->getContentHandlerUseDB() );
- $this->setMwGlobals(
- 'wgMultiContentRevisionSchemaMigrationStage',
- $this->getMcrMigrationStage()
- );
- $this->overrideMwServices();
+ $this->setMwGlobals( [
+ 'wgActorTableSchemaMigrationStage' => SCHEMA_COMPAT_NEW,
+ 'wgContentHandlerUseDB' => $this->getContentHandlerUseDB(),
+ 'wgMultiContentRevisionSchemaMigrationStage' => $this->getMcrMigrationStage(),
+ ] );
// First create our dummy page
$page = Title::newFromText( 'PageArchiveTest_thePage' );
$this->getMcrMigrationStage()
);
$this->pagesToDelete = [];
-
- $this->overrideMwServices();
}
protected function tearDown() {
--- /dev/null
+<?php
+
+/**
+ * @covers ParserFactory
+ */
+class ParserFactoryTest extends MediaWikiIntegrationTestCase {
+ use FactoryArgTestTrait;
+
+ protected static function getFactoryClass() {
+ return ParserFactory::class;
+ }
+
+ protected static function getInstanceClass() {
+ return Parser::class;
+ }
+
+ protected static function getFactoryMethodName() {
+ return 'create';
+ }
+
+ protected static function getExtraClassArgCount() {
+ // The parser factory itself is passed to the parser
+ return 1;
+ }
+
+ protected function getOverriddenMockValueForParam( ReflectionParameter $param ) {
+ if ( $param->getPosition() === 0 ) {
+ return [ $this->createMock( MediaWiki\Config\ServiceOptions::class ) ];
+ }
+ return [];
+ }
+}
*/
public function testCheckPopularPasswordBlacklist( $expected, $password ) {
global $IP;
- $this->hideDeprecated( 'PasswordPolicyChecks::checkPopularPasswordBlacklist' );
$this->setMwGlobals( [
'wgSitename' => 'sitename',
'wgPopularPasswordFile' => "$IP/includes/password/commonpasswords.cdb"
'modules' => [ 'test.scripts.user' ],
'only' => ResourceLoaderModule::TYPE_SCRIPTS,
'extra' => [],
- 'output' => '<script>(RLQ=window.RLQ||[]).push(function(){mw.loader.load("/w/load.php?lang=nl\u0026modules=test.scripts.user\u0026only=scripts\u0026user=Example\u0026version=0a56zyi");});</script>',
+ 'output' => '<script>(RLQ=window.RLQ||[]).push(function(){mw.loader.load("/w/load.php?lang=nl\u0026modules=test.scripts.user\u0026only=scripts\u0026user=Example\u0026version={blankCombi}");});</script>',
],
[
'context' => [],
'modules' => [ 'test.user' ],
'only' => ResourceLoaderModule::TYPE_COMBINED,
'extra' => [],
- 'output' => '<script>(RLQ=window.RLQ||[]).push(function(){mw.loader.load("/w/load.php?lang=nl\u0026modules=test.user\u0026user=Example\u0026version=0a56zyi");});</script>',
+ 'output' => '<script>(RLQ=window.RLQ||[]).push(function(){mw.loader.load("/w/load.php?lang=nl\u0026modules=test.user\u0026user=Example\u0026version={blankCombi}");});</script>',
],
[
'context' => [ 'debug' => 'true' ],
'modules' => [ 'test.shouldembed' ],
'only' => ResourceLoaderModule::TYPE_COMBINED,
'extra' => [],
- 'output' => '<script>(RLQ=window.RLQ||[]).push(function(){mw.loader.implement("test.shouldembed@09p30q0",null,{"css":[]});});</script>',
+ 'output' => '<script>(RLQ=window.RLQ||[]).push(function(){mw.loader.implement("test.shouldembed@{blankVer}",null,{"css":[]});});</script>',
],
[
'context' => [],
'modules' => [ 'test', 'test.shouldembed' ],
'only' => ResourceLoaderModule::TYPE_COMBINED,
'extra' => [],
- 'output' => '<script>(RLQ=window.RLQ||[]).push(function(){mw.loader.load("/w/load.php?lang=nl\u0026modules=test");mw.loader.implement("test.shouldembed@09p30q0",null,{"css":[]});});</script>',
+ 'output' => '<script>(RLQ=window.RLQ||[]).push(function(){mw.loader.load("/w/load.php?lang=nl\u0026modules=test");mw.loader.implement("test.shouldembed@{blankVer}",null,{"css":[]});});</script>',
],
[
'context' => [],
private static function expandVariables( $text ) {
return strtr( $text, [
+ '{blankCombi}' => ResourceLoaderTestCase::BLANK_COMBI,
'{blankVer}' => ResourceLoaderTestCase::BLANK_VERSION
] );
}
// Misc
$this->assertEquals( 'ltr', $ctx->getDirection() );
$this->assertEquals( 'qqx|fallback||||||||', $ctx->getHash() );
+ $this->assertSame( [], $ctx->getReqBase() );
$this->assertInstanceOf( User::class, $ctx->getUserObj() );
}
// Misc
$this->assertEquals( 'ltr', $ctx->getDirection() );
$this->assertEquals( 'zh|fallback|||styles|||||', $ctx->getHash() );
+ $this->assertSame( [ 'lang' => 'zh' ], $ctx->getReqBase() );
}
public static function provideDirection() {
'factory' => function () {
$mock = $this->getMockBuilder( ResourceLoaderTestModule::class )
->setMethods( [ 'getVersionHash' ] )->getMock();
- $mock->method( 'getVersionHash' )->willReturn( '1234567' );
+ $mock->method( 'getVersionHash' )->willReturn( '12345' );
return $mock;
}
]
mw.loader.register([
[
"test.version",
- "1234567"
+ "12345"
]
]);',
] ],
mw.loader.register([
[
"test.version",
- "016es8l"
+ "16es8"
]
]);',
] ],
* @coversNothing
*/
public function testServiceWiring() {
- $this->overrideMwServices();
-
$ranHook = 0;
$this->setMwGlobals( 'wgHooks', [
'ResourceLoaderRegisterModules' => [
);
$this->assertEquals(
- ResourceLoader::makeHash( self::BLANK_VERSION ),
+ self::BLANK_COMBI,
$rl->getCombinedVersion( $context, [ 'foo' ] ),
'compute foo'
);
$this->originalHandlers = TestingAccessWrapper::newFromClass( Hooks::class )->handlers;
TestingAccessWrapper::newFromClass( Hooks::class )->handlers = [];
-
- $this->overrideMwServices();
}
public function tearDown() {
+++ /dev/null
-<?php
-
-class SearchResultTest extends MediawikiTestCase {
- /**
- * @covers SearchResult::getExtensionData
- * @covers SearchResult::setExtensionData
- */
- public function testExtensionData() {
- $result = SearchResult::newFromTitle( Title::newMainPage() );
- $this->assertEquals( [], $result->getExtensionData(), 'starts empty' );
-
- $data = [ 'hello' => 'world' ];
- $result->setExtensionData( function () use ( &$data ) {
- return $data;
- } );
- $this->assertEquals( $data, $result->getExtensionData(), 'can set extension data' );
- $data['this'] = 'that';
- $this->assertEquals( $data, $result->getExtensionData(), 'refetches from callback' );
- }
-
- /**
- * @covers SearchResult::getExtensionData
- * @covers SearchResult::setExtensionData
- */
- public function testExtensionDataArrayBC() {
- $result = SearchResult::newFromTitle( Title::newMainPage() );
- $data = [ 'hello' => 'world' ];
- $this->hideDeprecated( 'SearchResult::setExtensionData with array argument' );
- $this->assertEquals( [], $result->getExtensionData(), 'starts empty' );
- $result->setExtensionData( $data );
- $this->assertEquals( $data, $result->getExtensionData(), 'can set extension data' );
- $data['this'] = 'that';
- $this->assertNotEquals( $data, $result->getExtensionData(), 'shouldnt hold any reference' );
-
- $result->setExtensionData( $data );
- $this->assertEquals( $data, $result->getExtensionData(), 'can replace extension data' );
- }
-}
--- /dev/null
+<?php
+
+class SearchResultTraitTest extends MediawikiTestCase {
+ /**
+ * @covers SearchResultTrait::getExtensionData
+ * @covers SearchResultTrait::setExtensionData
+ */
+ public function testExtensionData() {
+ $result = new class() {
+ use SearchResultTrait;
+ };
+ $this->assertEquals( [], $result->getExtensionData(), 'starts empty' );
+
+ $data = [ 'hello' => 'world' ];
+ $result->setExtensionData( function () use ( &$data ) {
+ return $data;
+ } );
+ $this->assertEquals( $data, $result->getExtensionData(), 'can set extension data' );
+ $data['this'] = 'that';
+ $this->assertEquals( $data, $result->getExtensionData(), 'refetches from callback' );
+ }
+
+ /**
+ * @covers SearchResultTrait::getExtensionData
+ * @covers SearchResultTrait::setExtensionData
+ */
+ public function testExtensionDataArrayBC() {
+ $result = new class() {
+ use SearchResultTrait;
+ };
+ $data = [ 'hello' => 'world' ];
+ $this->hideDeprecated( 'SearchResultTrait::setExtensionData with array argument' );
+ $this->assertEquals( [], $result->getExtensionData(), 'starts empty' );
+ $result->setExtensionData( $data );
+ $this->assertEquals( $data, $result->getExtensionData(), 'can set extension data' );
+ $data['this'] = 'that';
+ $this->assertNotEquals( $data, $result->getExtensionData(), 'shouldnt hold any reference' );
+
+ $result->setExtensionData( $data );
+ $this->assertEquals( $data, $result->getExtensionData(), 'can replace extension data' );
+ }
+}
--- /dev/null
+<?php
+
+use MediaWiki\Site\MediaWikiPageNameNormalizer;
+
+/**
+ * @covers MediaWiki\Site\MediaWikiPageNameNormalizer
+ *
+ * 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
+ *
+ * @since 1.27
+ *
+ * @group Site
+ * @group medium
+ *
+ * @author Marius Hoch
+ */
+class MediaWikiPageNameNormalizerTest extends MediaWikiIntegrationTestCase {
+
+ /**
+ * @dataProvider normalizePageTitleProvider
+ */
+ public function testNormalizePageTitle( $expected, $pageName, $getResponse ) {
+ MediaWikiPageNameNormalizerTestMockHttp::$response = $getResponse;
+
+ $normalizer = new MediaWikiPageNameNormalizer(
+ new MediaWikiPageNameNormalizerTestMockHttp()
+ );
+
+ $this->assertSame(
+ $expected,
+ $normalizer->normalizePageName( $pageName, 'https://www.wikidata.org/w/api.php' )
+ );
+ }
+
+ public function normalizePageTitleProvider() {
+ // Response are taken from wikidata and kkwiki using the following API request
+ // api.php?action=query&prop=info&redirects=1&converttitles=1&format=json&titles=…
+ return [
+ 'universe (Q1)' => [
+ 'Q1',
+ 'Q1',
+ '{"batchcomplete":"","query":{"pages":{"129":{"pageid":129,"ns":0,'
+ . '"title":"Q1","contentmodel":"wikibase-item","pagelanguage":"en",'
+ . '"pagelanguagehtmlcode":"en","pagelanguagedir":"ltr",'
+ . '"touched":"2016-06-23T05:11:21Z","lastrevid":350004448,"length":58001}}}}'
+ ],
+ 'Q404 redirects to Q395' => [
+ 'Q395',
+ 'Q404',
+ '{"batchcomplete":"","query":{"redirects":[{"from":"Q404","to":"Q395"}],"pages"'
+ . ':{"601":{"pageid":601,"ns":0,"title":"Q395","contentmodel":"wikibase-item",'
+ . '"pagelanguage":"en","pagelanguagehtmlcode":"en","pagelanguagedir":"ltr",'
+ . '"touched":"2016-06-23T08:00:20Z","lastrevid":350021914,"length":60108}}}}'
+ ],
+ 'D converted to Д (Latin to Cyrillic) (taken from kkwiki)' => [
+ 'Д',
+ 'D',
+ '{"batchcomplete":"","query":{"converted":[{"from":"D","to":"\u0414"}],'
+ . '"pages":{"510541":{"pageid":510541,"ns":0,"title":"\u0414",'
+ . '"contentmodel":"wikitext","pagelanguage":"kk","pagelanguagehtmlcode":"kk",'
+ . '"pagelanguagedir":"ltr","touched":"2015-11-22T09:16:18Z",'
+ . '"lastrevid":2373618,"length":3501}}}}'
+ ],
+ 'there is no Q0' => [
+ false,
+ 'Q0',
+ '{"batchcomplete":"","query":{"pages":{"-1":{"ns":0,"title":"Q0",'
+ . '"missing":"","contentmodel":"wikibase-item","pagelanguage":"en",'
+ . '"pagelanguagehtmlcode":"en","pagelanguagedir":"ltr"}}}}'
+ ],
+ 'invalid title' => [
+ false,
+ '{{',
+ '{"batchcomplete":"","query":{"pages":{"-1":{"title":"{{",'
+ . '"invalidreason":"The requested page title contains invalid '
+ . 'characters: \"{\".","invalid":""}}}}'
+ ],
+ 'error on get' => [ false, 'ABC', false ]
+ ];
+ }
+
+}
+
+/**
+ * @private
+ * @see Http
+ */
+class MediaWikiPageNameNormalizerTestMockHttp extends Http {
+
+ /**
+ * @var mixed
+ */
+ public static $response;
+
+ public static function get( $url, array $options = [], $caller = __METHOD__ ) {
+ PHPUnit_Framework_Assert::assertInternalType( 'string', $url );
+ PHPUnit_Framework_Assert::assertInternalType( 'string', $caller );
+
+ return self::$response;
+ }
+}
--- /dev/null
+<?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
+ *
+ * @ingroup Site
+ * @ingroup Test
+ *
+ * @group Site
+ *
+ * @covers SiteExporter
+ *
+ * @author Daniel Kinzler
+ */
+class SiteExporterTest extends MediaWikiIntegrationTestCase {
+
+ public function testConstructor_InvalidArgument() {
+ $this->setExpectedException( InvalidArgumentException::class );
+
+ new SiteExporter( 'Foo' );
+ }
+
+ public function testExportSites() {
+ $foo = Site::newForType( Site::TYPE_UNKNOWN );
+ $foo->setGlobalId( 'Foo' );
+
+ $acme = Site::newForType( Site::TYPE_UNKNOWN );
+ $acme->setGlobalId( 'acme.com' );
+ $acme->setGroup( 'Test' );
+ $acme->addLocalId( Site::ID_INTERWIKI, 'acme' );
+ $acme->setPath( Site::PATH_LINK, 'http://acme.com/' );
+
+ $tmp = tmpfile();
+ $exporter = new SiteExporter( $tmp );
+
+ $exporter->exportSites( [ $foo, $acme ] );
+
+ fseek( $tmp, 0 );
+ $xml = fread( $tmp, 16 * 1024 );
+
+ $this->assertContains( '<sites ', $xml );
+ $this->assertContains( '<site>', $xml );
+ $this->assertContains( '<globalid>Foo</globalid>', $xml );
+ $this->assertContains( '</site>', $xml );
+ $this->assertContains( '<globalid>acme.com</globalid>', $xml );
+ $this->assertContains( '<group>Test</group>', $xml );
+ $this->assertContains( '<localid type="interwiki">acme</localid>', $xml );
+ $this->assertContains( '<path type="link">http://acme.com/</path>', $xml );
+ $this->assertContains( '</sites>', $xml );
+
+ // NOTE: HHVM (at least on wmf Jenkins) doesn't like file URLs.
+ $xsdFile = __DIR__ . '/../../../../docs/sitelist-1.0.xsd';
+ $xsdData = file_get_contents( $xsdFile );
+
+ $document = new DOMDocument();
+ $document->loadXML( $xml, LIBXML_NONET );
+ $document->schemaValidateSource( $xsdData );
+ }
+
+ private function newSiteStore( SiteList $sites ) {
+ $store = $this->getMockBuilder( SiteStore::class )->getMock();
+
+ $store->expects( $this->once() )
+ ->method( 'saveSites' )
+ ->will( $this->returnCallback( function ( $moreSites ) use ( $sites ) {
+ foreach ( $moreSites as $site ) {
+ $sites->setSite( $site );
+ }
+ } ) );
+
+ $store->expects( $this->any() )
+ ->method( 'getSites' )
+ ->will( $this->returnValue( new SiteList() ) );
+
+ return $store;
+ }
+
+ public function provideRoundTrip() {
+ $foo = Site::newForType( Site::TYPE_UNKNOWN );
+ $foo->setGlobalId( 'Foo' );
+
+ $acme = Site::newForType( Site::TYPE_UNKNOWN );
+ $acme->setGlobalId( 'acme.com' );
+ $acme->setGroup( 'Test' );
+ $acme->addLocalId( Site::ID_INTERWIKI, 'acme' );
+ $acme->setPath( Site::PATH_LINK, 'http://acme.com/' );
+
+ $dewiki = Site::newForType( Site::TYPE_MEDIAWIKI );
+ $dewiki->setGlobalId( 'dewiki' );
+ $dewiki->setGroup( 'wikipedia' );
+ $dewiki->setForward( true );
+ $dewiki->addLocalId( Site::ID_INTERWIKI, 'wikipedia' );
+ $dewiki->addLocalId( Site::ID_EQUIVALENT, 'de' );
+ $dewiki->setPath( Site::PATH_LINK, 'http://de.wikipedia.org/w/' );
+ $dewiki->setPath( MediaWikiSite::PATH_PAGE, 'http://de.wikipedia.org/wiki/' );
+ $dewiki->setSource( 'meta.wikimedia.org' );
+
+ return [
+ 'empty' => [
+ new SiteList()
+ ],
+
+ 'some' => [
+ new SiteList( [ $foo, $acme, $dewiki ] ),
+ ],
+ ];
+ }
+
+ /**
+ * @dataProvider provideRoundTrip()
+ */
+ public function testRoundTrip( SiteList $sites ) {
+ $tmp = tmpfile();
+ $exporter = new SiteExporter( $tmp );
+
+ $exporter->exportSites( $sites );
+
+ fseek( $tmp, 0 );
+ $xml = fread( $tmp, 16 * 1024 );
+
+ $actualSites = new SiteList();
+ $store = $this->newSiteStore( $actualSites );
+
+ $importer = new SiteImporter( $store );
+ $importer->importFromXML( $xml );
+
+ $this->assertEquals( $sites, $actualSites );
+ }
+
+}
--- /dev/null
+<?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
+ *
+ * @ingroup Site
+ * @ingroup Test
+ *
+ * @group Site
+ *
+ * @covers SiteImporter
+ *
+ * @author Daniel Kinzler
+ */
+class SiteImporterTest extends MediaWikiIntegrationTestCase {
+
+ private function newSiteImporter( array $expectedSites, $errorCount ) {
+ $store = $this->getMockBuilder( SiteStore::class )->getMock();
+
+ $store->expects( $this->once() )
+ ->method( 'saveSites' )
+ ->will( $this->returnCallback( function ( $sites ) use ( $expectedSites ) {
+ $this->assertSitesEqual( $expectedSites, $sites );
+ } ) );
+
+ $store->expects( $this->any() )
+ ->method( 'getSites' )
+ ->will( $this->returnValue( new SiteList() ) );
+
+ $errorHandler = $this->getMockBuilder( Psr\Log\LoggerInterface::class )->getMock();
+ $errorHandler->expects( $this->exactly( $errorCount ) )
+ ->method( 'error' );
+
+ $importer = new SiteImporter( $store );
+ $importer->setExceptionCallback( [ $errorHandler, 'error' ] );
+
+ return $importer;
+ }
+
+ public function assertSitesEqual( $expected, $actual, $message = '' ) {
+ $this->assertEquals(
+ $this->getSerializedSiteList( $expected ),
+ $this->getSerializedSiteList( $actual ),
+ $message
+ );
+ }
+
+ public function provideImportFromXML() {
+ $foo = Site::newForType( Site::TYPE_UNKNOWN );
+ $foo->setGlobalId( 'Foo' );
+
+ $acme = Site::newForType( Site::TYPE_UNKNOWN );
+ $acme->setGlobalId( 'acme.com' );
+ $acme->setGroup( 'Test' );
+ $acme->addLocalId( Site::ID_INTERWIKI, 'acme' );
+ $acme->setPath( Site::PATH_LINK, 'http://acme.com/' );
+
+ $dewiki = Site::newForType( Site::TYPE_MEDIAWIKI );
+ $dewiki->setGlobalId( 'dewiki' );
+ $dewiki->setGroup( 'wikipedia' );
+ $dewiki->setForward( true );
+ $dewiki->addLocalId( Site::ID_INTERWIKI, 'wikipedia' );
+ $dewiki->addLocalId( Site::ID_EQUIVALENT, 'de' );
+ $dewiki->setPath( Site::PATH_LINK, 'http://de.wikipedia.org/w/' );
+ $dewiki->setPath( MediaWikiSite::PATH_PAGE, 'http://de.wikipedia.org/wiki/' );
+ $dewiki->setSource( 'meta.wikimedia.org' );
+
+ return [
+ 'empty' => [
+ '<sites></sites>',
+ [],
+ ],
+ 'no sites' => [
+ '<sites><Foo><globalid>Foo</globalid></Foo><Bar><quux>Bla</quux></Bar></sites>',
+ [],
+ ],
+ 'minimal' => [
+ '<sites>' .
+ '<site><globalid>Foo</globalid></site>' .
+ '</sites>',
+ [ $foo ],
+ ],
+ 'full' => [
+ '<sites>' .
+ '<site><globalid>Foo</globalid></site>' .
+ '<site>' .
+ '<globalid>acme.com</globalid>' .
+ '<localid type="interwiki">acme</localid>' .
+ '<group>Test</group>' .
+ '<path type="link">http://acme.com/</path>' .
+ '</site>' .
+ '<site type="mediawiki">' .
+ '<source>meta.wikimedia.org</source>' .
+ '<globalid>dewiki</globalid>' .
+ '<localid type="interwiki">wikipedia</localid>' .
+ '<localid type="equivalent">de</localid>' .
+ '<group>wikipedia</group>' .
+ '<forward/>' .
+ '<path type="link">http://de.wikipedia.org/w/</path>' .
+ '<path type="page_path">http://de.wikipedia.org/wiki/</path>' .
+ '</site>' .
+ '</sites>',
+ [ $foo, $acme, $dewiki ],
+ ],
+ 'skip' => [
+ '<sites>' .
+ '<site><globalid>Foo</globalid></site>' .
+ '<site><barf>Foo</barf></site>' .
+ '<site>' .
+ '<globalid>acme.com</globalid>' .
+ '<localid type="interwiki">acme</localid>' .
+ '<silly>boop!</silly>' .
+ '<group>Test</group>' .
+ '<path type="link">http://acme.com/</path>' .
+ '</site>' .
+ '</sites>',
+ [ $foo, $acme ],
+ 1
+ ],
+ ];
+ }
+
+ /**
+ * @dataProvider provideImportFromXML
+ */
+ public function testImportFromXML( $xml, array $expectedSites, $errorCount = 0 ) {
+ $importer = $this->newSiteImporter( $expectedSites, $errorCount );
+ $importer->importFromXML( $xml );
+ }
+
+ public function testImportFromXML_malformed() {
+ $this->setExpectedException( Exception::class );
+
+ $store = $this->getMockBuilder( SiteStore::class )->getMock();
+ $importer = new SiteImporter( $store );
+ $importer->importFromXML( 'THIS IS NOT XML' );
+ }
+
+ public function testImportFromFile() {
+ $foo = Site::newForType( Site::TYPE_UNKNOWN );
+ $foo->setGlobalId( 'Foo' );
+
+ $acme = Site::newForType( Site::TYPE_UNKNOWN );
+ $acme->setGlobalId( 'acme.com' );
+ $acme->setGroup( 'Test' );
+ $acme->addLocalId( Site::ID_INTERWIKI, 'acme' );
+ $acme->setPath( Site::PATH_LINK, 'http://acme.com/' );
+
+ $dewiki = Site::newForType( Site::TYPE_MEDIAWIKI );
+ $dewiki->setGlobalId( 'dewiki' );
+ $dewiki->setGroup( 'wikipedia' );
+ $dewiki->setForward( true );
+ $dewiki->addLocalId( Site::ID_INTERWIKI, 'wikipedia' );
+ $dewiki->addLocalId( Site::ID_EQUIVALENT, 'de' );
+ $dewiki->setPath( Site::PATH_LINK, 'http://de.wikipedia.org/w/' );
+ $dewiki->setPath( MediaWikiSite::PATH_PAGE, 'http://de.wikipedia.org/wiki/' );
+ $dewiki->setSource( 'meta.wikimedia.org' );
+
+ $importer = $this->newSiteImporter( [ $foo, $acme, $dewiki ], 0 );
+
+ $file = __DIR__ . '/SiteImporterTest.xml';
+ $importer->importFromFile( $file );
+ }
+
+ /**
+ * @param Site[] $sites
+ *
+ * @return array[]
+ */
+ private function getSerializedSiteList( $sites ) {
+ $serialized = [];
+
+ foreach ( $sites as $site ) {
+ $key = $site->getGlobalId();
+ $data = unserialize( $site->serialize() );
+
+ $serialized[$key] = $data;
+ }
+
+ return $serialized;
+ }
+}
--- /dev/null
+<sites version="1.0" xmlns="http://www.mediawiki.org/xml/sitelist-1.0/">
+ <site><globalid>Foo</globalid></site>
+ <site>
+ <globalid>acme.com</globalid>
+ <localid type="interwiki">acme</localid>
+ <group>Test</group>
+ <path type="link">http://acme.com/</path>
+ </site>
+ <site type="mediawiki">
+ <source>meta.wikimedia.org</source>
+ <globalid>dewiki</globalid>
+ <localid type="interwiki">wikipedia</localid>
+ <localid type="equivalent">de</localid>
+ <group>wikipedia</group>
+ <forward/>
+ <path type="link">http://de.wikipedia.org/w/</path>
+ <path type="page_path">http://de.wikipedia.org/wiki/</path>
+ </site>
+</sites>
public function testRcHidemyselfFilter() {
$this->setMwGlobals( 'wgActorTableSchemaMigrationStage', SCHEMA_COMPAT_NEW );
- $this->overrideMwServices();
$user = $this->getTestUser()->getUser();
$user->getActorId( wfGetDB( DB_MASTER ) );
$this->setMwGlobals(
'wgActorTableSchemaMigrationStage', SCHEMA_COMPAT_WRITE_BOTH | SCHEMA_COMPAT_READ_OLD
);
- $this->overrideMwServices();
$user = $this->getTestUser()->getUser();
$user->getActorId( wfGetDB( DB_MASTER ) );
public function testRcHidebyothersFilter() {
$this->setMwGlobals( 'wgActorTableSchemaMigrationStage', SCHEMA_COMPAT_NEW );
- $this->overrideMwServices();
$user = $this->getTestUser()->getUser();
$user->getActorId( wfGetDB( DB_MASTER ) );
$this->setMwGlobals(
'wgActorTableSchemaMigrationStage', SCHEMA_COMPAT_WRITE_BOTH | SCHEMA_COMPAT_READ_OLD
);
- $this->overrideMwServices();
$user = $this->getTestUser()->getUser();
$user->getActorId( wfGetDB( DB_MASTER ) );
public function testFilterUserExpLevelAllExperienceLevels() {
$this->setMwGlobals( 'wgActorTableSchemaMigrationStage', SCHEMA_COMPAT_NEW );
- $this->overrideMwServices();
$this->assertConditions(
[
$this->setMwGlobals(
'wgActorTableSchemaMigrationStage', SCHEMA_COMPAT_WRITE_BOTH | SCHEMA_COMPAT_READ_OLD
);
- $this->overrideMwServices();
$this->assertConditions(
[
public function testFilterUserExpLevelRegistrered() {
$this->setMwGlobals( 'wgActorTableSchemaMigrationStage', SCHEMA_COMPAT_NEW );
- $this->overrideMwServices();
$this->assertConditions(
[
$this->setMwGlobals(
'wgActorTableSchemaMigrationStage', SCHEMA_COMPAT_WRITE_BOTH | SCHEMA_COMPAT_READ_OLD
);
- $this->overrideMwServices();
$this->assertConditions(
[
public function testFilterUserExpLevelUnregistrered() {
$this->setMwGlobals( 'wgActorTableSchemaMigrationStage', SCHEMA_COMPAT_NEW );
- $this->overrideMwServices();
$this->assertConditions(
[
$this->setMwGlobals(
'wgActorTableSchemaMigrationStage', SCHEMA_COMPAT_WRITE_BOTH | SCHEMA_COMPAT_READ_OLD
);
- $this->overrideMwServices();
$this->assertConditions(
[
public function testFilterUserExpLevelRegistreredOrLearner() {
$this->setMwGlobals( 'wgActorTableSchemaMigrationStage', SCHEMA_COMPAT_NEW );
- $this->overrideMwServices();
$this->assertConditions(
[
$this->setMwGlobals(
'wgActorTableSchemaMigrationStage', SCHEMA_COMPAT_WRITE_BOTH | SCHEMA_COMPAT_READ_OLD
);
- $this->overrideMwServices();
$this->assertConditions(
[
public function testFilterUserExpLevelUnregistreredOrExperienced() {
$this->setMwGlobals( 'wgActorTableSchemaMigrationStage', SCHEMA_COMPAT_NEW );
- $this->overrideMwServices();
$conds = $this->buildQuery( [ 'userExpLevel' => 'unregistered;experienced' ] );
$this->setMwGlobals(
'wgActorTableSchemaMigrationStage', SCHEMA_COMPAT_WRITE_BOTH | SCHEMA_COMPAT_READ_OLD
);
- $this->overrideMwServices();
$conds = $this->buildQuery( [ 'userExpLevel' => 'unregistered;experienced' ] );
$count++;
}
] ] );
- $this->overrideMwServices();
$spf = MediaWikiServices::getInstance()->getSpecialPageFactory();
$spf->getNames();
$spf->getNames();
*/
public function testGetPage( $spec, $shouldReuseInstance ) {
$this->mergeMwGlobalArrayValue( 'wgSpecialPages', [ 'testdummy' => $spec ] );
- $this->overrideMwServices();
$page = SpecialPageFactory::getPage( 'testdummy' );
$this->assertInstanceOf( SpecialPage::class, $page );
*/
public function testGetNames() {
$this->mergeMwGlobalArrayValue( 'wgSpecialPages', [ 'testdummy' => SpecialAllPages::class ] );
- $this->overrideMwServices();
$names = SpecialPageFactory::getNames();
$this->assertInternalType( 'array', $names );
*/
public function testResolveAlias() {
$this->setContentLang( 'de' );
- $this->overrideMwServices();
list( $name, $param ) = SpecialPageFactory::resolveAlias( 'Spezialseiten/Foo' );
$this->assertEquals( 'Specialpages', $name );
*/
public function testGetLocalNameFor() {
$this->setContentLang( 'de' );
- $this->overrideMwServices();
$name = SpecialPageFactory::getLocalNameFor( 'Specialpages', 'Foo' );
$this->assertEquals( 'Spezialseiten/Foo', $name );
*/
public function testGetTitleForAlias() {
$this->setContentLang( 'de' );
- $this->overrideMwServices();
$title = SpecialPageFactory::getTitleForAlias( 'Specialpages/Foo' );
$this->assertEquals( 'Spezialseiten/Foo', $title->getText() );
$this->setMwGlobals( 'wgSpecialPages',
array_combine( array_keys( $aliasesList ), array_keys( $aliasesList ) )
);
- $this->overrideMwServices();
$this->setContentLang( $lang );
// Catch the warnings we expect to be raised
}
],
] );
- $this->overrideMwServices();
SpecialPageFactory::getLocalNameFor( 'Specialpages' );
$this->assertTrue( $called, 'Recursive call succeeded' );
}
<?php
+use MediaWiki\MediaWikiServices;
use Wikimedia\TestingAccessWrapper;
/**
/** @var ContribsPager */
private $pager;
+ /** @var LinkRenderer */
+ private $linkRenderer;
+
function setUp() {
+ $this->linkRenderer = MediaWikiServices::getInstance()->getLinkRenderer();
$context = new RequestContext();
$this->pager = new ContribsPager( $context, [
'start' => '2017-01-01',
'end' => '2017-02-02',
- ] );
+ ], $this->linkRenderer );
parent::setUp();
}
$pager = new ContribsPager( new RequestContext(), [
'start' => '',
'end' => '',
- ] );
+ ], $this->linkRenderer );
/** @var ContribsPager $pager */
$pager = TestingAccessWrapper::newFromObject( $pager );
'target' => '116.17.184.5/32',
'start' => '',
'end' => '',
- ] );
+ ], $this->linkRenderer );
/** @var ContribsPager $pager */
$pager = TestingAccessWrapper::newFromObject( $pager );
<?php
+
+use MediaWiki\MediaWikiServices;
+
/**
* Test class for ImageListPagerTest class.
*
* @covers ImageListPager::formatValue
*/
public function testFormatValuesThrowException() {
- $page = new ImageListPager( RequestContext::getMain() );
+ $page = new ImageListPager( RequestContext::getMain(), null, '', false, false,
+ MediaWikiServices::getInstance()->getLinkRenderer() );
$page->formatValue( 'invalid_field', 'invalid_value' );
}
}
class SpecialWatchlistTest extends SpecialPageTestBase {
public function setUp() {
parent::setUp();
-
+ $this->tablesUsed = [ 'watchlist' ];
$this->setTemporaryHook(
'ChangesListSpecialPageQuery',
null
*/
class BlockListPagerTest extends MediaWikiTestCase {
+ /**
+ * @var LinkRenderer
+ */
+ private $linkRenderer;
+
+ protected function setUp() {
+ parent::setUp();
+
+ $this->linkRenderer = MediaWikiServices::getInstance()->getLinkRenderer();
+ }
+
/**
* @covers ::formatValue
* @dataProvider formatValueEmptyProvider
$expected = $expected ?? MWTimestamp::getInstance()->format( 'H:i, j F Y' );
$row = $row ?: new stdClass;
- $pager = new BlockListPager( new SpecialPage(), [] );
+ $pager = new BlockListPager( new SpecialPage(), [], $this->linkRenderer );
$wrappedPager = TestingAccessWrapper::newFromObject( $pager );
$wrappedPager->mCurrentRow = $row;
'wgScript' => '/w/index.php',
] );
- $pager = new BlockListPager( new SpecialPage(), [] );
+ $pager = new BlockListPager( new SpecialPage(), [], $this->linkRenderer );
$row = (object)[
'ipb_id' => 0,
'ipb_sitewide' => 1,
'ipb_timestamp' => $this->db->timestamp( wfTimestamp( TS_MW ) ),
];
- $pager = new BlockListPager( new SpecialPage(), [] );
+ $pager = new BlockListPager( new SpecialPage(), [], $this->linkRenderer );
$pager->preprocessResults( [ $row ] );
foreach ( $links as $link ) {
'by_user_name' => 'Admin',
'ipb_sitewide' => 1,
];
- $pager = new BlockListPager( new SpecialPage(), [] );
+ $pager = new BlockListPager( new SpecialPage(), [], $this->linkRenderer );
$pager->preprocessResults( [ $row ] );
$this->assertObjectNotHasAttribute( 'ipb_restrictions', $row );
$result = $this->db->select( 'ipblocks', [ '*' ], [ 'ipb_id' => $block->getId() ] );
- $pager = new BlockListPager( new SpecialPage(), [] );
+ $pager = new BlockListPager( new SpecialPage(), [], $this->linkRenderer );
$pager->preprocessResults( $result );
$wrappedPager = TestingAccessWrapper::newFromObject( $pager );
$restriction = $restrictions[0];
$this->assertEquals( $page->getId(), $restriction->getValue() );
$this->assertEquals( $page->getId(), $restriction->getTitle()->getArticleID() );
- $this->assertEquals( $title->getDBKey(), $restriction->getTitle()->getDBKey() );
+ $this->assertEquals( $title->getDBkey(), $restriction->getTitle()->getDBkey() );
$this->assertEquals( $title->getNamespace(), $restriction->getTitle()->getNamespace() );
// Delete the block and the restrictions.
'wgRestrictionLevels' => [ '', 'autoconfirmed', 'sysop' ],
'wgAutopromote' => []
] );
- $this->resetServices();
$obj = $this->newObj();
$user = is_null( $groups ) ? null : $this->getTestUser( $groups )->getUser();
$this->assertSame( $expected, $obj->getRestrictionLevels( $ns, $user ) );
$this->userTester->addGroup( 'unittesters' );
$this->expiryTime = wfTimestamp( TS_MW, time() + 100500 );
$this->userTester->addGroup( 'testwriters', $this->expiryTime );
-
- $this->resetServices();
}
/**
'wgRevokePermissions' => [],
'wgActorTableSchemaMigrationStage' => SCHEMA_COMPAT_NEW,
] );
- $this->overrideMwServices();
$this->setUpPermissionGlobals();
RequestContext::getMain()->setRequest( $request );
TestingAccessWrapper::newFromObject( $user )->mRequest = $request;
$request->getSession()->setUser( $user );
- $this->overrideMwServices();
}
/**
$rights = array_diff( $rights, [ 'writetest' ] );
} );
- $this->resetServices();
$rights = $user->getRights();
$this->assertContains( 'test', $rights );
$this->assertContains( 'runtest', $rights );
$this->assertFalse( $user->isPingLimitable() );
$this->setMwGlobals( 'wgRateLimitsExcludedIPs', [] );
- $noRateLimitUser = $this->getMockBuilder( User::class )->disableOriginalConstructor()
- ->setMethods( [ 'getIP', 'getId', 'getGroups' ] )->getMock();
- $noRateLimitUser->expects( $this->any() )->method( 'getIP' )->willReturn( '1.2.3.4' );
- $noRateLimitUser->expects( $this->any() )->method( 'getId' )->willReturn( 0 );
- $noRateLimitUser->expects( $this->any() )->method( 'getGroups' )->willReturn( [] );
- $this->overrideUserPermissions( $noRateLimitUser, 'noratelimit' );
- $this->assertFalse( $noRateLimitUser->isPingLimitable() );
+ $this->overrideUserPermissions( $user, 'noratelimit' );
+ $this->assertFalse( $user->isPingLimitable() );
}
public function provideExperienceLevel() {
$this->setMwGlobals( [
'wgActorTableSchemaMigrationStage' => SCHEMA_COMPAT_WRITE_BOTH | SCHEMA_COMPAT_READ_OLD,
] );
- $this->overrideMwServices();
$domain = MediaWikiServices::getInstance()->getDBLoadBalancer()->getLocalDomainID();
$this->hideDeprecated( 'User::selectFields' );
--- /dev/null
+<?php
+
+/**
+ * @covers ZipDirectoryReader
+ */
+class ZipDirectoryReaderTest extends MediaWikiIntegrationTestCase {
+
+ protected $zipDir;
+ protected $entries;
+
+ protected function setUp() {
+ parent::setUp();
+ $this->zipDir = __DIR__ . '/../../data/zip';
+ }
+
+ function zipCallback( $entry ) {
+ $this->entries[] = $entry;
+ }
+
+ function readZipAssertError( $file, $error, $assertMessage ) {
+ $this->entries = [];
+ $status = ZipDirectoryReader::read( "{$this->zipDir}/$file", [ $this, 'zipCallback' ] );
+ $this->assertTrue( $status->hasMessage( $error ), $assertMessage );
+ }
+
+ function readZipAssertSuccess( $file, $assertMessage ) {
+ $this->entries = [];
+ $status = ZipDirectoryReader::read( "{$this->zipDir}/$file", [ $this, 'zipCallback' ] );
+ $this->assertTrue( $status->isOK(), $assertMessage );
+ }
+
+ public function testEmpty() {
+ $this->readZipAssertSuccess( 'empty.zip', 'Empty zip' );
+ }
+
+ public function testMultiDisk0() {
+ $this->readZipAssertError( 'split.zip', 'zip-unsupported',
+ 'Split zip error' );
+ }
+
+ public function testNoSignature() {
+ $this->readZipAssertError( 'nosig.zip', 'zip-wrong-format',
+ 'No signature should give "wrong format" error' );
+ }
+
+ public function testSimple() {
+ $this->readZipAssertSuccess( 'class.zip', 'Simple ZIP' );
+ $this->assertEquals( $this->entries, [ [
+ 'name' => 'Class.class',
+ 'mtime' => '20010115000000',
+ 'size' => 1,
+ ] ] );
+ }
+
+ public function testBadCentralEntrySignature() {
+ $this->readZipAssertError( 'wrong-central-entry-sig.zip', 'zip-bad',
+ 'Bad central entry error' );
+ }
+
+ public function testTrailingBytes() {
+ // Due to T40432 this is now zip-wrong-format instead of zip-bad
+ $this->readZipAssertError( 'trail.zip', 'zip-wrong-format',
+ 'Trailing bytes error' );
+ }
+
+ public function testWrongCDStart() {
+ $this->readZipAssertError( 'wrong-cd-start-disk.zip', 'zip-unsupported',
+ 'Wrong CD start disk error' );
+ }
+
+ public function testCentralDirectoryGap() {
+ $this->readZipAssertError( 'cd-gap.zip', 'zip-bad',
+ 'CD gap error' );
+ }
+
+ public function testCentralDirectoryTruncated() {
+ $this->readZipAssertError( 'cd-truncated.zip', 'zip-bad',
+ 'CD truncated error (should hit unpack() overrun)' );
+ }
+
+ public function testLooksLikeZip64() {
+ $this->readZipAssertError( 'looks-like-zip64.zip', 'zip-unsupported',
+ 'A file which looks like ZIP64 but isn\'t, should give error' );
+ }
+}
new WatchedItem( $user, $targets[0], '20151212010101' ),
new WatchedItem( $user, $targets[1], null ),
];
- $mockDb = $this->getMockDb();
- $mockDb->expects( $this->never() )->method( $this->anything() );
+ $mockDb = $this->createNoOpMock( IDatabase::class );
$mockCache = $this->getMockCache();
$mockCache->expects( $this->at( 1 ) )
}
public function testGetNotificationTimestampsBatch_anonymousUser() {
+ if ( defined( 'HHVM_VERSION' ) ) {
+ $this->markTestSkipped( 'HHVM Reflection buggy' );
+ }
+
$targets = [
new TitleValue( 0, 'SomeDbKey' ),
new TitleValue( 1, 'AnotherDbKey' ),
];
- $mockDb = $this->getMockDb();
- $mockDb->expects( $this->never() )->method( $this->anything() );
+ $mockDb = $this->createNoOpMock( IDatabase::class );
- $mockCache = $this->getMockCache();
- $mockCache->expects( $this->never() )->method( $this->anything() );
+ $mockCache = $this->createNoOpMock( HashBagOStuff::class );
$store = $this->newWatchedItemStore( [ 'db' => $mockDb, 'cache' => $mockCache ] );
$mockQueueGroup = $this->getMockJobQueueGroup();
- $mockRevisionRecord = $this->createMock( RevisionRecord::class );
- $mockRevisionRecord->expects( $this->never() )->method( $this->anything() );
+ $mockRevisionRecord = $this->createNoOpMock( RevisionRecord::class );
$mockRevisionLookup = $this->getMockRevisionLookup( [
'getTimestampFromId' => function () {
$oldid = 22;
$title = new TitleValue( 0, 'SomeDbKey' );
- $mockRevision = $this->createMock( RevisionRecord::class );
- $mockRevision->expects( $this->never() )->method( $this->anything() );
-
- $mockNextRevision = $this->createMock( RevisionRecord::class );
- $mockNextRevision->expects( $this->never() )->method( $this->anything() );
+ $mockRevision = $this->createNoOpMock( RevisionRecord::class );
+ $mockNextRevision = $this->createNoOpMock( RevisionRecord::class );
$mockDb = $this->getMockDb();
$mockDb->expects( $this->once() )
$mockQueueGroup = $this->getMockJobQueueGroup();
- $mockRevision = $this->createMock( RevisionRecord::class );
- $mockRevision->expects( $this->never() )->method( $this->anything() );
-
- $mockNextRevision = $this->createMock( RevisionRecord::class );
- $mockNextRevision->expects( $this->never() )->method( $this->anything() );
+ $mockRevision = $this->createNoOpMock( RevisionRecord::class );
+ $mockNextRevision = $this->createNoOpMock( RevisionRecord::class );
$mockRevisionLookup = $this->getMockRevisionLookup(
[
$mockQueueGroup = $this->getMockJobQueueGroup();
- $mockRevision = $this->createMock( RevisionRecord::class );
- $mockRevision->expects( $this->never() )->method( $this->anything() );
-
- $mockNextRevision = $this->createMock( RevisionRecord::class );
- $mockNextRevision->expects( $this->never() )->method( $this->anything() );
+ $mockRevision = $this->createNoOpMock( RevisionRecord::class );
+ $mockNextRevision = $this->createNoOpMock( RevisionRecord::class );
$mockRevisionLookup = $this->getMockRevisionLookup(
[
$mockQueueGroup = $this->getMockJobQueueGroup();
- $mockRevision = $this->createMock( RevisionRecord::class );
- $mockRevision->expects( $this->never() )->method( $this->anything() );
-
- $mockNextRevision = $this->createMock( RevisionRecord::class );
- $mockNextRevision->expects( $this->never() )->method( $this->anything() );
+ $mockRevision = $this->createNoOpMock( RevisionRecord::class );
+ $mockNextRevision = $this->createNoOpMock( RevisionRecord::class );
$mockRevisionLookup = $this->getMockRevisionLookup(
[
--- /dev/null
+<?php
+
+/**
+ * @coversDefaultClass Language
+ */
+class LanguageFallbackStaticMethodsTest extends MediaWikiIntegrationTestCase {
+ use LanguageFallbackTestTrait;
+
+ private function getCallee( array $options = [] ) {
+ if ( isset( $options['siteLangCode'] ) ) {
+ $this->setMwGlobals( 'wgLanguageCode', $options['siteLangCode'] );
+ $this->resetServices();
+ }
+ return Language::class;
+ }
+
+ private function getMessagesKey() {
+ return Language::MESSAGES_FALLBACKS;
+ }
+
+ private function getStrictKey() {
+ return Language::STRICT_FALLBACKS;
+ }
+}
use Wikimedia\TestingAccessWrapper;
class LanguageTest extends LanguageClassesTestCase {
- use LanguageNameUtilsTestTrait;
-
- /** @var array Copy of $wgHooks from before we unset LanguageGetTranslatedLanguageNames */
- private $origHooks;
-
- public function setUp() {
- global $wgHooks;
-
- parent::setUp();
-
- // Don't allow installed hooks to run, except if a test restores them via origHooks (needed
- // for testIsKnownLanguageTag_cldr)
- $this->origHooks = $wgHooks;
- $newHooks = $wgHooks;
- unset( $newHooks['LanguageGetTranslatedLanguageNames'] );
- $this->setMwGlobals( 'wgHooks', $newHooks );
- }
-
/**
* @covers Language::convertDoubleWidth
* @covers Language::normalizeForSearch
);
}
+ /**
+ * Test Language::isValidBuiltInCode()
+ * @dataProvider provideLanguageCodes
+ * @covers Language::isValidBuiltInCode
+ */
+ public function testBuiltInCodeValidation( $code, $expected, $message = '' ) {
+ $this->assertEquals( $expected,
+ (bool)Language::isValidBuiltInCode( $code ),
+ "validating code $code $message"
+ );
+ }
+
+ public static function provideLanguageCodes() {
+ return [
+ [ 'fr', true, 'Two letters, minor case' ],
+ [ 'EN', false, 'Two letters, upper case' ],
+ [ 'tyv', true, 'Three letters' ],
+ [ 'be-tarask', true, 'With dash' ],
+ [ 'be-x-old', true, 'With extension (two dashes)' ],
+ [ 'be_tarask', false, 'Reject underscores' ],
+ ];
+ }
+
+ /**
+ * Test Language::isKnownLanguageTag()
+ * @dataProvider provideKnownLanguageTags
+ * @covers Language::isKnownLanguageTag
+ */
+ public function testKnownLanguageTag( $code, $message = '' ) {
+ $this->assertTrue(
+ (bool)Language::isKnownLanguageTag( $code ),
+ "validating code $code - $message"
+ );
+ }
+
+ public static function provideKnownLanguageTags() {
+ return [
+ [ 'fr', 'simple code' ],
+ [ 'bat-smg', 'an MW legacy tag' ],
+ [ 'sgs', 'an internal standard MW name, for which a legacy tag is used externally' ],
+ ];
+ }
+
+ /**
+ * @covers Language::isKnownLanguageTag
+ */
+ public function testKnownCldrLanguageTag() {
+ if ( !class_exists( 'LanguageNames' ) ) {
+ $this->markTestSkipped( 'The LanguageNames class is not available. '
+ . 'The CLDR extension is probably not installed.' );
+ }
+
+ $this->assertTrue(
+ (bool)Language::isKnownLanguageTag( 'pal' ),
+ 'validating code "pal" an ancient language, which probably will '
+ . 'not appear in Names.php, but appears in CLDR in English'
+ );
+ }
+
+ /**
+ * Negative tests for Language::isKnownLanguageTag()
+ * @dataProvider provideUnKnownLanguageTags
+ * @covers Language::isKnownLanguageTag
+ */
+ public function testUnknownLanguageTag( $code, $message = '' ) {
+ $this->assertFalse(
+ (bool)Language::isKnownLanguageTag( $code ),
+ "checking that code $code is invalid - $message"
+ );
+ }
+
+ public static function provideUnknownLanguageTags() {
+ return [
+ [ 'mw', 'non-existent two-letter code' ],
+ [ 'foo"<bar', 'very invalid language code' ],
+ ];
+ }
+
/**
* Test too short timestamp
* @expectedException MWException
public function testClearCaches() {
$languageClass = TestingAccessWrapper::newFromClass( Language::class );
+ // Populate $dataCache
+ Language::getLocalisationCache()->getItem( 'zh', 'mainpage' );
+ $oldCacheObj = Language::$dataCache;
+ $this->assertNotCount( 0,
+ TestingAccessWrapper::newFromObject( Language::$dataCache )->loadedItems );
+
// Populate $mLangObjCache
$lang = Language::factory( 'en' );
$this->assertNotCount( 0, Language::$mLangObjCache );
$lang->getGrammarTransformations();
$this->assertNotNull( $languageClass->grammarTransformations );
+ // Populate $languageNameCache
+ Language::fetchLanguageNames();
+ $this->assertNotNull( $languageClass->languageNameCache );
+
Language::clearCaches();
+ $this->assertNotSame( $oldCacheObj, Language::$dataCache );
+ $this->assertCount( 0,
+ TestingAccessWrapper::newFromObject( Language::$dataCache )->loadedItems );
$this->assertCount( 0, Language::$mLangObjCache );
$this->assertCount( 0, $languageClass->fallbackLanguageCache );
$this->assertNull( $languageClass->grammarTransformations );
+ $this->assertNull( $languageClass->languageNameCache );
+ }
+
+ /**
+ * @dataProvider provideIsSupportedLanguage
+ * @covers Language::isSupportedLanguage
+ */
+ public function testIsSupportedLanguage( $code, $expected, $comment ) {
+ $this->assertEquals( $expected, Language::isSupportedLanguage( $code ), $comment );
+ }
+
+ public static function provideIsSupportedLanguage() {
+ return [
+ [ 'en', true, 'is supported language' ],
+ [ 'fi', true, 'is supported language' ],
+ [ 'bunny', false, 'is not supported language' ],
+ [ 'FI', false, 'is not supported language, input should be in lower case' ],
+ ];
}
/**
[ 'èl', 'Ll' , 'Non-ASCII is overridden', [ 'è' => 'L' ] ],
];
}
-
- // The following methods are for LanguageNameUtilsTestTrait
-
- private function isSupportedLanguage( $code ) {
- return Language::isSupportedLanguage( $code );
- }
-
- private function isValidCode( $code ) {
- return Language::isValidCode( $code );
- }
-
- private function isValidBuiltInCode( $code ) {
- return Language::isValidBuiltInCode( $code );
- }
-
- private function isKnownLanguageTag( $code ) {
- return Language::isKnownLanguageTag( $code );
- }
-
- /**
- * Call getLanguageName() and getLanguageNames() using the Language static methods.
- *
- * @param array $options To set globals for testing Language
- * @param string $expected
- * @param string $code
- * @param mixed ...$otherArgs Optionally, pass $inLanguage and/or $include.
- */
- private function assertGetLanguageNames( array $options, $expected, $code, ...$otherArgs ) {
- if ( $options ) {
- foreach ( $options as $key => $val ) {
- $this->setMwGlobals( "wg$key", $val );
- }
- $this->resetServices();
- }
- $this->assertSame( $expected,
- Language::fetchLanguageNames( ...$otherArgs )[strtolower( $code )] ?? '' );
- $this->assertSame( $expected, Language::fetchLanguageName( $code, ...$otherArgs ) );
- }
-
- private function getLanguageNames( ...$args ) {
- return Language::fetchLanguageNames( ...$args );
- }
-
- private function getLanguageName( ...$args ) {
- return Language::fetchLanguageName( ...$args );
- }
-
- private static function getFileName( ...$args ) {
- return Language::getFileName( ...$args );
- }
-
- private static function getMessagesFileName( $code ) {
- return Language::getMessagesFileName( $code );
- }
-
- private static function getJsonMessagesFileName( $code ) {
- return Language::getJsonMessagesFileName( $code );
- }
-
- /**
- * @todo This really belongs in the cldr extension's tests.
- *
- * @covers MediaWiki\Languages\LanguageNameUtils::isKnownLanguageTag
- * @covers Language::isKnownLanguageTag
- */
- public function testIsKnownLanguageTag_cldr() {
- if ( !class_exists( 'LanguageNames' ) ) {
- $this->markTestSkipped( 'The LanguageNames class is not available. '
- . 'The CLDR extension is probably not installed.' );
- }
-
- // We need to restore the extension's hook that we removed.
- $this->setMwGlobals( 'wgHooks', $this->origHooks );
-
- // "pal" is an ancient language, which probably will not appear in Names.php, but appears in
- // CLDR in English
- $this->assertTrue( Language::isKnownLanguageTag( 'pal' ) );
- }
}
<?php
-class MockSearchResult extends SearchResult {
+class MockSearchResult extends RevisionSearchResult {
private $isMissingRevision = false;
private $isBrokenTitle = false;
);
}
+ public function setup() {
+ parent::setup();
+
+ require_once __DIR__ . '/../common/TestSetup.php';
+ TestSetup::snapshotGlobals();
+ }
+
public function finalSetup() {
parent::finalSetup();
<?php
+use MediaWiki\MediaWikiServices;
+
/**
* Try to make sure that extensions register all rights in $wgAvailableRights
* or via the 'UserGetAllRights' hook.
private function getAllVisibleRights() {
global $wgGroupPermissions, $wgRevokePermissions;
- $rights = User::getAllRights();
+ $rights = MediaWikiServices::getInstance()->getPermissionManager()->getAllPermissions();
foreach ( $wgGroupPermissions as $permissions ) {
$rights = array_merge( $rights, array_keys( $permissions ) );
public function testAvailableRights() {
$missingRights = array_diff(
$this->getAllVisibleRights(),
- User::getAllRights()
+ MediaWikiServices::getInstance()->getPermissionManager()->getAllPermissions()
);
$this->assertEquals(
*/
private function checkMessagesExist( $prefix ) {
// Getting all user rights, for core: User::$mCoreRights, for extensions: $wgAvailableRights
- $allRights = User::getAllRights();
+ $allRights = MediaWikiServices::getInstance()->getPermissionManager()->getAllPermissions();
$allMessageKeys = Language::getMessageKeysFor( 'en' );
$messagesToCheck = [];
}
protected function setUp() {
- global $IP, $messageMemc, $wgMemc, $wgUser, $wgLang, $wgOut, $wgRequest, $wgStyleDirectory,
+ global $IP, $wgMemc, $wgUser, $wgLang, $wgOut, $wgRequest, $wgStyleDirectory,
$wgParserCacheType, $wgNamespaceAliases, $wgNamespaceProtection;
$tmpDir = $this->getNewTempDirectory();
$wgParserCacheType = CACHE_NONE;
DeferredUpdates::clearPendingUpdates();
$wgMemc = ObjectCache::getLocalClusterInstance();
- $messageMemc = wfGetMessageCacheStorage();
RequestContext::resetMain();
$context = RequestContext::getMain();
// the actual test: change config, reset services.
$this->setMwGlobals( 'wgLanguageCode', 'qqx' );
- $this->resetServices();
// the overridden service instance should still be there
$this->assertSame( $myReadOnlyMode, $services->getService( 'ReadOnlyMode' ) );
+++ /dev/null
-<?php
-
-namespace MediaWiki\Tests\Rest;
-
-use EmptyBagOStuff;
-use GuzzleHttp\Psr7\Uri;
-use GuzzleHttp\Psr7\Stream;
-use MediaWiki\Rest\BasicAccess\StaticBasicAuthorizer;
-use MediaWiki\Rest\Handler;
-use MediaWiki\Rest\EntryPoint;
-use MediaWiki\Rest\RequestData;
-use MediaWiki\Rest\ResponseFactory;
-use MediaWiki\Rest\Router;
-use WebResponse;
-
-/**
- * @covers \MediaWiki\Rest\EntryPoint
- * @covers \MediaWiki\Rest\Router
- */
-class EntryPointTest extends \MediaWikiUnitTestCase {
- private static $mockHandler;
-
- private function createRouter() {
- return new Router(
- [ __DIR__ . '/testRoutes.json' ],
- [],
- '/rest',
- new EmptyBagOStuff(),
- new ResponseFactory(),
- new StaticBasicAuthorizer() );
- }
-
- private function createWebResponse() {
- return $this->getMockBuilder( WebResponse::class )
- ->setMethods( [ 'header' ] )
- ->getMock();
- }
-
- public static function mockHandlerHeader() {
- return new class extends Handler {
- public function execute() {
- $response = $this->getResponseFactory()->create();
- $response->setHeader( 'Foo', 'Bar' );
- return $response;
- }
- };
- }
-
- public function testHeader() {
- $webResponse = $this->createWebResponse();
- $webResponse->expects( $this->any() )
- ->method( 'header' )
- ->withConsecutive(
- [ 'HTTP/1.1 200 OK', true, null ],
- [ 'Foo: Bar', true, null ]
- );
-
- $entryPoint = new EntryPoint(
- new RequestData( [ 'uri' => new Uri( '/rest/mock/EntryPoint/header' ) ] ),
- $webResponse,
- $this->createRouter() );
- $entryPoint->execute();
- $this->assertTrue( true );
- }
-
- public static function mockHandlerBodyRewind() {
- return new class extends Handler {
- public function execute() {
- $response = $this->getResponseFactory()->create();
- $stream = new Stream( fopen( 'php://memory', 'w+' ) );
- $stream->write( 'hello' );
- $response->setBody( $stream );
- return $response;
- }
- };
- }
-
- /**
- * Make sure EntryPoint rewinds a seekable body stream before reading.
- */
- public function testBodyRewind() {
- $entryPoint = new EntryPoint(
- new RequestData( [ 'uri' => new Uri( '/rest/mock/EntryPoint/bodyRewind' ) ] ),
- $this->createWebResponse(),
- $this->createRouter() );
- ob_start();
- $entryPoint->execute();
- $this->assertSame( 'hello', ob_get_clean() );
- }
-
-}
+++ /dev/null
-<?php
-
-namespace MediaWiki\Tests\Revision;
-
-use MediaWiki\Revision\MainSlotRoleHandler;
-use MediaWikiUnitTestCase;
-use PHPUnit\Framework\MockObject\MockObject;
-use Title;
-
-/**
- * @covers \MediaWiki\Revision\MainSlotRoleHandler
- */
-class MainSlotRoleHandlerTest extends MediaWikiUnitTestCase {
-
- private function makeTitleObject( $ns ) {
- /** @var Title|MockObject $title */
- $title = $this->getMockBuilder( Title::class )
- ->disableOriginalConstructor()
- ->getMock();
-
- $title->method( 'getNamespace' )
- ->willReturn( $ns );
-
- return $title;
- }
-
- /**
- * @covers \MediaWiki\Revision\MainSlotRoleHandler::__construct
- * @covers \MediaWiki\Revision\MainSlotRoleHandler::getRole()
- * @covers \MediaWiki\Revision\MainSlotRoleHandler::getNameMessageKey()
- * @covers \MediaWiki\Revision\MainSlotRoleHandler::getOutputLayoutHints()
- */
- public function testConstruction() {
- $handler = new MainSlotRoleHandler( [] );
- $this->assertSame( 'main', $handler->getRole() );
- $this->assertSame( 'slot-name-main', $handler->getNameMessageKey() );
-
- $hints = $handler->getOutputLayoutHints();
- $this->assertArrayHasKey( 'display', $hints );
- $this->assertArrayHasKey( 'region', $hints );
- $this->assertArrayHasKey( 'placement', $hints );
- }
-
- /**
- * @covers \MediaWiki\Revision\MainSlotRoleHandler::getDefaultModel()
- */
- public function testFetDefaultModel() {
- $handler = new MainSlotRoleHandler( [ 100 => CONTENT_MODEL_TEXT ] );
-
- // For the main handler, the namespace determins the default model
- $titleMain = $this->makeTitleObject( NS_MAIN );
- $this->assertSame( CONTENT_MODEL_WIKITEXT, $handler->getDefaultModel( $titleMain ) );
-
- $title100 = $this->makeTitleObject( 100 );
- $this->assertSame( CONTENT_MODEL_TEXT, $handler->getDefaultModel( $title100 ) );
- }
-
- /**
- * @covers \MediaWiki\Revision\MainSlotRoleHandler::isAllowedModel()
- */
- public function testIsAllowedModel() {
- $handler = new MainSlotRoleHandler( [] );
-
- // For the main handler, (nearly) all models are allowed
- $title = $this->makeTitleObject( NS_MAIN );
- $this->assertTrue( $handler->isAllowedModel( CONTENT_MODEL_WIKITEXT, $title ) );
- $this->assertTrue( $handler->isAllowedModel( CONTENT_MODEL_TEXT, $title ) );
- }
-
- /**
- * @covers \MediaWiki\Revision\MainSlotRoleHandler::supportsArticleCount()
- */
- public function testSupportsArticleCount() {
- $handler = new MainSlotRoleHandler( [] );
-
- $this->assertTrue( $handler->supportsArticleCount() );
- }
-
-}
+++ /dev/null
-<?php
-
-namespace MediaWiki\Tests\Revision;
-
-use InvalidArgumentException;
-use LogicException;
-use MediaWiki\Revision\IncompleteRevisionException;
-use MediaWiki\Revision\SlotRecord;
-use MediaWiki\Revision\SuppressedDataException;
-use MediaWikiUnitTestCase;
-use WikitextContent;
-
-/**
- * @covers \MediaWiki\Revision\SlotRecord
- */
-class SlotRecordTest extends MediaWikiUnitTestCase {
-
- private function makeRow( $data = [] ) {
- $data = $data + [
- 'slot_id' => 1234,
- 'slot_content_id' => 33,
- 'content_size' => '5',
- 'content_sha1' => 'someHash',
- 'content_address' => 'tt:456',
- 'model_name' => CONTENT_MODEL_WIKITEXT,
- 'format_name' => CONTENT_FORMAT_WIKITEXT,
- 'slot_revision_id' => '2',
- 'slot_origin' => '1',
- 'role_name' => 'myRole',
- ];
- return (object)$data;
- }
-
- public function testCompleteConstruction() {
- $row = $this->makeRow();
- $record = new SlotRecord( $row, new WikitextContent( 'A' ) );
-
- $this->assertTrue( $record->hasAddress() );
- $this->assertTrue( $record->hasContentId() );
- $this->assertTrue( $record->hasRevision() );
- $this->assertTrue( $record->isInherited() );
- $this->assertSame( 'A', $record->getContent()->getText() );
- $this->assertSame( 5, $record->getSize() );
- $this->assertSame( 'someHash', $record->getSha1() );
- $this->assertSame( CONTENT_MODEL_WIKITEXT, $record->getModel() );
- $this->assertSame( 2, $record->getRevision() );
- $this->assertSame( 1, $record->getOrigin() );
- $this->assertSame( 'tt:456', $record->getAddress() );
- $this->assertSame( 33, $record->getContentId() );
- $this->assertSame( CONTENT_FORMAT_WIKITEXT, $record->getFormat() );
- $this->assertSame( 'myRole', $record->getRole() );
- }
-
- public function testConstructionDeferred() {
- $row = $this->makeRow( [
- 'content_size' => null, // to be computed
- 'content_sha1' => null, // to be computed
- 'format_name' => function () {
- return CONTENT_FORMAT_WIKITEXT;
- },
- 'slot_revision_id' => '2',
- 'slot_origin' => '2',
- 'slot_content_id' => function () {
- return null;
- },
- ] );
-
- $content = function () {
- return new WikitextContent( 'A' );
- };
-
- $record = new SlotRecord( $row, $content );
-
- $this->assertTrue( $record->hasAddress() );
- $this->assertTrue( $record->hasRevision() );
- $this->assertFalse( $record->hasContentId() );
- $this->assertFalse( $record->isInherited() );
- $this->assertSame( 'A', $record->getContent()->getText() );
- $this->assertSame( 1, $record->getSize() );
- $this->assertNotEmpty( $record->getSha1() );
- $this->assertSame( CONTENT_MODEL_WIKITEXT, $record->getModel() );
- $this->assertSame( 2, $record->getRevision() );
- $this->assertSame( 2, $record->getRevision() );
- $this->assertSame( 'tt:456', $record->getAddress() );
- $this->assertSame( CONTENT_FORMAT_WIKITEXT, $record->getFormat() );
- $this->assertSame( 'myRole', $record->getRole() );
- }
-
- public function testNewUnsaved() {
- $record = SlotRecord::newUnsaved( 'myRole', new WikitextContent( 'A' ) );
-
- $this->assertFalse( $record->hasAddress() );
- $this->assertFalse( $record->hasContentId() );
- $this->assertFalse( $record->hasRevision() );
- $this->assertFalse( $record->isInherited() );
- $this->assertFalse( $record->hasOrigin() );
- $this->assertSame( 'A', $record->getContent()->getText() );
- $this->assertSame( 1, $record->getSize() );
- $this->assertNotEmpty( $record->getSha1() );
- $this->assertSame( CONTENT_MODEL_WIKITEXT, $record->getModel() );
- $this->assertSame( 'myRole', $record->getRole() );
- }
-
- public function provideInvalidConstruction() {
- yield 'both null' => [ null, null ];
- yield 'null row' => [ null, new WikitextContent( 'A' ) ];
- yield 'array row' => [ [], new WikitextContent( 'A' ) ];
- yield 'empty row' => [ (object)[], new WikitextContent( 'A' ) ];
- yield 'null content' => [ (object)[], null ];
- }
-
- /**
- * @dataProvider provideInvalidConstruction
- */
- public function testInvalidConstruction( $row, $content ) {
- $this->setExpectedException( InvalidArgumentException::class );
- new SlotRecord( $row, $content );
- }
-
- public function testGetContentId_fails() {
- $record = SlotRecord::newUnsaved( SlotRecord::MAIN, new WikitextContent( 'A' ) );
- $this->setExpectedException( IncompleteRevisionException::class );
-
- $record->getContentId();
- }
-
- public function testGetAddress_fails() {
- $record = SlotRecord::newUnsaved( SlotRecord::MAIN, new WikitextContent( 'A' ) );
- $this->setExpectedException( IncompleteRevisionException::class );
-
- $record->getAddress();
- }
-
- public function provideIncomplete() {
- $unsaved = SlotRecord::newUnsaved( SlotRecord::MAIN, new WikitextContent( 'A' ) );
- yield 'unsaved' => [ $unsaved ];
-
- $parent = new SlotRecord( $this->makeRow(), new WikitextContent( 'A' ) );
- $inherited = SlotRecord::newInherited( $parent );
- yield 'inherited' => [ $inherited ];
- }
-
- /**
- * @dataProvider provideIncomplete
- */
- public function testGetRevision_fails( SlotRecord $record ) {
- $record = SlotRecord::newUnsaved( SlotRecord::MAIN, new WikitextContent( 'A' ) );
- $this->setExpectedException( IncompleteRevisionException::class );
-
- $record->getRevision();
- }
-
- /**
- * @dataProvider provideIncomplete
- */
- public function testGetOrigin_fails( SlotRecord $record ) {
- $record = SlotRecord::newUnsaved( SlotRecord::MAIN, new WikitextContent( 'A' ) );
- $this->setExpectedException( IncompleteRevisionException::class );
-
- $record->getOrigin();
- }
-
- public function provideHashStability() {
- yield [ '', 'phoiac9h4m842xq45sp7s6u21eteeq1' ];
- yield [ 'Lorem ipsum', 'hcr5u40uxr81d3nx89nvwzclfz6r9c5' ];
- }
-
- /**
- * @dataProvider provideHashStability
- */
- public function testHashStability( $text, $hash ) {
- // Changing the output of the hash function will break things horribly!
-
- $this->assertSame( $hash, SlotRecord::base36Sha1( $text ) );
-
- $record = SlotRecord::newUnsaved( SlotRecord::MAIN, new WikitextContent( $text ) );
- $this->assertSame( $hash, $record->getSha1() );
- }
-
- public function testHashComputed() {
- $row = $this->makeRow();
- $row->content_sha1 = '';
-
- $rec = new SlotRecord( $row, new WikitextContent( 'A' ) );
- $this->assertNotEmpty( $rec->getSha1() );
- }
-
- public function testNewWithSuppressedContent() {
- $input = new SlotRecord( $this->makeRow(), new WikitextContent( 'A' ) );
- $output = SlotRecord::newWithSuppressedContent( $input );
-
- $this->setExpectedException( SuppressedDataException::class );
- $output->getContent();
- }
-
- public function testNewInherited() {
- $row = $this->makeRow( [ 'slot_revision_id' => 7, 'slot_origin' => 7 ] );
- $parent = new SlotRecord( $row, new WikitextContent( 'A' ) );
-
- // This would happen while doing an edit, before saving revision meta-data.
- $inherited = SlotRecord::newInherited( $parent );
-
- $this->assertSame( $parent->getContentId(), $inherited->getContentId() );
- $this->assertSame( $parent->getAddress(), $inherited->getAddress() );
- $this->assertSame( $parent->getContent(), $inherited->getContent() );
- $this->assertTrue( $inherited->isInherited() );
- $this->assertTrue( $inherited->hasOrigin() );
- $this->assertFalse( $inherited->hasRevision() );
-
- // make sure we didn't mess with the internal state of $parent
- $this->assertFalse( $parent->isInherited() );
- $this->assertSame( 7, $parent->getRevision() );
-
- // This would happen while doing an edit, after saving the revision meta-data
- // and content meta-data.
- $saved = SlotRecord::newSaved(
- 10,
- $inherited->getContentId(),
- $inherited->getAddress(),
- $inherited
- );
- $this->assertSame( $parent->getContentId(), $saved->getContentId() );
- $this->assertSame( $parent->getAddress(), $saved->getAddress() );
- $this->assertSame( $parent->getContent(), $saved->getContent() );
- $this->assertTrue( $saved->isInherited() );
- $this->assertTrue( $saved->hasRevision() );
- $this->assertSame( 10, $saved->getRevision() );
-
- // make sure we didn't mess with the internal state of $parent or $inherited
- $this->assertSame( 7, $parent->getRevision() );
- $this->assertFalse( $inherited->hasRevision() );
- }
-
- public function testNewSaved() {
- // This would happen while doing an edit, before saving revision meta-data.
- $unsaved = SlotRecord::newUnsaved( SlotRecord::MAIN, new WikitextContent( 'A' ) );
-
- // This would happen while doing an edit, after saving the revision meta-data
- // and content meta-data.
- $saved = SlotRecord::newSaved( 10, 20, 'theNewAddress', $unsaved );
- $this->assertFalse( $saved->isInherited() );
- $this->assertTrue( $saved->hasOrigin() );
- $this->assertTrue( $saved->hasRevision() );
- $this->assertTrue( $saved->hasAddress() );
- $this->assertTrue( $saved->hasContentId() );
- $this->assertSame( 'theNewAddress', $saved->getAddress() );
- $this->assertSame( 20, $saved->getContentId() );
- $this->assertSame( 'A', $saved->getContent()->getText() );
- $this->assertSame( 10, $saved->getRevision() );
- $this->assertSame( 10, $saved->getOrigin() );
-
- // make sure we didn't mess with the internal state of $unsaved
- $this->assertFalse( $unsaved->hasAddress() );
- $this->assertFalse( $unsaved->hasContentId() );
- $this->assertFalse( $unsaved->hasRevision() );
- }
-
- public function provideNewSaved_LogicException() {
- $freshRow = $this->makeRow( [
- 'content_id' => 10,
- 'content_address' => 'address:1',
- 'slot_origin' => 1,
- 'slot_revision_id' => 1,
- ] );
-
- $freshSlot = new SlotRecord( $freshRow, new WikitextContent( 'A' ) );
- yield 'mismatching address' => [ 1, 10, 'address:BAD', $freshSlot ];
- yield 'mismatching revision' => [ 5, 10, 'address:1', $freshSlot ];
- yield 'mismatching content ID' => [ 1, 17, 'address:1', $freshSlot ];
-
- $inheritedRow = $this->makeRow( [
- 'content_id' => null,
- 'content_address' => null,
- 'slot_origin' => 0,
- 'slot_revision_id' => 1,
- ] );
-
- $inheritedSlot = new SlotRecord( $inheritedRow, new WikitextContent( 'A' ) );
- yield 'inherited, but no address' => [ 1, 10, 'address:2', $inheritedSlot ];
- }
-
- /**
- * @dataProvider provideNewSaved_LogicException
- */
- public function testNewSaved_LogicException(
- $revisionId,
- $contentId,
- $contentAddress,
- SlotRecord $protoSlot
- ) {
- $this->setExpectedException( LogicException::class );
- SlotRecord::newSaved( $revisionId, $contentId, $contentAddress, $protoSlot );
- }
-
- public function provideNewSaved_InvalidArgumentException() {
- $unsaved = SlotRecord::newUnsaved( SlotRecord::MAIN, new WikitextContent( 'A' ) );
-
- yield 'bad revision id' => [ 'xyzzy', 5, 'address', $unsaved ];
- yield 'bad content id' => [ 7, 'xyzzy', 'address', $unsaved ];
- yield 'bad content address' => [ 7, 5, 77, $unsaved ];
- }
-
- /**
- * @dataProvider provideNewSaved_InvalidArgumentException
- */
- public function testNewSaved_InvalidArgumentException(
- $revisionId,
- $contentId,
- $contentAddress,
- SlotRecord $protoSlot
- ) {
- $this->setExpectedException( InvalidArgumentException::class );
- SlotRecord::newSaved( $revisionId, $contentId, $contentAddress, $protoSlot );
- }
-
- public function provideHasSameContent() {
- $fail = function () {
- self::fail( 'There should be no need to actually load the content.' );
- };
-
- $a100a1 = new SlotRecord(
- $this->makeRow(
- [
- 'model_name' => 'A',
- 'content_size' => 100,
- 'content_sha1' => 'hash-a',
- 'content_address' => 'xxx:a1',
- ]
- ),
- $fail
- );
- $a100a1b = new SlotRecord(
- $this->makeRow(
- [
- 'model_name' => 'A',
- 'content_size' => 100,
- 'content_sha1' => 'hash-a',
- 'content_address' => 'xxx:a1',
- ]
- ),
- $fail
- );
- $a100null = new SlotRecord(
- $this->makeRow(
- [
- 'model_name' => 'A',
- 'content_size' => 100,
- 'content_sha1' => 'hash-a',
- 'content_address' => null,
- ]
- ),
- $fail
- );
- $a100a2 = new SlotRecord(
- $this->makeRow(
- [
- 'model_name' => 'A',
- 'content_size' => 100,
- 'content_sha1' => 'hash-a',
- 'content_address' => 'xxx:a2',
- ]
- ),
- $fail
- );
- $b100a1 = new SlotRecord(
- $this->makeRow(
- [
- 'model_name' => 'B',
- 'content_size' => 100,
- 'content_sha1' => 'hash-a',
- 'content_address' => 'xxx:a1',
- ]
- ),
- $fail
- );
- $a200a1 = new SlotRecord(
- $this->makeRow(
- [
- 'model_name' => 'A',
- 'content_size' => 200,
- 'content_sha1' => 'hash-a',
- 'content_address' => 'xxx:a2',
- ]
- ),
- $fail
- );
- $a100x1 = new SlotRecord(
- $this->makeRow(
- [
- 'model_name' => 'A',
- 'content_size' => 100,
- 'content_sha1' => 'hash-x',
- 'content_address' => 'xxx:x1',
- ]
- ),
- $fail
- );
-
- yield 'same instance' => [ $a100a1, $a100a1, true ];
- yield 'no address' => [ $a100a1, $a100null, true ];
- yield 'same address' => [ $a100a1, $a100a1b, true ];
- yield 'different address' => [ $a100a1, $a100a2, true ];
- yield 'different model' => [ $a100a1, $b100a1, false ];
- yield 'different size' => [ $a100a1, $a200a1, false ];
- yield 'different hash' => [ $a100a1, $a100x1, false ];
- }
-
- /**
- * @dataProvider provideHasSameContent
- */
- public function testHasSameContent( SlotRecord $a, SlotRecord $b, $sameContent ) {
- $this->assertSame( $sameContent, $a->hasSameContent( $b ) );
- $this->assertSame( $sameContent, $b->hasSameContent( $a ) );
- }
-
-}
+++ /dev/null
-<?php
-
-/**
- * @covers WikiReference
- */
-class WikiReferenceTest extends MediaWikiUnitTestCase {
-
- public function provideGetDisplayName() {
- return [
- 'http' => [ 'foo.bar', 'http://foo.bar' ],
- 'https' => [ 'foo.bar', 'http://foo.bar' ],
-
- // apparently, this is the expected behavior
- 'invalid' => [ 'purple kittens', 'purple kittens' ],
- ];
- }
-
- /**
- * @dataProvider provideGetDisplayName
- */
- public function testGetDisplayName( $expected, $canonicalServer ) {
- $reference = new WikiReference( $canonicalServer, '/wiki/$1' );
- $this->assertEquals( $expected, $reference->getDisplayName() );
- }
-
- public function testGetCanonicalServer() {
- $reference = new WikiReference( 'https://acme.com', '/wiki/$1', '//acme.com' );
- $this->assertEquals( 'https://acme.com', $reference->getCanonicalServer() );
- }
-
- public function provideGetCanonicalUrl() {
- return [
- 'no fragment' => [
- 'https://acme.com/wiki/Foo',
- 'https://acme.com',
- '//acme.com',
- '/wiki/$1',
- 'Foo',
- null
- ],
- 'empty fragment' => [
- 'https://acme.com/wiki/Foo',
- 'https://acme.com',
- '//acme.com',
- '/wiki/$1',
- 'Foo',
- ''
- ],
- 'fragment' => [
- 'https://acme.com/wiki/Foo#Bar',
- 'https://acme.com',
- '//acme.com',
- '/wiki/$1',
- 'Foo',
- 'Bar'
- ],
- 'double fragment' => [
- 'https://acme.com/wiki/Foo#Bar%23Xus',
- 'https://acme.com',
- '//acme.com',
- '/wiki/$1',
- 'Foo',
- 'Bar#Xus'
- ],
- 'escaped fragment' => [
- 'https://acme.com/wiki/Foo%23Bar',
- 'https://acme.com',
- '//acme.com',
- '/wiki/$1',
- 'Foo#Bar',
- null
- ],
- 'empty path' => [
- 'https://acme.com/Foo',
- 'https://acme.com',
- '//acme.com',
- '/$1',
- 'Foo',
- null
- ],
- ];
- }
-
- /**
- * @dataProvider provideGetCanonicalUrl
- */
- public function testGetCanonicalUrl(
- $expected, $canonicalServer, $server, $path, $page, $fragmentId
- ) {
- $reference = new WikiReference( $canonicalServer, $path, $server );
- $this->assertEquals( $expected, $reference->getCanonicalUrl( $page, $fragmentId ) );
- }
-
- /**
- * @dataProvider provideGetCanonicalUrl
- * @note getUrl is an alias for getCanonicalUrl
- */
- public function testGetUrl( $expected, $canonicalServer, $server, $path, $page, $fragmentId ) {
- $reference = new WikiReference( $canonicalServer, $path, $server );
- $this->assertEquals( $expected, $reference->getUrl( $page, $fragmentId ) );
- }
-
- public function provideGetFullUrl() {
- return [
- 'no fragment' => [
- '//acme.com/wiki/Foo',
- 'https://acme.com',
- '//acme.com',
- '/wiki/$1',
- 'Foo',
- null
- ],
- 'empty fragment' => [
- '//acme.com/wiki/Foo',
- 'https://acme.com',
- '//acme.com',
- '/wiki/$1',
- 'Foo',
- ''
- ],
- 'fragment' => [
- '//acme.com/wiki/Foo#Bar',
- 'https://acme.com',
- '//acme.com',
- '/wiki/$1',
- 'Foo',
- 'Bar'
- ],
- 'double fragment' => [
- '//acme.com/wiki/Foo#Bar%23Xus',
- 'https://acme.com',
- '//acme.com',
- '/wiki/$1',
- 'Foo',
- 'Bar#Xus'
- ],
- 'escaped fragment' => [
- '//acme.com/wiki/Foo%23Bar',
- 'https://acme.com',
- '//acme.com',
- '/wiki/$1',
- 'Foo#Bar',
- null
- ],
- 'empty path' => [
- '//acme.com/Foo',
- 'https://acme.com',
- '//acme.com',
- '/$1',
- 'Foo',
- null
- ],
- ];
- }
-
- /**
- * @dataProvider provideGetFullUrl
- */
- public function testGetFullUrl( $expected, $canonicalServer, $server, $path, $page, $fragmentId ) {
- $reference = new WikiReference( $canonicalServer, $path, $server );
- $this->assertEquals( $expected, $reference->getFullUrl( $page, $fragmentId ) );
- }
-
-}
+++ /dev/null
-<?php
-
-/**
- * @covers DifferenceEngineSlotDiffRenderer
- */
-class DifferenceEngineSlotDiffRendererTest extends \MediaWikiUnitTestCase {
-
- public function testGetDiff() {
- $differenceEngine = new CustomDifferenceEngine();
- $slotDiffRenderer = new DifferenceEngineSlotDiffRenderer( $differenceEngine );
- $oldContent = ContentHandler::makeContent( 'xxx', null, CONTENT_MODEL_TEXT );
- $newContent = ContentHandler::makeContent( 'yyy', null, CONTENT_MODEL_TEXT );
-
- $diff = $slotDiffRenderer->getDiff( $oldContent, $newContent );
- $this->assertEquals( 'xxx|yyy', $diff );
-
- $diff = $slotDiffRenderer->getDiff( null, $newContent );
- $this->assertEquals( '|yyy', $diff );
-
- $diff = $slotDiffRenderer->getDiff( $oldContent, null );
- $this->assertEquals( 'xxx|', $diff );
- }
-
- public function testAddModules() {
- $output = $this->getMockBuilder( OutputPage::class )
- ->disableOriginalConstructor()
- ->setMethods( [ 'addModules' ] )
- ->getMock();
- $output->expects( $this->once() )
- ->method( 'addModules' )
- ->with( 'foo' );
- $differenceEngine = new CustomDifferenceEngine();
- $slotDiffRenderer = new DifferenceEngineSlotDiffRenderer( $differenceEngine );
- $slotDiffRenderer->addModules( $output );
- }
-
- public function testGetExtraCacheKeys() {
- $differenceEngine = new CustomDifferenceEngine();
- $slotDiffRenderer = new DifferenceEngineSlotDiffRenderer( $differenceEngine );
- $extraCacheKeys = $slotDiffRenderer->getExtraCacheKeys();
- $this->assertSame( [ 'foo' ], $extraCacheKeys );
- }
-
-}
+++ /dev/null
-<?php
-
-use Wikimedia\Assert\ParameterTypeException;
-use Wikimedia\TestingAccessWrapper;
-
-/**
- * @covers SlotDiffRenderer
- */
-class SlotDiffRendererTest extends \MediaWikiUnitTestCase {
-
- /**
- * @dataProvider provideNormalizeContents
- */
- public function testNormalizeContents(
- $oldContent, $newContent, $allowedClasses,
- $expectedOldContent, $expectedNewContent, $expectedExceptionClass
- ) {
- $slotDiffRenderer = $this->getMockBuilder( SlotDiffRenderer::class )
- ->getMock();
- try {
- // __call needs help deciding which parameter to take by reference
- call_user_func_array( [ TestingAccessWrapper::newFromObject( $slotDiffRenderer ),
- 'normalizeContents' ], [ &$oldContent, &$newContent, $allowedClasses ] );
- $this->assertEquals( $expectedOldContent, $oldContent );
- $this->assertEquals( $expectedNewContent, $newContent );
- } catch ( Exception $e ) {
- if ( !$expectedExceptionClass ) {
- throw $e;
- }
- $this->assertInstanceOf( $expectedExceptionClass, $e );
- }
- }
-
- public function provideNormalizeContents() {
- return [
- 'both null' => [ null, null, null, null, null, InvalidArgumentException::class ],
- 'left null' => [
- null, new WikitextContent( 'abc' ), null,
- new WikitextContent( '' ), new WikitextContent( 'abc' ), null,
- ],
- 'right null' => [
- new WikitextContent( 'def' ), null, null,
- new WikitextContent( 'def' ), new WikitextContent( '' ), null,
- ],
- 'type filter' => [
- new WikitextContent( 'abc' ), new WikitextContent( 'def' ), WikitextContent::class,
- new WikitextContent( 'abc' ), new WikitextContent( 'def' ), null,
- ],
- 'type filter (subclass)' => [
- new WikitextContent( 'abc' ), new WikitextContent( 'def' ), TextContent::class,
- new WikitextContent( 'abc' ), new WikitextContent( 'def' ), null,
- ],
- 'type filter (null)' => [
- new WikitextContent( 'abc' ), null, TextContent::class,
- new WikitextContent( 'abc' ), new WikitextContent( '' ), null,
- ],
- 'type filter failure (left)' => [
- new TextContent( 'abc' ), new WikitextContent( 'def' ), WikitextContent::class,
- null, null, ParameterTypeException::class,
- ],
- 'type filter failure (right)' => [
- new WikitextContent( 'abc' ), new TextContent( 'def' ), WikitextContent::class,
- null, null, ParameterTypeException::class,
- ],
- 'type filter (array syntax)' => [
- new WikitextContent( 'abc' ), new JsonContent( 'def' ),
- [ JsonContent::class, WikitextContent::class ],
- new WikitextContent( 'abc' ), new JsonContent( 'def' ), null,
- ],
- 'type filter failure (array syntax)' => [
- new WikitextContent( 'abc' ), new CssContent( 'def' ),
- [ JsonContent::class, WikitextContent::class ],
- null, null, ParameterTypeException::class,
- ],
- ];
- }
-
-}
--- /dev/null
+<?php
+
+use MediaWiki\FileBackend\FSFile\TempFSFileFactory;
+use MediaWiki\FileBackend\LockManager\LockManagerGroupFactory;
+use MediaWiki\Logger\LoggerFactory;
+
+/**
+ * Code shared by the FileBackendGroup integration and unit tests. They need merely provide a
+ * suitable newObj() method and everything else works magically.
+ */
+trait FileBackendGroupTestTrait {
+ /**
+ * @param array $options Dictionary to use as a source for ServiceOptions before defaults, plus
+ * the following options are available to override other arguments:
+ * * 'configuredROMode'
+ * * 'lmgFactory'
+ * * 'mimeAnalyzer'
+ * * 'tmpFileFactory'
+ */
+ abstract protected function newObj( array $options = [] ) : FileBackendGroup;
+
+ /**
+ * @param string $domain Expected argument that LockManagerGroupFactory::getLockManagerGroup
+ * will receive
+ */
+ abstract protected function getLockManagerGroupFactory( $domain )
+ : LockManagerGroupFactory;
+
+ /**
+ * @return string As from wfWikiID()
+ */
+ abstract protected static function getWikiID();
+
+ /** @var BagOStuff */
+ private $srvCache;
+
+ /** @var WANObjectCache */
+ private $wanCache;
+
+ /** @var LockManagerGroupFactory */
+ private $lmgFactory;
+
+ /** @var TempFSFileFactory */
+ private $tmpFileFactory;
+
+ private static function getDefaultLocalFileRepo() {
+ return [
+ 'class' => LocalRepo::class,
+ 'name' => 'local',
+ 'directory' => 'upload-dir',
+ 'thumbDir' => 'thumb/',
+ 'transcodedDir' => 'transcoded/',
+ 'fileMode' => 0664,
+ 'scriptDirUrl' => 'script-path/',
+ 'url' => 'upload-path/',
+ 'hashLevels' => 2,
+ 'thumbScriptUrl' => false,
+ 'transformVia404' => false,
+ 'deletedDir' => 'deleted/',
+ 'deletedHashLevels' => 3,
+ 'backend' => 'local-backend',
+ ];
+ }
+
+ private static function getDefaultOptions() {
+ return [
+ 'DirectoryMode' => 0775,
+ 'FileBackends' => [],
+ 'ForeignFileRepos' => [],
+ 'LocalFileRepo' => self::getDefaultLocalFileRepo(),
+ 'wikiId' => self::getWikiID(),
+ ];
+ }
+
+ /**
+ * @covers ::__construct
+ */
+ public function testConstructor_overrideImplicitBackend() {
+ $obj = $this->newObj( [ 'FileBackends' =>
+ [ [ 'name' => 'local-backend', 'class' => '', 'lockManager' => 'fsLockManager' ] ]
+ ] );
+ $this->assertSame( '', $obj->config( 'local-backend' )['class'] );
+ }
+
+ /**
+ * @covers ::__construct
+ */
+ public function testConstructor_backendObject() {
+ // 'backend' being an object makes that repo from configuration ignored
+ // XXX This is not documented in DefaultSettings.php, does it do anything useful?
+ $obj = $this->newObj( [ 'ForeignFileRepos' => [ [ 'backend' => new stdclass ] ] ] );
+ $this->assertSame( FSFileBackend::class, $obj->config( 'local-backend' )['class'] );
+ }
+
+ /**
+ * @dataProvider provideRegister_domainId
+ * @param string $key Key to check in return value of config()
+ * @param string|callable $expected Expected value of config()[$key], or callable returning it
+ * @param array $extraBackendsOptions To add to the FileBackends entry passed to newObj()
+ * @param array $otherExtraOptions To add to the array passed to newObj() (e.g., services)
+ * @covers ::register
+ */
+ public function testRegister(
+ $key, $expected, array $extraBackendsOptions = [], array $otherExtraOptions = []
+ ) {
+ if ( $expected instanceof Closure ) {
+ // Lame hack to get around providers being called too early
+ $expected = $expected();
+ }
+ if ( $key === 'domainId' ) {
+ // This will change the expected LMG name too
+ $otherExtraOptions['lmgFactory'] = $this->getLockManagerGroupFactory( $expected );
+ }
+ $obj = $this->newObj( $otherExtraOptions + [
+ 'FileBackends' => [
+ $extraBackendsOptions + [
+ 'name' => 'myname', 'class' => '', 'lockManager' => 'fsLockManager'
+ ]
+ ],
+ ] );
+ $this->assertSame( $expected, $obj->config( 'myname' )[$key] );
+ }
+
+ public static function provideRegister_domainId() {
+ return [
+ 'domainId with neither wikiId nor domainId set' => [
+ 'domainId',
+ function () {
+ return self::getWikiID();
+ },
+ ],
+ 'domainId with wikiId set but no domainId' =>
+ [ 'domainId', 'id0', [ 'wikiId' => 'id0' ] ],
+ 'domainId with wikiId and domainId set' =>
+ [ 'domainId', 'dom1', [ 'wikiId' => 'id0', 'domainId' => 'dom1' ] ],
+ 'readOnly without readOnly set' => [ 'readOnly', false ],
+ 'readOnly with readOnly set to string' =>
+ [ 'readOnly', 'cuz', [ 'readOnly' => 'cuz' ] ],
+ 'readOnly without readOnly set but with string in passed object' => [
+ 'readOnly',
+ 'cuz',
+ [],
+ [ 'configuredROMode' => new ConfiguredReadOnlyMode( 'cuz' ) ],
+ ],
+ 'readOnly with readOnly set to false but string in passed object' => [
+ 'readOnly',
+ false,
+ [ 'readOnly' => false ],
+ [ 'configuredROMode' => new ConfiguredReadOnlyMode( 'cuz' ) ],
+ ],
+ ];
+ }
+
+ /**
+ * @dataProvider provideRegister_exception
+ * @param array $fileBackends Value of FileBackends to pass to constructor
+ * @param string $class Expected exception class
+ * @param string $msg Expected exception message
+ * @covers ::__construct
+ * @covers ::register
+ */
+ public function testRegister_exception( $fileBackends, $class, $msg ) {
+ $this->setExpectedException( $class, $msg );
+ $this->newObj( [ 'FileBackends' => $fileBackends ] );
+ }
+
+ public static function provideRegister_exception() {
+ return [
+ 'Nameless' => [
+ [ [] ], InvalidArgumentException::class, "Cannot register a backend with no name."
+ ],
+ 'Duplicate' => [
+ [ [ 'name' => 'dupe', 'class' => '' ], [ 'name' => 'dupe' ] ],
+ LogicException::class,
+ "Backend with name 'dupe' already registered.",
+ ],
+ 'Classless' => [
+ [ [ 'name' => 'classless' ] ],
+ InvalidArgumentException::class,
+ "Backend with name 'classless' has no class.",
+ ],
+ ];
+ }
+
+ /**
+ * @covers ::__construct
+ * @covers ::config
+ * @covers ::get
+ */
+ public function testGet() {
+ $backend = $this->newObj()->get( 'local-backend' );
+ $this->assertTrue( $backend instanceof FSFileBackend );
+ }
+
+ /**
+ * @covers ::get
+ */
+ public function testGetUnrecognized() {
+ $this->setExpectedException( InvalidArgumentException::class,
+ "No backend defined with the name 'unrecognized'." );
+ $this->newObj()->get( 'unrecognized' );
+ }
+
+ /**
+ * @covers ::__construct
+ * @covers ::config
+ */
+ public function testConfig() {
+ $obj = $this->newObj();
+ $config = $obj->config( 'local-backend' );
+
+ // XXX How to actually test that a profiler is loaded?
+ $this->assertNull( $config['profiler']( 'x' ) );
+ // Equality comparison doesn't work for closures, so just set to null
+ $config['profiler'] = null;
+
+ $this->assertEquals( [
+ 'mimeCallback' => [ $obj, 'guessMimeInternal' ],
+ 'obResetFunc' => 'wfResetOutputBuffers',
+ 'streamMimeFunc' => [ StreamFile::class, 'contentTypeFromPath' ],
+ 'tmpFileFactory' => $this->tmpFileFactory,
+ 'statusWrapper' => [ Status::class, 'wrap' ],
+ 'wanCache' => $this->wanCache,
+ 'srvCache' => $this->srvCache,
+ 'logger' => LoggerFactory::getInstance( 'FileOperation' ),
+ // This was set to null above in $config, it's not really null
+ 'profiler' => null,
+ 'name' => 'local-backend',
+ 'containerPaths' => [
+ 'local-public' => 'upload-dir',
+ 'local-thumb' => 'thumb/',
+ 'local-transcoded' => 'transcoded/',
+ 'local-deleted' => 'deleted/',
+ 'local-temp' => 'upload-dir/temp',
+ ],
+ 'fileMode' => 0664,
+ 'directoryMode' => 0775,
+ 'domainId' => self::getWikiID(),
+ 'readOnly' => false,
+ 'class' => FSFileBackend::class,
+ 'lockManager' =>
+ $this->lmgFactory->getLockManagerGroup( self::getWikiID() )->get( 'fsLockManager' ),
+ 'fileJournal' =>
+ FileJournal::factory( [ 'class' => NullFileJournal::class ], 'local-backend' ),
+ ], $config );
+
+ // For config values that are objects, check object identity.
+ $this->assertSame( [ $obj, 'guessMimeInternal' ], $config['mimeCallback'] );
+ $this->assertSame( $this->tmpFileFactory, $config['tmpFileFactory'] );
+ $this->assertSame( $this->wanCache, $config['wanCache'] );
+ $this->assertSame( $this->srvCache, $config['srvCache'] );
+ }
+
+ /**
+ * @dataProvider provideConfig_default
+ * @param string $expected Expected default value
+ * @param string $inputName Name to set to null in LocalFileRepo setting
+ * @param string|array $key Key to check in array returned by config(), or array [ 'key1',
+ * 'key2' ] for nested key
+ * @covers ::__construct
+ * @covers ::config
+ */
+ public function testConfig_defaultNull( $expected, $inputName, $key ) {
+ $config = self::getDefaultLocalFileRepo();
+ $config[$inputName] = null;
+
+ $result = $this->newObj( [ 'LocalFileRepo' => $config ] )->config( 'local-backend' );
+
+ $actual = is_string( $key ) ? $result[$key] : $result[$key[0]][$key[1]];
+
+ $this->assertSame( $expected, $actual );
+ }
+
+ /**
+ * @dataProvider provideConfig_default
+ * @param string $expected Expected default value
+ * @param string $inputName Name to unset in LocalFileRepo setting
+ * @param string|array $key Key to check in array returned by config(), or array [ 'key1',
+ * 'key2' ] for nested key
+ * @covers ::__construct
+ * @covers ::config
+ */
+ public function testConfig_defaultUnset( $expected, $inputName, $key ) {
+ $config = self::getDefaultLocalFileRepo();
+ unset( $config[$inputName] );
+
+ $result = $this->newObj( [ 'LocalFileRepo' => $config ] )->config( 'local-backend' );
+
+ $actual = is_string( $key ) ? $result[$key] : $result[$key[0]][$key[1]];
+
+ $this->assertSame( $expected, $actual );
+ }
+
+ public static function provideConfig_default() {
+ return [
+ 'deletedDir' => [ false, 'deletedDir', [ 'containerPaths', 'local-deleted' ] ],
+ 'thumbDir' => [ 'upload-dir/thumb', 'thumbDir', [ 'containerPaths', 'local-thumb' ] ],
+ 'transcodedDir' => [
+ 'upload-dir/transcoded', 'transcodedDir', [ 'containerPaths', 'local-transcoded' ]
+ ],
+ 'fileMode' => [ 0644, 'fileMode', 'fileMode' ],
+ ];
+ }
+
+ /**
+ * @covers ::config
+ */
+ public function testConfig_fileJournal() {
+ $mockJournal = $this->createMock( FileJournal::class );
+ $mockJournal->expects( $this->never() )->method( $this->anything() );
+
+ $obj = $this->newObj( [ 'FileBackends' => [ [
+ 'name' => 'name',
+ 'class' => '',
+ 'lockManager' => 'fsLockManager',
+ 'fileJournal' => [ 'factory' =>
+ function () use ( $mockJournal ) {
+ return $mockJournal;
+ }
+ ],
+ ] ] ] );
+
+ $this->assertSame( $mockJournal, $obj->config( 'name' )['fileJournal'] );
+ }
+
+ /**
+ * @covers ::config
+ */
+ public function testConfigUnrecognized() {
+ $this->setExpectedException( InvalidArgumentException::class,
+ "No backend defined with the name 'unrecognized'." );
+ $this->newObj()->config( 'unrecognized' );
+ }
+
+ /**
+ * @dataProvider provideBackendFromPath
+ * @covers ::backendFromPath
+ * @param string|null $expected Name of backend that will be returned from 'get', or null
+ * @param string $storagePath
+ */
+ public function testBackendFromPath( $expected = null, $storagePath ) {
+ $obj = $this->newObj( [ 'FileBackends' => [
+ [ 'name' => '', 'class' => stdclass::class, 'lockManager' => 'fsLockManager' ],
+ [ 'name' => 'a', 'class' => stdclass::class, 'lockManager' => 'fsLockManager' ],
+ [ 'name' => 'b', 'class' => stdclass::class, 'lockManager' => 'fsLockManager' ],
+ ] ] );
+ $this->assertSame(
+ $expected === null ? null : $obj->get( $expected ),
+ $obj->backendFromPath( $storagePath )
+ );
+ }
+
+ public static function provideBackendFromPath() {
+ return [
+ 'Empty string' => [ null, '' ],
+ 'mwstore://' => [ null, 'mwstore://' ],
+ 'mwstore://a' => [ null, 'mwstore://a' ],
+ 'mwstore:///' => [ null, 'mwstore:///' ],
+ 'mwstore://a/' => [ null, 'mwstore://a/' ],
+ 'mwstore://a//' => [ null, 'mwstore://a//' ],
+ 'mwstore://a/b' => [ 'a', 'mwstore://a/b' ],
+ 'mwstore://a/b/' => [ 'a', 'mwstore://a/b/' ],
+ 'mwstore://a/b////' => [ 'a', 'mwstore://a/b////' ],
+ 'mwstore://a/b/c' => [ 'a', 'mwstore://a/b/c' ],
+ 'mwstore://a/b/c/d' => [ 'a', 'mwstore://a/b/c/d' ],
+ 'mwstore://b/b' => [ 'b', 'mwstore://b/b' ],
+ 'mwstore://c/b' => [ null, 'mwstore://c/b' ],
+ ];
+ }
+
+ /**
+ * @dataProvider provideGuessMimeInternal
+ * @covers ::guessMimeInternal
+ * @param string $storagePath
+ * @param string|null $content
+ * @param string|null $fsPath
+ * @param string|null $expectedExtensionType Expected return of
+ * MimeAnalyzer::guessTypesForExtension
+ * @param string|null $expectedGuessedMimeType Expected return value of
+ * MimeAnalyzer::guessMimeType (null if expected not to be called)
+ */
+ public function testGuessMimeInternal(
+ $storagePath,
+ $content,
+ $fsPath,
+ $expectedExtensionType,
+ $expectedGuessedMimeType
+ ) {
+ $mimeAnalyzer = $this->createMock( MimeAnalyzer::class );
+ $mimeAnalyzer->expects( $this->once() )->method( 'guessTypesForExtension' )
+ ->willReturn( $expectedExtensionType );
+ $tmpFileFactory = $this->createMock( TempFSFileFactory::class );
+
+ if ( !$expectedExtensionType && $fsPath ) {
+ $tmpFileFactory->expects( $this->never() )->method( 'newTempFSFile' );
+ $mimeAnalyzer->expects( $this->once() )->method( 'guessMimeType' )
+ ->with( $fsPath, false )->willReturn( $expectedGuessedMimeType );
+ } elseif ( !$expectedExtensionType && strlen( $content ) ) {
+ // XXX What should we do about the file creation here? Really we should mock
+ // file_put_contents() somehow. It's not very nice to ignore the value of
+ // $wgTmpDirectory.
+ $tmpFile = ( new TempFSFileFactory() )->newTempFSFile( 'mime_', '' );
+
+ $tmpFileFactory->expects( $this->once() )->method( 'newTempFSFile' )
+ ->with( 'mime_', '' )->willReturn( $tmpFile );
+ $mimeAnalyzer->expects( $this->once() )->method( 'guessMimeType' )
+ ->with( $tmpFile->getPath(), false )->willReturn( $expectedGuessedMimeType );
+ } else {
+ $tmpFileFactory->expects( $this->never() )->method( 'newTempFSFile' );
+ $mimeAnalyzer->expects( $this->never() )->method( 'guessMimeType' );
+ }
+
+ $mimeAnalyzer->expects( $this->never() )
+ ->method( $this->anythingBut( 'guessTypesForExtension', 'guessMimeType' ) );
+ $tmpFileFactory->expects( $this->never() )
+ ->method( $this->anythingBut( 'newTempFSFile' ) );
+
+ $obj = $this->newObj( [
+ 'mimeAnalyzer' => $mimeAnalyzer,
+ 'tmpFileFactory' => $tmpFileFactory,
+ ] );
+
+ $this->assertSame( $expectedExtensionType ?? $expectedGuessedMimeType ?? 'unknown/unknown',
+ $obj->guessMimeInternal( $storagePath, $content, $fsPath ) );
+ }
+
+ public static function provideGuessMimeInternal() {
+ return [
+ 'With extension' =>
+ [ 'foo.txt', null, null, 'text/plain', null ],
+ 'No extension' =>
+ [ 'foo', null, null, null, null ],
+ 'Empty content, with extension' =>
+ [ 'foo.txt', '', null, 'text/plain', null ],
+ 'Empty content, no extension' =>
+ [ 'foo', '', null, null, null ],
+ 'Non-empty content, with extension' =>
+ [ 'foo.txt', '<b>foo</b>', null, 'text/plain', null ],
+ 'Non-empty content, no extension' =>
+ [ 'foo', '<b>foo</b>', null, null, 'text/html' ],
+ 'Empty path, with extension' =>
+ [ 'foo.txt', null, '', 'text/plain', null ],
+ 'Empty path, no extension' =>
+ [ 'foo', null, '', null, null ],
+ 'Non-empty path, with extension' =>
+ [ 'foo.txt', null, '/bogus/path', 'text/plain', null ],
+ 'Non-empty path, no extension' =>
+ [ 'foo', null, '/bogus/path', null, 'text/html' ],
+ 'Empty path and content, with extension' =>
+ [ 'foo.txt', '', '', 'text/plain', null ],
+ 'Empty path and content, no extension' =>
+ [ 'foo', '', '', null, null ],
+ 'Non-empty path and content, with extension' =>
+ [ 'foo.txt', '<b>foo</b>', '/bogus/path', 'text/plain', null ],
+ 'Non-empty path and content, no extension' =>
+ [ 'foo', '<b>foo</b>', '/bogus/path', null, 'image/jpeg' ],
+ ];
+ }
+}
--- /dev/null
+<?php
+
+use MediaWiki\FileBackend\LockManager\LockManagerGroupFactory;
+use Wikimedia\Rdbms\LBFactory;
+
+/**
+ * @covers MediaWiki\FileBackend\LockManager\LockManagerGroupFactory
+ * @todo Should we somehow test that the LockManagerGroup objects are as we expect? How do we do
+ * that without getting into testing LockManagerGroup itself?
+ */
+class LockManagerGroupFactoryTest extends MediaWikiUnitTestCase {
+ public function testGetLockManagerGroup() {
+ $mockLbFactory = $this->createNoOpMock( LBFactory::class );
+
+ $factory = new LockManagerGroupFactory( 'defaultDomain', [], $mockLbFactory );
+ $lbmUnspecified = $factory->getLockManagerGroup();
+ $lbmFalse = $factory->getLockManagerGroup( false );
+ $lbmDefault = $factory->getLockManagerGroup( 'defaultDomain' );
+ $lbmOther = $factory->getLockManagerGroup( 'otherDomain' );
+
+ $this->assertSame( $lbmUnspecified, $lbmFalse );
+ $this->assertSame( $lbmFalse, $lbmDefault );
+ $this->assertSame( $lbmDefault, $lbmUnspecified );
+ $this->assertNotEquals( $lbmUnspecified, $lbmOther );
+ $this->assertNotEquals( $lbmFalse, $lbmOther );
+ $this->assertNotEquals( $lbmDefault, $lbmOther );
+
+ $this->assertSame( $lbmUnspecified, $factory->getLockManagerGroup() );
+ $this->assertSame( $lbmFalse, $factory->getLockManagerGroup( false ) );
+ $this->assertSame( $lbmDefault, $factory->getLockManagerGroup( 'defaultDomain' ) );
+ $this->assertSame( $lbmOther, $factory->getLockManagerGroup( 'otherDomain' ) );
+ }
+}
--- /dev/null
+<?php
+
+use Wikimedia\Rdbms\LBFactory;
+use Wikimedia\TestingAccessWrapper;
+
+/**
+ * Since this is a unit test, we don't test the singleton() or destroySingletons() methods. We also
+ * can't test get() with a valid argument, because that winds up calling static methods of
+ * ObjectCache and LoggerFactory that aren't yet compatible with proper unit tests. Those will be
+ * tested in the integration test for now.
+ *
+ * @covers LockManagerGroup
+ */
+class LockManagerGroupTest extends MediaWikiUnitTestCase {
+ private function getMockLBFactory() {
+ $mock = $this->createMock( LBFactory::class );
+ $mock->expects( $this->never() )->method( $this->anythingBut( '__destruct' ) );
+ return $mock;
+ }
+
+ public function testConstructorNoConfigs() {
+ new LockManagerGroup( 'domain', [], $this->getMockLBFactory() );
+ $this->assertTrue( true, 'No exception thrown' );
+ }
+
+ public function testConstructorConfigWithNoName() {
+ $this->setExpectedException( Exception::class,
+ 'Cannot register a lock manager with no name.' );
+
+ new LockManagerGroup( 'domain',
+ [ [ 'name' => 'a', 'class' => 'b' ], [ 'class' => 'c' ] ], $this->getMockLBFactory() );
+ }
+
+ public function testConstructorConfigWithNoClass() {
+ $this->setExpectedException( Exception::class,
+ 'Cannot register lock manager `c` with no class.' );
+
+ new LockManagerGroup( 'domain',
+ [ [ 'name' => 'a', 'class' => 'b' ], [ 'name' => 'c' ] ], $this->getMockLBFactory() );
+ }
+
+ public function testGetUndefined() {
+ $this->setExpectedException( Exception::class,
+ 'No lock manager defined with the name `c`.' );
+
+ $lmg = new LockManagerGroup( 'domain', [ [ 'name' => 'a', 'class' => 'b' ] ],
+ $this->getMockLBFactory() );
+ $lmg->get( 'c' );
+ }
+
+ public function testConfigUndefined() {
+ $this->setExpectedException( Exception::class,
+ 'No lock manager defined with the name `c`.' );
+
+ $lmg = new LockManagerGroup( 'domain', [ [ 'name' => 'a', 'class' => 'b' ] ],
+ $this->getMockLBFactory() );
+ $lmg->config( 'c' );
+ }
+
+ public function testConfig() {
+ $lmg = new LockManagerGroup( 'domain', [ [ 'name' => 'a', 'class' => 'b', 'foo' => 'c' ] ],
+ $this->getMockLBFactory() );
+ $this->assertSame(
+ [ 'class' => 'b', 'name' => 'a', 'foo' => 'c', 'domain' => 'domain' ],
+ $lmg->config( 'a' )
+ );
+ }
+
+ public function testGetDefaultNull() {
+ $lmg = new LockManagerGroup( 'domain', [], $this->getMockLBFactory() );
+ $expected = new NullLockManager( [] );
+ $actual = $lmg->getDefault();
+ // Have to get rid of the $sessions for equality check to work
+ TestingAccessWrapper::newFromObject( $actual )->session = null;
+ TestingAccessWrapper::newFromObject( $expected )->session = null;
+ $this->assertEquals( $expected, $actual );
+ }
+
+ public function testGetAnyException() {
+ // XXX Isn't the name 'getAny' misleading if we don't get whatever's available?
+ $this->setExpectedException( Exception::class,
+ 'No lock manager defined with the name `fsLockManager`.' );
+
+ $lmg = new LockManagerGroup( 'domain', [ [ 'name' => 'a', 'class' => 'b' ] ],
+ $this->getMockLBFactory() );
+ $lmg->getAny();
+ }
+}
+++ /dev/null
-<?php
-
-class FileBackendDBRepoWrapperTest extends MediaWikiUnitTestCase {
- protected $backendName = 'foo-backend';
- protected $repoName = 'pureTestRepo';
-
- /**
- * @dataProvider getBackendPathsProvider
- * @covers FileBackendDBRepoWrapper::getBackendPaths
- */
- public function testGetBackendPaths(
- $mocks,
- $latest,
- $dbReadsExpected,
- $dbReturnValue,
- $originalPath,
- $expectedBackendPath,
- $message ) {
- list( $dbMock, $backendMock, $wrapperMock ) = $mocks;
-
- $dbMock->expects( $dbReadsExpected )
- ->method( 'selectField' )
- ->will( $this->returnValue( $dbReturnValue ) );
-
- $newPaths = $wrapperMock->getBackendPaths( [ $originalPath ], $latest );
-
- $this->assertEquals(
- $expectedBackendPath,
- $newPaths[0],
- $message );
- }
-
- public function getBackendPathsProvider() {
- $prefix = 'mwstore://' . $this->backendName . '/' . $this->repoName;
- $mocksForCaching = $this->getMocks();
-
- return [
- [
- $mocksForCaching,
- false,
- $this->once(),
- '96246614d75ba1703bdfd5d7660bb57407aaf5d9',
- $prefix . '-public/f/o/foobar.jpg',
- $prefix . '-original/9/6/2/96246614d75ba1703bdfd5d7660bb57407aaf5d9',
- 'Public path translated correctly',
- ],
- [
- $mocksForCaching,
- false,
- $this->never(),
- '96246614d75ba1703bdfd5d7660bb57407aaf5d9',
- $prefix . '-public/f/o/foobar.jpg',
- $prefix . '-original/9/6/2/96246614d75ba1703bdfd5d7660bb57407aaf5d9',
- 'LRU cache leveraged',
- ],
- [
- $this->getMocks(),
- true,
- $this->once(),
- '96246614d75ba1703bdfd5d7660bb57407aaf5d9',
- $prefix . '-public/f/o/foobar.jpg',
- $prefix . '-original/9/6/2/96246614d75ba1703bdfd5d7660bb57407aaf5d9',
- 'Latest obtained',
- ],
- [
- $this->getMocks(),
- true,
- $this->never(),
- '96246614d75ba1703bdfd5d7660bb57407aaf5d9',
- $prefix . '-deleted/f/o/foobar.jpg',
- $prefix . '-original/f/o/o/foobar',
- 'Deleted path translated correctly',
- ],
- [
- $this->getMocks(),
- true,
- $this->once(),
- null,
- $prefix . '-public/b/a/baz.jpg',
- $prefix . '-public/b/a/baz.jpg',
- 'Path left untouched if no sha1 can be found',
- ],
- ];
- }
-
- /**
- * @covers FileBackendDBRepoWrapper::getFileContentsMulti
- */
- public function testGetFileContentsMulti() {
- list( $dbMock, $backendMock, $wrapperMock ) = $this->getMocks();
-
- $sha1Path = 'mwstore://' . $this->backendName . '/' . $this->repoName
- . '-original/9/6/2/96246614d75ba1703bdfd5d7660bb57407aaf5d9';
- $filenamePath = 'mwstore://' . $this->backendName . '/' . $this->repoName
- . '-public/f/o/foobar.jpg';
-
- $dbMock->expects( $this->once() )
- ->method( 'selectField' )
- ->will( $this->returnValue( '96246614d75ba1703bdfd5d7660bb57407aaf5d9' ) );
-
- $backendMock->expects( $this->once() )
- ->method( 'getFileContentsMulti' )
- ->will( $this->returnValue( [ $sha1Path => 'foo' ] ) );
-
- $result = $wrapperMock->getFileContentsMulti( [ 'srcs' => [ $filenamePath ] ] );
-
- $this->assertEquals(
- [ $filenamePath => 'foo' ],
- $result,
- 'File contents paths translated properly'
- );
- }
-
- protected function getMocks() {
- $dbMock = $this->getMockBuilder( Wikimedia\Rdbms\IDatabase::class )
- ->disableOriginalClone()
- ->disableOriginalConstructor()
- ->getMock();
-
- $backendMock = $this->getMockBuilder( FSFileBackend::class )
- ->setConstructorArgs( [ [
- 'name' => $this->backendName,
- 'wikiId' => wfWikiID()
- ] ] )
- ->getMock();
-
- $wrapperMock = $this->getMockBuilder( FileBackendDBRepoWrapper::class )
- ->setMethods( [ 'getDB' ] )
- ->setConstructorArgs( [ [
- 'backend' => $backendMock,
- 'repoName' => $this->repoName,
- 'dbHandleFactory' => null
- ] ] )
- ->getMock();
-
- $wrapperMock->expects( $this->any() )->method( 'getDB' )->will( $this->returnValue( $dbMock ) );
-
- return [ $dbMock, $backendMock, $wrapperMock ];
- }
-}
--- /dev/null
+<?php
+
+/**
+ * Code to test the getFallbackFor, getFallbacksFor, and getFallbacksIncludingSiteLanguage methods
+ * that have historically been static methods of the Language class. It can be used to test any
+ * class or object that implements those three methods.
+ */
+trait LanguageFallbackTestTrait {
+ /**
+ * @param array $options Valid keys:
+ * * expectedGets: How many times we expect to hit the localisation cache. (This can be
+ * ignored in integration tests -- it's enough to test in unit tests.)
+ * * siteLangCode
+ * @return string|object Name of class or object with the three methods getFallbackFor,
+ * getFallbacksFor, and getFallbacksIncludingSiteLanguage.
+ */
+ abstract protected function getCallee( array $options = [] );
+
+ /**
+ * @return int Value that was historically in Language::MESSAGES_FALLBACKS
+ */
+ abstract protected function getMessagesKey();
+
+ /**
+ * @return int Value that was historically in Language::STRICT_FALLBACKS
+ */
+ abstract protected function getStrictKey();
+
+ /**
+ * Convenience/readability wrapper to call a method on a class or object.
+ *
+ * @param string|object As in return value of getCallee()
+ * @param string $method Name of method to call
+ * @param mixed ...$params To pass to method
+ * @return mixed Return value of method
+ */
+ private function callMethod( $callee, $method, ...$params ) {
+ return [ $callee, $method ]( ...$params );
+ }
+
+ /**
+ * @param string $code
+ * @param array $expected
+ * @param array $options
+ * @dataProvider provideGetFallbacksFor
+ * @covers ::getFallbackFor
+ * @covers Language::getFallbackFor
+ */
+ public function testGetFallbackFor( $code, array $expected, array $options = [] ) {
+ $callee = $this->getCallee( $options );
+ // One behavior difference between the old static methods and the new instance methods:
+ // returning null instead of false.
+ $defaultExpected = is_object( $callee ) ? null : false;
+ $this->assertSame( $expected[0] ?? $defaultExpected,
+ $this->callMethod( $callee, 'getFallbackFor', $code ) );
+ }
+
+ /**
+ * @param string $code
+ * @param array $expected
+ * @param array $options
+ * @dataProvider provideGetFallbacksFor
+ * @covers ::getFallbacksFor
+ * @covers Language::getFallbacksFor
+ */
+ public function testGetFallbacksFor( $code, array $expected, array $options = [] ) {
+ $this->assertSame( $expected,
+ $this->callMethod( $this->getCallee( $options ), 'getFallbacksFor', $code ) );
+ }
+
+ /**
+ * @param string $code
+ * @param array $expected
+ * @param array $options
+ * @dataProvider provideGetFallbacksFor
+ * @covers ::getFallbacksFor
+ * @covers Language::getFallbacksFor
+ */
+ public function testGetFallbacksFor_messages( $code, array $expected, array $options = [] ) {
+ $this->assertSame( $expected,
+ $this->callMethod( $this->getCallee( $options ), 'getFallbacksFor',
+ $code, $this->getMessagesKey() ) );
+ }
+
+ public static function provideGetFallbacksFor() {
+ return [
+ 'en' => [ 'en', [], [ 'expectedGets' => 0 ] ],
+ 'fr' => [ 'fr', [ 'en' ] ],
+ 'sco' => [ 'sco', [ 'en' ] ],
+ 'yi' => [ 'yi', [ 'he', 'en' ] ],
+ 'ruq' => [ 'ruq', [ 'ruq-latn', 'ro', 'en' ] ],
+ 'sh' => [ 'sh', [ 'bs', 'sr-el', 'hr', 'en' ] ],
+ ];
+ }
+
+ /**
+ * @param string $code
+ * @param array $expected
+ * @param array $options
+ * @dataProvider provideGetFallbacksFor_strict
+ * @covers ::getFallbacksFor
+ * @covers Language::getFallbacksFor
+ */
+ public function testGetFallbacksFor_strict( $code, array $expected, array $options = [] ) {
+ $this->assertSame( $expected,
+ $this->callMethod( $this->getCallee( $options ), 'getFallbacksFor',
+ $code, $this->getStrictKey() ) );
+ }
+
+ public static function provideGetFallbacksFor_strict() {
+ return [
+ 'en' => [ 'en', [], [ 'expectedGets' => 0 ] ],
+ 'fr' => [ 'fr', [] ],
+ 'sco' => [ 'sco', [ 'en' ] ],
+ 'yi' => [ 'yi', [ 'he' ] ],
+ 'ruq' => [ 'ruq', [ 'ruq-latn', 'ro' ] ],
+ 'sh' => [ 'sh', [ 'bs', 'sr-el', 'hr' ] ],
+ ];
+ }
+
+ /**
+ * @covers ::getFallbacksFor
+ * @covers Language::getFallbacksFor
+ */
+ public function testGetFallbacksFor_exception() {
+ $this->setExpectedException( MWException::class, 'Invalid fallback mode "7"' );
+
+ $callee = $this->getCallee( [ 'expectedGets' => 0 ] );
+
+ // These should not throw, because of short-circuiting. If they do, it will fail the test,
+ // because we pass 5 and 6 instead of 7.
+ $this->callMethod( $callee, 'getFallbacksFor', 'en', 5 );
+ $this->callMethod( $callee, 'getFallbacksFor', '!!!', 6 );
+
+ // This is the one that should throw.
+ $this->callMethod( $callee, 'getFallbacksFor', 'fr', 7 );
+ }
+
+ /**
+ * @param string $code
+ * @param string $siteLangCode
+ * @param array $expected
+ * @param int $expectedGets
+ * @dataProvider provideGetFallbacksIncludingSiteLanguage
+ * @covers ::getFallbacksIncludingSiteLanguage
+ * @covers Language::getFallbacksIncludingSiteLanguage
+ */
+ public function testGetFallbacksIncludingSiteLanguage(
+ $code, $siteLangCode, array $expected, $expectedGets = 1
+ ) {
+ $callee = $this->getCallee(
+ [ 'siteLangCode' => $siteLangCode, 'expectedGets' => $expectedGets ] );
+ $this->assertSame( $expected,
+ $this->callMethod( $callee, 'getFallbacksIncludingSiteLanguage', $code ) );
+
+ // Call again to make sure we don't call LocalisationCache again
+ $this->callMethod( $callee, 'getFallbacksIncludingSiteLanguage', $code );
+ }
+
+ public static function provideGetFallbacksIncludingSiteLanguage() {
+ return [
+ 'en on en' => [ 'en', 'en', [ [], [ 'en' ] ], 0 ],
+ 'fr on en' => [ 'fr', 'en', [ [ 'en' ], [] ] ],
+ 'en on fr' => [ 'en', 'fr', [ [], [ 'fr', 'en' ] ] ],
+ 'fr on fr' => [ 'fr', 'fr', [ [ 'en' ], [ 'fr' ] ] ],
+
+ 'sco on en' => [ 'sco', 'en', [ [ 'en' ], [] ] ],
+ 'en on sco' => [ 'en', 'sco', [ [], [ 'sco', 'en' ] ] ],
+ 'sco on sco' => [ 'sco', 'sco', [ [ 'en' ], [ 'sco' ] ] ],
+
+ 'fr on sco' => [ 'fr', 'sco', [ [ 'en' ], [ 'sco' ] ], 2 ],
+ 'sco on fr' => [ 'sco', 'fr', [ [ 'en' ], [ 'fr' ] ], 2 ],
+
+ 'fr on yi' => [ 'fr', 'yi', [ [ 'en' ], [ 'yi', 'he' ] ], 2 ],
+ 'yi on fr' => [ 'yi', 'fr', [ [ 'he', 'en' ], [ 'fr' ] ], 2 ],
+ 'yi on yi' => [ 'yi', 'yi', [ [ 'he', 'en' ], [ 'yi' ] ] ],
+
+ 'sh on ruq' => [ 'sh', 'ruq',
+ [ [ 'bs', 'sr-el', 'hr', 'en' ], [ 'ruq', 'ruq-latn', 'ro' ] ], 2 ],
+ 'ruq on sh' => [ 'ruq', 'sh',
+ [ [ 'ruq-latn', 'ro', 'en' ], [ 'sh', 'bs', 'sr-el', 'hr' ] ], 2 ],
+ ];
+ }
+}
+++ /dev/null
-<?php
-
-use MediaWiki\Config\ServiceOptions;
-use MediaWiki\Languages\LanguageNameUtils;
-
-class LanguageNameUtilsTest extends MediaWikiUnitTestCase {
- /**
- * @param array $optionsArray
- */
- private static function newObj( array $optionsArray = [] ) : LanguageNameUtils {
- return new LanguageNameUtils( new ServiceOptions(
- LanguageNameUtils::$constructorOptions,
- $optionsArray,
- [
- 'ExtraLanguageNames' => [],
- 'LanguageCode' => 'en',
- 'UsePigLatinVariant' => false,
- ]
- ) );
- }
-
- use LanguageNameUtilsTestTrait;
-
- private function isSupportedLanguage( $code ) {
- return $this->newObj()->isSupportedLanguage( $code );
- }
-
- private function isValidCode( $code ) {
- return $this->newObj()->isValidCode( $code );
- }
-
- private function isValidBuiltInCode( $code ) {
- return $this->newObj()->isValidBuiltInCode( $code );
- }
-
- private function isKnownLanguageTag( $code ) {
- return $this->newObj()->isKnownLanguageTag( $code );
- }
-
- private function assertGetLanguageNames( array $options, $expected, $code, ...$otherArgs ) {
- $this->assertSame( $expected, $this->newObj( $options )
- ->getLanguageNames( ...$otherArgs )[strtolower( $code )] ?? '' );
- $this->assertSame( $expected,
- $this->newObj( $options )->getLanguageName( $code, ...$otherArgs ) );
- }
-
- private function getLanguageNames( ...$args ) {
- return $this->newObj()->getLanguageNames( ...$args );
- }
-
- private function getLanguageName( ...$args ) {
- return $this->newObj()->getLanguageName( ...$args );
- }
-
- private static function getFileName( ...$args ) {
- return self::newObj()->getFileName( ...$args );
- }
-
- private static function getMessagesFileName( $code ) {
- return self::newObj()->getMessagesFileName( $code );
- }
-
- private static function getJsonMessagesFileName( $code ) {
- return self::newObj()->getJsonMessagesFileName( $code );
- }
-}
+++ /dev/null
-<?php
-
-use MediaWiki\Languages\LanguageNameUtils;
-
-const AUTONYMS = LanguageNameUtils::AUTONYMS;
-const ALL = LanguageNameUtils::ALL;
-const DEFINED = LanguageNameUtils::DEFINED;
-const SUPPORTED = LanguageNameUtils::SUPPORTED;
-
-/**
- * For code shared between LanguageNameUtilsTest and LanguageTest.
- */
-trait LanguageNameUtilsTestTrait {
- abstract protected function isSupportedLanguage( $code );
-
- /**
- * @dataProvider provideIsSupportedLanguage
- * @covers MediaWiki\Languages\LanguageNameUtils::__construct
- * @covers MediaWiki\Languages\LanguageNameUtils::isSupportedLanguage
- * @covers Language::isSupportedLanguage
- */
- public function testIsSupportedLanguage( $code, $expected ) {
- $this->assertSame( $expected, $this->isSupportedLanguage( $code ) );
- }
-
- public static function provideIsSupportedLanguage() {
- return [
- 'en' => [ 'en', true ],
- 'fi' => [ 'fi', true ],
- 'bunny' => [ 'bunny', false ],
- 'qqq' => [ 'qqq', false ],
- 'uppercase is not considered supported' => [ 'FI', false ],
- ];
- }
-
- abstract protected function isValidCode( $code );
-
- /**
- * We don't test that the result is cached, because that should only be noticeable if the
- * configuration changes in between calls, and 1) that should never happen in normal operation,
- * 2) if you do it you deserve whatever you get, and 3) once the static Language method is
- * dropped and the invalid title regex is moved to something injected instead of a static call,
- * the cache will be undetectable.
- *
- * @todo Should we test changes to $wgLegalTitleChars here? Does anybody actually change that?
- * Is it possible to change it usefully without breaking everything?
- *
- * @dataProvider provideIsValidCode
- * @covers MediaWiki\Languages\LanguageNameUtils::isValidCode
- * @covers Language::isValidCode
- *
- * @param string $code
- * @param bool $expected
- */
- public function testIsValidCode( $code, $expected ) {
- $this->assertSame( $expected, $this->isValidCode( $code ) );
- }
-
- public static function provideIsValidCode() {
- $ret = [
- 'en' => [ 'en', true ],
- 'en-GB' => [ 'en-GB', true ],
- 'Funny chars' => [ "%!$()*,-.;=?@^_`~\x80\xA2\xFF+", true ],
- 'Percent escape not allowed' => [ 'a%aF', false ],
- 'Percent with only one following char is okay' => [ '%a', true ],
- 'Percent with non-hex following chars is okay' => [ '%AG', true ],
- 'Named char reference "a"' => [ 'a&a', false ],
- 'Named char reference "A"' => [ 'a&A', false ],
- 'Named char reference "0"' => [ 'a&0', false ],
- 'Named char reference non-ASCII' => [ "a&\x92", false ],
- 'Numeric char reference' => [ "a�", false ],
- 'Hex char reference 0' => [ "a�", false ],
- 'Hex char reference A' => [ "a
", false ],
- 'Lone ampersand is valid for title but not lang code' => [ '&', false ],
- 'Ampersand followed by just # is valid for title but not lang code' => [ '&#', false ],
- 'Ampersand followed by # and non-x/digit is valid for title but not lang code' =>
- [ '&#a', false ],
- ];
- $disallowedChars = ":/\\\000&<>'\"";
- foreach ( str_split( $disallowedChars ) as $char ) {
- $ret["Disallowed character $char"] = [ "a{$char}a", false ];
- }
- return $ret;
- }
-
- abstract protected function isValidBuiltInCode( $code );
-
- /**
- * @dataProvider provideIsValidBuiltInCode
- * @covers MediaWiki\Languages\LanguageNameUtils::isValidBuiltInCode
- * @covers Language::isValidBuiltInCode
- *
- * @param string $code
- * @param bool $expected
- */
- public function testIsValidBuiltInCode( $code, $expected ) {
- $this->assertSame( $expected, $this->isValidBuiltInCode( $code ) );
- }
-
- public static function provideIsValidBuiltInCode() {
- return [
- 'Two letters, lowercase' => [ 'fr', true ],
- 'Two letters, uppercase' => [ 'EN', false ],
- 'Three letters' => [ 'tyv', true ],
- 'With dash' => [ 'be-tarask', true ],
- 'With extension (two dashes)' => [ 'be-x-old', true ],
- 'Reject underscores' => [ 'be_tarask', false ],
- 'One letter' => [ 'a', false ],
- 'Only digits' => [ '00', true ],
- 'Only dashes' => [ '--', true ],
- 'Unreasonably long' => [ str_repeat( 'x', 100 ), true ],
- 'qqq' => [ 'qqq', true ],
- ];
- }
-
- abstract protected function isKnownLanguageTag( $code );
-
- /**
- * @dataProvider provideIsKnownLanguageTag
- * @covers MediaWiki\Languages\LanguageNameUtils::isKnownLanguageTag
- * @covers Language::isKnownLanguageTag
- *
- * @param string $code
- * @param bool $expected
- */
- public function testIsKnownLanguageTag( $code, $expected ) {
- $this->assertSame( $expected, $this->isKnownLanguageTag( $code ) );
- }
-
- public static function provideIsKnownLanguageTag() {
- $invalidBuiltInCodes = array_filter( static::provideIsValidBuiltInCode(),
- function ( $arr ) {
- // If isValidBuiltInCode() returns false, we want to also, but if it returns true,
- // we could still return false from isKnownLanguageTag(), so skip those.
- return !$arr[1];
- }
- );
- return array_merge( $invalidBuiltInCodes, [
- 'Simple code' => [ 'fr', true ],
- 'An MW legacy tag' => [ 'bat-smg', true ],
- 'An internal standard MW name, for which a legacy tag is used externally' =>
- [ 'sgs', true ],
- 'Non-existent two-letter code' => [ 'mw', false ],
- 'Very invalid language code' => [ 'foo"<bar', false ],
- ] );
- }
-
- abstract protected function assertGetLanguageNames(
- array $options, $expected, $code, ...$otherArgs
- );
-
- abstract protected function getLanguageNames( ...$args );
-
- abstract protected function getLanguageName( ...$args );
-
- /**
- * @dataProvider provideGetLanguageNames
- * @covers MediaWiki\Languages\LanguageNameUtils::getLanguageNames
- * @covers MediaWiki\Languages\LanguageNameUtils::getLanguageNamesUncached
- * @covers MediaWiki\Languages\LanguageNameUtils::getLanguageName
- * @covers Language::fetchLanguageNames
- * @covers Language::fetchLanguageName
- *
- * @param string $expected
- * @param string $code
- * @param mixed ...$otherArgs Optionally, pass $inLanguage and/or $include.
- */
- public function testGetLanguageNames( $expected, $code, ...$otherArgs ) {
- $this->assertGetLanguageNames( [], $expected, $code, ...$otherArgs );
- }
-
- public static function provideGetLanguageNames() {
- // @todo There are probably lots of interesting tests to add here.
- return [
- 'Simple code' => [ 'Deutsch', 'de' ],
- 'Simple code in a different language (doesn\'t work without hook)' =>
- [ 'Deutsch', 'de', 'fr' ],
- 'Invalid code' => [ '', '&' ],
- 'Pig Latin not enabled' => [ '', 'en-x-piglatin', AUTONYMS, ALL ],
- 'qqq doesn\'t have a name' => [ '', 'qqq', AUTONYMS, ALL ],
- 'An MW legacy tag is recognized' => [ 'žemaitėška', 'bat-smg' ],
- // @todo Is the next test's result desired?
- 'An MW legacy tag is not supported' => [ '', 'bat-smg', AUTONYMS, SUPPORTED ],
- 'An internal standard name, for which a legacy tag is used externally, is supported' =>
- [ 'žemaitėška', 'sgs', AUTONYMS, SUPPORTED ],
- ];
- }
-
- /**
- * @dataProvider provideGetLanguageNames_withHook
- * @covers MediaWiki\Languages\LanguageNameUtils::getLanguageNames
- * @covers MediaWiki\Languages\LanguageNameUtils::getLanguageNamesUncached
- * @covers MediaWiki\Languages\LanguageNameUtils::getLanguageName
- * @covers Language::fetchLanguageNames
- * @covers Language::fetchLanguageName
- *
- * @param string $expected Expected return value of getLanguageName()
- * @param string $code
- * @param mixed ...$otherArgs Optionally, pass $inLanguage and/or $include.
- */
- public function testGetLanguageNames_withHook( $expected, $code, ...$otherArgs ) {
- $this->setTemporaryHook( 'LanguageGetTranslatedLanguageNames',
- function ( &$names, $inLanguage ) {
- switch ( $inLanguage ) {
- case 'de':
- $names = [
- 'de' => 'Deutsch',
- 'en' => 'Englisch',
- 'fr' => 'Französisch',
- ];
- break;
-
- case 'en':
- $names = [
- 'de' => 'German',
- 'en' => 'English',
- 'fr' => 'French',
- 'sqsqsqsq' => '!!?!',
- 'bat-smg' => 'Samogitian',
- ];
- break;
-
- case 'fr':
- $names = [
- 'de' => 'allemand',
- 'en' => 'anglais',
- // Deliberate mistake (no cedilla)
- 'fr' => 'francais',
- ];
- break;
- }
- }
- );
-
- // Really we could dispense with assertGetLanguageNames() and just call
- // testGetLanguageNames() here, but it looks weird to call a test method from another test
- // method.
- $this->assertGetLanguageNames( [], $expected, $code, ...$otherArgs );
- }
-
- public static function provideGetLanguageNames_withHook() {
- return [
- 'Simple code in a different language' => [ 'allemand', 'de', 'fr' ],
- 'Invalid inLanguage defaults to English' => [ 'German', 'de', '&' ],
- 'If inLanguage not provided, default to autonym' => [ 'Deutsch', 'de' ],
- 'Hooks ignored for explicitly-requested autonym' => [ 'français', 'fr', 'fr' ],
- 'Hooks don\'t make a language supported' => [ '', 'bat-smg', 'en', SUPPORTED ],
- 'Hooks don\'t make a language defined' => [ '', 'sqsqsqsq', 'en', DEFINED ],
- 'Hooks do make a language name returned with ALL' => [ '!!?!', 'sqsqsqsq', 'en', ALL ],
- ];
- }
-
- /**
- * @dataProvider provideGetLanguageNames_ExtraLanguageNames
- * @covers MediaWiki\Languages\LanguageNameUtils::getLanguageNames
- * @covers MediaWiki\Languages\LanguageNameUtils::getLanguageNamesUncached
- * @covers MediaWiki\Languages\LanguageNameUtils::getLanguageName
- * @covers Language::fetchLanguageNames
- * @covers Language::fetchLanguageName
- *
- * @param string $expected Expected return value of getLanguageName()
- * @param string $code
- * @param mixed ...$otherArgs Optionally, pass $inLanguage and/or $include.
- */
- public function testGetLanguageNames_ExtraLanguageNames( $expected, $code, ...$otherArgs ) {
- $this->setTemporaryHook( 'LanguageGetTranslatedLanguageNames',
- function ( &$names ) {
- $names['de'] = 'die deutsche Sprache';
- }
- );
- $this->assertGetLanguageNames(
- [ 'ExtraLanguageNames' => [ 'de' => 'deutsche Sprache', 'sqsqsqsq' => '!!?!' ] ],
- $expected, $code, ...$otherArgs
- );
- }
-
- public static function provideGetLanguageNames_ExtraLanguageNames() {
- return [
- 'Simple extra language name' => [ '!!?!', 'sqsqsqsq' ],
- 'Extra language is defined' => [ '!!?!', 'sqsqsqsq', AUTONYMS, DEFINED ],
- 'Extra language is not supported' => [ '', 'sqsqsqsq', AUTONYMS, SUPPORTED ],
- 'Extra language overrides default' => [ 'deutsche Sprache', 'de' ],
- 'Extra language overrides hook for explicitly requested autonym' =>
- [ 'deutsche Sprache', 'de', 'de' ],
- 'Hook overrides extra language for non-autonym' =>
- [ 'die deutsche Sprache', 'de', 'fr' ],
- ];
- }
-
- /**
- * Test that getLanguageNames() defaults to DEFINED, and getLanguageName() defaults to ALL.
- *
- * @covers MediaWiki\Languages\LanguageNameUtils::getLanguageNames
- * @covers MediaWiki\Languages\LanguageNameUtils::getLanguageNamesUncached
- * @covers MediaWiki\Languages\LanguageNameUtils::getLanguageName
- * @covers Language::fetchLanguageNames
- * @covers Language::fetchLanguageName
- */
- public function testGetLanguageNames_parameterDefault() {
- $this->setTemporaryHook( 'LanguageGetTranslatedLanguageNames',
- function ( &$names ) {
- $names = [ 'sqsqsqsq' => '!!?!' ];
- }
- );
-
- // We use 'en' here because the hook is not run if we're requesting autonyms, although in
- // this case (language that isn't defined by MediaWiki itself) that behavior seems wrong.
- $this->assertArrayNotHasKey( 'sqsqsqsq', $this->getLanguageNames(), 'en' );
-
- $this->assertSame( '!!?!', $this->getLanguageName( 'sqsqsqsq', 'en' ) );
- }
-
- /**
- * @dataProvider provideGetLanguageNames_sorted
- * @covers MediaWiki\Languages\LanguageNameUtils::getLanguageNames
- * @covers MediaWiki\Languages\LanguageNameUtils::getLanguageNamesUncached
- * @covers Language::fetchLanguageNames
- *
- * @param mixed ...$args To pass to method
- */
- public function testGetLanguageNames_sorted( ...$args ) {
- $names = $this->getLanguageNames( ...$args );
- $sortedNames = $names;
- ksort( $sortedNames );
- $this->assertSame( $sortedNames, $names );
- }
-
- public static function provideGetLanguageNames_sorted() {
- return [
- [],
- [ AUTONYMS ],
- [ AUTONYMS, 'mw' ],
- [ AUTONYMS, ALL ],
- [ AUTONYMS, SUPPORTED ],
- [ 'he', 'mw' ],
- [ 'he', ALL ],
- [ 'he', SUPPORTED ],
- ];
- }
-
- /**
- * @covers MediaWiki\Languages\LanguageNameUtils::getLanguageNames
- * @covers MediaWiki\Languages\LanguageNameUtils::getLanguageNamesUncached
- * @covers Language::fetchLanguageNames
- */
- public function testGetLanguageNames_hookNotCalledForAutonyms() {
- $count = 0;
- $this->setTemporaryHook( 'LanguageGetTranslatedLanguageNames',
- function () use ( &$count ) {
- $count++;
- }
- );
-
- $this->getLanguageNames();
- $this->assertSame( 0, $count, 'Hook must not be called for autonyms' );
-
- // We test elsewhere that the hook works, but the following verifies that our test is
- // working and $count isn't being incremented above only because we're checking autonyms.
- $this->getLanguageNames( 'fr' );
- $this->assertSame( 1, $count, 'Hook must be called for non-autonyms' );
- }
-
- /**
- * @dataProvider provideGetLanguageNames_pigLatin
- * @covers MediaWiki\Languages\LanguageNameUtils::getLanguageNames
- * @covers MediaWiki\Languages\LanguageNameUtils::getLanguageNamesUncached
- * @covers MediaWiki\Languages\LanguageNameUtils::getLanguageName
- * @covers Language::fetchLanguageNames
- * @covers Language::fetchLanguageName
- *
- * @param string $expected
- * @param mixed ...$otherArgs Optionally, pass $inLanguage and/or $include.
- */
- public function testGetLanguageNames_pigLatin( $expected, ...$otherArgs ) {
- $this->setTemporaryHook( 'LanguageGetTranslatedLanguageNames',
- function ( &$names, $inLanguage ) {
- switch ( $inLanguage ) {
- case 'fr':
- $names = [ 'en-x-piglatin' => 'latin de cochons' ];
- break;
-
- case 'en-x-piglatin':
- // Deliberately lowercase
- $names = [ 'en-x-piglatin' => 'igpay atinlay' ];
- break;
- }
- }
- );
-
- $this->assertGetLanguageNames(
- [ 'UsePigLatinVariant' => true ], $expected, 'en-x-piglatin', ...$otherArgs );
- }
-
- public static function provideGetLanguageNames_pigLatin() {
- return [
- 'Simple test' => [ 'Igpay Atinlay' ],
- 'Not supported' => [ '', AUTONYMS, SUPPORTED ],
- 'Foreign language' => [ 'latin de cochons', 'fr' ],
- 'Hook doesn\'t override explicit autonym' =>
- [ 'Igpay Atinlay', 'en-x-piglatin', 'en-x-piglatin' ],
- ];
- }
-
- /**
- * Just for the sake of completeness, test that ExtraLanguageNames will not override the name
- * for pig Latin. Nobody actually cares about this and if anything current behavior is probably
- * wrong, but once we're testing the whole file we may as well be comprehensive.
- *
- * @covers MediaWiki\Languages\LanguageNameUtils::getLanguageNames
- * @covers MediaWiki\Languages\LanguageNameUtils::getLanguageNamesUncached
- * @covers MediaWiki\Languages\LanguageNameUtils::getLanguageName
- * @covers Language::fetchLanguageNames
- * @covers Language::fetchLanguageName
- */
- public function testGetLanguageNames_pigLatinAndExtraLanguageNames() {
- $this->assertGetLanguageNames(
- [
- 'UsePigLatinVariant' => true,
- 'ExtraLanguageNames' => [ 'en-x-piglatin' => 'igpay atinlay' ]
- ],
- 'Igpay Atinlay',
- 'en-x-piglatin'
- );
- }
-
- abstract protected static function getFileName( ...$args );
-
- /**
- * @dataProvider provideGetFileName
- * @covers MediaWiki\Languages\LanguageNameUtils::getFileName
- * @covers Language::getFileName
- *
- * @param string $expected
- * @param mixed ...$args To pass to method
- */
- public function testGetFileName( $expected, ...$args ) {
- $this->assertSame( $expected, $this->getFileName( ...$args ) );
- }
-
- public static function provideGetFileName() {
- return [
- 'Simple case' => [ 'MessagesXx.php', 'Messages', 'xx' ],
- 'With extension' => [ 'MessagesXx.ext', 'Messages', 'xx', '.ext' ],
- 'Replacing dashes' => [ '!__?', '!', '--', '?' ],
- 'Empty prefix and extension' => [ 'Xx', '', 'xx', '' ],
- 'Uppercase only first letter' => [ 'Messages_a.php', 'Messages', '-a' ],
- ];
- }
-
- abstract protected function getMessagesFileName( $code );
-
- /**
- * @dataProvider provideGetMessagesFileName
- * @covers MediaWiki\Languages\LanguageNameUtils::getMessagesFileName
- * @covers Language::getMessagesFileName
- *
- * @param string $code
- * @param string $expected
- */
- public function testGetMessagesFileName( $code, $expected ) {
- $this->assertSame( $expected, $this->getMessagesFileName( $code ) );
- }
-
- public static function provideGetMessagesFileName() {
- global $IP;
- return [
- 'Simple case' => [ 'en', "$IP/languages/messages/MessagesEn.php" ],
- 'Replacing dashes' => [ '--', "$IP/languages/messages/Messages__.php" ],
- 'Uppercase only first letter' => [ '-a', "$IP/languages/messages/Messages_a.php" ],
- ];
- }
-
- /**
- * @covers MediaWiki\Languages\LanguageNameUtils::getMessagesFileName
- * @covers Language::getMessagesFileName
- */
- public function testGetMessagesFileName_withHook() {
- $called = 0;
-
- $this->setTemporaryHook( 'Language::getMessagesFileName',
- function ( $code, &$file ) use ( &$called ) {
- global $IP;
-
- $called++;
-
- $this->assertSame( 'ab-cd', $code );
- $this->assertSame( "$IP/languages/messages/MessagesAb_cd.php", $file );
- $file = 'bye-bye';
- }
- );
-
- $this->assertSame( 'bye-bye', $this->getMessagesFileName( 'ab-cd' ) );
- $this->assertSame( 1, $called );
- }
-
- abstract protected function getJsonMessagesFileName( $code );
-
- /**
- * @covers MediaWiki\Languages\LanguageNameUtils::getJsonMessagesFileName
- * @covers Language::getJsonMessagesFileName
- */
- public function testGetJsonMessagesFileName() {
- global $IP;
-
- // Not so much to test here, one test seems to be enough
- $expected = "$IP/languages/i18n/en--123.json";
- $this->assertSame( $expected, $this->getJsonMessagesFileName( 'en--123' ) );
- }
-
- /**
- * getFileName, getMessagesFileName, and getJsonMessagesFileName all throw if they get an
- * invalid code. To save boilerplate, test them all in one method.
- *
- * @dataProvider provideExceptionFromInvalidCode
- * @covers MediaWiki\Languages\LanguageNameUtils::getFileName
- * @covers MediaWiki\Languages\LanguageNameUtils::getMessagesFileName
- * @covers MediaWiki\Languages\LanguageNameUtils::getJsonMessagesFileName
- * @covers Language::getFileName
- * @covers Language::getMessagesFileName
- * @covers Language::getJsonMessagesFileName
- *
- * @param callable $callback Will throw when passed $code
- * @param string $code
- */
- public function testExceptionFromInvalidCode( $callback, $code ) {
- $this->setExpectedException( MWException::class, "Invalid language code \"$code\"" );
-
- $callback( $code );
- }
-
- public static function provideExceptionFromInvalidCode() {
- $ret = [];
- foreach ( static::provideIsValidBuiltInCode() as $desc => list( $code, $valid ) ) {
- if ( $valid ) {
- // Won't get an exception from this one
- continue;
- }
-
- // For getFileName, we define an anonymous function because of the extra first param
- $ret["getFileName: $desc"] = [
- function ( $code ) {
- return static::getFileName( 'Messages', $code );
- },
- $code
- ];
-
- $ret["getMessagesFileName: $desc"] =
- [ [ static::class, 'getMessagesFileName' ], $code ];
-
- $ret["getJsonMessagesFileName: $desc"] =
- [ [ static::class, 'getJsonMessagesFileName' ], $code ];
- }
- return $ret;
- }
-}
--- /dev/null
+<?php
+
+require_once __DIR__ . '/TestFileJournal.php';
+
+use Wikimedia\Timestamp\ConvertibleTimestamp;
+
+/**
+ * @coversDefaultClass FileJournal
+ */
+class FileJournalTest extends MediaWikiUnitTestCase {
+ private function newObj( $options = [], $backend = '' ) {
+ return FileJournal::factory(
+ $options + [ 'class' => TestFileJournal::class ],
+ $backend
+ );
+ }
+
+ /**
+ * @covers ::factory
+ */
+ public function testConstructor_backend() {
+ $this->assertSame( 'some_backend', $this->newObj( [], 'some_backend' )->getBackend() );
+ }
+
+ /**
+ * @covers ::__construct
+ * @covers ::factory
+ */
+ public function testConstructor_ttlDays() {
+ $this->assertSame( 42, $this->newObj( [ 'ttlDays' => 42 ] )->getTtlDays() );
+ }
+
+ /**
+ * @covers ::__construct
+ * @covers ::factory
+ */
+ public function testConstructor_noTtlDays() {
+ $this->assertSame( false, $this->newObj()->getTtlDays() );
+ }
+
+ /**
+ * @covers ::__construct
+ * @covers ::factory
+ */
+ public function testConstructor_nullTtlDays() {
+ $this->assertSame( false, $this->newObj( [ 'ttlDays' => null ] )->getTtlDays() );
+ }
+
+ /**
+ * @covers ::factory
+ */
+ public function testFactory_invalidClass() {
+ $this->setExpectedException( UnexpectedValueException::class,
+ 'Expected instance of FileJournal, got stdClass' );
+
+ FileJournal::factory( [ 'class' => 'stdclass' ], '' );
+ }
+
+ /**
+ * @covers ::getTimestampedUUID
+ */
+ public function testGetTimestampedUUID() {
+ $obj = FileJournal::factory( [ 'class' => 'NullFileJournal' ], '' );
+ $uuids = [];
+ for ( $i = 0; $i < 10; $i++ ) {
+ $time1 = time();
+ $uuid = $obj->getTimestampedUUID();
+ $time2 = time();
+ $this->assertRegexp( '/^[0-9a-z]{31}$/', $uuid );
+ $this->assertArrayNotHasKey( $uuid, $uuids );
+ $uuids[$uuid] = true;
+
+ // Now test that the timestamp portion is as expected.
+ $time = ConvertibleTimestamp::convert( TS_UNIX, Wikimedia\base_convert(
+ substr( $uuid, 0, 9 ), 36, 10 ) );
+
+ $this->assertGreaterThanOrEqual( $time1, $time );
+ $this->assertLessThanOrEqual( $time2, $time );
+ }
+ }
+
+ /**
+ * @covers ::logChangeBatch
+ */
+ public function testLogChangeBatch() {
+ $this->assertEquals(
+ StatusValue::newGood( 'Logged' ), $this->newObj()->logChangeBatch( [ 1 ], '' ) );
+ }
+
+ /**
+ * @covers ::logChangeBatch
+ */
+ public function testLogChangeBatch_empty() {
+ $this->assertEquals( StatusValue::newGood(), $this->newObj()->logChangeBatch( [], '' ) );
+ }
+
+ /**
+ * @covers ::getCurrentPosition
+ */
+ public function testGetCurrentPosition() {
+ $this->assertEquals( 613, $this->newObj()->getCurrentPosition() );
+ }
+
+ /**
+ * @covers ::getPositionAtTime
+ */
+ public function testGetPositionAtTime() {
+ $this->assertEquals( 248, $this->newObj()->getPositionAtTime( 0 ) );
+ }
+
+ /**
+ * @dataProvider provideGetChangeEntries
+ * @covers ::getChangeEntries
+ * @param int|null $start
+ * @param int $limit
+ * @param string|null $expectedNext
+ * @param string[] $expectedReturn Expected id's of returned values
+ */
+ public function testGetChangeEntries( $start, $limit, $expectedNext, array $expectedReturn ) {
+ $expectedReturn = array_map(
+ function ( $val ) {
+ return [ 'id' => $val ];
+ }, $expectedReturn
+ );
+ $next = "Different from $expectedNext";
+ $ret = $this->newObj()->getChangeEntries( $start, $limit, $next );
+ $this->assertSame( $expectedNext, $next );
+ $this->assertSame( $expectedReturn, $ret );
+ }
+
+ public static function provideGetChangeEntries() {
+ return [
+ [ null, 0, null, [ 1, 2, 3 ] ],
+ [ null, 1, 2, [ 1 ] ],
+ [ null, 2, 3, [ 1, 2 ] ],
+ [ null, 3, null, [ 1, 2, 3 ] ],
+ [ 1, 0, null, [ 1, 2, 3 ] ],
+ [ 1, 2, 3, [ 1, 2 ] ],
+ [ 1, 1, 2, [ 1 ] ],
+ [ 2, 2, null, [ 2, 3 ] ],
+ ];
+ }
+
+ /**
+ * @covers ::purgeOldLogs
+ */
+ public function testPurgeOldLogs() {
+ $obj = $this->newObj();
+ $this->assertFalse( $obj->getPurged() );
+ $obj->purgeOldLogs();
+ $this->assertTrue( $obj->getPurged() );
+ }
+}
--- /dev/null
+<?php
+
+/**
+ * @coversDefaultClass NullFileJournal
+ */
+class NullFileJournalTest extends MediaWikiUnitTestCase {
+ public function newObj() : NullFileJournal {
+ return FileJournal::factory( [ 'class' => NullFileJournal::class ], '' );
+ }
+
+ /**
+ * @covers ::doLogChangeBatch
+ */
+ public function testLogChangeBatch() {
+ $this->assertEquals( StatusValue::newGood(), $this->newObj()->logChangeBatch( [ 1 ], '' ) );
+ }
+
+ /**
+ * @covers ::doGetCurrentPosition
+ */
+ public function testGetCurrentPosition() {
+ $this->assertFalse( $this->newObj()->getCurrentPosition() );
+ }
+
+ /**
+ * @covers ::doGetPositionAtTime
+ */
+ public function testGetPositionAtTime() {
+ $this->assertFalse( $this->newObj()->getPositionAtTime( 2 ) );
+ }
+
+ /**
+ * @covers ::doGetChangeEntries
+ */
+ public function testGetChangeEntries() {
+ $next = 1;
+ $entries = $this->newObj()->getChangeEntries( null, 0, $next );
+ $this->assertSame( [], $entries );
+ $this->assertNull( $next );
+ }
+
+ /**
+ * @covers ::doPurgeOldLogs
+ */
+ public function testPurgeOldLogs() {
+ $this->assertEquals( StatusValue::newGood(), $this->newObj()->purgeOldLogs() );
+ }
+}
--- /dev/null
+<?php
+
+class TestFileJournal extends NullFileJournal {
+ /** @var bool */
+ private $purged = false;
+
+ public function getTtlDays() {
+ return $this->ttlDays;
+ }
+
+ public function getBackend() {
+ return $this->backend;
+ }
+
+ protected function doLogChangeBatch( array $entries, $batchId ) {
+ return StatusValue::newGood( 'Logged' );
+ }
+
+ protected function doGetCurrentPosition() {
+ return 613;
+ }
+
+ protected function doGetPositionAtTime( $time ) {
+ return 248;
+ }
+
+ protected function doGetChangeEntries( $start, $limit ) {
+ return array_slice( [
+ [ 'id' => 1 ],
+ [ 'id' => 2 ],
+ [ 'id' => 3 ],
+ ], $start === null ? 0 : $start - 1, $limit ? $limit : null );
+ }
+
+ protected function doPurgeOldLogs() {
+ $this->purged = true;
+ }
+
+ public function getPurged() {
+ return $this->purged;
+ }
+}
+++ /dev/null
-<?php
-/**
- * @todo Could use a test of extended XMP segments. Hard to find programs that
- * create example files, and creating my own in vim propbably wouldn't
- * serve as a very good "test". (Adobe photoshop probably creates such files
- * but it costs money). The implementation of it currently in MediaWiki is based
- * solely on reading the standard, without any real world test files.
- *
- * @group Media
- * @covers JpegMetadataExtractor
- */
-class JpegMetadataExtractorTest extends MediaWikiUnitTestCase {
-
- protected $filePath;
-
- protected function setUp() {
- parent::setUp();
-
- $this->filePath = __DIR__ . '/../../../data/media/';
- }
-
- /**
- * We also use this test to test padding bytes don't
- * screw stuff up
- *
- * @param string $file Filename
- *
- * @dataProvider provideUtf8Comment
- */
- public function testUtf8Comment( $file ) {
- $res = JpegMetadataExtractor::segmentSplitter( $this->filePath . $file );
- $this->assertEquals( [ 'UTF-8 JPEG Comment — ¼' ], $res['COM'] );
- }
-
- public static function provideUtf8Comment() {
- return [
- [ 'jpeg-comment-utf.jpg' ],
- [ 'jpeg-padding-even.jpg' ],
- [ 'jpeg-padding-odd.jpg' ],
- ];
- }
-
- /** The file is iso-8859-1, but it should get auto converted */
- public function testIso88591Comment() {
- $res = JpegMetadataExtractor::segmentSplitter( $this->filePath . 'jpeg-comment-iso8859-1.jpg' );
- $this->assertEquals( [ 'ISO-8859-1 JPEG Comment - ¼' ], $res['COM'] );
- }
-
- /** Comment values that are non-textual (random binary junk) should not be shown.
- * The example test file has a comment with a 0x5 byte in it which is a control character
- * and considered binary junk for our purposes.
- */
- public function testBinaryCommentStripped() {
- $res = JpegMetadataExtractor::segmentSplitter( $this->filePath . 'jpeg-comment-binary.jpg' );
- $this->assertEmpty( $res['COM'] );
- }
-
- /* Very rarely a file can have multiple comments.
- * Order of comments is based on order inside the file.
- */
- public function testMultipleComment() {
- $res = JpegMetadataExtractor::segmentSplitter( $this->filePath . 'jpeg-comment-multiple.jpg' );
- $this->assertEquals( [ 'foo', 'bar' ], $res['COM'] );
- }
-
- public function testXMPExtraction() {
- $res = JpegMetadataExtractor::segmentSplitter( $this->filePath . 'jpeg-xmp-psir.jpg' );
- $expected = file_get_contents( $this->filePath . 'jpeg-xmp-psir.xmp' );
- $this->assertEquals( $expected, $res['XMP'] );
- }
-
- public function testPSIRExtraction() {
- $res = JpegMetadataExtractor::segmentSplitter( $this->filePath . 'jpeg-xmp-psir.jpg' );
- $expected = '50686f746f73686f7020332e30003842494d04040000000'
- . '000181c02190004746573741c02190003666f6f1c020000020004';
- $this->assertEquals( $expected, bin2hex( $res['PSIR'][0] ) );
- }
-
- public function testXMPExtractionAltAppId() {
- $res = JpegMetadataExtractor::segmentSplitter( $this->filePath . 'jpeg-xmp-alt.jpg' );
- $expected = file_get_contents( $this->filePath . 'jpeg-xmp-psir.xmp' );
- $this->assertEquals( $expected, $res['XMP'] );
- }
-
- public function testIPTCHashComparisionNoHash() {
- $segments = JpegMetadataExtractor::segmentSplitter( $this->filePath . 'jpeg-xmp-psir.jpg' );
- $res = JpegMetadataExtractor::doPSIR( $segments['PSIR'][0] );
-
- $this->assertEquals( 'iptc-no-hash', $res );
- }
-
- public function testIPTCHashComparisionBadHash() {
- $segments = JpegMetadataExtractor::segmentSplitter( $this->filePath . 'jpeg-iptc-bad-hash.jpg' );
- $res = JpegMetadataExtractor::doPSIR( $segments['PSIR'][0] );
-
- $this->assertEquals( 'iptc-bad-hash', $res );
- }
-
- public function testIPTCHashComparisionGoodHash() {
- $segments = JpegMetadataExtractor::segmentSplitter( $this->filePath . 'jpeg-iptc-good-hash.jpg' );
- $res = JpegMetadataExtractor::doPSIR( $segments['PSIR'][0] );
-
- $this->assertEquals( 'iptc-good-hash', $res );
- }
-
- public function testExifByteOrder() {
- $res = JpegMetadataExtractor::segmentSplitter( $this->filePath . 'exif-user-comment.jpg' );
- $expected = 'BE';
- $this->assertEquals( $expected, $res['byteOrder'] );
- }
-
- public function testInfiniteRead() {
- // test file truncated right after a segment, which previously
- // caused an infinite loop looking for the next segment byte.
- // Should get past infinite loop and throw in wfUnpack()
- $this->setExpectedException( 'MWException' );
- $res = JpegMetadataExtractor::segmentSplitter( $this->filePath . 'jpeg-segment-loop1.jpg' );
- }
-
- public function testInfiniteRead2() {
- // test file truncated after a segment's marker and size, which
- // would cause a seek past end of file. Seek past end of file
- // doesn't actually fail, but prevents further reading and was
- // devolving into the previous case (testInfiniteRead).
- $this->setExpectedException( 'MWException' );
- $res = JpegMetadataExtractor::segmentSplitter( $this->filePath . 'jpeg-segment-loop2.jpg' );
- }
-}
+++ /dev/null
-<?php
-
-/**
- * @covers ParserFactory
- */
-class ParserFactoryTest extends MediaWikiUnitTestCase {
- use FactoryArgTestTrait;
-
- protected static function getFactoryClass() {
- return ParserFactory::class;
- }
-
- protected static function getInstanceClass() {
- return Parser::class;
- }
-
- protected static function getFactoryMethodName() {
- return 'create';
- }
-
- protected static function getExtraClassArgCount() {
- // The parser factory itself is passed to the parser
- return 1;
- }
-
- protected function getOverriddenMockValueForParam( ReflectionParameter $param ) {
- if ( $param->getPosition() === 0 ) {
- return [ $this->createMock( MediaWiki\Config\ServiceOptions::class ) ];
- }
- return [];
- }
-}
+++ /dev/null
-<?php
-
-use MediaWiki\Site\MediaWikiPageNameNormalizer;
-
-/**
- * @covers MediaWiki\Site\MediaWikiPageNameNormalizer
- *
- * 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
- *
- * @since 1.27
- *
- * @group Site
- * @group medium
- *
- * @author Marius Hoch
- */
-class MediaWikiPageNameNormalizerTest extends MediaWikiUnitTestCase {
-
- /**
- * @dataProvider normalizePageTitleProvider
- */
- public function testNormalizePageTitle( $expected, $pageName, $getResponse ) {
- MediaWikiPageNameNormalizerTestMockHttp::$response = $getResponse;
-
- $normalizer = new MediaWikiPageNameNormalizer(
- new MediaWikiPageNameNormalizerTestMockHttp()
- );
-
- $this->assertSame(
- $expected,
- $normalizer->normalizePageName( $pageName, 'https://www.wikidata.org/w/api.php' )
- );
- }
-
- public function normalizePageTitleProvider() {
- // Response are taken from wikidata and kkwiki using the following API request
- // api.php?action=query&prop=info&redirects=1&converttitles=1&format=json&titles=…
- return [
- 'universe (Q1)' => [
- 'Q1',
- 'Q1',
- '{"batchcomplete":"","query":{"pages":{"129":{"pageid":129,"ns":0,'
- . '"title":"Q1","contentmodel":"wikibase-item","pagelanguage":"en",'
- . '"pagelanguagehtmlcode":"en","pagelanguagedir":"ltr",'
- . '"touched":"2016-06-23T05:11:21Z","lastrevid":350004448,"length":58001}}}}'
- ],
- 'Q404 redirects to Q395' => [
- 'Q395',
- 'Q404',
- '{"batchcomplete":"","query":{"redirects":[{"from":"Q404","to":"Q395"}],"pages"'
- . ':{"601":{"pageid":601,"ns":0,"title":"Q395","contentmodel":"wikibase-item",'
- . '"pagelanguage":"en","pagelanguagehtmlcode":"en","pagelanguagedir":"ltr",'
- . '"touched":"2016-06-23T08:00:20Z","lastrevid":350021914,"length":60108}}}}'
- ],
- 'D converted to Д (Latin to Cyrillic) (taken from kkwiki)' => [
- 'Д',
- 'D',
- '{"batchcomplete":"","query":{"converted":[{"from":"D","to":"\u0414"}],'
- . '"pages":{"510541":{"pageid":510541,"ns":0,"title":"\u0414",'
- . '"contentmodel":"wikitext","pagelanguage":"kk","pagelanguagehtmlcode":"kk",'
- . '"pagelanguagedir":"ltr","touched":"2015-11-22T09:16:18Z",'
- . '"lastrevid":2373618,"length":3501}}}}'
- ],
- 'there is no Q0' => [
- false,
- 'Q0',
- '{"batchcomplete":"","query":{"pages":{"-1":{"ns":0,"title":"Q0",'
- . '"missing":"","contentmodel":"wikibase-item","pagelanguage":"en",'
- . '"pagelanguagehtmlcode":"en","pagelanguagedir":"ltr"}}}}'
- ],
- 'invalid title' => [
- false,
- '{{',
- '{"batchcomplete":"","query":{"pages":{"-1":{"title":"{{",'
- . '"invalidreason":"The requested page title contains invalid '
- . 'characters: \"{\".","invalid":""}}}}'
- ],
- 'error on get' => [ false, 'ABC', false ]
- ];
- }
-
-}
-
-/**
- * @private
- * @see Http
- */
-class MediaWikiPageNameNormalizerTestMockHttp extends Http {
-
- /**
- * @var mixed
- */
- public static $response;
-
- public static function get( $url, array $options = [], $caller = __METHOD__ ) {
- PHPUnit_Framework_Assert::assertInternalType( 'string', $url );
- PHPUnit_Framework_Assert::assertInternalType( 'string', $caller );
-
- return self::$response;
- }
-}
+++ /dev/null
-<?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
- *
- * @ingroup Site
- * @ingroup Test
- *
- * @group Site
- *
- * @covers SiteExporter
- *
- * @author Daniel Kinzler
- */
-class SiteExporterTest extends MediaWikiUnitTestCase {
-
- public function testConstructor_InvalidArgument() {
- $this->setExpectedException( InvalidArgumentException::class );
-
- new SiteExporter( 'Foo' );
- }
-
- public function testExportSites() {
- $foo = Site::newForType( Site::TYPE_UNKNOWN );
- $foo->setGlobalId( 'Foo' );
-
- $acme = Site::newForType( Site::TYPE_UNKNOWN );
- $acme->setGlobalId( 'acme.com' );
- $acme->setGroup( 'Test' );
- $acme->addLocalId( Site::ID_INTERWIKI, 'acme' );
- $acme->setPath( Site::PATH_LINK, 'http://acme.com/' );
-
- $tmp = tmpfile();
- $exporter = new SiteExporter( $tmp );
-
- $exporter->exportSites( [ $foo, $acme ] );
-
- fseek( $tmp, 0 );
- $xml = fread( $tmp, 16 * 1024 );
-
- $this->assertContains( '<sites ', $xml );
- $this->assertContains( '<site>', $xml );
- $this->assertContains( '<globalid>Foo</globalid>', $xml );
- $this->assertContains( '</site>', $xml );
- $this->assertContains( '<globalid>acme.com</globalid>', $xml );
- $this->assertContains( '<group>Test</group>', $xml );
- $this->assertContains( '<localid type="interwiki">acme</localid>', $xml );
- $this->assertContains( '<path type="link">http://acme.com/</path>', $xml );
- $this->assertContains( '</sites>', $xml );
-
- // NOTE: HHVM (at least on wmf Jenkins) doesn't like file URLs.
- $xsdFile = __DIR__ . '/../../../../../docs/sitelist-1.0.xsd';
- $xsdData = file_get_contents( $xsdFile );
-
- $document = new DOMDocument();
- $document->loadXML( $xml, LIBXML_NONET );
- $document->schemaValidateSource( $xsdData );
- }
-
- private function newSiteStore( SiteList $sites ) {
- $store = $this->getMockBuilder( SiteStore::class )->getMock();
-
- $store->expects( $this->once() )
- ->method( 'saveSites' )
- ->will( $this->returnCallback( function ( $moreSites ) use ( $sites ) {
- foreach ( $moreSites as $site ) {
- $sites->setSite( $site );
- }
- } ) );
-
- $store->expects( $this->any() )
- ->method( 'getSites' )
- ->will( $this->returnValue( new SiteList() ) );
-
- return $store;
- }
-
- public function provideRoundTrip() {
- $foo = Site::newForType( Site::TYPE_UNKNOWN );
- $foo->setGlobalId( 'Foo' );
-
- $acme = Site::newForType( Site::TYPE_UNKNOWN );
- $acme->setGlobalId( 'acme.com' );
- $acme->setGroup( 'Test' );
- $acme->addLocalId( Site::ID_INTERWIKI, 'acme' );
- $acme->setPath( Site::PATH_LINK, 'http://acme.com/' );
-
- $dewiki = Site::newForType( Site::TYPE_MEDIAWIKI );
- $dewiki->setGlobalId( 'dewiki' );
- $dewiki->setGroup( 'wikipedia' );
- $dewiki->setForward( true );
- $dewiki->addLocalId( Site::ID_INTERWIKI, 'wikipedia' );
- $dewiki->addLocalId( Site::ID_EQUIVALENT, 'de' );
- $dewiki->setPath( Site::PATH_LINK, 'http://de.wikipedia.org/w/' );
- $dewiki->setPath( MediaWikiSite::PATH_PAGE, 'http://de.wikipedia.org/wiki/' );
- $dewiki->setSource( 'meta.wikimedia.org' );
-
- return [
- 'empty' => [
- new SiteList()
- ],
-
- 'some' => [
- new SiteList( [ $foo, $acme, $dewiki ] ),
- ],
- ];
- }
-
- /**
- * @dataProvider provideRoundTrip()
- */
- public function testRoundTrip( SiteList $sites ) {
- $tmp = tmpfile();
- $exporter = new SiteExporter( $tmp );
-
- $exporter->exportSites( $sites );
-
- fseek( $tmp, 0 );
- $xml = fread( $tmp, 16 * 1024 );
-
- $actualSites = new SiteList();
- $store = $this->newSiteStore( $actualSites );
-
- $importer = new SiteImporter( $store );
- $importer->importFromXML( $xml );
-
- $this->assertEquals( $sites, $actualSites );
- }
-
-}
+++ /dev/null
-<?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
- *
- * @ingroup Site
- * @ingroup Test
- *
- * @group Site
- *
- * @covers SiteImporter
- *
- * @author Daniel Kinzler
- */
-class SiteImporterTest extends MediaWikiUnitTestCase {
-
- private function newSiteImporter( array $expectedSites, $errorCount ) {
- $store = $this->getMockBuilder( SiteStore::class )->getMock();
-
- $store->expects( $this->once() )
- ->method( 'saveSites' )
- ->will( $this->returnCallback( function ( $sites ) use ( $expectedSites ) {
- $this->assertSitesEqual( $expectedSites, $sites );
- } ) );
-
- $store->expects( $this->any() )
- ->method( 'getSites' )
- ->will( $this->returnValue( new SiteList() ) );
-
- $errorHandler = $this->getMockBuilder( Psr\Log\LoggerInterface::class )->getMock();
- $errorHandler->expects( $this->exactly( $errorCount ) )
- ->method( 'error' );
-
- $importer = new SiteImporter( $store );
- $importer->setExceptionCallback( [ $errorHandler, 'error' ] );
-
- return $importer;
- }
-
- public function assertSitesEqual( $expected, $actual, $message = '' ) {
- $this->assertEquals(
- $this->getSerializedSiteList( $expected ),
- $this->getSerializedSiteList( $actual ),
- $message
- );
- }
-
- public function provideImportFromXML() {
- $foo = Site::newForType( Site::TYPE_UNKNOWN );
- $foo->setGlobalId( 'Foo' );
-
- $acme = Site::newForType( Site::TYPE_UNKNOWN );
- $acme->setGlobalId( 'acme.com' );
- $acme->setGroup( 'Test' );
- $acme->addLocalId( Site::ID_INTERWIKI, 'acme' );
- $acme->setPath( Site::PATH_LINK, 'http://acme.com/' );
-
- $dewiki = Site::newForType( Site::TYPE_MEDIAWIKI );
- $dewiki->setGlobalId( 'dewiki' );
- $dewiki->setGroup( 'wikipedia' );
- $dewiki->setForward( true );
- $dewiki->addLocalId( Site::ID_INTERWIKI, 'wikipedia' );
- $dewiki->addLocalId( Site::ID_EQUIVALENT, 'de' );
- $dewiki->setPath( Site::PATH_LINK, 'http://de.wikipedia.org/w/' );
- $dewiki->setPath( MediaWikiSite::PATH_PAGE, 'http://de.wikipedia.org/wiki/' );
- $dewiki->setSource( 'meta.wikimedia.org' );
-
- return [
- 'empty' => [
- '<sites></sites>',
- [],
- ],
- 'no sites' => [
- '<sites><Foo><globalid>Foo</globalid></Foo><Bar><quux>Bla</quux></Bar></sites>',
- [],
- ],
- 'minimal' => [
- '<sites>' .
- '<site><globalid>Foo</globalid></site>' .
- '</sites>',
- [ $foo ],
- ],
- 'full' => [
- '<sites>' .
- '<site><globalid>Foo</globalid></site>' .
- '<site>' .
- '<globalid>acme.com</globalid>' .
- '<localid type="interwiki">acme</localid>' .
- '<group>Test</group>' .
- '<path type="link">http://acme.com/</path>' .
- '</site>' .
- '<site type="mediawiki">' .
- '<source>meta.wikimedia.org</source>' .
- '<globalid>dewiki</globalid>' .
- '<localid type="interwiki">wikipedia</localid>' .
- '<localid type="equivalent">de</localid>' .
- '<group>wikipedia</group>' .
- '<forward/>' .
- '<path type="link">http://de.wikipedia.org/w/</path>' .
- '<path type="page_path">http://de.wikipedia.org/wiki/</path>' .
- '</site>' .
- '</sites>',
- [ $foo, $acme, $dewiki ],
- ],
- 'skip' => [
- '<sites>' .
- '<site><globalid>Foo</globalid></site>' .
- '<site><barf>Foo</barf></site>' .
- '<site>' .
- '<globalid>acme.com</globalid>' .
- '<localid type="interwiki">acme</localid>' .
- '<silly>boop!</silly>' .
- '<group>Test</group>' .
- '<path type="link">http://acme.com/</path>' .
- '</site>' .
- '</sites>',
- [ $foo, $acme ],
- 1
- ],
- ];
- }
-
- /**
- * @dataProvider provideImportFromXML
- */
- public function testImportFromXML( $xml, array $expectedSites, $errorCount = 0 ) {
- $importer = $this->newSiteImporter( $expectedSites, $errorCount );
- $importer->importFromXML( $xml );
- }
-
- public function testImportFromXML_malformed() {
- $this->setExpectedException( Exception::class );
-
- $store = $this->getMockBuilder( SiteStore::class )->getMock();
- $importer = new SiteImporter( $store );
- $importer->importFromXML( 'THIS IS NOT XML' );
- }
-
- public function testImportFromFile() {
- $foo = Site::newForType( Site::TYPE_UNKNOWN );
- $foo->setGlobalId( 'Foo' );
-
- $acme = Site::newForType( Site::TYPE_UNKNOWN );
- $acme->setGlobalId( 'acme.com' );
- $acme->setGroup( 'Test' );
- $acme->addLocalId( Site::ID_INTERWIKI, 'acme' );
- $acme->setPath( Site::PATH_LINK, 'http://acme.com/' );
-
- $dewiki = Site::newForType( Site::TYPE_MEDIAWIKI );
- $dewiki->setGlobalId( 'dewiki' );
- $dewiki->setGroup( 'wikipedia' );
- $dewiki->setForward( true );
- $dewiki->addLocalId( Site::ID_INTERWIKI, 'wikipedia' );
- $dewiki->addLocalId( Site::ID_EQUIVALENT, 'de' );
- $dewiki->setPath( Site::PATH_LINK, 'http://de.wikipedia.org/w/' );
- $dewiki->setPath( MediaWikiSite::PATH_PAGE, 'http://de.wikipedia.org/wiki/' );
- $dewiki->setSource( 'meta.wikimedia.org' );
-
- $importer = $this->newSiteImporter( [ $foo, $acme, $dewiki ], 0 );
-
- $file = __DIR__ . '/SiteImporterTest.xml';
- $importer->importFromFile( $file );
- }
-
- /**
- * @param Site[] $sites
- *
- * @return array[]
- */
- private function getSerializedSiteList( $sites ) {
- $serialized = [];
-
- foreach ( $sites as $site ) {
- $key = $site->getGlobalId();
- $data = unserialize( $site->serialize() );
-
- $serialized[$key] = $data;
- }
-
- return $serialized;
- }
-}
+++ /dev/null
-<sites version="1.0" xmlns="http://www.mediawiki.org/xml/sitelist-1.0/">
- <site><globalid>Foo</globalid></site>
- <site>
- <globalid>acme.com</globalid>
- <localid type="interwiki">acme</localid>
- <group>Test</group>
- <path type="link">http://acme.com/</path>
- </site>
- <site type="mediawiki">
- <source>meta.wikimedia.org</source>
- <globalid>dewiki</globalid>
- <localid type="interwiki">wikipedia</localid>
- <localid type="equivalent">de</localid>
- <group>wikipedia</group>
- <forward/>
- <path type="link">http://de.wikipedia.org/w/</path>
- <path type="page_path">http://de.wikipedia.org/wiki/</path>
- </site>
-</sites>
+++ /dev/null
-<?php
-
-/**
- * @covers ZipDirectoryReader
- * NOTE: this test is more like an integration test than a unit test
- */
-class ZipDirectoryReaderTest extends MediaWikiUnitTestCase {
-
- protected $zipDir;
- protected $entries;
-
- protected function setUp() {
- parent::setUp();
- $this->zipDir = __DIR__ . '/../../../data/zip';
- }
-
- function zipCallback( $entry ) {
- $this->entries[] = $entry;
- }
-
- function readZipAssertError( $file, $error, $assertMessage ) {
- $this->entries = [];
- $status = ZipDirectoryReader::read( "{$this->zipDir}/$file", [ $this, 'zipCallback' ] );
- $this->assertTrue( $status->hasMessage( $error ), $assertMessage );
- }
-
- function readZipAssertSuccess( $file, $assertMessage ) {
- $this->entries = [];
- $status = ZipDirectoryReader::read( "{$this->zipDir}/$file", [ $this, 'zipCallback' ] );
- $this->assertTrue( $status->isOK(), $assertMessage );
- }
-
- public function testEmpty() {
- $this->readZipAssertSuccess( 'empty.zip', 'Empty zip' );
- }
-
- public function testMultiDisk0() {
- $this->readZipAssertError( 'split.zip', 'zip-unsupported',
- 'Split zip error' );
- }
-
- public function testNoSignature() {
- $this->readZipAssertError( 'nosig.zip', 'zip-wrong-format',
- 'No signature should give "wrong format" error' );
- }
-
- public function testSimple() {
- $this->readZipAssertSuccess( 'class.zip', 'Simple ZIP' );
- $this->assertEquals( $this->entries, [ [
- 'name' => 'Class.class',
- 'mtime' => '20010115000000',
- 'size' => 1,
- ] ] );
- }
-
- public function testBadCentralEntrySignature() {
- $this->readZipAssertError( 'wrong-central-entry-sig.zip', 'zip-bad',
- 'Bad central entry error' );
- }
-
- public function testTrailingBytes() {
- // Due to T40432 this is now zip-wrong-format instead of zip-bad
- $this->readZipAssertError( 'trail.zip', 'zip-wrong-format',
- 'Trailing bytes error' );
- }
-
- public function testWrongCDStart() {
- $this->readZipAssertError( 'wrong-cd-start-disk.zip', 'zip-unsupported',
- 'Wrong CD start disk error' );
- }
-
- public function testCentralDirectoryGap() {
- $this->readZipAssertError( 'cd-gap.zip', 'zip-bad',
- 'CD gap error' );
- }
-
- public function testCentralDirectoryTruncated() {
- $this->readZipAssertError( 'cd-truncated.zip', 'zip-bad',
- 'CD truncated error (should hit unpack() overrun)' );
- }
-
- public function testLooksLikeZip64() {
- $this->readZipAssertError( 'looks-like-zip64.zip', 'zip-unsupported',
- 'A file which looks like ZIP64 but isn\'t, should give error' );
- }
-}
'Parse an ftp URI correctly with user and password'
);
+ uri = new mw.Uri( 'http://example.com/?foo[1]=b&foo[0]=a&foo[]=c' );
+
+ assert.deepEqual(
+ uri.query,
+ {
+ 'foo[1]': 'b',
+ 'foo[0]': 'a',
+ 'foo[]': 'c'
+ },
+ 'Array query parameters parsed as normal with arrayParams:false'
+ );
+
assert.throws(
function () {
return new mw.Uri( 'glaswegian penguins' );
} );
+ QUnit.test( 'arrayParams', function ( assert ) {
+ var uri1, uri2, uri3, expectedQ, expectedS,
+ uriMissing, expectedMissingQ, expectedMissingS,
+ uriWeird, expectedWeirdQ, expectedWeirdS;
+
+ uri1 = new mw.Uri( 'http://example.com/?foo[]=a&foo[]=b&foo[]=c', { arrayParams: true } );
+ uri2 = new mw.Uri( 'http://example.com/?foo[0]=a&foo[1]=b&foo[2]=c', { arrayParams: true } );
+ uri3 = new mw.Uri( 'http://example.com/?foo[1]=b&foo[0]=a&foo[]=c', { arrayParams: true } );
+ expectedQ = { foo: [ 'a', 'b', 'c' ] };
+ expectedS = 'foo%5B0%5D=a&foo%5B1%5D=b&foo%5B2%5D=c';
+
+ assert.deepEqual( uri1.query, expectedQ,
+ 'array query parameters are parsed (implicit indexes)' );
+ assert.deepEqual( uri1.getQueryString(), expectedS,
+ 'array query parameters are encoded (always with explicit indexes)' );
+ assert.deepEqual( uri2.query, expectedQ,
+ 'array query parameters are parsed (explicit indexes)' );
+ assert.deepEqual( uri2.getQueryString(), expectedS,
+ 'array query parameters are encoded (always with explicit indexes)' );
+ assert.deepEqual( uri3.query, expectedQ,
+ 'array query parameters are parsed (mixed indexes, out of order)' );
+ assert.deepEqual( uri3.getQueryString(), expectedS,
+ 'array query parameters are encoded (always with explicit indexes)' );
+
+ uriMissing = new mw.Uri( 'http://example.com/?foo[0]=a&foo[2]=c', { arrayParams: true } );
+ // eslint-disable-next-line no-sparse-arrays
+ expectedMissingQ = { foo: [ 'a', , 'c' ] };
+ expectedMissingS = 'foo%5B0%5D=a&foo%5B2%5D=c';
+
+ assert.deepEqual( uriMissing.query, expectedMissingQ,
+ 'array query parameters are parsed (missing array item)' );
+ assert.deepEqual( uriMissing.getQueryString(), expectedMissingS,
+ 'array query parameters are encoded (missing array item)' );
+
+ uriWeird = new mw.Uri( 'http://example.com/?foo[0]=a&foo[1][1]=b&foo[x]=c', { arrayParams: true } );
+ expectedWeirdQ = { foo: [ 'a' ], 'foo[1][1]': 'b', 'foo[x]': 'c' };
+ expectedWeirdS = 'foo%5B0%5D=a&foo%5B1%5D%5B1%5D=b&foo%5Bx%5D=c';
+
+ assert.deepEqual( uriWeird.query, expectedWeirdQ,
+ 'array query parameters are parsed (multi-dimensional or associative arrays are ignored)' );
+ assert.deepEqual( uriWeird.getQueryString(), expectedWeirdS,
+ 'array query parameters are encoded (multi-dimensional or associative arrays are ignored)' );
+ } );
+
QUnit.test( '.clone()', function ( assert ) {
var original, clone;
window.Set = this.nativeSet;
mw.redefineFallbacksForTest();
}
+ if ( this.resetStoreKey ) {
+ localStorage.removeItem( mw.loader.store.key );
+ }
// Remove any remaining temporary statics
// exposed for cross-file mocks.
delete mw.loader.testCallback;
require( 'testUrlIncDump' ).query,
{
modules: 'testUrlIncDump',
- // Expected: Wrapped hash just for this one module
- // $hash = hash( 'fnv132', 'dump');
- // base_convert( $hash, 16, 36 ); // "13e9zzn"
- // Previously: Wrapped hash for both modules, despite being in separate requests
- // $hash = hash( 'fnv132', 'urldump' );
- // base_convert( $hash, 16, 36 ); // "18kz9ca"
- version: '13e9zzn'
+ // Expected: Combine hashes only for the module in the specific HTTP request
+ // hash fnv132 => "13e9zzn"
+ // Wrong: Combine hashes for all requested modules, before request-splitting
+ // hash fnv132 => "18kz9ca"
+ version: '13e9z'
},
'Query parameters'
);
require( 'testUrlOrderDump' ).query,
{
modules: 'testUrlOrder,testUrlOrderDump|testUrlOrder.a,b',
- // Expected: Combined in order after string packing
- // $hash = hash( 'fnv132', 'urldump12' );
- // base_convert( $hash, 16, 36 ); // "1knqzan"
- // Previously: Combined in order of before string packing
- // $hash = hash( 'fnv132', 'url12dump' );
- // base_convert( $hash, 16, 36 ); // "11eo3in"
- version: '1knqzan'
+ // Expected: Combined by sorting names after string packing
+ // hash fnv132 = "1knqzan"
+ // Wrong: Combined by sorting names before string packing
+ // hash fnv132 => "11eo3in"
+ version: '1knqz'
},
'Query parameters'
);
} );
} );
+ QUnit.test( 'mw.loader.store.init - Invalid JSON', function ( assert ) {
+ // Reset
+ this.sandbox.stub( mw.loader.store, 'enabled', null );
+ this.sandbox.stub( mw.loader.store, 'items', {} );
+ this.resetStoreKey = true;
+ localStorage.setItem( mw.loader.store.key, 'invalid' );
+
+ mw.loader.store.init();
+ assert.strictEqual( mw.loader.store.enabled, true, 'Enabled' );
+ assert.strictEqual(
+ $.isEmptyObject( mw.loader.store.items ),
+ true,
+ 'Items starts fresh'
+ );
+ } );
+
+ QUnit.test( 'mw.loader.store.init - Wrong JSON', function ( assert ) {
+ // Reset
+ this.sandbox.stub( mw.loader.store, 'enabled', null );
+ this.sandbox.stub( mw.loader.store, 'items', {} );
+ this.resetStoreKey = true;
+ localStorage.setItem( mw.loader.store.key, JSON.stringify( { wrong: true } ) );
+
+ mw.loader.store.init();
+ assert.strictEqual( mw.loader.store.enabled, true, 'Enabled' );
+ assert.strictEqual(
+ $.isEmptyObject( mw.loader.store.items ),
+ true,
+ 'Items starts fresh'
+ );
+ } );
+
+ QUnit.test( 'mw.loader.store.init - Expired JSON', function ( assert ) {
+ // Reset
+ this.sandbox.stub( mw.loader.store, 'enabled', null );
+ this.sandbox.stub( mw.loader.store, 'items', {} );
+ this.resetStoreKey = true;
+ localStorage.setItem( mw.loader.store.key, JSON.stringify( {
+ items: { use: 'not me' },
+ vary: mw.loader.store.vary,
+ asOf: 130161 // 2011-04-01 12:00
+ } ) );
+
+ mw.loader.store.init();
+ assert.strictEqual( mw.loader.store.enabled, true, 'Enabled' );
+ assert.strictEqual(
+ $.isEmptyObject( mw.loader.store.items ),
+ true,
+ 'Items starts fresh'
+ );
+ } );
+
+ QUnit.test( 'mw.loader.store.init - Good JSON', function ( assert ) {
+ // Reset
+ this.sandbox.stub( mw.loader.store, 'enabled', null );
+ this.sandbox.stub( mw.loader.store, 'items', {} );
+ this.resetStoreKey = true;
+ localStorage.setItem( mw.loader.store.key, JSON.stringify( {
+ items: { use: 'me' },
+ vary: mw.loader.store.vary,
+ asOf: Math.ceil( Date.now() / 1e7 ) - 5 // ~ 13 hours ago
+ } ) );
+
+ mw.loader.store.init();
+ assert.strictEqual( mw.loader.store.enabled, true, 'Enabled' );
+ assert.deepEqual(
+ mw.loader.store.items,
+ { use: 'me' },
+ 'Stored items are loaded'
+ );
+ } );
+
QUnit.test( 'require()', function ( assert ) {
mw.loader.register( [
[ 'test.require1', '0' ],
/* Grade X */
+ // Open WebOS < 1.5 (Palm Pre, Palm Pixi)
+ 'Mozilla/5.0 (webOS/1.0; U; en-US) AppleWebKit/525.27.1 (KHTML, like Gecko) Version/1.0 Safari/525.27.1 Pre/1.0',
+ 'Mozilla/5.0 (webOS/1.4.0; U; en-US) AppleWebKit/532.2 (KHTML, like Gecko) Version/1.0 Safari/532.2 Pixi/1.1 ',
+ // SymbianOS
+ 'NokiaN95_8GB-3;Mozilla/5.0 SymbianOS/9.2;U;Series60/3.1 NokiaN95_8GB-3/11.2.011 Profile/MIDP-2.0 Configuration/CLDC-1.1 AppleWebKit/413 (KHTML, like Gecko)',
+ 'Nokia7610/2.0 (5.0509.0) SymbianOS/7.0s Series60/2.1 Profile/MIDP-2.0 Configuration/CLDC-1.0 ',
+ 'Mozilla/5.0 (SymbianOS/9.1; U; [en]; SymbianOS/91 Series60/3.0) AppleWebKit/413 (KHTML, like Gecko) Safari/413',
+ 'Mozilla/5.0 (SymbianOS/9.3; Series60/3.2 NokiaE52-2/091.003; Profile/MIDP-2.1 Configuration/CLDC-1.1 ) AppleWebKit/533.4 (KHTML, like Gecko) NokiaBrowser/7.3.1.34 Mobile Safari/533.4',
// Gecko
'Mozilla/5.0 (X11; U; Linux i686; en-US; rv:1.8.0.7) Gecko/20060928 (Debian|Debian-1.8.0.7-1) Epiphany/2.14',
'Mozilla/5.0 (X11; U; Linux i686 (x86_64); en-US; rv:1.8.1.6) Gecko/20070817 IceWeasel/2.0.0.6-g2',
'Mozilla/5.0 (compatible; MSIE 10.0; Windows NT 6.1; WOW64; Trident/6.0)',
// IE Mobile 10
'Mozilla/5.0 (compatible; MSIE 10.0; Windows Phone 8.0; Trident/6.0; IEMobile/10.0; ARM; Touch; HTC; Windows Phone 8X by HTC)',
- // Open WebOS < 1.5 (Palm Pre, Palm Pixi)
- 'Mozilla/5.0 (webOS/1.0; U; en-US) AppleWebKit/525.27.1 (KHTML, like Gecko) Version/1.0 Safari/525.27.1 Pre/1.0',
- 'Mozilla/5.0 (webOS/1.4.0; U; en-US) AppleWebKit/532.2 (KHTML, like Gecko) Version/1.0 Safari/532.2 Pixi/1.1 ',
- // SymbianOS
- 'NokiaN95_8GB-3;Mozilla/5.0 SymbianOS/9.2;U;Series60/3.1 NokiaN95_8GB-3/11.2.011 Profile/MIDP-2.0 Configuration/CLDC-1.1 AppleWebKit/413 (KHTML, like Gecko)',
- 'Nokia7610/2.0 (5.0509.0) SymbianOS/7.0s Series60/2.1 Profile/MIDP-2.0 Configuration/CLDC-1.0 ',
- 'Mozilla/5.0 (SymbianOS/9.1; U; [en]; SymbianOS/91 Series60/3.0) AppleWebKit/413 (KHTML, like Gecko) Safari/413',
- 'Mozilla/5.0 (SymbianOS/9.3; Series60/3.2 NokiaE52-2/091.003; Profile/MIDP-2.1 Configuration/CLDC-1.1 ) AppleWebKit/533.4 (KHTML, like Gecko) NokiaBrowser/7.3.1.34 Mobile Safari/533.4',
// NetFront
'Mozilla/4.0 (compatible; Linux 2.6.10) NetFront/3.3 Kindle/1.0 (screen 600x800)',
'Mozilla/4.0 (compatible; Linux 2.6.22) NetFront/3.4 Kindle/2.0 (screen 824x1200; rotate)',
// Test reporter for stdout.
// See also: http://webdriver.io/guide/testrunner/reporters.html
- reporters: [ 'spec', 'junit' ],
+ reporters: [ 'dot', 'junit' ],
reporterOptions: {
junit: {
outputDir: logPath