* (T180052) Mirandese (mwl) now supports gendered NS_USER/NS_USER_TALK namespaces.
* (T182305) New language support: Nyungar (nys).
+* (T186359) New language support: Siberian Tatar [cебертатар] (sty).
=== Other changes in 1.31 ===
* Introducing multi-content-revision capability into the storage layer. For details,
Setting template variables by reference allowed violating the principle of data being
immutable once added to the skin template. In practice, this method was not being
used for that. Rather, setRef() existed as memory optimisation for PHP 4.
+* QuickTemplate::setTranslator() was deprecated in favour of Skin::msg() parameters.
+* MediaWikiI18N::set() was deprecated in favour of Skin::msg() parameters.
+* MediaWikiI18N::translate() was deprecated in favour of Skin::msg() or wfMessage().
* Passing false to ParserOptions::setWrapOutputClass() is deprecated. Use the
'unwrap' transform to ParserOutput::getText() instead.
+* ParserOutput objects generated using a non-default value for
+ ParserOptions::setWrapOutputClass() can no longer be added to the parser
+ cache.
+* The following deprecated methods from the OutputPage class have been removed:
+ * OutputPage::addExtensionStyle(); deprecated in 1.27
+ * OutputPage::getExtStyle(); deprecated in 1.27
+ * OutputPage::setETag(); deprecated in 1.28 (obsolete no-op)
+ * OutputPage::setSquidMaxage(); deprecated in 1.27
+ * OutputPage::readOnlyPage(); deprecated in 1.25
+ * OutputPage::rateLimited(); deprecated in 1.25
+* The no-op method Skin::showIPinHeader(), deprecated in 1.27, was removed.
== Compatibility ==
MediaWiki 1.31 requires PHP 5.5.9 or later. Although HHVM 3.18.5 or later is supported,
$this->mScripts .= $script;
}
- /**
- * Register and add a stylesheet from an extension directory.
- *
- * @deprecated since 1.27 use addModuleStyles() or addStyle() instead
- * @param string $url Path to sheet. Provide either a full url (beginning
- * with 'http', etc) or a relative path from the document root
- * (beginning with '/'). Otherwise it behaves identically to
- * addStyle() and draws from the /skins folder.
- */
- public function addExtensionStyle( $url ) {
- wfDeprecated( __METHOD__, '1.27' );
- array_push( $this->mExtStyles, $url );
- }
-
- /**
- * Get all styles added by extensions
- *
- * @deprecated since 1.27
- * @return array
- */
- function getExtStyle() {
- wfDeprecated( __METHOD__, '1.27' );
- return $this->mExtStyles;
- }
-
/**
* Add a JavaScript file out of skins/common, or a given relative path.
* Internal use only. Use OutputPage::addModules() if possible.
$this->mAdditionalBodyClasses = array_merge( $this->mAdditionalBodyClasses, (array)$classes );
}
- /**
- * @deprecated since 1.28 Obsolete - wgUseETag experiment was removed.
- * @param string $tag
- */
- public function setETag( $tag ) {
- }
-
/**
* Set whether the output should only contain the body of the article,
* without any skin, sidebar, etc.
return Parser::stripOuterParagraph( $parsed );
}
- /**
- * @param int $maxage
- * @deprecated since 1.27 Use setCdnMaxage() instead
- */
- public function setSquidMaxage( $maxage ) {
- wfDeprecated( __METHOD__, '1.27' );
- $this->setCdnMaxage( $maxage );
- }
-
/**
* Set the value of the "s-maxage" part of the "Cache-control" HTTP header
*
return $text;
}
- /**
- * Display a page stating that the Wiki is in read-only mode.
- * Should only be called after wfReadOnly() has returned true.
- *
- * Historically, this function was used to show the source of the page that the user
- * was trying to edit and _also_ permissions error messages. The relevant code was
- * moved into EditPage in 1.19 (r102024 / d83c2a431c2a) and removed here in 1.25.
- *
- * @deprecated since 1.25; throw the exception directly
- * @throws ReadOnlyError
- */
- public function readOnlyPage() {
- if ( func_num_args() > 0 ) {
- throw new MWException( __METHOD__ . ' no longer accepts arguments since 1.25.' );
- }
-
- throw new ReadOnlyError;
- }
-
- /**
- * Turn off regular page output and return an error response
- * for when rate limiting has triggered.
- *
- * @deprecated since 1.25; throw the exception directly
- */
- public function rateLimited() {
- wfDeprecated( __METHOD__, '1.25' );
- throw new ThrottledError;
- }
-
/**
* Show a warning about replica DB lag
*
/** @var bool */
private static $loaded = false;
-
/** @var int[] */
private static $pageCount = [];
self::$row = self::loadAndLazyInit();
- # This code is somewhat schema-agnostic, because I'm changing it in a minor release -- TS
- if ( !isset( self::$row->ss_total_pages ) && self::$row->ss_total_pages == -1 ) {
- # Update schema
- $u = new SiteStatsUpdate( 0, 0, 0 );
- $u->doUpdate();
- self::$row = self::doLoad( wfGetDB( DB_REPLICA ) );
- }
-
self::$loaded = true;
}
}
}
- if ( !$wgMiserMode && !self::isSane( $row ) ) {
- // Normally the site_stats table is initialized at install time.
- // Some manual construction scenarios may leave the table empty or
- // broken, however, for instance when importing from a dump into a
- // clean schema with mwdumper.
- wfDebug( __METHOD__ . ": initializing damaged or missing site_stats\n" );
-
- SiteStatsInit::doAllAndCommit( wfGetDB( DB_REPLICA ) );
+ if ( !self::isSane( $row ) ) {
+ if ( $wgMiserMode ) {
+ // Start off with all zeroes, assuming that this is a new wiki or any
+ // repopulations where done manually via script.
+ SiteStatsInit::doPlaceholderInit();
+ } else {
+ // Normally the site_stats table is initialized at install time.
+ // Some manual construction scenarios may leave the table empty or
+ // broken, however, for instance when importing from a dump into a
+ // clean schema with mwdumper.
+ wfDebug( __METHOD__ . ": initializing damaged or missing site_stats\n" );
+ SiteStatsInit::doAllAndCommit( wfGetDB( DB_REPLICA ) );
+ }
$row = self::doLoad( wfGetDB( DB_MASTER ) );
}
if ( !self::isSane( $row ) ) {
wfDebug( __METHOD__ . ": site_stats persistently nonsensical o_O\n" );
+
+ $row = (object)array_fill_keys( self::selectFields(), 0 );
}
return $row;
* @return bool|stdClass
*/
static function doLoad( $db ) {
- return $db->selectRow( 'site_stats', [
- 'ss_row_id',
- 'ss_total_edits',
- 'ss_good_articles',
- 'ss_total_pages',
- 'ss_users',
- 'ss_active_users',
- 'ss_images',
- ], [], __METHOD__ );
+ return $db->selectRow( 'site_stats', self::selectFields(), [], __METHOD__ );
}
/**
return self::$pageCount[$ns];
}
+ /**
+ * @return array
+ */
+ public static function selectFields() {
+ return [
+ 'ss_row_id',
+ 'ss_total_edits',
+ 'ss_good_articles',
+ 'ss_total_pages',
+ 'ss_users',
+ 'ss_active_users',
+ 'ss_images',
+ ];
+ }
+
/**
* Is the provided row of site stats sane, or should it be regenerated?
*
}
}
+ /**
+ * Insert a dummy row with all zeroes if no row is present
+ */
+ public static function doPlaceholderInit() {
+ $dbw = wfGetDB( DB_MASTER );
+ if ( $dbw->selectRow( 'site_stats', '1', [], __METHOD__ ) === false ) {
+ $dbw->insert(
+ 'site_stats',
+ array_fill_keys( SiteStats::selectFields(), 0 ),
+ __METHOD__,
+ [ 'IGNORE' ]
+ );
+ }
+ }
+
/**
* Refresh site_stats
*/
"Danny B.",
"LordMsz",
"Dvorapa",
- "Matěj Suchánek"
+ "Matěj Suchánek",
+ "Ilimanaq29"
]
},
- "apihelp-main-extended-description": "<div class=\"hlist plainlinks api-main-links\">\n* [[mw:Special:MyLanguage/API:Main_page|Dokumentace]]\n* [[mw:Special:MyLanguage/API:FAQ|FAQ]]\n* [https://lists.wikimedia.org/mailman/listinfo/mediawiki-api E-mailová konference]\n* [https://lists.wikimedia.org/mailman/listinfo/mediawiki-api-announce Oznámení k API]\n* [https://phabricator.wikimedia.org/maniphest/query/GebfyV4uCaLd/#R Chyby a požadavky]\n</div>\n<strong>Stav:</strong> Všechny funkce uvedené na této stránce by měly fungovat, ale API se stále aktivně vyvíjí a může se kdykoli změnit. Upozornění na změny získáte přihlášením se k [https://lists.wikimedia.org/pipermail/mediawiki-api-announce/ e-mailové konferenci mediawiki-api-announce].\n\n<strong>Chybné požadavky:</strong> Pokud jsou do API zaslány chybné požadavky, bude vrácena HTTP hlavička s klíčem „MediaWiki-API-Error“ a hodnota této hlavičky a chybový kód budou nastaveny na stejnou hodnotu. Více informací najdete [[mw:Special:MyLanguage/API:Errors_and_warnings|v dokumentaci]].\n\n<strong>Testování:</strong> Pro jednoduché testování požadavků na API zkuste [[Special:ApiSandbox]].",
+ "apihelp-main-extended-description": "<div class=\"hlist plainlinks api-main-links\">\n* [[mw:Special:MyLanguage/API:Main_page|Dokumentace]]\n* [[mw:Special:MyLanguage/API:FAQ|Otázky a odpovědi]]\n* [https://lists.wikimedia.org/mailman/listinfo/mediawiki-api E-mailová konference]\n* [https://lists.wikimedia.org/mailman/listinfo/mediawiki-api-announce Oznámení k API]\n* [https://phabricator.wikimedia.org/maniphest/query/GebfyV4uCaLd/#R Chyby a požadavky]\n</div>\n<strong>Stav:</strong> Všechny funkce uvedené na této stránce by měly fungovat, ale API se stále aktivně vyvíjí a může se kdykoli změnit. Upozornění na změny získáte přihlášením se k [https://lists.wikimedia.org/pipermail/mediawiki-api-announce/ e-mailové konferenci mediawiki-api-announce].\n\n<strong>Chybné požadavky:</strong> Pokud jsou do API zaslány chybné požadavky, bude vrácena HTTP hlavička s klíčem „MediaWiki-API-Error“ a hodnota této hlavičky a chybový kód budou nastaveny na stejnou hodnotu. Více informací najdete [[mw:Special:MyLanguage/API:Errors_and_warnings|v dokumentaci]].\n\n<strong>Testování:</strong> Pro jednoduché testování požadavků na API zkuste [[Special:ApiSandbox]].",
"apihelp-main-param-action": "Která akce se má provést.",
"apihelp-main-param-format": "Formát výstupu.",
"apihelp-main-param-maxlag": "Maximální zpoždění lze použít, když je MediaWiki nainstalováno na cluster s replikovanou databází. Abyste se vyhnuli zhoršování už tak špatného replikačního zpoždění, můžete tímto parametrem nechat klienta čekat, dokud replikační zpoždění neklesne pod uvedenou hodnotu. V případě příliš vysokého zpoždění se vrátí chybový kód „<samp>maxlag</samp>“ s hlášením typu „<samp>Waiting for $host: $lag seconds lagged</samp>“.<br />Více informací najdete v [[mw:Special:MyLanguage/Manual:Maxlag_parameter|příručce]].",
// loading context. This file will then register the alias and, as class_alias() does
// by default, it will trigger a plain autoload for the destination class.
-// The below uses string concatenation for the alias to avoid being seen by ClassCollector,
-// which would insist on adding it to autoload.php, after which AutoLoaderTest will
+// The below uses a namespaced class reference, to to avoid being seen by ClassCollector,
+// which would otherwise add it to autoload.php, after which AutoLoaderTest will
// complain about class_alias() not being in the target class file.
/**
* @deprecated since 1.29
* @since 1.20
*/
-class_alias( Wikimedia\Timestamp\TimestampException::class, 'Timestamp' . 'Exception' );
+class_alias( Wikimedia\Timestamp\TimestampException::class, 'TimestampException' );
} while ( $end - 2 < $length && $s[$end - 2] === '\\' );
// Correction (1): Undo speculative add, keep only one (end of regexp)
$end--;
+ if ( $end > $length ) {
+ // Correction (2): Loop wrongly assumed "]" was seen
+ // String ended without ending char class or regexp. Correct $end.
+ // TODO: This is invalid and should throw.
+ $end--;
+ break;
+ }
}
// Search past the regexp modifiers (gi)
while ( $end < $length && ctype_alpha( $s[$end] ) ) {
/**
* @return resource
+ * @throws Exception
*/
protected function getCurlMulti() {
if ( !$this->multiHandle ) {
+ if ( !function_exists( 'curl_multi_init' ) ) {
+ throw new Exception( "PHP cURL extension missing. " .
+ "Check https://www.mediawiki.org/wiki/Manual:CURL" );
+ }
$cmh = curl_multi_init();
curl_multi_setopt( $cmh, CURLMOPT_PIPELINING, (int)$this->usePipelining );
curl_multi_setopt( $cmh, CURLMOPT_MAXCONNECTS, (int)$this->maxConnsPerHost );
$knownReachedPos instanceof DBMasterPos &&
$knownReachedPos->hasReached( $this->mWaitForPos )
) {
- $this->replLogger->debug( __METHOD__ .
+ $this->replLogger->debug(
+ __METHOD__ .
': replica DB {dbserver} known to be caught up (pos >= $knownReachedPos).',
- [ 'dbserver' => $server ] );
+ [ 'dbserver' => $server ]
+ );
return true;
}
$conn = $this->getAnyOpenConnection( $index );
if ( !$conn ) {
if ( !$open ) {
- $this->replLogger->debug( __METHOD__ . ': no connection open for {dbserver}',
- [ 'dbserver' => $server ] );
+ $this->replLogger->debug(
+ __METHOD__ . ': no connection open for {dbserver}',
+ [ 'dbserver' => $server ]
+ );
return false;
} else {
$conn = $this->openConnection( $index, self::DOMAIN_ANY );
if ( !$conn ) {
- $this->replLogger->warning( __METHOD__ . ': failed to connect to {dbserver}',
- [ 'dbserver' => $server ] );
+ $this->replLogger->warning(
+ __METHOD__ . ': failed to connect to {dbserver}',
+ [ 'dbserver' => $server ]
+ );
return false;
}
}
}
- $this->replLogger->info( __METHOD__ . ': Waiting for replica DB {dbserver} to catch up...',
- [ 'dbserver' => $server ] );
+ $this->replLogger->info(
+ __METHOD__ .
+ ': Waiting for replica DB {dbserver} to catch up...',
+ [ 'dbserver' => $server ]
+ );
+
$timeout = $timeout ?: $this->mWaitTimeout;
$result = $conn->masterPosWait( $this->mWaitForPos, $timeout );
- if ( $result == -1 || is_null( $result ) ) {
- // Timed out waiting for replica DB, use master instead
+ if ( $result === null ) {
+ $this->replLogger->warning(
+ __METHOD__ . ': Errored out waiting on {host} pos {pos}',
+ [
+ 'host' => $server,
+ 'pos' => $this->mWaitForPos,
+ 'trace' => ( new RuntimeException() )->getTraceAsString()
+ ]
+ );
+ $ok = false;
+ } elseif ( $result == -1 ) {
$this->replLogger->warning(
__METHOD__ . ': Timed out waiting on {host} pos {pos}',
- [ 'host' => $server, 'pos' => $this->mWaitForPos ]
+ [
+ 'host' => $server,
+ 'pos' => $this->mWaitForPos,
+ 'trace' => ( new RuntimeException() )->getTraceAsString()
+ ]
);
$ok = false;
} else {
$result = $conn->masterPosWait( $pos, $timeout );
if ( $result == -1 || is_null( $result ) ) {
$msg = __METHOD__ . ': Timed out waiting on {host} pos {pos}';
- $this->replLogger->warning( $msg,
- [ 'host' => $conn->getServer(), 'pos' => $pos ] );
+ $this->replLogger->warning( $msg, [
+ 'host' => $conn->getServer(),
+ 'pos' => $pos,
+ 'trace' => ( new RuntimeException() )->getTraceAsString()
+ ] );
$ok = false;
} else {
$this->replLogger->info( __METHOD__ . ': Done' );
}
} else {
$ok = false; // something is misconfigured
- $this->replLogger->error( 'Could not get master pos for {host}',
- [ 'host' => $conn->getServer() ] );
+ $this->replLogger->error(
+ __METHOD__ . ': could not get master pos for {host}',
+ [
+ 'host' => $conn->getServer(),
+ 'trace' => ( new RuntimeException() )->getTraceAsString()
+ ]
+ );
}
return $ok;
LinkTarget $linkTarget,
$timestamp
) {
- // wfDeprecated( __METHOD__, '1.27' );
+ wfDeprecated( __METHOD__, '1.27' );
$config = RequestContext::getMain()->getConfig();
if ( !$config->get( 'EnotifWatchlist' ) && !$config->get( 'ShowUpdatedMarker' ) ) {
return [];
'stubthreshold' => true,
'printable' => true,
'userlang' => true,
- 'wrapclass' => true,
];
/**
/**
* CSS class to use to wrap output from Parser::parse()
* @since 1.30
- * @param string|bool $className Set false to disable wrapping.
- * Passing false is deprecated since MediaWiki 1.31
+ * @param string $className Class name to use for wrapping.
+ * Passing false to indicate "no wrapping" was deprecated in MediaWiki 1.31.
* @return string|bool Current value
*/
public function setWrapOutputClass( $className ) {
if ( $className === true ) { // DWIM, they probably want the default class name
$className = 'mw-parser-output';
}
+ if ( $className === false ) {
+ wfDeprecated( __METHOD__ . '( false )', '1.31' );
+ }
return $this->setOption( 'wrapclass', $className );
}
if ( isset( $item['text'] ) ) {
$text = $item['text'];
} else {
- $text = $this->translator->translate( isset( $item['msg'] ) ? $item['msg'] : $key );
+ $text = wfMessage( isset( $item['msg'] ) ? $item['msg'] : $key )->text();
}
$html = htmlspecialchars( $text );
$realAttrs = [
'type' => 'submit',
'name' => $mode,
- 'value' => $this->translator->translate(
- $mode == 'go' ? 'searcharticle' : 'searchbutton' ),
+ 'value' => wfMessage( $mode == 'go' ? 'searcharticle' : 'searchbutton' )->text(),
];
$realAttrs = array_merge(
$realAttrs,
'src' => $attrs['src'],
'alt' => isset( $attrs['alt'] )
? $attrs['alt']
- : $this->translator->translate( 'searchbutton' ),
+ : wfMessage( 'searchbutton' )->text(),
'width' => isset( $attrs['width'] ) ? $attrs['width'] : null,
'height' => isset( $attrs['height'] ) ? $attrs['height'] : null,
];
class MediaWikiI18N {
private $context = [];
+ /**
+ * @deprecate since 1.31 Use BaseTemplate::msg() or Skin::msg() instead for setting
+ * message parameters.
+ */
function set( $varName, $value ) {
+ wfDeprecated( __METHOD__, '1.31' );
$this->context[$varName] = $value;
}
+ /**
+ * @deprecate since 1.31 Use BaseTemplate::msg(), Skin::msg(), or wfMessage() instead.
+ */
function translate( $value ) {
+ wfDeprecated( __METHOD__, '1.31' );
// Hack for i18n:attributes in PHPTAL 1.0.0 dev version as of 2004-10-23
$value = preg_replace( '/^string:/', '', $value );
/**
* @param MediaWikiI18N &$t
+ * @deprecate since 1.31 Use BaseTemplate::msg() or Skin::msg() instead for setting
+ * message parameters.
*/
public function setTranslator( &$t ) {
+ wfDeprecated( __METHOD__, '1.31' );
$this->translator = &$t;
}
/**
* @private
- * @param string $str
+ * @param string $msgKey
*/
- function msg( $str ) {
- echo htmlspecialchars( $this->translator->translate( $str ) );
+ function msg( $msgKey ) {
+ echo htmlspecialchars( wfMessage( $msgKey )->text() );
}
/**
* @private
- * @param string $str
+ * @param string $msgKey
*/
- function msgHtml( $str ) {
- echo $this->translator->translate( $str );
+ function msgHtml( $msgKey ) {
+ echo wfMessage( $msgKey )->text();
}
/**
* @private
* @param string $str
*/
- function msgWiki( $str ) {
+ function msgWiki( $msgKey ) {
global $wgOut;
- $text = $this->translator->translate( $str );
+ $text = wfMessage( $msgKey )->text();
echo $wgOut->parse( $text );
}
/**
* @private
*
- * @param string $str
+ * @param string $msgKey
* @return bool
*/
- function haveMsg( $str ) {
- $msg = $this->translator->translate( $str );
- return ( $msg != '-' ) && ( $msg != '' ); # ????
+ function haveMsg( $msgKey ) {
+ $msg = wfMessage( $msgKey );
+ return $msg->exists() && !$msg->isDisabled();
}
/**
return $subpages;
}
- /**
- * @deprecated since 1.27, feature removed
- * @return bool Always false
- */
- function showIPinHeader() {
- wfDeprecated( __METHOD__, '1.27' );
- return false;
- }
-
/**
* @return string
*/
* @deprecated since 1.23, use SpecialPage::getPageTitle
*/
function getTitle( $subpage = false ) {
+ wfDeprecated( __METHOD__, '1.23' );
return $this->getPageTitle( $subpage );
}
'srn' => 'Sranantongo', # Sranan Tongo
'ss' => 'SiSwati', # Swati
'st' => 'Sesotho', # Southern Sotho
+ 'sty' => 'cебертатар', # Siberian Tatar
'stq' => 'Seeltersk', # Saterland Frisian
'su' => 'Basa Sunda', # Sundanese
'sv' => 'svenska', # Swedish
"right-move-subpages": "Перанос старонак разам зь іх падстаронкамі",
"right-move-rootuserpages": "перанос карэнных старонак удзельнікаў",
"right-move-categorypages": "перанос старонак катэгорыяў",
- "right-movefile": "перайменаваньне файлаў",
+ "right-movefile": "Ð\9fерайменаваньне файлаў",
"right-suppressredirect": "не ствараць перанакіраваньне са старой назвы пасьля пераносу старонкі",
"right-upload": "загрузка файлаў",
"right-reupload": "перазапіс існуючых файлаў",
"postedit-confirmation-created": "Creouse a páxina.",
"postedit-confirmation-restored": "Restaurouse a páxina.",
"postedit-confirmation-saved": "Gardouse a súa edición.",
+ "postedit-confirmation-published": "A súa edición foi publicada.",
"edit-already-exists": "Non se pode crear a nova páxina.\nEsta xa existe.",
"defaultmessagetext": "Texto predeterminado",
"content-failed-to-parse": "Erro ao analizar o contido de \"$2\" para o modelo de $1: $3",
"lockmanager-fail-closelock": "Non se puido pechar o ficheiro de peche de \"$1\".",
"lockmanager-fail-deletelock": "Non se puido borrar o ficheiro de peche de \"$1\".",
"lockmanager-fail-acquirelock": "Non se puido obter o peche de \"$1\".",
- "lockmanager-fail-openlock": "Non se puido abrir o ficheiro de peche de \"$1\".",
+ "lockmanager-fail-openlock": "Non se puido abrir o ficheiro de bloqueo de \"$1\". Revise que o directorio de cargas estea configurado correctamente e que o seu servidor web teña permisos de escritura nese directorio. Consulte https://www.mediawiki.org/wiki/Special:MyLanguage/Manual:$wgUploadDirectory para obter máis información.",
"lockmanager-fail-releaselock": "Non se puido liberar o peche de \"$1\".",
"lockmanager-fail-db-bucket": "Non se puido contactar cos peches de bases de datos suficientes no cubo $1.",
"lockmanager-fail-db-release": "Non se puideron liberar os peches na base de datos $1.",
"doubleredirects": "Redireccións dobres",
"doubleredirectstext": "Esta lista contén as páxinas que redirixen cara a outras páxinas de redirección.\nCada ringleira contén ligazóns cara á primeira e segunda redireccións, así como a primeira liña de texto da segunda páxina, que é frecuentemente o artigo \"real\", á que a primeira redirección debera apuntar.\nAs entradas <del>riscadas</del> xa foron resoltas.",
"double-redirect-fixed-move": "Trasladouse a páxina \"[[$1]]\".\nActualizouse automaticamente e agora é unha redirección cara a \"[[$2]]\".",
- "double-redirect-fixed-maintenance": "Arranxo automaticamente a redirección dobre entre \"[[$1]]\" e \"[[$2]]\" como tarefa de mantemento.",
+ "double-redirect-fixed-maintenance": "Arranxo automático da redirección dobre entre \"[[$1]]\" e \"[[$2]]\" nunha tarefa de mantemento",
"double-redirect-fixer": "Amañador de redireccións",
"brokenredirects": "Redireccións rotas",
"brokenredirectstext": "As seguintes redireccións ligan cara a páxinas que non existen:",
"rcfilters-advancedfilters": "Napredni filtri",
"rcfilters-limit-title": "Rezultata za prikaz",
"rcfilters-limit-and-date-label": "{{PLURAL:$1|$1 izmjena|$1 izmjene|$1 izmjena}}, $2",
- "rcfilters-date-popup-title": "Vremensko razdoblje za pretragu",
+ "rcfilters-date-popup-title": "Razdoblje za pretraživanje",
"rcfilters-days-title": "Nedavnih dana",
"rcfilters-hours-title": "Nedavnih sati",
"rcfilters-days-show-days": "$1 {{PLURAL:$1|dan|dana}}",
"rcfilters-activefilters": "Virkar síur",
"rcfilters-advancedfilters": "Ítarlegar síur",
"rcfilters-limit-title": "Breytingar sem á að birta",
+ "rcfilters-limit-and-date-label": "$1 {{PLURAL:$1|breyting|breytingar}}, $2",
"rcfilters-date-popup-title": "Tímarammi sem á að leita í",
"rcfilters-days-title": "Síðustu daga",
"rcfilters-hours-title": "Síðustu klukkutíma",
"rcfilters-highlighted-filters-list": "Áherslulitað: $1",
"rcfilters-quickfilters": "Vistaðar síur",
"rcfilters-quickfilters-placeholder-title": "Engar síur vistaðar",
- "rcfilters-quickfilters-placeholder-description": "Til þess að vista þínar síustillingar og nota þær aftur seinna, smelltu á bókamerkistáknið undir Virkum síum hér fyrir neðan.",
+ "rcfilters-quickfilters-placeholder-description": "Til þess að vista síustillingarnar þínar og nota þær aftur seinna, smelltu á bókamerkistáknið undir 'Virkar síur' hér fyrir neðan.",
"rcfilters-savedqueries-defaultlabel": "Vistaðar síur",
"rcfilters-savedqueries-rename": "Endurnefna",
"rcfilters-savedqueries-setdefault": "Setja sem sjálfgefið",
"rcfilters-liveupdates-button-title-off": "Sýna nýjar breytingar um leið og þær gerast",
"rcfilters-watchlist-markseen-button": "Merkja allar breytingar sem skoðaðar",
"rcfilters-watchlist-edit-watchlist-button": "Breyta þínum lista yfir vaktaðar síður",
+ "rcfilters-filter-showlinkedfrom-label": "Sýna breytingar á síðum sem tengt er í frá",
+ "rcfilters-filter-showlinkedfrom-option-label": "<strong>Síður sem tengt er í</strong> frá valinni síðu",
+ "rcfilters-filter-showlinkedto-label": "Sýna breytingar á síðum sem tengjast í",
+ "rcfilters-filter-showlinkedto-option-label": "<strong>Síður sem tengjast í</strong> valda síðu",
"rcfilters-target-page-placeholder": "Settu inn síðuheiti (eða flokk)",
"rcnotefrom": "Að neðan {{PLURAL:$5|er breyting síðan|eru breytingar síðan}} <strong>$3, $4</strong> (allt að <strong>$1</strong> sýndar).",
"rclistfromreset": "Endurstilla dagsetningarval",
"postedit-confirmation-created": "문서가 만들어졌습니다.",
"postedit-confirmation-restored": "문서가 되돌려졌습니다.",
"postedit-confirmation-saved": "편집을 저장했습니다.",
+ "postedit-confirmation-published": "편집이 게시되었습니다.",
"edit-already-exists": "새 문서를 만들 수 없습니다.\n문서가 이미 존재합니다.",
"defaultmessagetext": "기본 메시지 글",
"content-failed-to-parse": "$1 모델에 대한 $2 내용을 구문 분석하는 데 실패했습니다: $3",
"site-atom-feed": "Feed Atom de $1",
"page-rss-feed": "Feed RSS pe \"$1\"",
"page-atom-feed": "Feed Atom pe \"$1\"",
- "red-link-title": "$1 (a pàgina no esiste)",
+ "red-link-title": "$1 (a pàgina a no existe)",
"sort-descending": "Ordine decrescente",
"sort-ascending": "Ordine crescente",
"nstab-main": "Pàgina",
"userlogin-yourname-ph": "Inserisci o teu nómme uténte",
"createacct-another-username-ph": "Scrivi o teu nomme utente",
"yourpassword": "Pòula segretta:",
- "userlogin-yourpassword": "Ciâve",
+ "userlogin-yourpassword": "Inserisci a teu ciâve",
"userlogin-yourpassword-ph": "Scrivi a tu poula segretta.",
"createacct-yourpassword-ph": "Scrivi 'na poula segretta.",
"yourpasswordagain": "Riscrivi a pòula segrétta:",
"emailuserfooter": "Questa email a l'è stæta {{GENDER:$1|inviâ}} da $1 a {{GENDER:$2|$2}} a traverso a fonçion \"{{int:emailuser}}\" insce {{SITENAME}}. Se {{GENDER:$2|ti ghe rispondi}}, a to email de risposta a saiâ spedia direttamente {{GENDER:$1|a-o|a-a}} mittente originâ, rivelando{{GENDER:$1|ghe}} o {{GENDER:$2|to}} adresso de posta elettronica.",
"usermessage-summary": "Messaggio de scistema",
"usermessage-editor": "Messaggê de scistema",
- "watchlist": "Ã\92servòi speciâli",
- "mywatchlist": "òservòi speciâli",
+ "watchlist": "Ã\92servæ speciâli",
+ "mywatchlist": "òservæ speciâli",
"watchlistfor2": "Pe $1 $2",
"nowatchlist": "A lista di öservæ speciali a l'è voeua.",
"watchlistanontext": "Pe vixualizzâ e modificâ l'elenco di öservæ l'è necessaio eseguî l'accesso.",
"watchlist-details": "Tu uzraugi $1 {{PLURAL:$1|lapas|lapu|lapas}} (neieskaitot diskusiju lapas).",
"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",
"rcfilters-watchlist-markseen-button": "Oznacz wszystkie zmiany jako obejrzane",
"rcfilters-watchlist-edit-watchlist-button": "Edytuj swoją listę obserwowanych stron",
"rcfilters-watchlist-showupdated": "<strong>Wytłuszczono</strong> strony, których nie odwiedził{{GENDER:|e|a|e}}ś od czasu zapisania ostatnich zmian.",
- "rcfilters-preference-label": "Wyłącz ulepszenia strony Ostatnie zmiany",
+ "rcfilters-preference-label": "Wyłącz ulepszenia strony Ostatnich zmian",
"rcfilters-preference-help": "Wycofuje wszystkie zmiany interfejsu z 2017 i narzędzia dodane od tamtej pory.",
"rcfilters-filter-showlinkedfrom-label": "Pokaż zmiany na stronach linkowanych z",
"rcfilters-filter-showlinkedfrom-option-label": "<strong>Strony linkowane z</strong> zaznaczonej strony",
"log-action-filter-managetags-activate": "активирање ознаке",
"log-action-filter-managetags-deactivate": "деактивирање ознаке",
"log-action-filter-move-move": "премештање без преснимавања преусмерења",
- "log-action-filter-move-move_redir": "Ð\9fÑ\80емеÑ\88Ñ\82аÑ\9aе Ñ\81а пÑ\80епиÑ\81ивањем преусмерења",
+ "log-action-filter-move-move_redir": "пÑ\80емеÑ\88Ñ\82аÑ\9aе Ñ\81а пÑ\80еÑ\81нимавањем преусмерења",
"log-action-filter-newusers-create": "отворио анониман корисник",
"log-action-filter-newusers-create2": "отворио регистрован корисник",
"log-action-filter-newusers-autocreate": "аутоматски отворен",
"log-action-filter-protect-protect": "закључавање",
"log-action-filter-protect-modify": "измена закључавања",
"log-action-filter-protect-unprotect": "уклањање закључавања",
- "log-action-filter-protect-move_prot": "Ð\9fремештање заштите",
+ "log-action-filter-protect-move_prot": "премештање заштите",
"log-action-filter-rights-rights": "ручно",
"log-action-filter-rights-autopromote": "аутоматски",
- "log-action-filter-upload-upload": "Ð\9dово отпремање",
+ "log-action-filter-upload-upload": "ново отпремање",
"log-action-filter-upload-overwrite": "промена постојећег",
"authmanager-authplugin-setpass-failed-title": "Неуспешна промена лозинке",
"authmanager-email-label": "Имејл",
"mw-widgets-usersmultiselect-placeholder": "Dodaj još...",
"randomrootpage": "Slučajna korenska stranica",
"log-action-filter-all": "Sve",
- "log-action-filter-move-move_redir": "Premeštanje sa prepisivanjem preusmerenja",
- "log-action-filter-protect-move_prot": "Premeštanje zaštite",
- "log-action-filter-upload-upload": "Novo otpremanje",
+ "log-action-filter-move-move_redir": "premeštanje sa presnimavanjem preusmerenja",
+ "log-action-filter-protect-move_prot": "premeštanje zaštite",
+ "log-action-filter-upload-upload": "novo otpremanje",
"authmanager-email-label": "Imejl",
"authmanager-email-help": "Imejl adresa",
"changecredentials": "Promjena akreditiva",
--- /dev/null
+<?php
+/** Siberian Tatar (cебертатар)
+ *
+ * To improve a translation please visit https://translatewiki.net
+ *
+ * @ingroup Language
+ * @file
+ */
+
+$fallback = 'ru';
border: 1pt dashed #000;
padding: 1em 0;
font-size: 8pt;
- white-space: pre;
+ white-space: pre-wrap;
word-wrap: break-word;
- overflow: auto;
}
/* Prevent citations and subscripts from interfering with the line-height */
var apiPromise = this.get( {
formatversion: 2,
prop: 'categoryinfo',
- titles: String( title )
+ titles: [ String( title ) ]
} );
return apiPromise
.then( function ( data ) {
- return !!data.query.pages[ 0 ].categoryinfo;
+ return !!(
+ data.query && // query is missing on title=""
+ data.query.pages && // query.pages is missing on title="#" or title="mw:"
+ data.query.pages[ 0 ].categoryinfo
+ );
} )
.promise( { abort: apiPromise.abort } );
},
var apiPromise = this.get( {
formatversion: 2,
prop: 'categories',
- titles: String( title )
+ titles: [ String( title ) ]
} );
return apiPromise
.then( function ( data ) {
- var page = data.query.pages[ 0 ];
+ var page;
+ if ( !data.query || !data.query.pages ) {
+ return false;
+ }
+ page = data.query.pages[ 0 ];
if ( !page.categories ) {
return false;
}
edit: function ( title, transform ) {
var basetimestamp, curtimestamp,
api = this;
+
+ title = String( title );
+
return api.get( {
action: 'query',
prop: 'revisions',
rvprop: [ 'content', 'timestamp' ],
- titles: String( title ),
+ titles: [ title ],
formatversion: '2',
curtimestamp: true
} )
return $.Deferred().reject( 'unknown' );
}
page = data.query.pages[ 0 ];
- if ( !page || page.missing ) {
+ if ( !page || page.invalid ) {
+ return $.Deferred().reject( 'invalidtitle' );
+ }
+ if ( page.missing ) {
return $.Deferred().reject( 'nocreate-missing' );
}
revision = page.revisions[ 0 ];
}
}
+ SiteStatsInit::doPlaceholderInit();
+
User::resetIdByNameCache();
// Make sysop user
*/
class RevisionStoreDbTest extends MediaWikiTestCase {
+ public function setUp() {
+ parent::setUp();
+ $this->tablesUsed[] = 'archive';
+ $this->tablesUsed[] = 'page';
+ $this->tablesUsed[] = 'revision';
+ $this->tablesUsed[] = 'comment';
+ }
+
/**
* @return LoadBalancer
*/
// FIXME: This is invalid, but currently tolerated
[ "*/", "*/", false ],
+ // Cover failure case of incomplete char class in regexp (T75556)
+ // FIXME: This is invalid, but currently tolerated
+ [ "/a[b/.test", "/a[b/.test", false ],
+
// Cover failure case of incomplete string at end of file (T75556)
// FIXME: This is invalid, but currently tolerated
[ "'a", "'a", false ],
'stubthreshold' => true,
'printable' => true,
'userlang' => true,
- 'wrapclass' => true,
];
}
'Non-in-key options are not ok' => [ false, [
'removeComments' => false,
] ],
+ 'Non-in-key options are not ok (2)' => [ false, [
+ 'wrapclass' => 'foobar',
+ ] ],
'Canonical override, not default (1)' => [ true, [
'tidy' => true,
] ],
$wgHooks['ParserOptionsRegister'] = [];
$this->assertSame( [
'dateformat', 'numberheadings', 'printable', 'stubthreshold',
- 'thumbsize', 'userlang', 'wrapclass',
+ 'thumbsize', 'userlang'
], ParserOptions::allCacheVaryingOptions() );
self::clearCache();
};
$this->assertSame( [
'dateformat', 'foo', 'numberheadings', 'printable', 'stubthreshold',
- 'thumbsize', 'userlang', 'wrapclass',
+ 'thumbsize', 'userlang'
], ParserOptions::allCacheVaryingOptions() );
}
"class_alias( Foo::class, 'Bar' );",
[ 'Bar' ],
],
+ [
+ // Namespaced class is not currently supported. Must use namespace declaration
+ // earlier in the file.
+ "class_alias( Example\Foo::class, 'Bar' );",
+ [],
+ ],
[
"namespace Example;\nclass Foo {}\nclass_alias( Foo::class, 'Bar' );",
[ 'Example\Foo', 'Bar' ],
);
} );
} );
+
+ QUnit.test( '.isCategory("")', function ( assert ) {
+ this.server.respondWith( /titles=$/, [
+ 200,
+ { 'Content-Type': 'application/json' },
+ '{"batchcomplete":true}'
+ ] );
+ return new mw.Api().isCategory( '' ).then( function ( response ) {
+ assert.equal( response, false );
+ } );
+ } );
+
+ QUnit.test( '.isCategory("#")', function ( assert ) {
+ this.server.respondWith( /titles=%23$/, [
+ 200,
+ { 'Content-Type': 'application/json' },
+ '{"batchcomplete":true,"query":{"normalized":[{"fromencoded":false,"from":"#","to":""}]}}'
+ ] );
+ return new mw.Api().isCategory( '#' ).then( function ( response ) {
+ assert.equal( response, false );
+ } );
+ } );
+
+ QUnit.test( '.isCategory("mw:")', function ( assert ) {
+ this.server.respondWith( /titles=mw%3A$/, [
+ 200,
+ { 'Content-Type': 'application/json' },
+ '{"batchcomplete":true,"query":{"interwiki":[{"title":"mw:","iw":"mw"}]}}'
+ ] );
+ return new mw.Api().isCategory( 'mw:' ).then( function ( response ) {
+ assert.equal( response, false );
+ } );
+ } );
+
+ QUnit.test( '.isCategory("|")', function ( assert ) {
+ this.server.respondWith( /titles=%1F%7C$/, [
+ 200,
+ { 'Content-Type': 'application/json' },
+ '{"batchcomplete":true,"query":{"pages":[{"title":"|","invalidreason":"The requested page title contains invalid characters: \\"|\\".","invalid":true}]}}'
+ ] );
+ return new mw.Api().isCategory( '|' ).then( function ( response ) {
+ assert.equal( response, false );
+ } );
+ } );
+
+ QUnit.test( '.getCategories("")', function ( assert ) {
+ this.server.respondWith( /titles=$/, [
+ 200,
+ { 'Content-Type': 'application/json' },
+ '{"batchcomplete":true}'
+ ] );
+ return new mw.Api().getCategories( '' ).then( function ( response ) {
+ assert.equal( response, false );
+ } );
+ } );
+
+ QUnit.test( '.getCategories("#")', function ( assert ) {
+ this.server.respondWith( /titles=%23$/, [
+ 200,
+ { 'Content-Type': 'application/json' },
+ '{"batchcomplete":true,"query":{"normalized":[{"fromencoded":false,"from":"#","to":""}]}}'
+ ] );
+ return new mw.Api().getCategories( '#' ).then( function ( response ) {
+ assert.equal( response, false );
+ } );
+ } );
+
+ QUnit.test( '.getCategories("mw:")', function ( assert ) {
+ this.server.respondWith( /titles=mw%3A$/, [
+ 200,
+ { 'Content-Type': 'application/json' },
+ '{"batchcomplete":true,"query":{"interwiki":[{"title":"mw:","iw":"mw"}]}}'
+ ] );
+ return new mw.Api().getCategories( 'mw:' ).then( function ( response ) {
+ assert.equal( response, false );
+ } );
+ } );
+
+ QUnit.test( '.getCategories("|")', function ( assert ) {
+ this.server.respondWith( /titles=%1F%7C$/, [
+ 200,
+ { 'Content-Type': 'application/json' },
+ '{"batchcomplete":true,"query":{"pages":[{"title":"|","invalidreason":"The requested page title contains invalid characters: \\"|\\".","invalid":true}]}}'
+ ] );
+ return new mw.Api().getCategories( '|' ).then( function ( response ) {
+ assert.equal( response, false );
+ } );
+ } );
+
}( mediaWiki ) );
} );
} );
+ QUnit.test( 'edit( mw.Title, transform String )', function ( assert ) {
+ this.server.respond( function ( req ) {
+ if ( /query.+titles=Sandbox/.test( req.url ) ) {
+ req.respond( 200, { 'Content-Type': 'application/json' }, JSON.stringify( {
+ curtimestamp: '2016-01-02T12:00:00Z',
+ query: {
+ pages: [ {
+ pageid: 1,
+ ns: 0,
+ title: 'Sandbox',
+ revisions: [ {
+ timestamp: '2016-01-01T12:00:00Z',
+ contentformat: 'text/x-wiki',
+ contentmodel: 'wikitext',
+ content: 'Sand.'
+ } ]
+ } ]
+ }
+ } ) );
+ }
+ if ( /edit.+basetimestamp=2016-01-01.+starttimestamp=2016-01-02.+text=Box%2E/.test( req.requestBody ) ) {
+ req.respond( 200, { 'Content-Type': 'application/json' }, JSON.stringify( {
+ edit: {
+ result: 'Success',
+ oldrevid: 11,
+ newrevid: 13,
+ newtimestamp: '2016-01-03T12:00:00Z'
+ }
+ } ) );
+ }
+ } );
+
+ return new mw.Api()
+ .edit( new mw.Title( 'Sandbox' ), function ( revision ) {
+ return revision.content.replace( 'Sand', 'Box' );
+ } )
+ .then( function ( edit ) {
+ assert.equal( edit.newrevid, 13 );
+ } );
+ } );
+
QUnit.test( 'edit( title, transform Promise )', function ( assert ) {
this.server.respond( function ( req ) {
if ( /query.+titles=Async/.test( req.url ) ) {
} );
} );
+ QUnit.test( 'edit( invalid-title, transform String )', function ( assert ) {
+ this.server.respond( function ( req ) {
+ if ( /query.+titles=%1F%7C/.test( req.url ) ) {
+ req.respond( 200, { 'Content-Type': 'application/json' }, JSON.stringify( {
+ query: {
+ pages: [ {
+ title: '|',
+ invalidreason: 'The requested page title contains invalid characters: "|".',
+ invalid: true
+ } ]
+ }
+ } ) );
+ }
+ } );
+
+ return new mw.Api()
+ .edit( '|', function ( revision ) {
+ return revision.content.replace( 'Sand', 'Box' );
+ } )
+ .then( function () {
+ return $.Deferred().reject( 'Unexpected success' );
+ }, function ( reason ) {
+ assert.equal( reason, 'invalidtitle' );
+ } );
+ } );
+
QUnit.test( 'create( title, content )', function ( assert ) {
this.server.respond( function ( req ) {
if ( /edit.+text=Sand/.test( req.requestBody ) ) {