* (T198214) The 'disabletidy' parameter to action=parse has been
deprecated; untidy output will not be supported by future wikitext
parsers.
+* Added intestactionsdetail to action=query&prop=info to allow retrieving the
+ reasons an action is not allowed.
+* Deprecated action=query&prop=info inprop=readable in favor of
+ intestactions=read.
=== Action API internal changes in 1.32 ===
* Added 'ApiParseMakeOutputPage' hook.
* ApiUsageException::getCodeString() (deprecated in 1.29)
* ApiUsageException::getMessageArray() (deprecated in 1.29)
* Class UsageException, deprecated in 1.29, has been removed.
+* ApiErrorFormatter: Added getFormat() and newWithFormat(). In particular, you
+ can now easily test $formatter->getFormat() === 'bc', and then call
+ $formatter->newWithFormat( 'plaintext' ) to get a non-BC formatter.
=== Languages updated in 1.32 ===
MediaWiki supports over 350 languages. Many localisations are updated regularly.
* The $wgUseKeyHeader configuration option and the
OutputPage::getKeyHeader() method have been deprecated; the relevant
draft IETF spec expired without becoming a standard.
+* Deprecated API action=query&prop=info inprop=readable in favor of
+ intestactions=read.
=== Other changes in 1.32 ===
* (T198811) The following tables have had their UNIQUE indexes turned into
--- /dev/null
+== MediaWiki 1.33 ==
+
+THIS IS NOT A RELEASE YET
+
+MediaWiki 1.33 is an alpha-quality branch and is not recommended for use in
+production.
+
+=== Configuration changes in 1.33 ===
+
+==== New configuration ====
+* …
+
+==== Changed configuration ====
+* …
+
+==== Removed configuration ====
+* …
+
+=== New features in 1.33 ===
+* …
+
+=== External library changes in 1.33 ===
+
+==== New external libraries ====
+* …
+
+==== Changed external libraries ====
+* …
+
+==== Removed external libraries ====
+* …
+
+=== Bug fixes in 1.33 ===
+* …
+
+=== Action API changes in 1.33 ===
+* …
+
+=== Action API internal changes in 1.33 ===
+* …
+
+=== Languages updated in 1.33 ===
+MediaWiki supports over 350 languages. Many localisations are updated regularly.
+Below only new and removed languages are listed, as well as changes to languages
+because of Phabricator reports.
+
+* …
+
+=== Breaking changes in 1.33 ===
+* …
+
+=== Deprecations in 1.33 ===
+* …
+
+=== Other changes in 1.33 ===
+* …
+
+== Compatibility ==
+MediaWiki 1.33 requires PHP 7.0.0 or later. Although HHVM 3.18.5 or later is
+supported, it is generally advised to use PHP 7.0.0 or later for long term
+support.
+
+MySQL/MariaDB is the recommended DBMS. PostgreSQL or SQLite can also be used,
+but support for them is somewhat less mature. There is experimental support for
+Oracle and Microsoft SQL Server.
+
+The supported versions are:
+
+* MySQL 5.5.8 or later
+* PostgreSQL 9.2 or later
+* SQLite 3.3.7 or later
+* Oracle 9.0.1 or later
+* Microsoft SQL Server 2005 (9.00.1399)
+
+== Upgrading ==
+1.33 has several database changes since 1.32, and will not work without schema
+updates. Note that due to changes to some very large tables like the revision
+table, the schema update may take quite long (minutes on a medium sized site,
+many hours on a large site).
+
+Don't forget to always back up your database before upgrading!
+
+See the file UPGRADE for more detailed upgrade instructions, including
+important information when upgrading from versions prior to 1.11.
+
+For notes on 1.32.x and older releases, see HISTORY.
+
+== Online documentation ==
+Documentation for both end-users and site administrators is available on
+MediaWiki.org, and is covered under the GNU Free Documentation License (except
+for pages that explicitly state that their contents are in the public domain):
+
+ https://www.mediawiki.org/wiki/Special:MyLanguage/Documentation
+
+== Mailing list ==
+A mailing list is available for MediaWiki user support and discussion:
+
+ https://lists.wikimedia.org/mailman/listinfo/mediawiki-l
+
+A low-traffic announcements-only list is also available:
+
+ https://lists.wikimedia.org/mailman/listinfo/mediawiki-announce
+
+It's highly recommended that you sign up for one of these lists if you're
+going to run a public MediaWiki, so you can be notified of security fixes.
+
+== IRC help ==
+There's usually someone online in #mediawiki on irc.freenode.net.
* MediaWiki version number
* @since 1.2
*/
-$wgVersion = '1.32.0-alpha';
+$wgVersion = '1.33.0-alpha';
/**
* Name of the site. It must be changed in LocalSettings.php
*/
$wgActorTableSchemaMigrationStage = SCHEMA_COMPAT_OLD;
-/**
- * Temporary option to disable the date picker from the Expiry Widget.
- *
- * @since 1.32
- * @deprecated 1.32
- * @var bool
- */
-$wgExpiryWidgetNoDatePicker = false;
-
/**
* change_tag table schema migration stage.
*
function wfWaitForSlaves(
$ifWritesSince = null, $wiki = false, $cluster = false, $timeout = null
) {
+ $lbFactory = MediaWikiServices::getInstance()->getDBLoadBalancerFactory();
+
if ( $cluster === '*' ) {
$cluster = false;
- $wiki = false;
+ $domain = false;
} elseif ( $wiki === false ) {
- $wiki = wfWikiID();
+ $domain = $lbFactory->getLocalDomainID();
+ } else {
+ $domain = $wiki;
}
$opts = [
- 'wiki' => $wiki,
+ 'domain' => $domain,
'cluster' => $cluster,
// B/C: first argument used to be "max seconds of lag"; ignore such values
'ifWritesSince' => ( $ifWritesSince > 1e9 ) ? $ifWritesSince : null
$opts['timeout'] = $timeout;
}
- $lbFactory = MediaWikiServices::getInstance()->getDBLoadBalancerFactory();
return $lbFactory->waitForReplication( $opts );
}
*/
class PHPVersionCheck {
/* @var string The number of the MediaWiki version used */
- var $mwVersion = '1.32';
+ var $mwVersion = '1.33';
var $functionsExtensionsMapping = array(
'mb_substr' => 'mbstring',
'xml_parser_create' => 'xml',
$dbw = wfGetDB( DB_MASTER );
$dbw->onTransactionPreCommitOrIdle(
- function () {
- ResourceLoaderWikiModule::invalidateModuleCache( $this, null, null, wfWikiID() );
+ function () use ( $dbw ) {
+ ResourceLoaderWikiModule::invalidateModuleCache(
+ $this, null, null, $dbw->getDomainId() );
},
__METHOD__
);
$this->format = $format;
}
+ /**
+ * Return a formatter like this one but with a different format
+ *
+ * @since 1.32
+ * @param string $format New format.
+ * @return ApiErrorFormatter
+ */
+ public function newWithFormat( $format ) {
+ return new self( $this->result, $this->lang, $format, $this->useDB );
+ }
+
+ /**
+ * Fetch the format for this formatter
+ * @since 1.32
+ * @return string
+ */
+ public function getFormat() {
+ return $this->format;
+ }
+
/**
* Fetch the Language for this formatter
* @since 1.29
parent::__construct( $result, Language::factory( 'en' ), 'none', false );
}
+ public function getFormat() {
+ return 'bc';
+ }
+
public function arrayFromStatus( StatusValue $status, $type = 'error', $format = null ) {
if ( $status->isGood() || !$status->getErrors() ) {
return [];
return null; // force a continuation
}
+ $detailLevel = $this->params['testactionsdetail'];
+ $rigor = $detailLevel === 'quick' ? 'quick' : 'secure';
+ $errorFormatter = $this->getErrorFormatter();
+ if ( $errorFormatter->getFormat() === 'bc' ) {
+ // Eew, no. Use a more modern format here.
+ $errorFormatter = $errorFormatter->newWithFormat( 'plaintext' );
+ }
+
$user = $this->getUser();
$pageInfo['actions'] = [];
foreach ( $this->params['testactions'] as $action ) {
$this->countTestedActions++;
- $pageInfo['actions'][$action] = $title->userCan( $action, $user );
+
+ if ( $detailLevel === 'boolean' ) {
+ $pageInfo['actions'][$action] = $title->userCan( $action, $user );
+ } else {
+ $pageInfo['actions'][$action] = $errorFormatter->arrayFromStatus( $this->errorArrayToStatus(
+ $title->getUserPermissionsErrors( $action, $user, $rigor ),
+ $user
+ ) );
+ }
}
}
// need to be added to getCacheMode()
],
ApiBase::PARAM_HELP_MSG_PER_VALUE => [],
+ ApiBase::PARAM_DEPRECATED_VALUES => [
+ 'readable' => true, // Since 1.32
+ ],
],
'testactions' => [
ApiBase::PARAM_TYPE => 'string',
ApiBase::PARAM_ISMULTI => true,
],
+ 'testactionsdetail' => [
+ ApiBase::PARAM_TYPE => [ 'boolean', 'full', 'quick' ],
+ ApiBase::PARAM_DFLT => 'boolean',
+ ApiBase::PARAM_HELP_MSG_PER_VALUE => [],
+ ],
'token' => [
ApiBase::PARAM_DEPRECATED => true,
ApiBase::PARAM_ISMULTI => true,
"apierror-assertnameduserfailed": "تأكيد أن المستخدم \"$1\" فشل.",
"apierror-assertuserfailed": "التأكيد على فشل تسجيل الدخول للمستخدم.",
"apierror-autoblocked": "عنوان الآيبي الخاص بك تم منعه تلقائيا; لأنه تم استخدامه بواسطة مستخدم ممنوع.",
+ "apierror-bad-badfilecontexttitle": "عنوان غير صالح في الوسيط <var>$1badfilecontexttitle</var>.",
"apierror-badconfig-resulttoosmall": "إن قيمة <code>$wgAPIMaxResultSize</code> في هذا الويكي صغيرة جدا لا تحتوي على معلومات النتائج الأساسية.",
"apierror-badcontinue": "متابعة غير صحيحة; يجب عليك تمرير القيمة الأصلية التي تم إرجاعها بواسطة الاستعلام السابق.",
"apierror-baddiff": "لا يمكن استرجاع الفرقك; إحدى أو كلا المراجعتين غير موجودة أو ليست لديك صلاحية لعرضها.",
"apiwarn-deprecation-withreplacement": "تم إيقاف <kbd>$1</kbd>; الرجاء استخدام <kbd>$2</kbd> بدلا من ذلك.",
"apiwarn-difftohidden": "لا يمكنك إجراء مقارنة مع r$1: المحتوى مخفي.",
"apiwarn-errorprinterfailed": "فشل خطأ الطباعة; سوف يعيد دون وسائط.",
- "apiwarn-errorprinterfailed-ex": "فشل خطأ الطباعة (سوف يعيد دون وسائط): $1.",
"apiwarn-ignoring-invalid-templated-value": "تجاهل القيمة <kbd>$2</kbd> في <var>$1</var> عند معالجة وسائط القوالب.",
"apiwarn-invalidcategory": "\"$1\" ليس تصنيفا.",
"apiwarn-invalidtitle": "\"$1\" ليس عنوانا صالحا.",
"apihelp-compare-paramvalue-prop-diff": "Das Unterschieds-HTML.",
"apihelp-compare-paramvalue-prop-diffsize": "Die Größe des Unterschieds-HTML in Bytes.",
"apihelp-compare-paramvalue-prop-title": "Die Seitentitel der Versionen „Von“ und „Nach“.",
+ "apihelp-compare-paramvalue-prop-size": "Die Größe der Versionen „from“ und „to“.",
"apihelp-compare-example-1": "Unterschied zwischen Version 1 und 2 abrufen",
"apihelp-createaccount-summary": "Erstellt ein neues Benutzerkonto.",
"apihelp-createaccount-param-preservestate": "Falls <kbd>[[Special:ApiHelp/query+authmanagerinfo|action=query&meta=authmanagerinfo]]</kbd> für <samp>hasprimarypreservedstate</samp> wahr ausgegeben hat, sollten Anfragen, die als <samp>primary-required</samp> markiert wurden, ausgelassen werden. Falls ein nicht-leerer Wert für <samp>preservedusername</samp> zurückgegeben wurde, muss dieser Benutzername für den Parameter <var>username</var> verwendet werden.",
"apihelp-query+allrevisions-param-generatetitles": "Wenn als Generator verwendet, werden eher Titel als Bearbeitungs-IDs erzeugt.",
"apihelp-query+allrevisions-example-user": "Liste die letzten 50 Beiträge, sortiert nach Benutzer <kbd>Beispiel</kbd> auf.",
"apihelp-query+allrevisions-example-ns-main": "Liste die ersten 50 Bearbeitungen im Hauptnamensraum auf.",
+ "apihelp-query+mystashedfiles-summary": "Ruft eine Liste der Dateien im aktuellen Benutzeruploadspeicher ab.",
"apihelp-query+mystashedfiles-param-prop": "Welche Eigenschaften für die Dateien abgerufen werden sollen.",
"apihelp-query+mystashedfiles-paramvalue-prop-size": "Ruft die Dateigröße und Bildabmessungen ab.",
"apihelp-query+mystashedfiles-paramvalue-prop-type": "Ruft den MIME- und Medientyp der Datei ab.",
"apihelp-query+filearchive-paramvalue-prop-archivename": "Fügt den Dateinamen der Archivversion für die nicht-neuesten Versionen hinzu.",
"apihelp-query+filearchive-example-simple": "Eine Liste aller gelöschten Dateien auflisten",
"apihelp-query+filerepoinfo-summary": "Gebe Metainformationen über Bild-Repositorien zurück, die im Wiki eingerichtet sind.",
+ "apihelp-query+filerepoinfo-paramvalue-prop-displayname": "Der menschenlesbare Name des Repositoriumwikis.",
"apihelp-query+filerepoinfo-paramvalue-prop-local": "Ob dieses Repositorium das lokale ist oder nicht.",
"apihelp-query+filerepoinfo-paramvalue-prop-rootUrl": "Wurzel-URL-Pfad für Bildpfade.",
"apihelp-query+filerepoinfo-paramvalue-prop-scriptDirUrl": "Wurzel-URL-Pfad für die MediaWiki-Installation des Repositoriumwikis.",
"apihelp-query+info-paramvalue-prop-notificationtimestamp": "Der Beobachtungslisten-Benachrichtigungs-Zeitstempel jeder Seite.",
"apihelp-query+info-paramvalue-prop-subjectid": "Die Seitenkennung der Elternseite jeder Diskussionsseite.",
"apihelp-query+info-paramvalue-prop-readable": "Ob der Benutzer diese Seite betrachten darf.",
+ "apihelp-query+info-paramvalue-prop-preload": "Gibt den Text aus, der von EditFormPreloadText zurückgegeben wurde.",
"apihelp-query+info-paramvalue-prop-displaytitle": "Gibt die Art und Weise an, in der der Seitentitel tatsächlich angezeigt wird.",
"apihelp-query+info-paramvalue-prop-varianttitles": "Gibt den Anzeigetitel in allen Varianten der Sprache des Websiteinhalts aus.",
"apihelp-query+info-param-testactions": "Überprüft, ob der aktuelle Benutzer gewisse Aktionen auf der Seite ausführen kann.",
"apihelp-query+iwlinks-param-prefix": "Gibt nur Interwiki-Links mit diesem Präfix zurück.",
"apihelp-query+iwlinks-param-dir": "Die Auflistungsrichtung.",
"apihelp-query+iwlinks-example-simple": "Ruft die Interwikilinks von der Seite <kbd>Hauptseite</kbd> ab.",
+ "apihelp-query+langbacklinks-summary": "Findet alle Seiten, die auf den angegebenen Sprachlink verlinken.",
"apihelp-query+langbacklinks-param-lang": "Sprache für den Sprachlink.",
"apihelp-query+langbacklinks-param-limit": "Wie viele Gesamtseiten zurückgegeben werden sollen.",
"apihelp-query+langbacklinks-param-prop": "Zurückzugebende Eigenschaften:",
+ "apihelp-query+langbacklinks-paramvalue-prop-lllang": "Ergänzt den Sprachcode des Sprachlinks.",
"apihelp-query+langbacklinks-paramvalue-prop-lltitle": "Ergänzt den Titel des Sprachlinks.",
"apihelp-query+langbacklinks-param-dir": "Die Auflistungsrichtung.",
"apihelp-query+langbacklinks-example-simple": "Ruft Seiten ab, die auf [[:fr:Test]] verlinken.",
+ "apihelp-query+langlinks-summary": "Gibt alle Interlanguagelinks von den angegebenen Seiten zurück.",
"apihelp-query+langlinks-param-limit": "Wie viele Sprachlinks zurückgegeben werden sollen.",
"apihelp-query+langlinks-param-prop": "Zusätzlich zurückzugebende Eigenschaften jedes Interlanguage-Links:",
"apihelp-query+langlinks-paramvalue-prop-url": "Ergänzt die vollständige URL.",
"apihelp-query+linkshere-paramvalue-prop-pageid": "Die Seitenkennung jeder Seite.",
"apihelp-query+linkshere-paramvalue-prop-title": "Titel jeder Seite.",
"apihelp-query+linkshere-paramvalue-prop-redirect": "Markieren, falls die Seite eine Weiterleitung ist.",
+ "apihelp-query+linkshere-param-namespace": "Nur Seiten in diesen Namensräumen einschließen.",
"apihelp-query+linkshere-param-limit": "Wie viel zurückgegeben werden soll.",
"apihelp-query+linkshere-example-simple": "Holt eine Liste von Seiten, die auf [[Main Page]] verlinken.",
"apihelp-query+logevents-summary": "Ruft Ereignisse von Logbüchern ab.",
"apihelp-query+logevents-paramvalue-prop-user": "Ergänzt den verantwortlichen Benutzer für das Logbuchereignis.",
"apihelp-query+logevents-paramvalue-prop-timestamp": "Ergänzt den Zeitstempel des Logbucheintrags.",
"apihelp-query+logevents-paramvalue-prop-comment": "Ergänzt den Kommentar des Logbuchereignisses.",
+ "apihelp-query+logevents-paramvalue-prop-parsedcomment": "Ergänzt den geparsten Kommentar des Logbuchereignisses.",
"apihelp-query+logevents-paramvalue-prop-details": "Listet zusätzliche Einzelheiten über das Logbuchereignis auf.",
"apihelp-query+logevents-paramvalue-prop-tags": "Listet Markierungen für das Logbuchereignis auf.",
"apihelp-query+logevents-param-type": "Filtert nur Logbucheinträge mit diesem Typ heraus.",
"api-help-right-apihighlimits": "Höhere Beschränkungen in API-Anfragen verwenden (langsame Anfragen: $1; schnelle Anfragen: $2). Die Beschränkungen für langsame Anfragen werden auch auf Mehrwertparameter angewandt.",
"api-help-open-in-apisandbox": "<small>[in Spielwiese öffnen]</small>",
"api-help-authmanagerhelper-messageformat": "Zu verwendendes Format zur Rückgabe von Nachrichten.",
+ "apierror-bad-badfilecontexttitle": "Ungültiger Titel im Parameter <var>$1badfilecontexttitle</var>.",
"apierror-badgenerator-unknown": "<kbd>generator=$1</kbd> unbekannt.",
"apierror-badip": "Der IP-Parameter ist nicht gültig.",
"apierror-badmd5": "Die angegebene MD5-Prüfsumme war falsch.",
"apihelp-query+info-paramvalue-prop-notificationtimestamp": "The watchlist notification timestamp of each page.",
"apihelp-query+info-paramvalue-prop-subjectid": "The page ID of the parent page for each talk page.",
"apihelp-query+info-paramvalue-prop-url": "Gives a full URL, an edit URL, and the canonical URL for each page.",
- "apihelp-query+info-paramvalue-prop-readable": "Whether the user can read this page.",
+ "apihelp-query+info-paramvalue-prop-readable": "Whether the user can read this page. Use <kbd>intestactions=read</kbd> instead.",
"apihelp-query+info-paramvalue-prop-preload": "Gives the text returned by EditFormPreloadText.",
"apihelp-query+info-paramvalue-prop-displaytitle": "Gives the manner in which the page title is actually displayed.",
"apihelp-query+info-paramvalue-prop-varianttitles": "Gives the display title in all variants of the site content language.",
"apihelp-query+info-param-testactions": "Test whether the current user can perform certain actions on the page.",
+ "apihelp-query+info-param-testactionsdetail": "Detail level for <var>$1testactions</var>. Use the [[Special:ApiHelp/main|main module]]'s <var>errorformat</var> and <var>errorlang</var> parameters to control the format of the messages returned.",
+ "apihelp-query+info-paramvalue-testactionsdetail-boolean": "Return a boolean value for each action.",
+ "apihelp-query+info-paramvalue-testactionsdetail-full": "Return messages describing why the action is disallowed, or an empty array if it is allowed.",
+ "apihelp-query+info-paramvalue-testactionsdetail-quick": "Like <kbd>full</kbd> but skipping expensive checks.",
"apihelp-query+info-param-token": "Use [[Special:ApiHelp/query+tokens|action=query&meta=tokens]] instead.",
"apihelp-query+info-example-simple": "Get information about the page <kbd>Main Page</kbd>.",
"apihelp-query+info-example-protection": "Get general and protection information about the page <kbd>Main Page</kbd>.",
"apierror-assertnameduserfailed": "La vérification que l’utilisateur est « $1 » a échoué.",
"apierror-assertuserfailed": "La vérification que l’utilisateur est connecté a échoué.",
"apierror-autoblocked": "Votre adresse IP a été bloquée automatiquement, parce qu’elle a été utilisée par un utilisateur bloqué.",
+ "apierror-bad-badfilecontexttitle": "Titre invalide dans le paramètre <var>$1badfilecontexttitle</var> .",
"apierror-badconfig-resulttoosmall": "La valeur de <code>$wgAPIMaxResultSize</code> sur ce wiki est trop petite pour contenir des informations de résultat basiques.",
"apierror-badcontinue": "Paramètre de continuation non valide. Vous devez passer la valeur d’origine renvoyée par la requête précédente.",
"apierror-baddiff": "La différence ne peut être récupérée. Une ou les deux révisions n’existent pas ou vous n’avez pas le droit de les voir.",
"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é.",
"apiwarn-errorprinterfailed": "Erreur échec imprimante. Nouvel essai sans paramètres.",
- "apiwarn-errorprinterfailed-ex": "Erreur d’échec de l’impression (réessayera sans paramètres) : $1",
"apiwarn-ignoring-invalid-templated-value": "Ignorer la valeur <kbd>$2</kbd> dans <var>$1</var> en traitant les paramètres de modèle.",
"apiwarn-invalidcategory": "« $1 » n'est pas une catégorie.",
"apiwarn-invalidtitle": "« $1 » n’est pas un titre valide.",
"apiwarn-deprecation-withreplacement": "<kbd>$1</kbd> מיושן. יש להשתמש ב־<kbd>$2</kbd> במקום זה.",
"apiwarn-difftohidden": "לא היה אפשר לעשות השוואה עם גרסה $1: התוכן מוסתר.",
"apiwarn-errorprinterfailed": "מדפיס השגיאות לא עבד. ינסה שוב ללא פרמטרים.",
- "apiwarn-errorprinterfailed-ex": "מדפיס השגיאות לא עבד (ינסה שוב ללא פרמטרים): $1",
"apiwarn-ignoring-invalid-templated-value": "לא ייעשה שימוש בערך <kbd>$2</kbd> שבפרמטר <var>$1</var> בעת עיבוד הפרמטרים בתבנית.",
"apiwarn-invalidcategory": "\"$1\" אינה קטגוריה.",
"apiwarn-invalidtitle": "\"$1\" אינה כותרת תקינה.",
"api-help-authmanagerhelper-returnurl": "URL di ritorno per i flussi di autenticazione di terze parti, deve essere assoluto. E' necessario fornirlo, oppure va fornito <var>$1continue</var>.\n\nAlla ricezione di una risposta <samp>REDIRECT</samp>, in genere si apre un browser o una vista web all'URL specificato <samp>redirecttarget</samp> per un flusso di autenticazione di terze parti. Quando questo è completato, la terza parte invierà il browser o la vista web a questo URL. Dovresti estrarre qualsiasi parametro POST o della richiesta dall'URL e passarli come un request <var>$1continue</var> a questo modulo API.",
"api-help-authmanagerhelper-continue": "Questa richiesta è una continuazione dopo una precedente risposta <samp>UI</samp> o <samp>REDIRECT</samp>. È necessario fornirlo, oppure fornire <var>$1returnurl</var>.",
"api-help-authmanagerhelper-additional-params": "Questo modulo accetta parametri aggiuntivi a seconda delle richieste di autenticazione disponibili. Utilizza <kbd>[[Special:ApiHelp/query+authmanagerinfo|action=query&meta=authmanagerinfo]]</kbd> con <kbd>amirequestsfor=$1</kbd> (o una precedente risposta da questo modulo, se applicabile) per determinare le richieste disponibili e i campi usati da queste.",
+ "apierror-bad-badfilecontexttitle": "Titolo non valido nel parametro <var>$1badfilecontexttitle</var>.",
"apierror-compare-notext": "Il parametro <var>$1</var> non può essere usato senza <var>$2</var>.",
"apierror-invalidoldimage": "Il parametro <var>oldimage</var> ha un formato non valido.",
"apierror-invaliduserid": "L'ID utente <var>$1</var> non è valido.",
"apierror-assertnameduserfailed": "사용자의 \"$1\" 지정 표명이 실패했습니다.",
"apierror-assertuserfailed": "사용자의 로그인 실패 표명이 발생했습니다.",
"apierror-autoblocked": "사용자의 IP 주소는 차단된 사용자에 의해 사용되었으므로 자동으로 차단된 상태입니다.",
+ "apierror-bad-badfilecontexttitle": "<var>$1badfilecontexttitle</var> 변수에 유효하지 않은 제목이 있습니다.",
"apierror-badgenerator-unknown": "알 수 없는 <kbd>generator=$1</kbd>.",
"apierror-badip": "IP 변수가 유효하지 않습니다.",
"apierror-badmd5": "제공된 MD5 해시가 잘못되었습니다.",
"apierror-assertnameduserfailed": "Afirmação de que o usuário é \"$1\" falhou.",
"apierror-assertuserfailed": "Afirmação de que o usuário está logado falhou.",
"apierror-autoblocked": "O seu endereço de IP foi bloqueado automaticamente, porque ele foi usado por um usuário bloqueado.",
+ "apierror-bad-badfilecontexttitle": "Título inválido no parâmetro <var>$1badfilecontexttitle</var>.",
"apierror-badconfig-resulttoosmall": "O valor de <code>$wgAPIMaxResultSize</code> nesta wiki é muito pequeno para manter a informação básica de resultados.",
"apierror-badcontinue": "Parâmetro continue inválido. Você deve passar o valor original retornado pela consulta anterior.",
"apierror-baddiff": "O diff não pode ser recuperado. Uma ou ambas as revisões não existem ou você não tem permissão para visualizá-las.",
"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-errorprinterfailed": "Falha na impressora de erro. Repetirá sem parâmetros.",
- "apiwarn-errorprinterfailed-ex": "Falha na impressora de erro (repetirá sem parâmetros): $1",
"apiwarn-ignoring-invalid-templated-value": "Ignorando o valor <kbd>$2</kbd> em <var>$1</var> ao processar parâmetros de predefinição.",
"apiwarn-invalidcategory": "\"$1\" não é uma categoria.",
"apiwarn-invalidtitle": "\"$1\" não é um título válido.",
"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.",
"apiwarn-errorprinterfailed": "A impressora de erros falhou. Será feita nova tentativa sem parâmetros.",
- "apiwarn-errorprinterfailed-ex": "A impressora de erros falhou (será feita nova tentativa sem parâmetros): $1",
"apiwarn-ignoring-invalid-templated-value": "A ignorar o valor <kbd>$2</kbd> em <var>$1</var> ao processar parâmetros modelados.",
"apiwarn-invalidcategory": "\"$1\" não é uma categoria.",
"apiwarn-invalidtitle": "\"$1\" não é um título válido.",
"apihelp-query+info-paramvalue-prop-displaytitle": "{{doc-apihelp-paramvalue|query+info|prop|displaytitle}}",
"apihelp-query+info-paramvalue-prop-varianttitles": "{{doc-apihelp-paramvalue|query+info|prop|varianttitles}}",
"apihelp-query+info-param-testactions": "{{doc-apihelp-param|query+info|testactions}}",
+ "apihelp-query+info-param-testactionsdetail": "{{doc-apihelp-param|query+info|testactionsdetail}}",
+ "apihelp-query+info-paramvalue-testactionsdetail-boolean": "{{doc-apihelp-paramvalue|query+info|testactionsdetail|boolean}}",
+ "apihelp-query+info-paramvalue-testactionsdetail-full": "{{doc-apihelp-paramvalue|query+info|testactionsdetail|full}}",
+ "apihelp-query+info-paramvalue-testactionsdetail-quick": "{{doc-apihelp-paramvalue|query+info|testactionsdetail|quick}}",
"apihelp-query+info-param-token": "{{doc-apihelp-param|query+info|token}}",
"apihelp-query+info-example-simple": "{{doc-apihelp-example|query+info}}",
"apihelp-query+info-example-protection": "{{doc-apihelp-example|query+info}}",
"apierror-assertnameduserfailed": "Проверка того, что участник — «$1», провалилась.",
"apierror-assertuserfailed": "Проверка того, что участник авторизован, провалилась.",
"apierror-autoblocked": "Ваш IP-адрес был автоматически заблокирован, потому что он был использован заблокированным участником.",
+ "apierror-bad-badfilecontexttitle": "Неверное название в параметре <var>$1badfilecontexttitle</var>.",
"apierror-badconfig-resulttoosmall": "Значение <code>$wgAPIMaxResultSize</code> этой вики слишком мало, чтобы вместить базовую информацию о результате.",
"apierror-badcontinue": "Некорректный параметр continue. Вы должны передать значение, возвращённое предыдущим запросом.",
"apierror-baddiff": "Сравнение версий не может быть проведено. Одна или обе версии не существуют или у вас не достаточно прав чтобы просматривать их.",
"apiwarn-deprecation-withreplacement": "<kbd>$1</kbd> не поддерживается. Пожалуйста, используйте <kbd>$2</kbd>.",
"apiwarn-difftohidden": "Невозможно сравнить с r$1: содержимое скрыто.",
"apiwarn-errorprinterfailed": "Сборщик ошибок упал. Будет совершена повторная попытка без параметров.",
- "apiwarn-errorprinterfailed-ex": "Сборщик ошибок упал (будет совершена повторная попытка без параметров): $1",
"apiwarn-ignoring-invalid-templated-value": "При обработке шаблонных параметров значение <kbd>$2</kbd> параметра <var>$1</var> проигнорировано.",
"apiwarn-invalidcategory": "«$1» не является категорией.",
"apiwarn-invalidtitle": "«$1» не является некорректным заголовком.",
"apiwarn-deprecation-withreplacement": "<kbd>$1</kbd> є застарілим. Будь ласка, використовуйте натомість <kbd>$2</kbd>.",
"apiwarn-difftohidden": "Не вдалося відкрити версію r$1: вміст приховано.",
"apiwarn-errorprinterfailed": "Невдача через помилку принтера. Буде здійснено повторну спробу без параметрів.",
- "apiwarn-errorprinterfailed-ex": "Невдача через помилку принтера (буде здійснено повторну спробу без параметрів): $1",
"apiwarn-invalidcategory": "«$1» не є категорією.",
"apiwarn-invalidtitle": "«$1» не є коректною назвою.",
"apiwarn-invalidxmlstylesheetext": "Таблиця стилів повинна мати розширення <code>.xsl</code>.",
"apiwarn-deprecation-withreplacement": "<kbd>$1</kbd>已弃用。请改用<kbd>$2</kbd>。",
"apiwarn-difftohidden": "不能与r$1做差异比较:内容被隐藏。",
"apiwarn-errorprinterfailed": "错误打印失败。将在没有参数的前提下重试。",
- "apiwarn-errorprinterfailed-ex": "错误打印失败(将在没有参数的前提下重试):$1",
"apiwarn-ignoring-invalid-templated-value": "当处理模板参数时,忽略<var>$1</var>中的值<kbd>$2</kbd>。",
"apiwarn-invalidcategory": "“$1”不是一个分类。",
"apiwarn-invalidtitle": "“$1”不是一个有效的标题。",
*/
protected $cache;
+ /**
+ * Map of (lowercase message key => index) for all software defined messages
+ *
+ * @var array
+ */
+ protected $overridable;
+
/**
* @var bool[] Map of (language code => boolean)
*/
return true;
}
+ $this->overridable = array_flip( Language::getMessageKeysFor( $code ) );
+
# 8 lines of code just to say (once) that message cache is disabled
if ( $this->mDisable ) {
static $shownDisabled = false;
$this->cache->getField( $code, 'HASH' )
);
} else {
- // Message page does not exist or does not override a software message.
- // Load the message page, utilizing the individual message cache.
- $entry = $this->loadCachedMessagePageEntry(
- $title,
- $code,
- $this->cache->getField( $code, 'HASH' )
- );
- if ( substr( $entry, 0, 1 ) !== ' ' ) {
+ // Message page either does not exist or does not override a software message
+ if ( !isset( $this->overridable[$this->contLang->lcfirst( $title )] ) ) {
+ // Message page does not override any software-defined message. A custom
+ // message might be defined to have content or settings specific to the wiki.
+ // Load the message page, utilizing the individual message cache as needed.
+ $entry = $this->loadCachedMessagePageEntry(
+ $title,
+ $code,
+ $this->cache->getField( $code, 'HASH' )
+ );
+ }
+ if ( $entry === null || substr( $entry, 0, 1 ) !== ' ' ) {
// Message does not have a MediaWiki page definition; try hook handlers
$message = false;
Hooks::run( 'MessagesPreLoad', [ $title, &$message, $code ] );
if ( $count == 0 ) {
$lbFactory = $services->getDBLoadBalancerFactory();
$lbFactory->waitForReplication( [
- 'wiki' => wfWikiID(), 'timeout' => self::REPLICATION_WAIT_TIMEOUT ] );
+ 'domain' => $lbFactory->getLocalDomainID(),
+ 'timeout' => self::REPLICATION_WAIT_TIMEOUT
+ ] );
}
$this->db->insert( 'templatelinks',
[
}
// Bail out if there is too much DB lag.
// This check should not block as we want to try other wiki queues.
- list( , $maxLag ) = $lbFactory->getMainLB( wfWikiID() )->getMaxLag();
+ list( , $maxLag ) = $lbFactory->getMainLB()->getMaxLag();
if ( $maxLag >= self::MAX_ALLOWED_LAG ) {
$response['reached'] = 'replica-lag-limit';
return $response;
$syncThreshold = $this->config->get( 'JobSerialCommitThreshold' );
$time = false;
- $lb = $lbFactory->getMainLB( wfWikiID() );
+ $lb = $lbFactory->getMainLB();
if ( $syncThreshold !== false && $lb->getServerCount() > 1 ) {
// Generally, there is one master connection to the local DB
$dbwSerial = $lb->getAnyOpenConnection( $lb->getWriterIndex() );
if ( !isset( $this->params['range'] ) ) {
$lbFactory = MediaWikiServices::getInstance()->getDBLoadBalancerFactory();
if ( !$lbFactory->waitForReplication( [
- 'wiki' => wfWikiID(),
+ 'domain' => $lbFactory->getLocalDomainID(),
'timeout' => self::LAG_WAIT_TIMEOUT
] ) ) { // only try so hard
$stats = MediaWikiServices::getInstance()->getStatsdDataFactory();
$database = null;
}
+ if ( $schema === '' ) {
+ $schema = null;
+ }
+
return new self( $database, $schema, $prefix );
}
/**
* @param DatabaseDomain|string $other
- * @return bool
+ * @return bool Whether the domain instances are the same by value
*/
public function equals( $other ) {
- if ( $other instanceof DatabaseDomain ) {
+ if ( $other instanceof self ) {
return (
$this->database === $other->database &&
$this->schema === $other->schema &&
return ( $this->getId() === $other );
}
+ /**
+ * Check whether the domain $other meets the specifications of this domain
+ *
+ * If this instance has a null database specifier, then $other can have any database
+ * specified, including the null, and likewise if the schema specifier is null. This
+ * is not transitive like equals() since a domain that explicitly wants a certain
+ * database or schema cannot be satisfied by one of another (nor null). If the prefix
+ * is empty and the DB and schema are both null, then the entire domain is considered
+ * unspecified, and any prefix of $other is considered compatible.
+ *
+ * @param DatabaseDomain|string $other
+ * @return bool
+ * @since 1.32
+ */
+ public function isCompatible( $other ) {
+ if ( $this->isUnspecified() ) {
+ return true; // even the prefix doesn't matter
+ }
+
+ $other = ( $other instanceof self ) ? $other : self::newFromId( $other );
+
+ return (
+ ( $this->database === $other->database || $this->database === null ) &&
+ ( $this->schema === $other->schema || $this->schema === null ) &&
+ $this->prefix === $other->prefix
+ );
+ }
+
+ /**
+ * @return bool
+ * @since 1.32
+ */
+ public function isUnspecified() {
+ return (
+ $this->database === null && $this->schema === null && $this->prefix === ''
+ );
+ }
+
/**
* @return string|null Database name
*/
if ( $this->schema !== null ) {
$parts[] = $this->schema;
}
- if ( $this->prefix != '' ) {
+ if ( $this->prefix != '' || $this->schema !== null ) {
+ // If there is a schema, then we need the prefix to disambiguate.
+ // For engines like Postgres that use schemas, this awkwardness is hopefully
+ // avoided since it is easy to have one DB per server (to avoid having many users)
+ // and use schema/prefix to have wiki farms. For example, a domain schemes could be
+ // wiki-<project>-<language>, e.g. "wiki-fitness-es"/"wiki-sports-fr"/"wiki-news-en".
$parts[] = $this->prefix;
}
use EmptyBagOStuff;
use WANObjectCache;
use ArrayUtils;
+use UnexpectedValueException;
use InvalidArgumentException;
use RuntimeException;
use Exception;
}
}
+ // 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}')." );
+ }
+
return $conn;
}
}
}
- // Increment reference count
if ( $conn instanceof IDatabase ) {
+ // 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'." );
+ }
+ // Increment reference count
$refCount = $conn->getLBInfo( 'foreignPoolRefCount' );
$conn->setLBInfo( 'foreignPoolRefCount', $refCount + 1 );
}
* @param int $userId
*/
public static function purge( $wikiId, $userId ) {
- $cache = ObjectCache::getMainWANInstance();
+ $cache = MediaWikiServices::getInstance()->getMainWANObjectCache();
$key = $cache->makeGlobalKey( 'user', 'id', $wikiId, $userId );
$cache->delete( $key );
}
* @return string
*/
protected function getCacheKey( WANObjectCache $cache ) {
- return $cache->makeGlobalKey( 'user', 'id', wfWikiID(), $this->mId );
+ $cache = MediaWikiServices::getInstance()->getMainWANObjectCache();
+ $lbFactory = MediaWikiServices::getInstance()->getDBLoadBalancerFactory();
+
+ return $cache->makeGlobalKey( 'user', 'id', $lbFactory->getLocalDomainID(), $this->mId );
}
/**
*/
protected $relativeInput;
- /**
- * @var bool
- */
- protected $noDatePicker;
-
/**
* @var bool
*/
public function __construct( Widget $relativeInput, array $options = [] ) {
$config = \RequestContext::getMain()->getConfig();
- $options['noDatePicker'] = $config->get( 'ExpiryWidgetNoDatePicker' );
-
parent::__construct( $options );
- $this->noDatePicker = $options['noDatePicker'];
$this->required = $options['required'] ?? false;
// Properties
$this->relativeInput->addClasses( [ 'mw-widget-ExpiryWidget-relative' ] );
// Initialization
- $classes = [
- 'mw-widget-ExpiryWidget',
- ];
- if ( $options['noDatePicker'] === false ) {
- $classes[] = 'mw-widget-ExpiryWidget-hasDatePicker';
- }
$this
- ->addClasses( $classes )
+ ->addClasses( [
+ 'mw-widget-ExpiryWidget',
+ 'mw-widget-ExpiryWidget-hasDatePicker'
+ ] )
->appendContent( $this->relativeInput );
}
* {@inheritdoc}
*/
public function getConfig( &$config ) {
- $config['noDatePicker'] = $this->noDatePicker;
$config['required'] = $this->required;
$config['relativeInput'] = [];
$this->relativeInput->getConfig( $config['relativeInput'] );
"right-editusercss": "Редактиране на CSS файловете на други потребители",
"right-edituserjson": "Редактиране на JSON файловете на други потребители",
"right-edituserjs": "Редактиране на JavaScript файловете на други потребители",
+ "right-editsitecss": "Редактиране на CSS за цялото уики",
+ "right-editsitejson": "Редактиране на JSON за цялото уики",
+ "right-editsitejs": "Редактиране на JavaScript за цялото уики",
"right-editmyusercss": "Редактиране на собствените потребителски CSS файлове",
"right-editmyuserjson": "Редактиране на собствените потребителски JSON файлове",
"right-editmyuserjs": "Редактиране на собствените потребителски JavaScript файлове",
"Fitoschido"
]
},
- "tog-underline": "ھێڵ ھێنان بەژێر بەستەرەکان:",
+ "tog-underline": "ھێڵھێنان بەژێر بەستەرەکان:",
"tog-hideminor": "دەستکارییە بچووکەکان لە دوایین گۆڕانکارییەکاندا بشارەوە",
"tog-hidepatrolled": "لە دوایین گۆڕانکارییەکاندا دەستکارییە پاس دراوەکان بشارەوە",
"tog-newpageshidepatrolled": "لە پێرستی پەڕە نوێکاندا پەڕە پاس دراوەکان بشارەوە",
"yourpasswordagain": "دیسان تێپەڕوشەکە بنووسەوە:",
"createacct-yourpasswordagain": "تێپەروشە پشتڕاست بکەرەوە",
"createacct-yourpasswordagain-ph": "تێپەروشە دیسان بنووسەوە",
- "userlogin-remembermypassword": "چوونەژوورەوەکەم ڕابگرە",
+ "userlogin-remembermypassword": "لەژوورەوە بمھێڵەرەوە",
"userlogin-signwithsecure": "پەیوەندیی دڵنیا بەکاربھێنە",
"cannotlogin-title": "ناتوانیت بچیتە ژوورەوە",
"cannotlogin-text": "توانای چوونەژوورەوەت نییە",
"wrongpasswordempty": "تێپەڕەوشەی لێدراو بەتاڵبوو.\nتکایە هەوڵ بدەوە.",
"passwordtooshort": "تێپەڕوشەکەت لانی کەم دەبێ {{PLURAL:$1|١ پیت|$1 پیت}} بێت.",
"passwordtoolong": "تێپەڕ وشەکان ناتوانرێت لە {{PLURAL:$1|١ کارەکتەر|$1 کارەکتەر}} درێژتر بێت.",
- "passwordtoopopular": "تێپەڕ وشە باوەکان ناتواندرێت دابنرێن. تکایە تێپەڕ وشەیەکی دەگمەنتر ھەڵبژێرە.",
+ "passwordtoopopular": "تێپەڕەوشە باوەکان ناکرێت دابنرێن. تکایە تێپەڕەوشەیەکی دەگمەنتر ھەڵبژێرە.",
"password-name-match": "تێپەڕوشەکەت ئەبێ جیاواز بێت لە ناوی بەکارهێنەریت.",
"password-login-forbidden": "بەکارهێنانی ئەم ناوی بەکارهێنەر و تێپەڕەووشەیە قەدەغەکراوە.",
"mailmypassword": "تێپەڕوشەکە ڕێک بخەوە",
"resetpass-temp-emailed": "تۆ بە تێپەڕوشەیەکی کاتیی ھاتوویتە ژوورەوە. بۆ تەواوکردنی چوونە ژوورەوە تێپەڕوشەیەکی نوێ لێرە دابنێ.",
"resetpass-temp-password": "تێپەڕوشەی کاتی:",
"resetpass-expired": "تێپەڕ وشەکەت بەسەر چووە، تکایە تێپەڕ وشەیەکی نوێ دابنێ بۆ چوونە ژوورەوە",
- "resetpass-validity-soft": "تێپەڕ وشەکەت دروست نییە: $1",
+ "resetpass-validity-soft": "تێپەڕ وشەکەت دروست نییە: $1\n\nتکایە تێپەڕەوشەیەکی نوێ ھەڵبژێرە ئێستا، یان کرتە بکە لە \"{{int:authprovider-resetpass-skip-label}}\" بۆ گۆڕینی لە دواییدا.",
"passwordreset": "ڕێکخستنەوەی تێپەڕوشە",
"passwordreset-text-one": "ئەم فۆرمە تەواو بکە بۆ بەدەستھێنانی تێپەڕ وشەیەکی کاتیی بە ئیمەیڵ",
"passwordreset-text-many": "{{PLURAL:$1|یەکێک لەم بۆشاییانە بڕ بکەرەوە بۆ بەدەستھێنانی تێپەڕ وشەیەکی کاتیی بە ئیمەیڵ}}",
"anonpreviewwarning": "«نەڕۆشتوویتە ژوورەوە. پاشەکەوتکردن، ئەدرەسی IPەکەت لە مێژووی دەستکاریی ئەم پەڕە تۆمار دەکات.»",
"missingsummary": "'''وە بیر خستنەوە:''' پوختەیەکت نەنووسیوە بۆ چۆنیەتی گۆڕانکارییەکەت.\nئەگەر جارێکی تر پاشکەوت کردن لێبدەی، بێ پوختە تۆمار دەکرێ.",
"selfredirect": "<strong>ئاگاداری:</strong> تۆ خەریکی گواستنەوەی ئەم پەڕەیەیت بۆ سەر خۆی. لەوانەیە خەریکی گواستنەوەی پەڕەیەکی ھەڵە بیت یان ھەوڵی گواستنەوە دەدەیت بۆ ئامانجێکی ھەڵە. \nئەگەر دووبارە کرتە لەسەر «$1» بکەیتەوە، ڕەوانەکەرەکە دروست دەکرێت بەھەرحاڵ.",
- "missingcommenttext": "تکاÛ\8cÛ\95 Ù\84Û\95 Ø®Ù\88ارÛ\95Ù\88Û\95 شرÛ\86Ú¤Û\95Û\8cÛ\95ک بنووسە.",
+ "missingcommenttext": "تکاÛ\8cÛ\95 Ù\84Û\8eدÙ\88اÙ\86Û\8eک بنووسە.",
"missingcommentheader": "'''بیرهێنانەوە:''' بۆ ئەم بۆچوونەت سەردێڕ\\بابەت ڕاچاو نەکردووە.\nئەگەر دیسان «$1» لێبدەی، دەستکاریەکەت بێ سەردێڕ یان بابەت پاشەکەوت دەبێ.",
"summary-preview": "پێشبینینی کورتەی دەستکاری:",
"subject-preview": "پێشبینینی بابەت:",
"revdelete-legend": "ڕێکخستنی سنووردارکردنی دیاریکردن",
"revdelete-hide-text": "دەقی پێداچوونەوە",
"revdelete-hide-image": "ناوەڕۆکی پەڕگە بشارەوە",
- "revdelete-hide-name": "داشاردÙ\86Û\8c Ù\85Û\95بÛ\95ست Ù\88 کردÛ\95Ù\88Û\95",
+ "revdelete-hide-name": "شاردÙ\86Û\95Ù\88Û\95Û\8c ئاÙ\85اÙ\86ج Ù\88 Ú\95اگÛ\95Û\8cÛ\8eÙ\86Û\95کاÙ\86",
"revdelete-hide-comment": "کورتەی دەستکاری",
"revdelete-hide-user": "ناوی بەکارھێنەر/ناونیشانی ئایپی دەستکاریکەر",
"revdelete-hide-restricted": "بەرگری دراوە لە بەڕێوبەران هەر وەک ئەوانی دیکە",
"recentchangesdays": "ژمارە ڕۆژە نیشاندراوەکان لە دوایین گۆڕانکارییەکان:",
"recentchangesdays-max": "(ئەوپەڕی $1 {{PLURAL:$1|ڕۆژە|ڕۆژە}})",
"recentchangescount": "ژمارەی گۆڕانکارییەکان کە نیشان ئەدرێن لە حاڵەتی دیفاڵت:",
- "prefs-help-recentchangescount": "ئÛ\95Ù\85Û\95 دÙ\88اÛ\8cÛ\8cÙ\86 Ú¯Û\86Ú\95اÙ\86کارÛ\8cÛ\8cÛ\95کاÙ\86Ø\8c Ù\85Û\8eÚ\98Ù\88Ù\88Û\8c Ù¾Û\95Ú\95Û\95کاÙ\86 Ù\88 Ù\84Û\86Ú¯Û\95کاÙ\86Û\8cØ´ Ù\84Û\95بÛ\95ردÛ\95گرÛ\8eت.",
+ "prefs-help-recentchangescount": "زÛ\86رترÛ\8cÙ\86 Ú\98Ù\85ارÛ\95: Ù¡Ù Ù Ù ",
"prefs-help-watchlist-token2": "ئەمە کلیلێکی تایبەتیی پێڕستی چاودێرییەکەتە. ھەرکەسێک بیزانێت دەتوانێت پێڕستی چاودێرییەکەت ببینێت، بۆیە لای خۆت بیپارێزە.\nئەگەر پێویستی کرد، [[Special:ResetTokens|دەتوانیت بیگۆڕیت]].",
"savedprefs": "ھەڵبژاردەکانت پاشەکەوت کران",
"timezonelegend": "ناوچەی کاتی:",
"prefs-files": "پەڕگەکان",
"prefs-custom-css": "CSSی دڵخواز",
"prefs-custom-js": "جاڤاسکریپتی دڵخواز",
- "prefs-common-config": "سیئێسئێس/جاڤاسکریپتی ھاوبەش بۆ گشت پێستەکان:",
+ "prefs-common-config": "سیئێسئێس/جەیسن/جاڤاسکریپتی ھاوبەش بۆ گشت پێستەکان:",
"prefs-reset-intro": "دەتوانی لەم لاپەڕە بۆ گەڕانەوەی هەڵبژاردەکانت بۆ بنچینەیی ماڵپەر کەڵک وەرگریت.\nگەر ئەوە بکەی ئیتر گۆڕانەکەت ناگەڕێتەوە.",
"prefs-emailconfirm-label": "پشتڕاستکردنەوەی ئیمەیل:",
"youremail": "ئیمەیل:",
"badsig": "کۆدی ئیمزای ھەڵە.\nبە تاگە HTMLکاندا بچۆرەوە.",
"badsiglength": "واژووەکەت زۆر درێژە.\nواژوو نابێ لە $1 {{PLURAL:$1|نووسە}} درێژتر بێت.",
"yourgender": "پێت خۆشە چۆن وەسف بکرێیت؟",
- "gender-unknown": "Ù¾Û\8eÙ\85 Ø®Û\86Ø´Û\95 باسÛ\8c Ù\86Û\95Ú©Û\95Ù\85",
+ "gender-unknown": "Ù\84Û\95کاتÛ\8c ئاÙ\85اÚ\98Û\95داÙ\86 بÛ\95تÛ\86Ø\8c Ù\86Û\95رÙ\85اÙ\85Û\8eرÛ\95Ú©Û\95 Ù\88Ø´Û\95Û\8c Ú\95Û\95Ú¯Û\95زھاÙ\88تا بÛ\95کار دÛ\95بات بÛ\95Ù¾Û\8eÛ\8c تÙ\88اÙ\86ا",
"gender-male": "نێر",
"gender-female": "مێ",
"prefs-help-gender": "ئەم ھەڵبژاردەیە دڵخوازانەیە.\nبۆ بانگکردن و ئاماژەپێکردن بە شێوەیەکی دروست لەلایەن نەرمامێرەوە بەکاردێت.\nئەم زانیارییە گشتی دەبێت.",
"group-sysop": "بەڕێوەبەران",
"group-interface-admin": "بەڕێوەبەرانی ڕووکار",
"group-bureaucrat": "بیوروکراتەکان",
- "group-suppress": "چاودێرەکان",
+ "group-suppress": "سەرکووتکەرەکان",
"group-all": "(ھەموو)",
"group-user-member": "{{GENDER:$1|بەکارھێنەر}}",
"group-autoconfirmed-member": "{{GENDER:$1|بەکارھێنەرانی پەسەندکراوی خۆگەڕ}}",
"badarticleerror": "Seda toimingut ei saa sellel leheküljel sooritada.",
"cannotdelete": "Lehekülge või faili \"$1\" ei saa kustutada.\nVõimalik, et keegi on selle juba kustutanud.",
"cannotdelete-title": "Lehekülge \"$1\" ei saa kustutada",
+ "delete-scheduled": "Lehekülje \"$1\" kustutamine ootab järge.\nPalun ole kannatlik.",
"delete-hook-aborted": "Haak katkestas kustutamise.\nSeletust pole toodud.",
"no-null-revision": "Lehekülje \"$1\" nullredaktsiooni ei õnnestunud teha.",
"badtitle": "Vigane pealkiri",
"movepage-moved": "<strong>\"$1\" on teisaldatud pealkirja \"$2\" alla.</strong>",
"movepage-moved-redirect": "Ümbersuunamisleht loodud.",
"movepage-moved-noredirect": "Ümbersuunamist ei loodud.",
+ "movepage-delete-first": "Sihtlehekülge ei saa teisaldamise käigus kustutada, kuna sellel on liiga palju redaktsioone. Palun kustuta lehekülg kõigepealt käsitsi ja proovi seejärel uuesti.",
"articleexists": "Sellise pealkirjaga lehekülg on juba olemas või pole valitud pealkiri lubatav.\nPalun vali teistsugune pealkiri.",
"cantmove-titleprotected": "Lehte ei saa sinna teisaldada, sest uus pealkiri on artikli loomise eest kaitstud",
"movetalk": "Teisalda seonduv arutelulehekülg",
"pageinfo-category-files": "Faile",
"pageinfo-user-id": "Kasutaja identifikaator",
"pageinfo-file-hash": "Räsiväärtus",
+ "pageinfo-view-protect-log": "Vaata selle lehekülje kaitsmislogi.",
"markaspatrolleddiff": "Märgi kontrollituks",
"markaspatrolledtext": "Märgi see leht kontrollituks",
"markaspatrolledtext-file": "Märgi see failiversioon kontrollituks",
"rcfilters-view-tags": "Redakturi etiketizata",
"rcfilters-view-namespaces-tooltip": "Filtrar rezulti segun nomo",
"rcfilters-liveupdates-button": "Quika aktualigi",
+ "rcfilters-watchlist-markseen-button": "Indikar \"vidita\" en omna modifikuri",
"rcnotefrom": "Infre {{PLURAL:$5|esas la chanjo|esas la chanji}} de <strong>$3, $4</strong> (montrata til <strong>$1</strong>).",
"rclistfrom": "Montrar nova chanji startante de $3 $2",
"rcshowhideminor": "$1 mikra redakturi",
"sp-contributions-hideminor": "Celar kurta redaktaji",
"sp-contributions-submit": "Serchez",
"whatlinkshere": "Quo ligesas adhike",
- "whatlinkshere-title": "Pagini qui ligas ad \"$1\"",
+ "whatlinkshere-title": "Pagini qui ligesas a(d) \"$1\"",
"whatlinkshere-page": "Pagino:",
"linkshere": "Ca pagini esas ligilizita a(d) <strong>$2</strong>:",
"nolinkshere": "Nula pagino ligas ad <strong>$2</strong>.",
"tooltip-n-recentchanges": "Listo di recenta chanji en la wiki.",
"tooltip-n-randompage": "Vizitez hazarda pagino",
"tooltip-n-help": "La loko por trovar ulo.",
- "tooltip-t-whatlinkshere": "Montrez omna wiki pagini qui ligas ad hike",
+ "tooltip-t-whatlinkshere": "Listo di omna Wikipagini qui ligesas adhike",
"tooltip-t-recentchangeslinked": "Recenta chanji di pagini ligita de ca pagino",
"tooltip-feed-rss": "RSS provizero por ica pagino",
"tooltip-feed-atom": "Atom provizero por ica pagino",
"filehist-comment": "Komentārs",
"imagelinks": "Faila lietojums",
"linkstoimage": "Šo failu izmanto {{PLURAL:$1|šajās $1 lapās|šajā $1 lapā|šajās $1 lapās}}:",
- "linkstoimage-more": "Uz šo failu ir saites vairāk nekā $1 {{PLURAL:$1|lapās|lapā|lapās}}.\nŠajā sarakstā ir tikai {{PLURAL:$1|pirmās $1 saistītās lapas|pirmā $1 saistītā lapa|pirmās $1 saistītās lapas}} uz šo failu.\nPieejams arī [[Special:WhatLinksHere/$2|pilns saraksts]].",
+ "linkstoimage-more": "Šo failu izmanto vairāk nekā $1 {{PLURAL:$1|lapās|lapā|lapās}}.\nŠajā sarakstā ir tikai {{PLURAL:$1|pirmās $1 lapas|pirmā lapa|pirmās $1 lapas}}, kas izmanto šo failu.\nPieejams arī [[Special:WhatLinksHere/$2|pilns saraksts]].",
"nolinkstoimage": "Šo failu neizmanto nevienā lapā.",
"morelinkstoimage": "Skatīt [[Special:WhatLinksHere/$1|vairāk saites]] uz šo failu.",
"linkstoimage-redirect": "$1 (faila pāradresācija) $2",
"right-nominornewtalk": "Невыписованя новых повідомлїнь по малых управах діскузной сторінкы",
"right-apihighlimits": "Хоснованя высшых лімітів в API запытах",
"right-writeapi": "Хосновати API про писаня",
- "right-delete": "Ð\97мазаня сторінок",
+ "right-delete": "Ð\9cазаня сторінок",
"right-bigdelete": "Мазаня сторінок з довгов історіёв",
"right-deletelogentry": "Мазаня тай обновлїня окремых записів лоґів\n,",
"right-deleterevision": "Мазаня і обновованя конкретных ревізій сторінок",
"group-autoconfirmed": "خود توثیق شدہ صارفین",
"group-bot": "روبہ جات",
"group-sysop": "منتظمین",
+ "group-interface-admin": "انٹرفیس منتظمین",
"group-bureaucrat": "مامورین اداری",
"group-suppress": "Suppressors",
"group-all": "(تمام)",
"group-autoconfirmed-member": "خودتوثیق شدہ صارف",
"group-bot-member": "خودکار صارف",
"group-sysop-member": "{{GENDER:$1|منتظم}}",
+ "group-interface-admin-member": "{{GENDER:$1|انٹرفیس منتظم}}",
"group-bureaucrat-member": "{{GENDER:$1|مامور اداری}}",
"group-suppress-member": "{{GENDER:$1|suppressor}}",
"grouppage-user": "{{ns:project}}:صارفین",
"grouppage-autoconfirmed": "{{ns:project}}:خود توثیق شدہ صارف",
"grouppage-bot": "{{ns:project}}:روبہ جات",
"grouppage-sysop": "{{ns:project}}:منتظمین",
+ "grouppage-interface-admin": "{{ns:project}}:انٹرفیس منتظمین",
"grouppage-bureaucrat": "{{ns:project}}:مامورین اداری",
"grouppage-suppress": "{{ns:project}}:پوشیدگی",
"right-read": "مطالعہ صفحات",
"badarticleerror": "מען קען נישט טאן די אקציע וואס איר ווילט אויף דעם בלאט.",
"cannotdelete": "נישט געווען מעגלעך אויסמעקן דעם בלאט אדער די טעקע \"$1\".\nקען זיין אז דאס איז שוין געווארן אויסגעמעקט דורך אן אנדערן.",
"cannotdelete-title": "מען קען נישט אויסמעקן בלאט \"$1\"",
+ "delete-scheduled": "דעם בלאט \"$1\" פלאנירט מען אויסצומעקן.\nהאטס געדולד.",
"delete-hook-aborted": "אויסמעקונג אנולירט דורך hook.\nנישט געגעבן קיין דערקלערונג.",
"no-null-revision": "נישט מעגלעך צו שאפן א נול־ווערסיע פונעם בלאט \"$1\".",
"badtitle": "שלעכט קעפל",
"botpasswords-existing": "עקזיסטירנדע באט פאסווערטער",
"botpasswords-createnew": "שאפֿן א ניי באט פאסווארט",
"botpasswords-editexisting": "רעדאקטירן אן עקזיסטירנדיק באט פאסווארט",
+ "botpasswords-label-needsreset": "(פאסווארט דארף ווערן צוריקגעשטעלט)",
"botpasswords-label-appid": "באט נאמען:",
"botpasswords-label-create": "שאַפֿן",
"botpasswords-label-update": "דערהײַנטיקן",
"prefs-watchlist-edits": "מאַקסימום צאָל ענדערונגען צו ווייַזן אין אויפֿפאַסונג ליסטע:",
"prefs-watchlist-edits-max": "מאַקסימום נומער: 1000",
"prefs-watchlist-token": "אויפֿפאַסונג ליסטע סימן:",
+ "prefs-watchlist-managetokens": "פֿארוואלטן סימנים",
"prefs-misc": "פֿאַרשידנס",
"prefs-resetpass": "טוישן פאַסווארט",
"prefs-changeemail": "ענדערן אדער אראפנעמען ע-פּאָסט אַדרעס",
"group-autoconfirmed": "באַשטעטיקטע באַניצער",
"group-bot": "באטס",
"group-sysop": "סיסאפן",
+ "group-interface-admin": "אייבערפֿלאך־אדמיניסטראטארן",
"group-bureaucrat": "ביוראקראטן",
"group-suppress": "אונטערדריקער",
"group-all": "(אלע)",
"group-autoconfirmed-member": "{{GENDER:$1|באַשטעטיקטער באַניצער|באַשטעטיקטע באַניצערין}}",
"group-bot-member": "{{GENDER:$1|באט}}",
"group-sysop-member": "{{GENDER:$1|סיסאפ}}",
+ "group-interface-admin-member": "{{GENDER:$1|אייבערפֿלאך־אדמיניסטראטאר}}",
"group-bureaucrat-member": "{{GENDER:$1|ביוראקראַט}}",
"group-suppress-member": "{{GENDER:$1|אונטעדריקער}}",
"grouppage-user": "{{ns:project}}:אײַנגעשריבענער באניצער",
"action-editcontentmodel": "רעדאקטירן אינהאלט־מאדעל פון א בלאט",
"action-managechangetags": "שאפן און (אומ)אקטיווירן טאגן פון דער דאטנבאזע",
"action-applychangetags": "אנווענדן טאגן צוזאמען מיט אייערע ענדערונגען",
+ "action-deletechangetags": "אויסמעקן טאגן פון דער דאטנבאזע",
"action-purge": "אויסרייניגן דעם דאזיגן בלאט",
"nchanges": "{{PLURAL:$1|ענדערונג|$1 ענדערונגען}}",
"enhancedrc-since-last-visit": "$1 {{PLURAL:$1|זײַט לעצטן וויזיט}}",
"rcfilters-savedqueries-new-name-label": "נאָמען",
"rcfilters-savedqueries-apply-label": "שאפן פילטער",
"rcfilters-savedqueries-cancel-label": "אַנולירן",
+ "rcfilters-clear-all-filters": "אפראמען אלע פֿילטערן",
"rcfilters-show-new-changes": "ווייזן די נייעסטע ענדערונגען",
"rcfilters-search-placeholder": "פֿילטערן ענדערונגען (ניצט מעניו אדער זוכט פֿילטער־נאמען)",
"rcfilters-invalid-filter": "אומגילטיגער פֿילטער",
"rcfilters-filter-minor-description": "רעדאקטירונגען וואס דער שרייבער האט מארקירט פֿארמינערט.",
"rcfilters-filter-watchlist-watched-label": "אויף דער אויפֿפאַסונג ליסטע",
"rcfilters-filter-watchlist-notwatched-label": "נישט אויף דער אויפֿפאַסונג ליסטע",
+ "rcfilters-filter-watchlistactivity-seen-label": "געזעענע ענדערונגען",
"rcfilters-filtergroup-changetype": "טיפ ענדערונג",
"rcfilters-filter-pageedits-label": "בלאט רעדאקטירונגען",
"rcfilters-filter-newpages-label": "בלאַט־שאַפֿונגען",
"filehist-filesize": "טעקע גרייס",
"filehist-comment": "באמערקונג",
"imagelinks": "טעקע באַניץ",
- "linkstoimage": "{{PLURAL:$1|×\93ער פ×\90×\9c×\92× ×\93ער ×\91×\9c×\90×\98 × ×\99צ×\98|×\93×\99 פ×\90×\9c×\92× ×\93×¢ ×\91×\9c×¢×\98ער × ×\99צ×\9f}} ×\93×\90ס ×\93×\90×\96×\99×\92×¢ ×\91×\99×\9c×\93:",
+ "linkstoimage": "{{PLURAL:$1|×\93ער פ×\90×\9c×\92× ×\93ער ×\91×\9c×\90×\98 × ×\99צ×\98|×\93×\99 פ×\90×\9c×\92× ×\93×¢ ×\91×\9c×¢×\98ער × ×\99צ×\9f}} ×\93×\99 ×\93×\90×\96×\99×\92×¢ ×\98עקע:",
"linkstoimage-more": "מער ווי $1 {{PLURAL:$1|בלאַט ניצט|בלעטער ניצן}} די דאזיגע טעקע.\nדי פֿאלגנדע ליסטע ווײַזט נאר {{PLURAL:$1|דעם ערשטן בלאַט וואס ניצט|די ערשטע $1 בלעטער וואס ניצן}} די טעקע.\nס'איז פֿאַראַן א [[Special:WhatLinksHere/$2|פֿולע רשימה]].",
- "nolinkstoimage": "× ×\99ש×\98×\90 ק×\99×\99×\9f ×\91×\9c×¢×\98ער ×\95×\95×\90ס פ×\90ר×\91×\99× ×\93×\9f צ×\95 די טעקע.",
+ "nolinkstoimage": "× ×\99ש×\98×\90 ק×\99×\99×\9f ×\91×\9c×¢×\98ער ×\95×\95×\90ס × ×\99צ×\9f די טעקע.",
"morelinkstoimage": "באַקוקן [[Special:WhatLinksHere/$1|מער לינקען]] צו דער טעקע.",
"linkstoimage-redirect": "$1 (טעקע ווײַטערפֿירונג) $2",
"duplicatesoffile": "די פֿאלגנדע {{PLURAL:$1|טעקע דופליקירט|$1 טעקעס דופליקירן}} די דאזיגע טעקע ([[Special:FileDuplicateSearch/$2|נאך פרטים]]):",
"cachedspecial-refresh-now": "באקוקן די לעצטע.",
"categories": "קאַטעגאָריעס",
"categories-submit": "ווייזן",
- "categoriespagetext": "×\93×\99 פֿ×\90×\9c×\92×¢× ×\93×¢ {{PLURAL:$1| ק×\90Ö·×\98×¢×\92×\90ָר×\99×¢ ×\90Ö·× ×\98×\94×\90Ö·×\9c×\98|ק×\90Ö·×\98×¢×\92×\90ָר×\99עס ×\90Ö·× ×\98×\94×\90Ö·×\9c×\98×\9f}} ×\91×\9c×¢×\98ער ×\90×\93ער ×\9e×¢×\93×\99×¢.\n[[Special:UnusedCategories|×\90×\95×\9e×\91×\90Ö·× ×\99צ×\98×¢ ק×\90Ö·×\98×¢×\92×\90ר×\99עס]] ×\96×¢× ×¢×\9f × ×\99ש×\98 ×\92×¢×\95×\95×\99×\96×\9f ×\93×\90.\nזעט אויך [[Special:WantedCategories|געזוכטע קאַטעגאריעס]].",
+ "categoriespagetext": "×\93×\99 פֿ×\90×\9c×\92×¢× ×\93×¢ {{PLURAL:$1| ק×\90Ö·×\98×¢×\92×\90ָר×\99×¢ עק×\96×\99ס×\98×\99ר×\98|ק×\90Ö·×\98×¢×\92×\90ָר×\99עס עק×\96×\99ס×\98×\99ר×\9f}} ×\90×\95×\99×£ ×\93ער ×\95×\95×\99ק×\99, ×\90×\95×\9f ×\90×\99×\96 ×\90פשר ×\90×\99×\9f ×\91×\90× ×\99×¥ ×\90פשר × ×\99ש×\98.\n\nזעט אויך [[Special:WantedCategories|געזוכטע קאַטעגאריעס]].",
"categoriesfrom": "ווײַזן קאַטעגאריעס אָנהייבנדיג פֿון:",
"deletedcontributions": "אויסגעמעקטע באַניצער בײַשטײַערונגען",
"deletedcontributions-title": "אויסגעמעקטע באַניצער בײַשטײַערונגען",
"move-page-legend": "באַוועגן בלאַט",
"movepagetext": "זיך באניצן מיט דעם פֿארעם וועט פֿארענדערן דעם נאמען פֿון דעם בלאט, און וועט אריבערפֿירן זיין געשיכטע צום נייעם נאמען.\nדאס אלטע קעפל וועט ווערן א ווייטערפֿירונג בלאט צום נייעם קעפל.\n\nאיר קענט דערהיינטיגן ווייטערפֿירונגען צום אלטן נאמען אויטאמאטיש.\n\nטאמער נישט, טוט פֿארזיכערן אז עס איז נישטא קיין [[Special:DoubleRedirects|געטאפלטע]] אדער [[Special:BrokenRedirects|צעבראכענע ווייטערפֿירונגען]].\n\nאיר זענט פֿאראנטווארטלעך זיכער מאכן אז אלע פֿארבינדונגען ווערן געריכטעט צום געהעריגן ציל.\n\nדער בלאט וועט <strong> נישט</strong> ווערן אריבערגעפֿירט אויב עס איז שוין דא א בלאט אונטער דעם נייעם נאמען, אחוץ ווען ער איז א ווייטערפֿירונג בלאט, און ער האט נישט קיין געשיכטע פון ענדערונגען.\nפשט דערפֿון, אז איר קענט איבערקערן א ווייטערפֿירונג וואס איר האט אט געמאכט בטעות, און איר קענט נישט אריבערשרייבן אן עקסיסטירנדן בלאט.\n\n<strong>הערה:</strong>\n אזא ענדערונג קען זיין דראסטיש און נישט געווינטשען פאר א פאפולערן בלאט;\nביטע פֿארזיכערט אז איר פֿארשטייט די ווייטגרייכנדע קאנסקווענסן צו דער אקציע בעפֿאר איר פֿירט דאס אויס.",
"movepagetext-noredirectfixer": "זיך באניצן מיט דעם פֿארעם אונטן וועט פֿארענדערן דעם נאמען פֿון דעם בלאט, און וועט אריבערפֿירן זיין געשיכטע צום נייעם נאמען.\n\nדאס אלטע קעפל וועט ווערן א ווייטערפֿירן בלאט צום נײַעם נאמען.\n\nטוט פֿארזיכערן אז עס בלײַבן נישט קיין [[Special:DoubleRedirects|געטאפלטע]] אדער [[Special:BrokenRedirects|צעבראכענע]] ווייטערפֿירונגען.\n\nאיר זענט פֿאראנטווארטלעך זיכער מאכן אז אלע פֿארבינדונגען ווערן געריכטעט צו דער געהעריגער ריכטונג.\n\nאַכטונג: דער בלאַט וועט <strong>נישט</strong> ווערן אַריבערגעפֿירט אויב עס איז שוין דאָ א בלאט אונטער דעם נײַעם נאמען, אחוץ ווען ער איז א ווײַטערפֿירונג בלאט, און ער האט נישט קיין געשיכטע פון ענדערונגען.\nפשט דערפֿון, אז איר קענט איבערקערן א ווייטערפֿירונג וואס איר האט אט געמאכט בטעות, און איר קענט נישט אריבערשרײַבן אַן עקסיסטירנדן בלאט.\n\n<strong>הערה:</strong> אזא ענדערונג קען זיין דראַסטיש און נישט געוואונטשן פֿאַר א פאפולערן בלאַט; ביטע פֿאַרזיכערט אז איר פֿאַרשטייט די ווײַטגרייכנדע קאנסעקווענסן צו דער אַקציע בעפֿאַר איר גייט ווײַטער.",
- "movepagetalktext": "×\98×\90×\9eער צ×\99×\99×\9b× ×¡ איר דאס קעסטל, וועט דער אסאסיציאירטער רעדן בלאט ווערן באַוועגט אויטאמאֵטיש צום נײַעם קעפל, אחוץ ווען ס'איז שוין דא א נישט-ליידיגער רעדן־בלאט.\n\nאין דעם פֿאל, וועט איר דארפֿן באַוועגן אדער צונויפֿגיסן דעם בלאט האַנטלעך, ווען איר ווילט.",
+ "movepagetalktext": "×\98×\90×\9eער צ×\99×\99×\9b× ×\98 איר דאס קעסטל, וועט דער אסאסיציאירטער רעדן בלאט ווערן באַוועגט אויטאמאֵטיש צום נײַעם קעפל, אחוץ ווען ס'איז שוין דא א נישט-ליידיגער רעדן־בלאט.\n\nאין דעם פֿאל, וועט איר דארפֿן באַוועגן אדער צונויפֿגיסן דעם בלאט האַנטלעך, ווען איר ווילט.",
"moveuserpage-warning": "'''ווארענונג:''' איר האלט ביי באוועגן א באניצער בלאט. ביטע באמערקט אז נאר דער בלאט ווערט באוועגט אבער דער באניצער נאמען ווערט ''נישט'' געענדערט.",
"movecategorypage-warning": "<strong>ווארענונג:</strong> איר האלט ביי באוועגן א קאטעגאריע בלאט. גיט אכט אז נאר דער בלאט וועט ווערן באוועגט, אבער די בלעטער אין דער אלטער קאטעגאריע וועט מען <em>נישט</em> ארײַנשטעלן אין דער נייער קאטעגאריע.",
"movenologintext": "איר דארפֿט זיך אײַנשרײַבן און זײַן [[Special:UserLogin|אַרײַנלאגירט]] צו באַוועגן א בלאַט.",
"previousdiff": "פריערדיקער אונטערשייד →",
"nextdiff": "קומענדיקע ווערסיע ←",
"mediawarning": "'''ווארענונג''': דער טעקע טיפ קען אנטהאלטן בייזוויליקן קאד.\nדורכפירן דעם קאד קען שעדיקן אייער סיסטעם.",
- "imagemaxsize": "מאקסימאלע בילד גרייס :<br />''(פאר טעקע באשרייבונג בלעטער)''",
+ "imagemaxsize": "מאקסימאלע בילד גרייס אויף טעקע באשרייבונג בלעטער:",
"thumbsize": "קליינבילד גרייס:",
"widthheight": "$1 × $2",
"widthheightpage": "$1 × $2, {{PLURAL:$3|איין בלאט|$3 בלעטער}}",
];
$bookstoreList = [
- 'Aladin.co.kr' => 'http://www.aladin.co.kr/catalog/book.asp?ISBN=$1',
+ 'Aladin.co.kr' => 'https://www.aladin.co.kr/catalog/book.asp?ISBN=$1',
+ 'National Library of Korea' => 'http://www.nl.go.kr/search/web_search/search/list.php?search_field1=all&tmode=1&value1=$1',
+ 'Naver' => 'https://book.naver.com/search/search.nhn?query=$1',
'inherit' => true,
];
-// Common Less mixin library for MediaWiki
+// Common LESS mixin library for MediaWiki
//
// By default the folder containing this file is included in the LESS import paths,
// which makes this file importable by all less files via `@import 'mediawiki.mixins';`.
// Parent constructor
mw.widgets.ExpiryWidget.parent.call( this, config );
- // If the wiki does not want the date picker, then initialize the relative
- // field and exit.
- if ( config.noDatePicker ) {
- this.relativeField.on( 'change', function ( event ) {
- // Emit a change event for this widget.
- this.emit( 'change', event );
- }.bind( this ) );
-
- // Initialization
- this.$element
- .addClass( 'mw-widget-ExpiryWidget' )
- .append(
- this.relativeField.$element
- );
-
- return;
- }
-
// Properties
this.inputSwitch = new OO.ui.ButtonSelectWidget( {
tabIndex: -1,
$result = new ApiResult( 8388608 );
$formatter = new ApiErrorFormatter( $result, Language::factory( 'de' ), 'wikitext', false );
$this->assertSame( 'de', $formatter->getLanguage()->getCode() );
+ $this->assertSame( 'wikitext', $formatter->getFormat() );
$formatter->addMessagesFromStatus( null, Status::newGood() );
$this->assertSame(
);
}
+ /**
+ * @covers ApiErrorFormatter
+ * @covers ApiErrorFormatter_BackCompat
+ */
+ public function testNewWithFormat() {
+ $result = new ApiResult( 8388608 );
+ $formatter = new ApiErrorFormatter( $result, Language::factory( 'de' ), 'wikitext', false );
+ $formatter2 = $formatter->newWithFormat( 'html' );
+
+ $this->assertSame( $formatter->getLanguage(), $formatter2->getLanguage() );
+ $this->assertSame( 'html', $formatter2->getFormat() );
+
+ $formatter3 = new ApiErrorFormatter_BackCompat( $result );
+ $formatter4 = $formatter3->newWithFormat( 'html' );
+ $this->assertNotInstanceOf( ApiErrorFormatter_BackCompat::class, $formatter4 );
+ $this->assertSame( $formatter3->getLanguage(), $formatter4->getLanguage() );
+ $this->assertSame( 'html', $formatter4->getFormat() );
+ }
+
/**
* @covers ApiErrorFormatter
* @dataProvider provideErrorFormatter
$formatter = new ApiErrorFormatter_BackCompat( $result );
$this->assertSame( 'en', $formatter->getLanguage()->getCode() );
+ $this->assertSame( 'bc', $formatter->getFormat() );
$this->assertSame( [], $formatter->arrayFromStatus( Status::newGood() ) );
--- /dev/null
+<?php
+
+/**
+ * @group API
+ * @group medium
+ * @group Database
+ *
+ * @coversDefaultClass ApiQueryInfo
+ */
+class ApiQueryInfoTest extends ApiTestCase {
+
+ /**
+ * @covers ::execute
+ * @covers ::extractPageInfo
+ */
+ public function testExecute() {
+ $page = $this->getExistingTestPage( 'Pluto' );
+ $title = $page->getTitle();
+
+ list( $data ) = $this->doApiRequest( [
+ 'action' => 'query',
+ 'prop' => 'info',
+ 'titles' => $title->getText(),
+ ] );
+
+ $this->assertArrayHasKey( 'query', $data );
+ $this->assertArrayHasKey( 'pages', $data['query'] );
+ $this->assertArrayHasKey( $page->getId(), $data['query']['pages'] );
+
+ $info = $data['query']['pages'][$page->getId()];
+ $this->assertSame( $page->getId(), $info['pageid'] );
+ $this->assertSame( $title->getNamespace(), $info['ns'] );
+ $this->assertSame( $title->getText(), $info['title'] );
+ $this->assertSame( $title->getContentModel(), $info['contentmodel'] );
+ $this->assertSame( $title->getPageLanguage()->getCode(), $info['pagelanguage'] );
+ $this->assertSame( $title->getPageLanguage()->getHtmlCode(), $info['pagelanguagehtmlcode'] );
+ $this->assertSame( $title->getPageLanguage()->getDir(), $info['pagelanguagedir'] );
+ $this->assertSame( wfTimestamp( TS_ISO_8601, $title->getTouched() ), $info['touched'] );
+ $this->assertSame( $title->getLatestRevID(), $info['lastrevid'] );
+ $this->assertSame( $title->getLength(), $info['length'] );
+ $this->assertSame( $title->isNewPage(), $info['new'] );
+ $this->assertArrayNotHasKey( 'actions', $info );
+ }
+
+ /**
+ * @covers ::execute
+ * @covers ::extractPageInfo
+ */
+ public function testExecuteEditActions() {
+ $page = $this->getExistingTestPage( 'Pluto' );
+ $title = $page->getTitle();
+
+ list( $data ) = $this->doApiRequest( [
+ 'action' => 'query',
+ 'prop' => 'info',
+ 'titles' => $title->getText(),
+ 'intestactions' => 'edit'
+ ] );
+
+ $this->assertArrayHasKey( 'query', $data );
+ $this->assertArrayHasKey( 'pages', $data['query'] );
+ $this->assertArrayHasKey( $page->getId(), $data['query']['pages'] );
+
+ $info = $data['query']['pages'][$page->getId()];
+ $this->assertArrayHasKey( 'actions', $info );
+ $this->assertArrayHasKey( 'edit', $info['actions'] );
+ $this->assertTrue( $info['actions']['edit'] );
+ }
+
+ /**
+ * @covers ::execute
+ * @covers ::extractPageInfo
+ */
+ public function testExecuteEditActionsFull() {
+ $page = $this->getExistingTestPage( 'Pluto' );
+ $title = $page->getTitle();
+
+ list( $data ) = $this->doApiRequest( [
+ 'action' => 'query',
+ 'prop' => 'info',
+ 'titles' => $title->getText(),
+ 'intestactions' => 'edit',
+ 'intestactionsdetail' => 'full',
+ ] );
+
+ $this->assertArrayHasKey( 'query', $data );
+ $this->assertArrayHasKey( 'pages', $data['query'] );
+ $this->assertArrayHasKey( $page->getId(), $data['query']['pages'] );
+
+ $info = $data['query']['pages'][$page->getId()];
+ $this->assertArrayHasKey( 'actions', $info );
+ $this->assertArrayHasKey( 'edit', $info['actions'] );
+ $this->assertInternalType( 'array', $info['actions']['edit'] );
+ $this->assertSame( [], $info['actions']['edit'] );
+ }
+
+ /**
+ * @covers ::execute
+ * @covers ::extractPageInfo
+ */
+ public function testExecuteEditActionsFullBlock() {
+ $badActor = $this->getTestUser()->getUser();
+ $sysop = $this->getTestSysop()->getUser();
+
+ $block = new \Block( [
+ 'address' => $badActor->getName(),
+ 'user' => $badActor->getId(),
+ 'by' => $sysop->getId(),
+ 'expiry' => 'infinity',
+ 'sitewide' => 0,
+ 'enableAutoblock' => true,
+ ] );
+
+ $block->insert();
+
+ $page = $this->getExistingTestPage( 'Pluto' );
+ $title = $page->getTitle();
+
+ list( $data ) = $this->doApiRequest( [
+ 'action' => 'query',
+ 'prop' => 'info',
+ 'titles' => $title->getText(),
+ 'intestactions' => 'edit',
+ 'intestactionsdetail' => 'full',
+ ], null, false, $badActor );
+
+ $block->delete();
+
+ $this->assertArrayHasKey( 'query', $data );
+ $this->assertArrayHasKey( 'pages', $data['query'] );
+ $this->assertArrayHasKey( $page->getId(), $data['query']['pages'] );
+
+ $info = $data['query']['pages'][$page->getId()];
+ $this->assertArrayHasKey( 'actions', $info );
+ $this->assertArrayHasKey( 'edit', $info['actions'] );
+ $this->assertInternalType( 'array', $info['actions']['edit'] );
+ $this->assertArrayHasKey( 0, $info['actions']['edit'] );
+ $this->assertArrayHasKey( 'code', $info['actions']['edit'][0] );
+ $this->assertSame( 'blocked', $info['actions']['edit'][0]['code'] );
+ $this->assertArrayHasKey( 'data', $info['actions']['edit'][0] );
+ $this->assertArrayHasKey( 'blockinfo', $info['actions']['edit'][0]['data'] );
+ $this->assertArrayHasKey( 'blockid', $info['actions']['edit'][0]['data']['blockinfo'] );
+ $this->assertSame( $block->getId(), $info['actions']['edit'][0]['data']['blockinfo']['blockid'] );
+ }
+
+}
[ 'ćaB', 'ćaB' ],
];
}
+
+ public function testNoDBAccess() {
+ global $wgContLanguageCode;
+
+ $dbr = wfGetDB( DB_REPLICA );
+
+ MessageCache::singleton()->getMsgFromNamespace( 'allpages', $wgContLanguageCode );
+
+ $this->assertEquals( 0, $dbr->trxLevel() );
+ $dbr->setFlag( DBO_TRX, $dbr::REMEMBER_PRIOR ); // make queries trigger TRX
+
+ MessageCache::singleton()->getMsgFromNamespace( 'go', $wgContLanguageCode );
+
+ $dbr->restoreFlags();
+
+ $this->assertEquals( 0, $dbr->trxLevel(), "No DB read queries" );
+ }
}
$this->assertSame( null, $domain->getSchema() );
$this->assertSame( '', $domain->getTablePrefix() );
}
+
+ public static function provideIsCompatible() {
+ return [
+ 'Basic' =>
+ [ 'foo', 'foo', null, '', true ],
+ 'db+prefix' =>
+ [ 'foo-bar', 'foo', null, 'bar', true ],
+ 'db+schema+prefix' =>
+ [ 'foo-bar-baz', 'foo', 'bar', 'baz', true ],
+ 'db+dontcare_schema+prefix' =>
+ [ 'foo-bar-baz', 'foo', null, 'baz', false ],
+ '?h -> -' =>
+ [ 'foo?hbar-baz-baa', 'foo-bar', 'baz', 'baa', true ],
+ '?? -> ?' =>
+ [ 'foo??bar-baz-baa', 'foo?bar', 'baz', 'baa', true ],
+ 'Nothing' =>
+ [ '', null, null, '', true ],
+ 'dontcaredb+dontcaredbschema+prefix' =>
+ [ 'mywiki-mediawiki-prefix', null, null, 'prefix', false ],
+ 'dontcaredb+schema+prefix' =>
+ [ 'mywiki-schema-prefix', null, 'schema', 'prefix', false ],
+ 'db+dontcareschema+prefix' =>
+ [ 'mywiki-schema-prefix', 'mywiki', null, 'prefix', false ],
+ 'postgres-db-jobqueue' =>
+ [ 'postgres-mediawiki-', 'postgres', null, '', false ]
+ ];
+ }
+
+ /**
+ * @dataProvider provideIsCompatible
+ * @covers Wikimedia\Rdbms\DatabaseDomain::isCompatible
+ */
+ public function testIsCompatible( $id, $db, $schema, $prefix, $transitive ) {
+ $compareIdObj = DatabaseDomain::newFromId( $id );
+ $this->assertInstanceOf( DatabaseDomain::class, $compareIdObj );
+
+ $fromId = new DatabaseDomain( $db, $schema, $prefix );
+
+ $this->assertTrue( $fromId->isCompatible( $id ), 'constructed equals string' );
+ $this->assertTrue( $fromId->isCompatible( $compareIdObj ), 'fromId equals string' );
+
+ $this->assertEquals( $transitive, $compareIdObj->isCompatible( $fromId ),
+ 'test transitivity of nulls components' );
+ }
+
+ public static function provideIsCompatible2() {
+ return [
+ 'db+schema+prefix' =>
+ [ 'mywiki-schema-prefix', 'thatwiki', 'schema', 'prefix' ],
+ 'dontcaredb+dontcaredbschema+prefix' =>
+ [ 'thatwiki-mediawiki-otherprefix', null, null, 'prefix' ],
+ 'dontcaredb+schema+prefix' =>
+ [ 'mywiki-otherschema-prefix', null, 'schema', 'prefix' ],
+ 'db+dontcareschema+prefix' =>
+ [ 'notmywiki-schema-prefix', 'mywiki', null, 'prefix' ],
+ ];
+ }
+
+ /**
+ * @dataProvider provideIsCompatible2
+ * @covers Wikimedia\Rdbms\DatabaseDomain::isCompatible
+ */
+ public function testIsCompatible2( $id, $db, $schema, $prefix ) {
+ $compareIdObj = DatabaseDomain::newFromId( $id );
+ $this->assertInstanceOf( DatabaseDomain::class, $compareIdObj );
+
+ $fromId = new DatabaseDomain( $db, $schema, $prefix );
+
+ $this->assertFalse( $fromId->isCompatible( $id ), 'constructed equals string' );
+ $this->assertFalse( $fromId->isCompatible( $compareIdObj ), 'fromId equals string' );
+ }
+
+ /**
+ * @covers Wikimedia\Rdbms\DatabaseDomain::isUnspecified
+ */
+ public function testIsUnspecified() {
+ $domain = new DatabaseDomain( null, null, '' );
+ $this->assertTrue( $domain->isUnspecified() );
+ $domain = new DatabaseDomain( 'mywiki', null, '' );
+ $this->assertFalse( $domain->isUnspecified() );
+ $domain = new DatabaseDomain( 'mywiki', null, '' );
+ $this->assertFalse( $domain->isUnspecified() );
+ }
}
}
public function testActorId() {
+ $domain = MediaWikiServices::getInstance()->getDBLoadBalancer()->getLocalDomainID();
$this->hideDeprecated( 'User::selectFields' );
// Newly-created user has an actor ID
'Actor ID can be retrieved for user loaded with User::selectFields()' );
$this->db->delete( 'actor', [ 'actor_user' => $id ], __METHOD__ );
- User::purge( wfWikiId(), $id );
+ User::purge( $domain, $id );
// Because WANObjectCache->delete() stupidly doesn't delete from the process cache.
ObjectCache::getMainWANInstance()->clearProcessCache();
npm run selenium
-By default, Chrome will run in headless mode. If you want to see Chrome, set DISPLAY
-environment variable to any value:
+There are three supported modes of running the tests:
+
+- Headless. It's the default. You will not see the browser while tests are
+ running because it's running in a headless mode. This mode should run fine
+ on all supported platforms.
+- Headless recording. Set DISPLAY environment variable to a value that starts
+ with colon (`:`) and video of each test will be recorded. Browser will run
+ headless. Recording videos works only on Linux.
+- Visible. If you want to see the browser, set DISPLAY environment variable to
+ any value that does not start with colon. This mode will not work in a
+ headless environment like MediaWiki-Vagrant.
+
+Example recording session:
+
+ sudo apt-get install chromedriver ffmpeg xvfb
+ export DISPLAY=:94
+ Xvfb "$DISPLAY" -screen 0 1280x1024x24 &
+ npm run selenium
+
+Example visible session:
DISPLAY=1 npm run selenium
const fs = require( 'fs' ),
path = require( 'path' ),
- saveScreenshot = require( 'wdio-mediawiki' ).saveScreenshot,
- logPath = process.env.LOG_DIR || __dirname + '/log';
+ logPath = process.env.LOG_DIR || path.join( __dirname, '/log' );
+let ffmpeg;
+
+// get current test title and clean it, to use it as file name
+function fileName( title ) {
+ return encodeURIComponent( title.replace( /\s+/g, '-' ) );
+}
+
+// build file path
+function filePath( test, screenshotPath, extension ) {
+ return path.join( screenshotPath, `${fileName( test.parent )}-${fileName( test.title )}.${extension}` );
+}
+
+// relative path
function relPath( foo ) {
return path.resolve( __dirname, '../..', foo );
}
// =====
// See also: http://webdriver.io/guide/testrunner/configurationfile.html
+ /**
+ * Function to be executed before a test (in Mocha/Jasmine) or a step (in Cucumber) starts.
+ * @param {Object} test test details
+ */
+ beforeTest: function ( test ) {
+ if ( process.env.DISPLAY && process.env.DISPLAY.startsWith( ':' ) ) {
+ let videoPath = filePath( test, this.screenshotPath, 'mp4' );
+ const { spawn } = require( 'child_process' );
+ ffmpeg = spawn( 'ffmpeg', [
+ '-f', 'x11grab', // grab the X11 display
+ '-video_size', '1280x1024', // video size
+ '-i', process.env.DISPLAY, // input file url
+ '-loglevel', 'error', // log only errors
+ '-y', // overwrite output files without asking
+ '-pix_fmt', 'yuv420p', // QuickTime Player support, "Use -pix_fmt yuv420p for compatibility with outdated media players"
+ videoPath // output file
+ ] );
+
+ ffmpeg.stdout.on( 'data', ( data ) => {
+ console.log( `ffmpeg stdout: ${data}` );
+ } );
+
+ ffmpeg.stderr.on( 'data', ( data ) => {
+ console.log( `ffmpeg stderr: ${data}` );
+ } );
+
+ ffmpeg.on( 'close', ( code ) => {
+ console.log( '\n\tVideo location:', videoPath, '\n' );
+ console.log( `ffmpeg exited with code ${code}` );
+ } );
+ }
+ },
+
/**
* Save a screenshot when test fails.
*
* @param {Object} test Mocha Test object
*/
afterTest: function ( test ) {
- var filePath;
- if ( !test.passed ) {
- filePath = saveScreenshot( test.title );
- console.log( '\n\tScreenshot: ' + filePath + '\n' );
+ if ( ffmpeg ) {
+ // stop video recording
+ ffmpeg.kill( 'SIGINT' );
+ }
+
+ // if test passed, ignore, else take and save screenshot
+ if ( test.passed ) {
+ return;
}
+ // save screenshot
+ let screenshotPath = filePath( test, this.screenshotPath, 'png' );
+ browser.saveScreenshot( screenshotPath );
+ console.log( '\n\tScreenshot location:', screenshotPath, '\n' );
}
};