Merge "Remove unused key in WANObjectCache::newEmpty()"
authorjenkins-bot <jenkins-bot@gerrit.wikimedia.org>
Fri, 9 Jun 2017 00:54:15 +0000 (00:54 +0000)
committerGerrit Code Review <gerrit@wikimedia.org>
Fri, 9 Jun 2017 00:54:16 +0000 (00:54 +0000)
39 files changed:
RELEASE-NOTES-1.30
docs/hooks.txt
includes/EditPage.php
includes/GlobalFunctions.php
includes/Sanitizer.php
includes/actions/HistoryAction.php
includes/api/i18n/he.json
includes/api/i18n/hu.json
includes/api/i18n/lt.json
includes/changes/ChangesList.php
includes/changes/EnhancedChangesList.php
includes/changes/OldChangesList.php
includes/import/WikiImporter.php
includes/logging/LogEventsList.php
includes/resourceloader/ResourceLoader.php
includes/specials/SpecialNewpages.php
includes/specials/pagers/ContribsPager.php
includes/specials/pagers/DeletedContribsPager.php
includes/templates/EnhancedChangesListGroup.mustache
includes/user/PasswordReset.php
languages/i18n/ar.json
languages/i18n/atj.json
languages/i18n/be-tarask.json
languages/i18n/bg.json
languages/i18n/cs.json
languages/i18n/hr.json
languages/i18n/jv.json
languages/i18n/lt.json
languages/i18n/sah.json
languages/i18n/tt-cyrl.json
languages/i18n/yi.json
languages/i18n/zh-hant.json
maintenance/importDump.php
resources/src/mediawiki.special/mediawiki.special.search.interwikiwidget.styles.less
tests/phpunit/includes/GlobalFunctions/wfArrayFilterTest.php [new file with mode: 0644]
tests/phpunit/includes/SanitizerTest.php
tests/phpunit/includes/changes/EnhancedChangesListTest.php
tests/phpunit/includes/changes/OldChangesListTest.php
tests/phpunit/includes/user/PasswordResetTest.php

index 343c296..cd800da 100644 (file)
@@ -99,6 +99,13 @@ changes to languages because of Phabricator reports.
   or wikilinks.
 * (T163966) Page moves are now counted as edits for the purposes of
   autopromotion, i.e., they increment the user_editcount field in the database.
+* Two new hooks, LogEventsListLineEnding and NewPagesLineEnding were added for
+  manipulating Special:Log and Special:NewPages lines.
+* The OldChangesListRecentChangesLine, EnhancedChangesListModifyLineData,
+  PageHistoryLineEnding, ContributionsLineEnding and DeletedContributionsLineEnding
+  hooks have an additional parameter, for manipulating HTML data attributes of
+  RC/history lines. EnhancedChangesListModifyBlockLineData can do that via the
+  $data['attribs'] subarray.
 
 == Compatibility ==
 MediaWiki 1.30 requires PHP 5.5.9 or later. There is experimental support for
index 0e8b508..3d310c3 100644 (file)
@@ -1155,6 +1155,9 @@ $page: SpecialPage object for contributions
 &$ret: the HTML line
 $row: the DB row for this line
 &$classes: the classes to add to the surrounding <li>
+&$attribs: associative array of other HTML attributes for the <li> element.
+  Currently only data attributes reserved to MediaWiki are allowed
+  (see Sanitizer::isReservedDataAttribute).
 
 'ContributionsToolLinks': Change tool links above Special:Contributions
 $id: User identifier
@@ -1200,6 +1203,9 @@ $page: SpecialPage object for DeletedContributions
 &$ret: the HTML line
 $row: the DB row for this line
 &$classes: the classes to add to the surrounding <li>
+&$attribs: associative array of other HTML attributes for the <li> element.
+  Currently only data attributes reserved to MediaWiki are allowed
+  (see Sanitizer::isReservedDataAttribute).
 
 'DifferenceEngineAfterLoadNewText': called in DifferenceEngine::loadNewText()
 after the new revision's content has been loaded into the class member variable
@@ -1512,6 +1518,9 @@ $changesList: EnhancedChangesList object
 $block: An array of RecentChange objects in that block
 $rc: The RecentChange object for this line
 &$classes: An array of classes to change
+&$attribs: associative array of other HTML attributes for the <tr> element.
+  Currently only data attributes reserved to MediaWiki are allowed
+  (see Sanitizer::isReservedDataAttribute).
 
 'EnhancedChangesListModifyBlockLineData': to alter data used to build
 a non-grouped recent change line in EnhancedChangesList.
@@ -1999,6 +2008,16 @@ $file: the File object or false if broken link
 &$attribs: the attributes to be applied
 &$ret: the value to return if your hook returns false
 
+'LogEventsListLineEnding': Called before a Special:Log line is finished
+$page: the LogEventsList object
+&$ret: the HTML line
+$entry: the DatabaseLogEntry object for this row
+&$classes: the classes to add to the surrounding <li>
+&$attribs: associative array of other HTML attributes for the <li> element.
+  Currently only data attributes reserved to MediaWiki are allowed
+  (see Sanitizer::isReservedDataAttribute).
+
+
 'HtmlPageLinkRendererBegin':
 Used when generating internal and interwiki links in
 LinkRenderer, before processing starts.  Return false to skip default
@@ -2284,6 +2303,16 @@ $title: the diff page title (nullable)
 $old: the ?old= param value from the url
 $new: the ?new= param value from the url
 
+'NewPagesLineEnding': Called before a NewPages line is finished.
+$page: the SpecialNewPages object
+&$ret: the HTML line
+$row: the database row for this page (the recentchanges record and a few extras - see
+  NewPagesPager::getQueryInfo)
+&$classes: the classes to add to the surrounding <li>
+&$attribs: associative array of other HTML attributes for the <li> element.
+  Currently only data attributes reserved to MediaWiki are allowed
+  (see Sanitizer::isReservedDataAttribute).
+
 'NewRevisionFromEditComplete': Called when a revision was inserted due to an
 edit.
 $wikiPage: the WikiPage edited
@@ -2296,7 +2325,10 @@ return false to omit the line from RecentChanges and Watchlist special pages.
 &$changeslist: The OldChangesList instance.
 &$s: HTML of the form "<li>...</li>" containing one RC entry.
 $rc: The RecentChange object.
-&$classes: array of css classes for the <li> element
+&$classes: array of css classes for the <li> element.
+&$attribs: associative array of other HTML attributes for the <li> element.
+  Currently only data attributes reserved to MediaWiki are allowed
+  (see Sanitizer::isReservedDataAttribute).
 
 'OpenSearchUrls': Called when constructing the OpenSearch description XML. Hooks
 can alter or append to the array of URLs for search & suggestion formats.
@@ -2404,6 +2436,9 @@ $historyAction: the action object
 &$row: the revision row for this line
 &$s: the string representing this parsed line
 &$classes: array containing the <li> element classes
+&$attribs: associative array of other HTML attributes for the <li> element.
+  Currently only data attributes reserved to MediaWiki are allowed
+  (see Sanitizer::isReservedDataAttribute).
 
 'PageHistoryPager::doBatchLookups': Called after the pager query was run, before
 any output is generated, to allow batch lookups for prefetching information
index f79a286..6be8771 100644 (file)
@@ -4335,8 +4335,6 @@ HTML
                $buttonLabel = $this->context->msg( $this->getSaveButtonLabel() )->text();
 
                $attribs = [
-                       'id' => 'wpSaveWidget',
-                       'inputId' => 'wpSave',
                        'name' => 'wpSave',
                        'tabindex' => ++$tabindex,
                ] + Linker::tooltipAndAccesskeyAttribs( 'save' );
@@ -4344,6 +4342,8 @@ HTML
                if ( $this->oouiEnabled ) {
                        $saveConfig = OOUI\Element::configFromHtmlAttributes( $attribs );
                        $buttons['save'] = new OOUI\ButtonInputWidget( [
+                               'id' => 'wpSaveWidget',
+                               'inputId' => 'wpSave',
                                // Support: IE 6 – Use <input>, otherwise it can't distinguish which button was clicked
                                'useInputTag' => true,
                                'flags' => [ 'constructive', 'primary' ],
@@ -4354,20 +4354,20 @@ HTML
                } else {
                        $buttons['save'] = Html::submitButton(
                                $buttonLabel,
-                               $attribs,
+                               $attribs + [ 'id' => 'wpSave' ],
                                [ 'mw-ui-progressive' ]
                        );
                }
 
                $attribs = [
-                       'id' => 'wpPreviewWidget',
-                       'inputId' => 'wpPreview',
                        'name' => 'wpPreview',
                        'tabindex' => ++$tabindex,
                ] + Linker::tooltipAndAccesskeyAttribs( 'preview' );
                if ( $this->oouiEnabled ) {
                        $previewConfig = OOUI\Element::configFromHtmlAttributes( $attribs );
                        $buttons['preview'] = new OOUI\ButtonInputWidget( [
+                               'id' => 'wpPreviewWidget',
+                               'inputId' => 'wpPreview',
                                // Support: IE 6 – Use <input>, otherwise it can't distinguish which button was clicked
                                'useInputTag' => true,
                                'label' => $this->context->msg( 'showpreview' )->text(),
@@ -4377,18 +4377,18 @@ HTML
                } else {
                        $buttons['preview'] = Html::submitButton(
                                $this->context->msg( 'showpreview' )->text(),
-                               $attribs
+                               $attribs + [ 'id' => 'wpPreview' ]
                        );
                }
                $attribs = [
-                       'id' => 'wpDiffWidget',
-                       'inputId' => 'wpDiff',
                        'name' => 'wpDiff',
                        'tabindex' => ++$tabindex,
                ] + Linker::tooltipAndAccesskeyAttribs( 'diff' );
                if ( $this->oouiEnabled ) {
                        $diffConfig = OOUI\Element::configFromHtmlAttributes( $attribs );
                        $buttons['diff'] = new OOUI\ButtonInputWidget( [
+                               'id' => 'wpDiffWidget',
+                               'inputId' => 'wpDiff',
                                // Support: IE 6 – Use <input>, otherwise it can't distinguish which button was clicked
                                'useInputTag' => true,
                                'label' => $this->context->msg( 'showdiff' )->text(),
@@ -4398,7 +4398,7 @@ HTML
                } else {
                        $buttons['diff'] = Html::submitButton(
                                $this->context->msg( 'showdiff' )->text(),
-                               $attribs
+                               $attribs + [ 'id' => 'wpDiff' ]
                        );
                }
 
index c6ccf31..2090d90 100644 (file)
@@ -203,6 +203,38 @@ function wfArrayDiff2_cmp( $a, $b ) {
        }
 }
 
+/**
+ * Like array_filter with ARRAY_FILTER_USE_BOTH, but works pre-5.6.
+ *
+ * @param array $arr
+ * @param callable $callback Will be called with the array value and key (in that order) and
+ *   should return a bool which will determine whether the array element is kept.
+ * @return array
+ */
+function wfArrayFilter( array $arr, callable $callback ) {
+       if ( defined( 'ARRAY_FILTER_USE_BOTH' ) ) {
+               return array_filter( $arr, $callback, ARRAY_FILTER_USE_BOTH );
+       }
+       $filteredKeys = array_filter( array_keys( $arr ), function ( $key ) use ( $arr, $callback ) {
+               return call_user_func( $callback, $arr[$key], $key );
+       } );
+       return array_intersect_key( $arr, array_fill_keys( $filteredKeys, true ) );
+}
+
+/**
+ * Like array_filter with ARRAY_FILTER_USE_KEY, but works pre-5.6.
+ *
+ * @param array $arr
+ * @param callable $callback Will be called with the array key and should return a bool which
+ *   will determine whether the array element is kept.
+ * @return array
+ */
+function wfArrayFilterByKey( array $arr, callable $callback ) {
+       return wfArrayFilter( $arr, function ( $val, $key ) use ( $callback ) {
+               return call_user_func( $callback, $key );
+       } );
+}
+
 /**
  * Appends to second array if $value differs from that in $default
  *
index c4883ba..5aaa3ed 100644 (file)
@@ -782,15 +782,12 @@ class Sanitizer {
 
                        # Allow any attribute beginning with "data-"
                        # However:
-                       # * data-ooui is reserved for ooui
-                       # * data-mw and data-parsoid are reserved for parsoid
-                       # * data-mw-<name here> is reserved for extensions (or core) if
-                       #   they need to communicate some data to the client and want to be
-                       #   sure that it isn't coming from an untrusted user.
+                       # * Disallow data attributes used by MediaWiki code
                        # * Ensure that the attribute is not namespaced by banning
                        #   colons.
-                       if ( !preg_match( '/^data-(?!ooui|mw|parsoid)[^:]*$/i', $attribute )
+                       if ( !preg_match( '/^data-[^:]*$/i', $attribute )
                                && !isset( $whitelist[$attribute] )
+                               || self::isReservedDataAttribute( $attribute )
                        ) {
                                continue;
                        }
@@ -858,6 +855,24 @@ class Sanitizer {
                return $out;
        }
 
+       /**
+        * Given an attribute name, checks whether it is a reserved data attribute
+        * (such as data-mw-foo) which is unavailable to user-generated HTML so MediaWiki
+        * core and extension code can safely use it to communicate with frontend code.
+        * @param string $attr Attribute name.
+        * @return bool
+        */
+       public static function isReservedDataAttribute( $attr ) {
+               // data-ooui is reserved for ooui.
+               // data-mw and data-parsoid are reserved for parsoid.
+               // data-mw-<name here> is reserved for extensions (or core) if
+               // they need to communicate some data to the client and want to be
+               // sure that it isn't coming from an untrusted user.
+               // We ignore the possibility of namespaces since user-generated HTML
+               // can't use them anymore.
+               return (bool)preg_match( '/^data-(ooui|mw|parsoid)/i', $attr );
+       }
+
        /**
         * Merge two sets of HTML attributes.  Conflicting items in the second set
         * will override those in the first, except for 'class' attributes which
index d1be7d4..7460340 100644 (file)
@@ -780,9 +780,11 @@ class HistoryPager extends ReverseChronologicalPager {
                        $s .= ' <span class="mw-changeslist-separator">. .</span> ' . $s2;
                }
 
-               Hooks::run( 'PageHistoryLineEnding', [ $this, &$row, &$s, &$classes ] );
+               $attribs = [ 'data-mw-revid' => $rev->getId() ];
+
+               Hooks::run( 'PageHistoryLineEnding', [ $this, &$row, &$s, &$classes, &$attribs ] );
+               $attribs = wfArrayFilterByKey( $attribs, [ Sanitizer::class, 'isReservedDataAttribute' ] );
 
-               $attribs = [];
                if ( $classes ) {
                        $attribs['class'] = implode( ' ', $classes );
                }
index b6a5b09..36a19bc 100644 (file)
        "apihelp-compare-param-fromtitle": "כותרת ראשונה להשוואה.",
        "apihelp-compare-param-fromid": "מס׳ זיהוי של העמוד הראשון להשוואה.",
        "apihelp-compare-param-fromrev": "גרסה ראשונה להשוואה.",
+       "apihelp-compare-param-fromtext": "להשתמש בטקסט הזה במקום תוכן הגרסה שהוגדרה על־ידי <var dir=\"ltr\">fromtitle</var>, <var dir=\"ltr\">fromid</var> או <var dir=\"ltr\">fromrev</var>.",
+       "apihelp-compare-param-frompst": "לעשות התמרה לפני שמירה ב־<var>fromtext</var>.",
+       "apihelp-compare-param-fromcontentmodel": "מודל התוכן של <var>fromtext</var>. אם זה לא סופק, ייעשה ניחוש על סמך פרמטרים אחרים.",
+       "apihelp-compare-param-fromcontentformat": "תסדיר הסדרת תוכן של <var>fromtext</var>.",
        "apihelp-compare-param-totitle": "כותרת שנייה להשוואה.",
        "apihelp-compare-param-toid": "מס׳ מזהה של העמוד השני להשוואה.",
        "apihelp-compare-param-torev": "גרסה שנייה להשוואה.",
+       "apihelp-compare-param-torelative": "להשתמש בגרסה יחסית לגרסה שהוסקה מ<var dir=\"ltr\">fromtitle</var>, <var dir=\"ltr\">fromid</var> או <var dir=\"ltr\">fromrev</var>. לכל אפשריות ה־\"to\" האחרות לא תהיה השפעה.",
+       "apihelp-compare-param-totext": "להשתמש בטקסט הזה במקום התוכן של הגרסה שהוגדר ב־<var dir=\"ltr\">totitle</var>, <var dir=\"ltr\">toid</var> or <var dir=\"ltr\">torev</var>.",
+       "apihelp-compare-param-topst": "לעשות התמרה לפני שמירה ב־<var>totext</var>.",
+       "apihelp-compare-param-tocontentmodel": "מודל התוכן של <var>totext</var>. אם זה לא סופק, ייעשה ניחוש על סמך פרמטרים אחרים.",
+       "apihelp-compare-param-tocontentformat": "תסדיר הסדרת תוכן של <var>fromtext</var>.",
+       "apihelp-compare-param-prop": "אילו פריטי מידע לקבל.",
+       "apihelp-compare-paramvalue-prop-diff": "ה־HTML של ההשוואה.",
+       "apihelp-compare-paramvalue-prop-diffsize": "גודל ה־HTML של ההשוואה, בבתים.",
+       "apihelp-compare-paramvalue-prop-rel": "מזהי הגרסאות של הגרסאות לפני \"from\" ואחרי \"to\", אם יש כאלה.",
        "apihelp-compare-example-1": "יצירת תיעוד שינוי בין גרסה 1 ל־2.",
        "apihelp-createaccount-description": "יצירת חשבון משתמש חדש.",
        "apihelp-createaccount-param-preservestate": "אם <kbd>[[Special:ApiHelp/query+authmanagerinfo|action=query&meta=authmanagerinfo]]</kbd> החזיר true עבור <samp>hasprimarypreservedstate</samp>, בקשות שמסומנות בתור <samp>primary-required</samp> אמורות להיות מושמטות. אם מוחזר ערך לא ריק ל־<samp>preservedusername</samp>, שם המשתמש הזה ישמש לפרמטר <var>username</var>.",
        "apierror-changeauth-norequest": "יצירת בקשת השינוי נכשלה.",
        "apierror-chunk-too-small": "גודל הפלח המזערי הוא {{PLURAL:$1|בית אחד|$1 בתים}} בשביל פלחים לא סופיים.",
        "apierror-cidrtoobroad": "טווחי CIDR של $1 שרחבים יותר מ־/$2 אינם קבילים.",
-       "apierror-compare-inputneeded": "כותרת, מזהה דף, או מספר גרסה נחוצים בשביל הפרמטרים <var>from</var> ו־<var>to</var>.",
        "apierror-contentserializationexception": "הסדרת התוכן נכשלה: $1",
        "apierror-contenttoobig": "התוכן שסיפקת חורג מגודל הערך המרבי של {{PLURAL:$1|קילובייט אחד|$1 קילובייטים}}.",
        "apierror-copyuploadbaddomain": "העלאות לפי URL אינם מורשות מהמתחם הזה.",
index 5ae31c1..75a05f8 100644 (file)
        "apihelp-resetpassword-param-email": "A visszaállítandó felhasználó e-mail-címe.",
        "apihelp-resetpassword-example-user": "Jelszó-visszaállító e-mail küldése <kbd>Example</kbd> felhasználónak.",
        "apihelp-resetpassword-example-email": "Jelszó-visszaállító e-mail küldése az összes <kbd>user@example.com</kbd> e-mail-című felhasználónak.",
+       "apihelp-revisiondelete-description": "Változatok törlése és helyreállítása.",
+       "apihelp-revisiondelete-param-ids": "A törlendő lapváltozatok azonosítói.",
+       "apihelp-revisiondelete-param-reason": "A törlés vagy helyreállítás indoklása.",
+       "apihelp-revisiondelete-example-revision": "A <kbd>12345</kbd> lapváltozat tartalmának elrejtése a <kbd>Main Page</kbd> lapon.",
+       "apihelp-revisiondelete-example-log": "A <kbd>67890</kbd> naplóbejegyzés összes adatának elrejtése <kbd>BLP violation</kbd> indoklással.",
        "apihelp-userrights-param-userid": "Felhasználói azonosító.",
        "api-help-title": "MediaWiki API súgó",
        "api-help-lead": "Ez egy automatikusan generált MediaWiki API-dokumentációs lap.\n\nDokumentáció és példák: https://www.mediawiki.org/wiki/API",
index 0935c59..f923e18 100644 (file)
@@ -14,6 +14,7 @@
        "apihelp-compare-param-fromid": "Pirmojo lyginamo puslapio ID.",
        "apihelp-compare-param-totitle": "Antrasis pavadinimas palyginimui.",
        "apihelp-compare-param-toid": "Antrojo lyginamo puslapio ID.",
+       "apihelp-compare-param-prop": "Kokią informaciją gauti.",
        "apihelp-createaccount-description": "Kurti naują vartotojo paskyrą.",
        "apihelp-createaccount-param-name": "Naudotojo vardas.",
        "apihelp-createaccount-param-email": "Vartotojo el. pašto adresas (nebūtina).",
index 92a3d3f..00d842f 100644 (file)
@@ -739,4 +739,26 @@ class ChangesList extends ContextSource {
                        && intval( $rcObj->getAttribute( 'rc_this_oldid' ) ) === 0;
        }
 
+       /**
+        * Get recommended data attributes for a change line.
+        * @param RecentChange $rc
+        * @return string[] attribute name => value
+        */
+       protected function getDataAttributes( RecentChange $rc ) {
+               $type = $rc->getAttribute( 'rc_source' );
+               switch ( $type ) {
+                       case RecentChange::SRC_EDIT:
+                       case RecentChange::SRC_NEW:
+                               return [
+                                       'data-mw-revid' => $rc->mAttribs['rc_this_oldid'],
+                               ];
+                       case RecentChange::SRC_LOG:
+                               return [
+                                       'data-mw-logid' => $rc->mAttribs['rc_logid'],
+                                       'data-mw-logaction' => $rc->mAttribs['rc_log_type'] . '/' . $rc->mAttribs['rc_log_action'],
+                               ];
+                       default:
+                               return [];
+               }
+       }
 }
index b34a33f..03f63f6 100644 (file)
@@ -447,13 +447,16 @@ class EnhancedChangesList extends ChangesList {
                # Tags
                $data['tags'] = $this->getTags( $rcObj, $classes );
 
+               $attribs = $this->getDataAttributes( $rcObj );
+
                // give the hook a chance to modify the data
                $success = Hooks::run( 'EnhancedChangesListModifyLineData',
-                       [ $this, &$data, $block, $rcObj, &$classes ] );
+                       [ $this, &$data, $block, $rcObj, &$classes, &$attribs ] );
                if ( !$success ) {
                        // skip entry if hook aborted it
                        return [];
                }
+               $attribs = wfArrayFilterByKey( $attribs, [ Sanitizer::class, 'isReservedDataAttribute' ] );
 
                $lineParams['recentChangesFlagsRaw'] = [];
                if ( isset( $data['recentChangesFlags'] ) ) {
@@ -469,6 +472,7 @@ class EnhancedChangesList extends ChangesList {
                }
 
                $lineParams['classes'] = array_values( $classes );
+               $lineParams['attribs'] = Html::expandAttributes( $attribs );
 
                // everything else: makes it easier for extensions to add or remove data
                $lineParams['data'] = array_values( $data );
@@ -671,6 +675,8 @@ class EnhancedChangesList extends ChangesList {
                # Show how many people are watching this if enabled
                $data['watchingUsers'] = $this->numberofWatchingusers( $rcObj->numberofWatchingusers );
 
+               $data['attribs'] = array_merge( $this->getDataAttributes( $rcObj ), [ 'class' => $classes ] );
+
                // give the hook a chance to modify the data
                $success = Hooks::run( 'EnhancedChangesListModifyBlockLineData',
                        [ $this, &$data, $rcObj ] );
@@ -678,9 +684,11 @@ class EnhancedChangesList extends ChangesList {
                        // skip entry if hook aborted it
                        return '';
                }
+               $attribs = $data['attribs'];
+               unset( $data['attribs'] );
+               $attribs = wfArrayFilterByKey( $attribs, [ Sanitizer::class, 'isReservedDataAttribute' ] );
 
-               $line = Html::openElement( 'table', [ 'class' => $classes ] ) .
-                       Html::openElement( 'tr' );
+               $line = Html::openElement( 'table', $attribs ) . Html::openElement( 'tr' );
                $line .= '<td class="mw-enhanced-rc"><span class="mw-enhancedchanges-arrow-space"></span>';
 
                if ( isset( $data['recentChangesFlags'] ) ) {
index a5d5191..2a53d66 100644 (file)
@@ -50,16 +50,23 @@ class OldChangesList extends ChangesList {
                                $rc->mAttribs['rc_namespace'] . '-' . $rc->mAttribs['rc_title'] );
                }
 
+               $attribs = $this->getDataAttributes( $rc );
+
                // Avoid PHP 7.1 warning from passing $this by reference
                $list = $this;
-               if ( !Hooks::run( 'OldChangesListRecentChangesLine', [ &$list, &$html, $rc, &$classes ] ) ) {
+               if ( !Hooks::run( 'OldChangesListRecentChangesLine',
+                       [ &$list, &$html, $rc, &$classes, &$attribs ] )
+               ) {
                        return false;
                }
+               $attribs = wfArrayFilterByKey( $attribs, [ Sanitizer::class, 'isReservedDataAttribute' ] );
 
                $dateheader = ''; // $html now contains only <li>...</li>, for hooks' convenience.
                $this->insertDateHeader( $dateheader, $rc->mAttribs['rc_timestamp'] );
 
-               return "$dateheader<li class=\"" . implode( ' ', $classes ) . "\">" . $html . "</li>\n";
+               $attribs['class'] = implode( ' ', $classes );
+
+               return $dateheader . Html::rawElement( 'li', $attribs,  $html ) . "\n";
        }
 
        /**
index 06b579a..2fc9f5e 100644 (file)
@@ -39,6 +39,7 @@ class WikiImporter {
        private $mNoticeCallback, $mDebug;
        private $mImportUploads, $mImageBasePath;
        private $mNoUpdates = false;
+       private $pageOffset = 0;
        /** @var Config */
        private $config;
        /** @var ImportTitleFactory */
@@ -146,6 +147,16 @@ class WikiImporter {
                $this->mNoUpdates = $noupdates;
        }
 
+       /**
+        * Sets 'pageOffset' value. So it will skip the first n-1 pages
+        * and start from the nth page. It's 1-based indexing.
+        * @param int $nthPage
+        * @since 1.29
+        */
+       function setPageOffset( $nthPage ) {
+               $this->pageOffset = $nthPage;
+       }
+
        /**
         * Set a callback that displays notice messages
         *
@@ -562,9 +573,19 @@ class WikiImporter {
                $keepReading = $this->reader->read();
                $skip = false;
                $rethrow = null;
+               $pageCount = 0;
                try {
                        while ( $keepReading ) {
                                $tag = $this->reader->localName;
+                               if ( $this->pageOffset ) {
+                                       if ( $tag === 'page' ) {
+                                               $pageCount++;
+                                       }
+                                       if ( $pageCount < $this->pageOffset ) {
+                                               $keepReading = $this->reader->next();
+                                               continue;
+                                       }
+                               }
                                $type = $this->reader->nodeType;
 
                                if ( !Hooks::run( 'ImportHandleToplevelXMLTag', [ $this ] ) ) {
index 317652a..c5501cb 100644 (file)
@@ -390,9 +390,18 @@ class LogEventsList extends ContextSource {
                        [ 'mw-logline-' . $entry->getType() ],
                        $newClasses
                );
+               $attribs = [
+                       'data-mw-logid' => $entry->getId(),
+                       'data-mw-logaction' => $entry->getFullType(),
+               ];
+               $ret = "$del $time $action $comment $revert $tagDisplay";
+
+               // Let extensions add data
+               Hooks::run( 'LogEventsListLineEnding', [ $this, &$ret, $entry, &$classes, &$attribs ] );
+               $attribs = wfArrayFilterByKey( $attribs, [ Sanitizer::class, 'isReservedDataAttribute' ] );
+               $attribs['class'] = implode( ' ', $classes );
 
-               return Html::rawElement( 'li', [ 'class' => $classes ],
-                       "$del $time $action $comment $revert $tagDisplay" ) . "\n";
+               return Html::rawElement( 'li', $attribs, $ret ) . "\n";
        }
 
        /**
index 767046b..c2faf48 100644 (file)
@@ -1170,7 +1170,7 @@ MESSAGE;
         * @param array $templates Keys are name of templates and values are the source of
         *   the template.
         * @throws MWException
-        * @return string
+        * @return string JavaScript code
         */
        protected static function makeLoaderImplementScript(
                $name, $scripts, $styles, $messages, $templates
@@ -1200,7 +1200,7 @@ MESSAGE;
         *
         * @param mixed $messages Either an associative array mapping message key to value, or a
         *   JSON-encoded message blob containing the same data, wrapped in an XmlJsCode object.
-        * @return string
+        * @return string JavaScript code
         */
        public static function makeMessageSetScript( $messages ) {
                return Xml::encodeJsCall(
@@ -1256,7 +1256,7 @@ MESSAGE;
         *
         * @param string $name
         * @param string $state
-        * @return string
+        * @return string JavaScript code
         */
        public static function makeLoaderStateScript( $name, $state = null ) {
                if ( is_array( $name ) ) {
@@ -1286,7 +1286,7 @@ MESSAGE;
         * @param string $group Group which the module is in.
         * @param string $source Source of the module, or 'local' if not foreign.
         * @param string $script JavaScript code
-        * @return string
+        * @return string JavaScript code
         */
        public static function makeCustomLoaderScript( $name, $version, $dependencies,
                $group, $source, $script
@@ -1358,7 +1358,7 @@ MESSAGE;
         * @param string $group Group which the module is in
         * @param string $source Source of the module, or 'local' if not foreign
         * @param string $skip Script body of the skip function
-        * @return string
+        * @return string JavaScript code
         */
        public static function makeLoaderRegisterScript( $name, $version = null,
                $dependencies = null, $group = null, $source = null, $skip = null
@@ -1412,7 +1412,7 @@ MESSAGE;
         *
         * @param string $id Source ID
         * @param string $loadUrl load.php url
-        * @return string
+        * @return string JavaScript code
         */
        public static function makeLoaderSourcesScript( $id, $loadUrl = null ) {
                if ( is_array( $id ) ) {
@@ -1436,7 +1436,7 @@ MESSAGE;
         *
         * @deprecated since 1.25; use makeInlineScript instead
         * @param string $script JavaScript code
-        * @return string
+        * @return string JavaScript code
         */
        public static function makeLoaderConditionalScript( $script ) {
                return '(window.RLQ=window.RLQ||[]).push(function(){' .
@@ -1466,7 +1466,7 @@ MESSAGE;
         * the given value.
         *
         * @param array $configuration List of configuration values keyed by variable name
-        * @return string
+        * @return string JavaScript code
         */
        public static function makeConfigSetScript( array $configuration ) {
                return Xml::encodeJsCall(
index be8ad8f..83482f6 100644 (file)
@@ -314,6 +314,7 @@ class SpecialNewpages extends IncludableSpecialPage {
                $rev->setTitle( $title );
 
                $classes = [];
+               $attribs = [ 'data-mw-revid' => $result->rev_id ];
 
                $lang = $this->getLanguage();
                $dm = $lang->getDirMark();
@@ -378,11 +379,19 @@ class SpecialNewpages extends IncludableSpecialPage {
                        $tagDisplay = '';
                }
 
-               $css = count( $classes ) ? ' class="' . implode( ' ', $classes ) . '"' : '';
-
                # Display the old title if the namespace/title has been changed
                $oldTitleText = '';
                $oldTitle = Title::makeTitle( $result->rc_namespace, $result->rc_title );
+               $ret = "{$time} {$dm}{$plink} {$hist} {$dm}{$length} {$dm}{$ulink} {$comment} "
+                       . "{$tagDisplay} {$oldTitleText}";
+
+               // Let extensions add data
+               Hooks::run( 'NewPagesLineEnding', [ $this, &$ret, $result, &$classes, &$attribs ] );
+               $attribs = wfArrayFilterByKey( $attribs, [ Sanitizer::class, 'isReservedDataAttribute' ] );
+
+               if ( count( $classes ) ) {
+                       $attribs['class'] = implode( ' ', $classes );
+               }
 
                if ( !$title->equals( $oldTitle ) ) {
                        $oldTitleText = $oldTitle->getPrefixedText();
@@ -393,8 +402,7 @@ class SpecialNewpages extends IncludableSpecialPage {
                        );
                }
 
-               return "<li{$css}>{$time} {$dm}{$plink} {$hist} {$dm}{$length} "
-                       . "{$dm}{$ulink} {$comment} {$tagDisplay} {$oldTitleText}</li>\n";
+               return Html::rawElement( 'li', $attribs, $ret ) . "\n";
        }
 
        /**
index a3880ee..6bd7eb0 100644 (file)
@@ -365,9 +365,9 @@ class ContribsPager extends RangeChronologicalPager {
         * @return string
         */
        function formatRow( $row ) {
-
                $ret = '';
                $classes = [];
+               $attribs = [];
 
                $linkRenderer = MediaWikiServices::getInstance()->getLinkRenderer();
 
@@ -388,7 +388,7 @@ class ContribsPager extends RangeChronologicalPager {
                MediaWiki\restoreWarnings();
 
                if ( $validRevision ) {
-                       $classes = [];
+                       $attribs['data-mw-revid'] = $rev->getId();
 
                        $page = Title::newFromRow( $row );
                        $link = $linkRenderer->makeLink(
@@ -535,19 +535,21 @@ class ContribsPager extends RangeChronologicalPager {
                }
 
                // Let extensions add data
-               Hooks::run( 'ContributionsLineEnding', [ $this, &$ret, $row, &$classes ] );
+               Hooks::run( 'ContributionsLineEnding', [ $this, &$ret, $row, &$classes, &$attribs ] );
+               $attribs = wfArrayFilterByKey( $attribs, [ Sanitizer::class, 'isReservedDataAttribute' ] );
 
                // TODO: Handle exceptions in the catch block above.  Do any extensions rely on
                // receiving empty rows?
 
-               if ( $classes === [] && $ret === '' ) {
+               if ( $classes === [] && $attribs === [] && $ret === '' ) {
                        wfDebug( "Dropping Special:Contribution row that could not be formatted\n" );
                        return "<!-- Could not format Special:Contribution row. -->\n";
                }
+               $attribs['class'] = $classes;
 
                // FIXME: The signature of the ContributionsLineEnding hook makes it
                // very awkward to move this LI wrapper into the template.
-               return Html::rawElement( 'li', [ 'class' => $classes ], $ret ) . "\n";
+               return Html::rawElement( 'li', $attribs, $ret ) . "\n";
        }
 
        /**
index 78e1092..43d7ad4 100644 (file)
@@ -195,6 +195,7 @@ class DeletedContribsPager extends IndexPager {
        function formatRow( $row ) {
                $ret = '';
                $classes = [];
+               $attribs = [];
 
                /*
                 * There may be more than just revision rows. To make sure that we'll only be processing
@@ -213,17 +214,20 @@ class DeletedContribsPager extends IndexPager {
                MediaWiki\restoreWarnings();
 
                if ( $validRevision ) {
+                       $attribs['data-mw-revid'] = $rev->getId();
                        $ret = $this->formatRevisionRow( $row );
                }
 
                // Let extensions add data
-               Hooks::run( 'DeletedContributionsLineEnding', [ $this, &$ret, $row, &$classes ] );
+               Hooks::run( 'DeletedContributionsLineEnding', [ $this, &$ret, $row, &$classes, &$attribs ] );
+               $attribs = wfArrayFilterByKey( $attribs, [ Sanitizer::class, 'isReservedDataAttribute' ] );
 
-               if ( $classes === [] && $ret === '' ) {
+               if ( $classes === [] && $attribs === [] && $ret === '' ) {
                        wfDebug( "Dropping Special:DeletedContribution row that could not be formatted\n" );
                        $ret = "<!-- Could not format Special:DeletedContribution row. -->\n";
                } else {
-                       $ret = Html::rawElement( 'li', [ 'class' => $classes ], $ret ) . "\n";
+                       $attribs['class'] = $classes;
+                       $ret = Html::rawElement( 'li', $attribs, $ret ) . "\n";
                }
 
                return $ret;
index 352eb17..3a37c2e 100644 (file)
@@ -14,7 +14,7 @@
                </td>
        </tr>
        {{# lines }}
-       <tr class="{{# classes }}{{ . }} {{/ classes }}">
+       <tr class="{{# classes }}{{ . }} {{/ classes }}"{{{ attribs }}}>
                <td></td>
                <td class="mw-enhanced-rc">{{{ recentChangesFlags }}}&#160;</td>
                <td class="mw-enhanced-rc-nested">
index 4ee256c..dd16fb7 100644 (file)
@@ -100,9 +100,10 @@ class PasswordReset implements LoggerAwareInterface {
                        } elseif ( !$user->isAllowed( 'editmyprivateinfo' ) ) {
                                // Maybe not all users have permission to change private data
                                $status = StatusValue::newFatal( 'badaccess' );
-                       } elseif ( $user->isBlocked() ) {
+                       } elseif ( $this->isBlocked( $user ) ) {
                                // Maybe the user is blocked (check this here rather than relying on the parent
-                               // method as we have a more specific error message to use here
+                               // method as we have a more specific error message to use here and we want to
+                               // ignore some types of blocks)
                                $status = StatusValue::newFatal( 'blocked-mailpassword' );
                        }
 
@@ -250,6 +251,37 @@ class PasswordReset implements LoggerAwareInterface {
                return StatusValue::newGood( $passwords );
        }
 
+       /**
+        * Check whether the user is blocked.
+        * Ignores certain types of system blocks that are only meant to force users to log in.
+        * @param User $user
+        * @return bool
+        * @since 1.30
+        */
+       protected function isBlocked( User $user ) {
+               $block = $user->getBlock() ?: $user->getGlobalBlock();
+               if ( !$block ) {
+                       return false;
+               }
+               $type = $block->getSystemBlockType();
+               if ( in_array( $type, [ null, 'global-block' ], true ) ) {
+                       // Normal block. Maybe it was meant for someone else and the user just needs to log in;
+                       // or maybe it was issued specifically to prevent some IP from messing with password
+                       // reset? Go out on a limb and use the registration allowed flag to decide.
+                       return $block->prevents( 'createaccount' );
+               } elseif ( $type === 'proxy' ) {
+                       // we disallow actions through proxy even if the user is logged in
+                       // so it makes sense to disallow password resets as well
+                       return true;
+               } elseif ( in_array( $type, [ 'dnsbl', 'wgSoftBlockRanges' ], true ) ) {
+                       // these are just meant to force login so let's not prevent that
+                       return false;
+               } else {
+                       // some extension - we'll have to guess
+                       return true;
+               }
+       }
+
        /**
         * @param string $email
         * @return User[]
index 7829324..2020de3 100644 (file)
@@ -77,9 +77,9 @@
        "tog-underline": "سطر تحت الوصلات:",
        "tog-hideminor": "أخف التعديلات الطفيفة في أحدث التغييرات",
        "tog-hidepatrolled": "أخف التعديلات المراجعة في أحدث التغييرات",
-       "tog-newpageshidepatrolled": "أخÙ\81 Ø§Ù\84صÙ\81حات Ø§Ù\84Ù\85عاÙ\8aÙ\86ة من قائمة الصفحات الجديدة",
+       "tog-newpageshidepatrolled": "أخÙ\81 Ø§Ù\84صÙ\81حات Ø§Ù\84Ù\85راجعة من قائمة الصفحات الجديدة",
        "tog-hidecategorization": "أخف تصنيف الصفحات",
-       "tog-extendwatchlist": "Ù\85دد قائمة المراقبة لتعرض كل التغييرات، وليس أحدثها فقط",
+       "tog-extendwatchlist": "Ù\88سع قائمة المراقبة لتعرض كل التغييرات، وليس أحدثها فقط",
        "tog-usenewrc": "طي التغييرات حسب الصفحة في أحدث التغييرات وقائمة المراقبة",
        "tog-numberheadings": "ترقيم العناوين تلقائيا",
        "tog-showtoolbar": "إظهار شريط التحرير",
@@ -89,8 +89,8 @@
        "tog-watchdefault": "أضف الصفحات والملفات التي أعدلها إلى قائمة مراقبتي",
        "tog-watchmoves": "أضف الصفحات والملفات التي أنقلها إلى قائمة مراقبتي",
        "tog-watchdeletion": "أضف الصفحات والملفات التي أحذفها إلى قائمة مراقبتي",
-       "tog-watchuploads": "أضÙ\81 Ø§Ù\84Ù\85Ù\84Ù\81ات Ø§Ù\84جدÙ\8aدة Ø§Ù\84تÙ\8a Ø±Ù\81عتها إلى قائمة مراقبتي",
-       "tog-watchrollback": "أضÙ\81 Ø¥Ù\84Ù\89 Ù\82ائÙ\85Ø© Ù\85راÙ\82بتÙ\8a Ø§Ù\84صÙ\81حات Ø§Ù\84تÙ\8a Ù\83Ù\86ت Ø£Ø¬Ø±Ù\8aت Ù\81Ù\8aÙ\87ا Ø§Ø³ØªØ±Ø¬Ø§Ø¹Ø§Øª",
+       "tog-watchuploads": "أضÙ\81 Ø§Ù\84Ù\85Ù\84Ù\81ات Ø§Ù\84جدÙ\8aدة Ø§Ù\84تÙ\8a Ø£Ø±Ù\81عها إلى قائمة مراقبتي",
+       "tog-watchrollback": "أضÙ\81 Ø§Ù\84صÙ\81حات Ø§Ù\84تÙ\8a Ø£Ø¬Ø±Ù\8a Ø¹Ù\84Ù\8aÙ\87ا Ø§Ø³ØªØ±Ø¬Ø§Ø¹Ø§Øª Ø¥Ù\84Ù\89 Ù\82ائÙ\85Ø© Ù\85راÙ\82بتÙ\8a",
        "tog-minordefault": "أشِّر كل التعديلات على أنها طفيفة مبدئيا",
        "tog-previewontop": "أظهر معاينة النص فوق صندوق التحرير",
        "tog-previewonfirst": "أظهر معاينة مع أول تعديل",
        "tog-watchlisthideown": "أخف تعديلاتي من قائمة المراقبة",
        "tog-watchlisthidebots": "أخف تعديلات البوتات من قائمة المراقبة",
        "tog-watchlisthideminor": "أخف التعديلات الطفيفة من قائمة المراقبة",
-       "tog-watchlisthideliu": "أخف تعديلات المستخدمين المسجلين في قائمة المراقبة\n\n\nإخفاء التعديلات التي كتبها تسجيل الدخول للمستخدمين من قائمة المراقبة",
+       "tog-watchlisthideliu": "أخف تعديلات المستخدمين المسجلين في قائمة المراقبة",
        "tog-watchlistreloadautomatically": "أعد تحميل قائمة المراقبة بصفة آلية حينما يتغير مرشح ما (يتطلب جافاسكربت)",
        "tog-watchlisthideanons": "أخف تعديلات المستخدمين المجهولين في قائمة المراقبة",
        "tog-watchlisthidepatrolled": "أخف التعديلات المراجعة في قائمة المراقبة",
        "tog-ccmeonemails": "أرسل إلي نسخا من الرسائل الإلكترونية التي أرسلها إلى المستخدمين الآخرين",
        "tog-diffonly": "لا تعرض محتوى الصفحة أسفل الفرق",
        "tog-showhiddencats": "أظهر التصنيفات المخفية",
-       "tog-norollbackdiff": "لا تظهر الفروق بعد إجراء التراجع",
+       "tog-norollbackdiff": "لا تظهر الفروق بعد إجراء استرجاع",
        "tog-useeditwarning": "حذّرني عندما أغادر تحرير صفحة فيها تغييرات لم أحفظها",
-       "tog-prefershttps": "دائÙ\85ا Ø§Ø³ØªØ®Ø¯Ù\85 اتصالا آمنا عند تسجيل الدخول",
+       "tog-prefershttps": "استخدÙ\85 Ø¯Ø§Ø¦Ù\85ا اتصالا آمنا عند تسجيل الدخول",
        "underline-always": "دائما",
        "underline-never": "أبدا",
        "underline-default": "وفق المظهر أو المتصفح",
        "oct": "تشرين الأول",
        "nov": "تشرين الثاني",
        "dec": "كانون الأول",
-       "january-date": "يناير/كانون الثاني $1",
-       "february-date": "فبراير/شباط $1",
-       "march-date": "مارس/آذار $1",
-       "april-date": "أبريل/نيسان $1",
-       "may-date": "مايو/أيار $1",
-       "june-date": "يونيو/حزيران $1",
-       "july-date": "يوليو/تموز $1",
-       "august-date": "أغسطس/آب $1",
-       "september-date": "سبتمبر/أيلول $1",
-       "october-date": "أكتوبر/تشرين الأول $1",
-       "november-date": "نوفمبر/تشرين الثاني $1",
-       "december-date": "ديسمبر/كانون الأول $1",
+       "january-date": "$1 يناير",
+       "february-date": "$1 فبراير",
+       "march-date": "$1 مارس",
+       "april-date": "$1 أبريل",
+       "may-date": "$1 مايو",
+       "june-date": "$1 يونيو",
+       "july-date": "$1 يوليو",
+       "august-date": "$1 أغسطس",
+       "september-date": "$1 سبتمبر",
+       "october-date": "$1 أكتوبر",
+       "november-date": "$1 نوفمبر",
+       "december-date": "$1 ديسمبر",
        "period-am": "صباحًا",
        "period-pm": "مساءً",
        "pagecategories": "{{PLURAL:$1|بلا تصنيف|تصنيف|تصنيفان|تصنيفات}}",
        "category_header": "صفحات تصنيف «$1»",
        "subcategories": "تصنيفات فرعية",
        "category-media-header": "ملفات تصنيف \"$1\"",
-       "category-empty": "هذا التصنيف لا يحتوي حالياً على أي صفحات أو ملفات.",
+       "category-empty": "<em>هذا التصنيف لا يحتوي حالياً على أي صفحات أو ملفات.</em>",
        "hidden-categories": "{{PLURAL:$1|لا تصنيفات مخفية|تصنيف مخفي|تصنيفان مخفيان|تصنيفات مخفية}}",
        "hidden-category-category": "تصنيفات مخفية",
        "category-subcat-count": "{{PLURAL:$2|هذا التصنيف يحوي التصنيف الفرعي التالي|هذا التصنيف يحوي {{PLURAL:$1||التصنيف الفرعي|تصنيفين فرعيين|$1 تصنيفات فرعية}}، من إجمالي $2.}}",
        "history": "تاريخ الصفحة",
        "history_short": "التاريخ",
        "history_small": "تاريخ",
-       "updatedmarker": "عدلت منذ زيارتي الأخيرة",
+       "updatedmarker": "عُدلت منذ زيارتي الأخيرة",
        "printableversion": "نسخة للطباعة",
        "permalink": "رابط دائم",
        "print": "اطبع",
        "redirectedfrom": "(بالتحويل من $1)",
        "redirectpagesub": "صفحة تحويل",
        "redirectto": "تحويل إلى",
-       "lastmodifiedat": "آخر تعديل لهذه الصفحة كان يوم $1 الساعة $2.",
+       "lastmodifiedat": "آخر تعديل لهذه الصفحة كان يوم $1، الساعة $2.",
        "viewcount": "{{PLURAL:$1|لم تعرض هذه الصفحة أبدا|تم عرض هذه الصفحة مرة واحدة|تم عرض هذه الصفحة مرتين|تم عرض هذه الصفحة $1 مرات|تم عرض هذه الصفحة $1 مرة}}.",
        "protectedpage": "صفحة محمية",
        "jumpto": "اذهب إلى:",
        "jumptonavigation": "تصفح",
        "jumptosearch": "ابحث",
-       "view-pool-error": "عذراØ\8c Ø§Ù\84Ø®Ù\88ادÙ\8aÙ\85 Ù\85Ù\86Ù\87Ù\83Ø© Ø­Ø§Ù\84Ù\8aا.\nÙ\8aحاÙ\88Ù\84 Ù\85ستخدÙ\85Ù\88Ù\86 Ù\83ثر Ø§Ù\84Ù\88صÙ\88Ù\84 Ø¥Ù\84Ù\89 Ù\87Ø°Ù\87 Ø§Ù\84صÙ\81حة.\nÙ\85Ù\86 Ù\81ضÙ\84Ù\83 ØªÙ\85Ù\87Ù\91Ù\84 Ù\82Ù\84Ù\8aÙ\84ا Ù\82بÙ\84 Ù\85حاÙ\88Ù\84Ø© Ø§Ù\84Ù\88صÙ\88Ù\84 Ø¥Ù\84Ù\89 Ù\87Ø°Ù\87 Ø§Ù\84صÙ\81حة Ù\85جددا.\n\n$1",
-       "generic-pool-error": "عذرا، الخوادم مشغولة حاليا لوجود مستخدمون كثر يطلبون عرض هذا المورد. انتظر قليلا وأعد المحاولة.",
+       "view-pool-error": "عذرا، الخوادم منهكة حاليا.\nيحاول مستخدمون كثر الوصول إلى هذه الصفحة.\nمن فضلك تمهّل قليلا قبل محاولة الوصول إلى هذه الصفحة مجددا.\n\n$1",
+       "generic-pool-error": "عذرا، الخوادم منهكة حاليا.\nيحاول مستخدمون كثر الوصول إلى هذا المورد.\nمن فضلك تمهّل قليلا قبل محاولة الوصول إلى هذا المورد مجددا.",
        "pool-timeout": "انتهت مهلة القفل",
        "pool-queuefull": "الطابور ملآن",
        "pool-errorunknown": "خطأ غير معروف",
        "portal-url": "Project:بوابة المجتمع",
        "privacy": "سياسة الخصوصية",
        "privacypage": "Project:سياسة الخصوصية",
-       "badaccess": "عطÙ\84 في الصلاحيات",
+       "badaccess": "خطأ في الصلاحيات",
        "badaccess-group0": "غير مصرّح لك بتنفيذ الفعل الذي اعتزمته.",
        "badaccess-groups": "الفعل الذي اعتزمته مقصور على المستخدمين أعضاء {{PLURAL:$2||المجموعة|إحدى المجموعتين|إحدى المجموعات}}: $1.",
        "versionrequired": "تلزم الإصدارة $1 من ميدياويكي",
        "versionrequiredtext": "تلزم الإصدارة $1 من ميدياويكي لاستعمال هذه الصفحة. طالع [[Special:Version|صفحة معلومات الإصدارة]]",
        "ok": "موافق",
        "retrievedfrom": "مجلوبة من \"$1\"",
-       "youhavenewmessages": "{{PLURAL:$3|لك}} $1 ($2).",
+       "youhavenewmessages": "{{PLURAL:$3|لديك}} $1 ($2).",
        "youhavenewmessagesfromusers": "{{PLURAL:$4|لديك}} $1 من {{PLURAL:$3|مستخدم واحد|مستخدم واحد|مستخدمين اثنين|$3 مستخدمين|$3 مستخدما|$3 مستخدم}} ($2).",
        "youhavenewmessagesmanyusers": "لديك $1 من مستخدمين كثر ($2).",
        "newmessageslinkplural": "{{PLURAL:$1|رسالة جديدة|999=رسائل جديدة}}",
        "feed-unavailable": "التلقيمات غير متوفرة",
        "site-rss-feed": "تلقيمة آر إس إس $1",
        "site-atom-feed": "تلقيمة أتوم $1",
-       "page-rss-feed": "تلقيمة آر إس إس \"$1\"",
-       "page-atom-feed": "تلقيمة أتوم \"$1\"",
+       "page-rss-feed": "تلقيمة آر إس إس لصفحة \"$1\"",
+       "page-atom-feed": "تلقيمة أتوم لصفحة \"$1\"",
        "feed-atom": "أتوم",
        "feed-rss": "أر إس إس",
        "red-link-title": "$1 (الصفحة غير موجودة)",
        "nosuchactiontext": "الفعل المحدد بواسطة المسار غير صحيح.\nربما تكون قد كتبت المسار بطريقة غير صحيحة، أو اتبعت رابطا غير صحيح.\nو قد يكون مرجع هذا علة في {{SITENAME}}.",
        "nosuchspecialpage": "لا توجد صفحة خاصة بهذا الاسم",
        "nospecialpagetext": "<strong>لقد طلبت صفحة خاصة غير صحيحة.</strong>\n\nقائمة الصفحات الخاصة موجودة في [[Special:SpecialPages|{{int:specialpages}}]].",
-       "error": "عطÙ\84",
-       "databaseerror": "عطÙ\84 في قاعدة البيانات",
+       "error": "خطأ",
+       "databaseerror": "خطأ في قاعدة البيانات",
        "databaseerror-text": "حدث خطأ في إستعلام قاعدة البيانات. قد يشير هذا إلى خطأ في البرنامج.",
        "databaseerror-textcl": "حدث خطأ في إستعلام قاعدة البيانات.",
        "databaseerror-query": "استعلام: $1",
        "tooltip-pt-login": "يفضل أن تسجل الدخول، لكنه ليس إلزاميا.",
        "tooltip-pt-login-private": "عليك تسجيل الدخول لاستخدام هذه الويكي.",
        "tooltip-pt-logout": "تسجيل الخروج",
-       "tooltip-pt-createaccount": "نشجعك على عمل حساب وتسجيل دخولك; لكنه غير ضروري على اي حال",
+       "tooltip-pt-createaccount": "نشجعك على عمل حساب وتسجيل دخولك؛ لكنه غير ضروري على اي حال",
        "tooltip-ca-talk": "نقاش عن صفحة المحتوى",
        "tooltip-ca-edit": "تعديل هذه الصفحة",
        "tooltip-ca-addsection": "ابدأ قسما جديدا",
        "tooltip-search": "ابحث في {{SITENAME}}",
        "tooltip-search-go": "اذهب إلى صفحة بالاسم نفسه إن وجدت",
        "tooltip-search-fulltext": "ابحث في الصفحات عن هذا النص",
-       "tooltip-p-logo": "الصفحة الرئيسية",
+       "tooltip-p-logo": "زÙ\8fر Ø§Ù\84صÙ\81حة Ø§Ù\84رئÙ\8aسÙ\8aØ©",
        "tooltip-n-mainpage": "زر الصفحة الرئيسية",
        "tooltip-n-mainpage-description": "زر الصفحة الرئيسية",
        "tooltip-n-portal": "حول المشروع، ماذا يمكن أن تفعل، أين يمكن أن تجد ما تحتاجه",
        "tooltip-n-currentevents": "مطالعة سريعة لأهم الأحداث الجارية",
        "tooltip-n-recentchanges": "قائمة أحدث التغييرات في الويكي.",
        "tooltip-n-randompage": "حمل صفحة عشوائية",
-       "tooltip-n-help": "اÙ\84Ù\85Ù\83اÙ\86 Ù\84لمساعدة",
+       "tooltip-n-help": "Ø­Ù\8aØ« ØªØ¬Ø¯ Ø§لمساعدة",
        "tooltip-t-whatlinkshere": "قائمة بكل صفحات الويكي التي تصل هنا",
        "tooltip-t-recentchangeslinked": "أحدث التغييرات في الصفحات الموصولة من هذه الصفحة",
        "tooltip-feed-rss": "تلقيم أر إس إس لهذه الصفحة",
index 6f23131..da62cd8 100644 (file)
        "tog-newpageshidepatrolled": " Katcicta paskickwemakana ka ki koski aci tapwatcikateki  taci e ici masinateki ocki paskickwemikana",
        "tog-hidecategorization": "Katcicta tipanictawin paskickwemikana",
        "tog-extendwatchlist": "Ekoci kaskina kata nokok nohwe nosinesinihan ka kweskisinihikateki ka masinateki aka tepirak nohwe kata nokok aka weckat ka ki otci otamirotakaniwiki.",
+       "tog-usenewrc": "Tatwa paskickwemakan mamowicta ka ki meckotcitakaniwoki  aka weckat kaki otci kweskisinihikateki acit nta nosinesinihikanik.",
        "tog-numberheadings": " Nicike kata masinihikepirik akitasowina  e icinikateki tipanisinihikanica",
        "tog-showtoolbar": "Motena ka maskotikw kata nokoki irapitcitcikana masinihikakan e nisawitakaniwok",
+       "tog-editondblclick": " Nicowaw mamakona kata kweskisinahaman paskickwemakana",
        "underline-always": "Mocak",
        "underline-never": "Nama wiskat",
        "sunday": "Manactakaniwon",
index 9b82d2a..7898bf3 100644 (file)
        "authprovider-confirmlink-request-label": "Рахункі, якія павінны быць злучаныя",
        "authprovider-confirmlink-success-line": "$1: пасьпяхова далучаны.",
        "authprovider-confirmlink-failed": "Далучэньне рахунку не атрымалася цалкам: $1",
+       "authprovider-confirmlink-ok-help": "Працягнуць пасьля паказу паведамленьняў пра памылкі далучэньня.",
        "changecredentials": "Зьмена ўліковых зьвестак",
        "removecredentials": "Выдаленьне ўліковых зьвестак",
        "removecredentials-submit": "Выдаліць уліковыя зьвесткі",
index 77d31be..1004ee3 100644 (file)
        "nstab-template": "Шаблон",
        "nstab-help": "Помощ",
        "nstab-category": "Категория",
-       "mainpage-nstab": "Ð\93лавна страница",
+       "mainpage-nstab": "Ð\9dаÑ\87ална страница",
        "nosuchaction": "Няма такова действие",
        "nosuchactiontext": "Действието, указано в интернет адреса, е невалидно.\nМоже би сте допуснали грешка в изписването на адреса или сте последвали некоректна хипервръзка.\nПроблемът може да се дължи и на грешка в софтуера на {{SITENAME}}.",
        "nosuchspecialpage": "Няма такава специална страница",
        "showdiff": "Показване на промените",
        "blankarticle": "<strong>Предупреждение:</strong> Статията, която създавате е празна.\nАко щракнете на „$1“ отново, статията ще бъде създадена без никакво съдържание.",
        "anoneditwarning": "<strong>Внимание:</strong> Не сте влезли в системата. Ако направите редакция IP-адресът Ви ще бъде публично видим. Ако <strong>[$1 влезете]</strong> или си <strong>[$2 създадете акаунт]</strong>, редакциите Ви ще бъдат свързани с потребителското Ви име, заедно с други преимущества.",
-       "anonpreviewwarning": "Внимание: Не сте влезли в системата. Ако съхраните редакцията си, тя ще бъде записана в историята на страницата с вашият IP-адрес.",
-       "missingsummary": "'''Напомняне:''' Не е въведено кратко описание на промените. При повторно натискане на бутона „Съхраняване“, редакцията ще бъде съхранена без резюме.",
+       "anonpreviewwarning": "<em>Не сте влезли в системата. Ако съхраните редакцията си, тя ще бъде записана в историята на страницата с вашия IP-адрес.</em>",
+       "missingsummary": "<strong>Напомняне:</strong> Не е въведено кратко описание на промените.\nПри повторно натискане на бутона „$1“, редакцията ще бъде съхранена без резюме.",
        "missingcommenttext": "По-долу въведете вашето съобщение.",
        "missingcommentheader": "<strong>Напомняне:</strong> Не е въведено заглавие на коментара.\nПри повторно натискане на „$1“, редакцията ще бъде записана без коментар.",
        "summary-preview": "Предварителен преглед на резюмето:",
        "grant-editprotected": "Редактиране на защитени страници",
        "grant-highvolume": "Голям обем за редактиране",
        "grant-oversight": "Скриване на потребители и прикриване на редакции",
-       "grant-patrol": "Патрулират промени страници",
+       "grant-patrol": "Патрулиране промени на страници",
        "grant-privateinfo": "Достъп до лична информация",
        "grant-protect": "Защита и премахване на защита на страници",
        "grant-rollback": "Връщане на промени по страници",
        "grant-sendemail": "Изпращане на имейл до други потребители",
-       "grant-uploadeditmovefile": "Качване, заменяне и прехвърляне на файлове",
+       "grant-uploadeditmovefile": "Качване, замяна и преместване на файлове",
        "grant-uploadfile": "Качване на нови файлове",
        "grant-basic": "Основни права",
-       "grant-viewdeleted": "Преглед на изтрити файлове и страници",
+       "grant-viewdeleted": "Преглед на изтритите файлове и страници",
        "grant-viewmywatchlist": "Преглед на списъка ви за наблюдение",
        "newuserlogpage": "Дневник на регистрациите",
        "newuserlogpagetext": "В този дневник се записват регистрациите на потребители.",
        "rcfilters-filter-user-experience-level-learner-description": "Повече опит от „Новодошли“, но по-малко от „Опитни потребители“.",
        "rcfilters-filter-user-experience-level-experienced-label": "Опитни потребители",
        "rcfilters-filter-user-experience-level-experienced-description": "Повече от 30 дни активност и 500 редакции.",
-       "rcfilters-filtergroup-automated": "Автоматизирани приноси",
+       "rcfilters-filtergroup-automated": "Автоматизирани редакции",
        "rcfilters-filter-bots-label": "Бот",
        "rcfilters-filter-bots-description": "Редакции, направени с помощта на автоматизирани инструменти.",
        "rcfilters-filter-humans-label": "Човек (не бот)",
        "upload-dialog-button-upload": "Качване",
        "upload-form-label-infoform-title": "Подробности",
        "upload-form-label-infoform-name": "Име",
-       "upload-form-label-infoform-name-tooltip": "Уникално описателно заглавие на файла, което ще бъде записано като име на файла. Можете да използвате обикновен текст с разстояние. Не включвайте файловото разширение.",
+       "upload-form-label-infoform-name-tooltip": "Уникално описателно заглавие на файла, което ще бъде записано като име на файла. Можете да използвате обикновен текст с интервали. Не добавяйте разширението на файла.",
        "upload-form-label-infoform-description": "Описание",
        "upload-form-label-infoform-description-tooltip": "Накратко опишете всичко, което си струва да се каже за тази творба.\nНапример, ако е снимка, опишете основните неща, които са снимани, повода, местоположението и т.н.",
        "upload-form-label-usage-title": "Използване",
index bcb5dc9..f029b3d 100644 (file)
        "recentchanges-legend-plusminus": "(''±123'')",
        "recentchanges-submit": "Zobrazit",
        "rcfilters-activefilters": "Aktivní filtry",
-       "rcfilters-quickfilters": "Od data:",
+       "rcfilters-quickfilters": "Uložená nastavení filtrů",
        "rcfilters-quickfilters-placeholder-title": "Zatím neuloženy žádné odkazy",
        "rcfilters-quickfilters-placeholder-description": "Pokud chcete uložit svá nastavení filtrů a použít je později, klikněte na ikonku záložky v ploše aktivních filtrů níže.",
        "rcfilters-savedqueries-defaultlabel": "Uložené filtry",
        "rcfilters-savedqueries-unsetdefault": "Nemít jako výchozí",
        "rcfilters-savedqueries-remove": "Odstranit",
        "rcfilters-savedqueries-new-name-label": "Název",
-       "rcfilters-savedqueries-apply-label": "Vytvořit rychlý odkaz",
+       "rcfilters-savedqueries-apply-label": "Uložit nastavení",
        "rcfilters-savedqueries-cancel-label": "Zrušit",
-       "rcfilters-savedqueries-add-new-title": "Uložit filtry jako rychlý odkaz",
+       "rcfilters-savedqueries-add-new-title": "Uložit současné nastavení filtrů",
        "rcfilters-restore-default-filters": "Obnovit výchozí filtry",
        "rcfilters-clear-all-filters": "Zrušit všechny filtry",
        "rcfilters-search-placeholder": "Filtrovat nedávné změny (prohlížejte nebo začněte psát)",
        "rcfilters-filter-watchlist-notwatched-description": "Vše kromě změn vašich sledovaných stránek.",
        "rcfilters-filtergroup-changetype": "Typ změny",
        "rcfilters-filter-pageedits-label": "Editace stránek",
-       "rcfilters-filter-pageedits-description": "Editace obsahu wiki, diskusí, popisů kategorií...",
+       "rcfilters-filter-pageedits-description": "Editace obsahu wiki, diskusí, popisů kategorií",
        "rcfilters-filter-newpages-label": "Založení stránek",
        "rcfilters-filter-newpages-description": "Editace, které vytvářejí nové stránky.",
        "rcfilters-filter-categorization-label": "Změny kategorií",
        "rcfilters-filter-categorization-description": "Záznamy stránek zařazených do nebo vyřazených z kategorií.",
        "rcfilters-filter-logactions-label": "Zaznamenané činnosti",
-       "rcfilters-filter-logactions-description": "Administrativní úkony, založení účtů, mazání stránek, načtení souborů...",
+       "rcfilters-filter-logactions-description": "Administrativní úkony, založení účtů, mazání stránek, načtení souborů",
        "rcfilters-hideminor-conflicts-typeofchange-global": "Filtr „Malé editace“ je v konfliktu s jedním nebo více filtry podle typu změny, protože určité typy změn nelze označit jako malé. Dotyčné filtry jsou označeny nahoře, v prostoru „Aktivní filtry“.",
        "rcfilters-hideminor-conflicts-typeofchange": "Určité typy změn nelze označit jako malé, tento filtr je proto v konfliktu s následujícími filtry podle typu změny: $1",
        "rcfilters-typeofchange-conflicts-hideminor": "Tento filtr podle typu změny je v konfliktu s filtrem „Malé editace“. Určité typy změn nelze označit jako malé.",
index 8fc3630..8687fb6 100644 (file)
        "editinguser": "Promjena suradničkih prava {{GENDER:$1|suradnika|suradnice}} <strong>[[User:$1|$1]]</strong> $2",
        "viewinguserrights": "Pregled suradničkih prava {{GENDER:$1|suradnika|suradnice}} <strong>[[User:$1|$1]]</strong> $2",
        "userrights-editusergroup": "Uređivanje {{GENDER:$1|suradnikove|suradničine}} pripadnosti skupinama",
-       "userrights-viewusergroup": "Vidi {{GENDER:$1|suradničke}} skupine",
+       "userrights-viewusergroup": "Vidi {{GENDER:$1|suradnikove|suradničine|suradničke}} skupine",
        "saveusergroups": "Spremi {{GENDER:$1|suradnikove|suradničine|suradničke}} skupine",
        "userrights-groupsmember": "{{GENDER:$2|Pripadnik|Pripadnica}} {{PLURAL:$1|skupine|skupinama|skupina}}:",
        "userrights-groupsmember-auto": "{{GENDER:$2|Pripadnik|Pripadnica}} {{PLURAL:$1|obuhvaćene skupine|obuhvaćenih skupina}}:",
index c5a399a..da37325 100644 (file)
@@ -77,7 +77,7 @@
        "thursday": "Kemis",
        "friday": "Jumuwah",
        "saturday": "Setu",
-       "sun": "Min",
+       "sun": "Nga",
        "mon": "Sen",
        "tue": "Sel",
        "wed": "Reb",
        "aug": "Agu",
        "sep": "Sèp",
        "oct": "Okt",
-       "nov": "Nop",
+       "nov": "Nov",
        "dec": "Dhé",
        "january-date": "Januari $1",
        "february-date": "Fèbruari $1",
        "october-date": "Oktober $1",
        "november-date": "$1 Novèmber",
        "december-date": "$1 Dhésèmber",
-       "period-am": "Isuk-Awan",
-       "period-pm": "Soré-Wengi",
+       "period-am": "Rina",
+       "period-pm": "Ratri",
        "pagecategories": "{{PLURAL:$1|Kategori}}",
        "category_header": "Kaca sajeroning kategori \"$1\"",
        "subcategories": "Anak kategori",
        "virus-badscanner": "Kasalahan konfigurasi: pamindai virus ora dikenal: ''$1''",
        "virus-scanfailed": "''Pemindaian'' utawa ''scan'' gagal (kode $1)",
        "virus-unknownscanner": "antivirus buhbuhan:",
-       "logouttext": "<strong>Panjenengan saiki wis metu log.</strong>\n\nTulung gatèkaké yèn sawenèh kaca bokmanawa bakal isih katon kaya déné yèn panjenengan isih mlebu log, mula busaken cache pangluruné panjenengan.",
+       "logouttext": "<strong>Panjenengan wis metu log.</strong>\n\nTulung gatèkaké yèn sawenèh kaca bokmanawa bakal isih katon kaya déné yèn panjenengan isih mlebu log, kajaba panjenengan mbusak ''cache'' pangluruné panjenengan.",
        "cannotlogoutnow-title": "Ora bisa metu saiki",
        "cannotlogoutnow-text": "Metu ora mungkin menawa nganggo $1.",
        "welcomeuser": "Sugeng Rawuh, $1!",
        "noarticletext-nopermission": "Saiki lagi ora ana tèks ing kaca iki. \nPanjenengan bisa [[Special:Search/{{PAGENAME}}|nggolèk sesirah kaca iki]] ing kaca liyané, \nutawa <span class=\"plainlinks\">[{{fullurl:{{#Special:Log}}|page={{urlencode:{{FULLPAGENAME}}}}}} nggolèk ing log sing gegayutan]</span>, nanging panjenengan ora kawogan nggawé kaca iki.",
        "missing-revision": "Révisi #$1 saka kaca ajeneng \"{{FULLPAGENAME}}\" ora ana.\n\nIki biyasané kasababaké awit nututi pranala sujarah sing wis lawas saka sawijiné kaca sing wis dibusak.\nRerincèné bisa digolèki ing [{{fullurl:{{#Special:Log}}/delete|page={{FULLPAGENAMEE}}}} log busak].",
        "userpage-userdoesnotexist": "Akun panganggo \"$1\" ora kadhaftar.\nMangga pesthèkaké dhisik yèn panjenengan péngin nggawé/mbesut kaca iki.",
-       "userpage-userdoesnotexist-view": "Panganggo \"$1\" ora kadhaptar.",
+       "userpage-userdoesnotexist-view": "Akun panganggo \"$1\" ora kadhaftar.",
        "blocked-notice-logextract": "Panganggo iki saiki lagi diblokir.\nLog pamblokiran pungkasan dituduhaké ing ngisor iki minangka bahan rujukan:",
        "clearyourcache": "<strong>Cathetan:</strong> Nalika rampung nyimpen, panjenengan kudu mbusak cache-né pangluruné panjenengan supaya owahané ketara.\n* <strong>Firefox / Safari:</strong> Pencèt <em>Shift</em> nalika ngeklik <em>Reload</em>, utawa pencèt <em>Ctrl-F5</em> utawa <em>Ctrl-R</em> (<em>⌘-R</em> ing Mac)\n* <strong>Google Chrome:</strong> Pencèt <em>Ctrl-Shift-R</em> (<em>⌘-Shift-R</em> ing Mac)\n* <strong>Internet Explorer:</strong> Pencèt <em>Ctrl</em> nalika ngeklik <em>Refresh</em>, utawa pencèt <em>Ctrl-F5</em>\n* <strong>Opera:</strong> Nyang <em>Menu → Settings</em> (<em>Opera → Preferences</em> ing Mac) nuli nyang <em>Privacy & security → Clear browsing data → Cached images and files</em>.",
        "usercssyoucanpreview": "'''Tips:''' Gunakna tombol \"{{int:showpreview}}\" kanggo ngetès CSS anyar panjenengan sadurungé disimpen.",
        "previewnote": "<strong>Élinga yèn iki mung pratuduh.</strong>\nOwahanmu durung kasimpen!",
        "continue-editing": "Menyang pambesutan",
        "previewconflict": "Pratuduh iki nuduhaké tèksé ing pérangan ndhuwur kothak besutan tèks lan nuduhaké wujudé kaya déné yèn wis disimpen.",
-       "session_fail_preview": "Ngapunten! Kita ora bisa mrosès besutan panjenengan amarga ilangé sèsi data.\n\nPanjenengan bokmanawa wis metu log. <strong>Mangga vèrifikasi manawa panjenengan isih mlebu log lan jajala manèh</strong>.\nManawa isih durung kena, jajala [[Special:UserLogout|metu log]] lan mlebu log manèh, banjur priksaa apa browser panjenengan ngidinaké kuki saka situs iki.",
+       "session_fail_preview": "Ngapunten! Kita ora bisa ngayahi besutané panjenengan amarga ilangé sèsi dhata.\n\nPanjenengan bokmanawa wis metu log. <strong>Mangga vèrifikasi manawa panjenengan isih mlebu log lan jajalen manèh</strong>.\nManawa isih durung kena, jajalen [[Special:UserLogout|metu log]] lan mlebu log manèh, banjur priksanen apa pangluruné panjenengan ngidinaké kuki saka situs iki.",
        "session_fail_preview_html": "'''Nuwun sèwu! Kita ora bisa prosès suntingan panjenengan amerga data sési ilang.'''\n\n''Amerga wiki iki ngidinaké panrapan HTML mentah, pratayang didelikaké minangka penggakan marang serangan Javascript.''\n\n'''Yèn iki sawijining upaya suntingan sing absah, mangga dicoba manèh. Yèn isih tetep ora kasil, cobanen metu log utawa oncat lan mlebua manèh.'''",
        "token_suffix_mismatch": "<strong>Besutané panjenengan ditulak amarga aplikasi klièné panjenengan ngowahi karakter tandha waca ing token besutané.</strong>\nBesutané wis ditulak kanggo nyegah rusaké tèks kaca.\nSing kaya mangkono biyasané kadadéan nalika panjenengan nganggo paladenan proksi anonim sing lelandhesan jaringan.",
        "edit_form_incomplete": "<strong>Sawenèh pérangan formulir besut ora nyandhak paladèné; priksanen manèh yèn besutané panjenengan isih wutuh banjur jajalen manèh.</strong>",
        "longpageerror": "'''Kasalahan: Tèks sing Sampéyan lebokaké dawané {{PLURAL:$1|sak kilobita|$1 kilobita}}, luwih dawa saka maksimal {{PLURAL:$2|sak kilobita|$2 kilobita}}.'''\nKuwi ora bisa disimpen.",
        "readonlywarning": "'''PÈNGET: Basis data lagi dikunci amerga ana pangopènan, dadi saiki panjenengan ora bisa nyimpen kasil panyuntingan panjenengan. Panjenengan mbokmenawa prelu mindhahaké kasil panyuntingan panjenengan iki menyang panggonan liya kanggo disimpen bésuk.'''\n\nPangurus sing ngunci basis data mènèhi katrangan kaya mengkéné: $1",
        "protectedpagewarning": "<strong>Pélik: Kaca iki wis direksa, mula mung panganggo mawa hak mirunggan pangurus sing bisa mbesut.</strong>\nÈntri log sing pungkasan ana ing ngisor iki minangka rujukan:",
-       "semiprotectedpagewarning": "'''Cathetan:''' Kaca iki lagi pinuju direksa, dadi namung panganggo kadaftar sing bisa nyunting.\nEntri cathetan pungkasan disadiakake ing ngisor kanggo referensi:",
+       "semiprotectedpagewarning": "<strong>Cathetan:</strong> Kaca iki pinuju direksa, mula mung panganggo sing kadhaftar sing bisa mbesut.\nÈntri log pungkasan cumepak ana ing ngisor kanggo rujukan:",
        "cascadeprotectedwarning": "<strong>Pènget:</strong> Kaca iki wis direksa saéngga mung panganggo kanthi hak pangurus waé sing bisa mbesut amarga kaca iki katranklusi ing {{PLURAL:$1|kaca|kaca-kaca}} sing kareksa runut ngisor iki:",
        "titleprotectedwarning": "'''Pènget: Kaca iki wis dikunci saéngga perlu [[Special:ListGroupRights|hak mligi]] kanggo gawéné.'''\nEntri cathetan pungkasan disadiakake ing ngisor kanggo referensi:",
        "templatesused": "{{PLURAL:$1|Cithakan|Cithakan}} sing dienggo ing kaca iki:",
        "permissionserrorstext": "Panjengan ora kagungan idin kanggo nglakoni sing panjenengan gayuh amerga {{PLURAL:$1|alesan|alesan-alesan}} iki:",
        "permissionserrorstext-withaction": "Panjenengan ora duwé hak aksès kanggo $2, amarga {{PLURAL:$1|alasan|alasan}} ing ngisor iki:",
        "recreate-moveddeleted-warn": "'''Pènget: Panjenengan gawé manèh sawijining kaca sing wis tau dibusak.'''\n\nMangga digagas manèh apa pantes nerusaké nyunting kaca iki.\nIng ngisor iki kapacak log pambusakan lan pamindhahan saka kaca iki:",
-       "moveddeleted-notice": "Kaca iki wis dibusak.\nCathetan busakan lan lih-lihan kaca ana ing ngisor minangka rujukan.",
+       "moveddeleted-notice": "Kaca iki wis dibusak.\nLog busak lan alih ngenani kacané cumepak ing ngisor kanggo rujukan.",
        "log-fulllog": "Deleng cathetan wutuh",
        "edit-hook-aborted": "Besutan diwurungaké déning cangkolan.\nOra ana katerangané.",
        "edit-gone-missing": "Ora bisa nganyari kaca.\nKatoné kaca iki wis dibusak.",
        "revdelete-reason-dropdown": "*Alasan penghapusan yang umum\n** Pelanggaran hak cipta\n** Komentar atau informasi pribadi yang tidak pantas\n** Nama pengguna yang tidak pantas\n** Berpotensi mencemarkan nama baik",
        "revdelete-otherreason": "Alesan liya/tambahan:",
        "revdelete-reasonotherlist": "Alesan liya",
-       "revdelete-edit-reasonlist": "Besut jalaraning pambusak",
+       "revdelete-edit-reasonlist": "Besut alesané pambusak",
        "revdelete-offender": "Juru pangriptaning owahan:",
        "suppressionlog": "Log barang-barang sing didelikaké (''oversight'')",
        "suppressionlogtext": "Ngisor iki daptar apa-apa waé sing wis dibusak lan diblokir kalebu kontèn sing didhelikaké saka para pangurus.\nDelok [[Special:BlockList|daptar blokiran]] sing isiné daptar apa-apa waé sing lagi dilarang lan diblokir.",
        "statistics-files": "Berkas sing diunggahaké",
        "statistics-edits": "Gunggung suntingan wiwit {{SITENAME}} diwiwiti",
        "statistics-edits-average": "Rata-rata suntingan saben kaca",
-       "statistics-users": "Gunggung [[Special:ListUsers|panganggo kadaftar]]",
+       "statistics-users": "[[Special:ListUsers|Panganggo]] kadhaftar",
        "statistics-users-active": "Para panganggo aktif",
        "statistics-users-active-desc": "Panganggo sing ngayahi aktivitas jroning {{PLURAL:$1|dia|$1 dina}} pungkasan",
        "pageswithprop": "Kaca-kaca mawa ubarampé",
        "deletepage": "Busak kaca",
        "confirm": "Dhedhes (konfirmasi)",
        "excontent": "isi sadurungé: '$1'",
-       "excontentauthor": "isiné mung arupa: '$1' (lan siji-sijiné sing nyumbang yaiku '$2')",
+       "excontentauthor": "isiné: \"$1\", lan sing nyumbang mung \"[[Special:Contributions/$2|$2]]\" ([[User talk:$2|parembugan]])",
        "exbeforeblank": "isi sadurungé dikosongaké: '$1'",
        "delete-confirm": "Busak \"$1\"",
        "delete-legend": "Busak",
        "historywarning": "'''Pènget''': Kaca sing bakal panjenengan busak ana sajarahé kanthi $1 {{PLURAL:$1|révisi|révisi}}:",
        "historyaction-submit": "Tuduhaké",
-       "confirmdeletetext": "Panjenengan bakal mbusak kaca utawa berkas iki minangka permanèn karo kabèh sajarahé saka basis data. Pastèkna dhisik menawa panjenengan pancèn nggayuh iki, ngerti kabèh akibat lan konsekwènsiné, lan apa sing bakal panjenengan tumindak iku cocog karo [[{{MediaWiki:Policy-url}}|kawicaksanan {{SITENAME}}]].",
+       "confirmdeletetext": "Panjenengan nedya mbusak kaca dalah kabèh sujarahé.\nMangga konfirmasi yèn panjenengan pancèn nedya ngayahi iki, ngerti kabèh temahané, lan tumindaké panjenengan miturut [[{{MediaWiki:Policy-url}}|pranatan]].",
        "actioncomplete": "Kasil diayahi",
        "actionfailed": "Tindakan gagal",
        "deletedtext": "\"$1\" wis dibusak. \nDelenga $2 minangka cathetan ngenani sing pungkasan kabusak.",
        "deleteotherreason": "Alesan liya utawa tambahan:",
        "deletereasonotherlist": "Alesan liya",
        "deletereason-dropdown": "*Alesan pambusakan\n** Spam\n** Vandalisme\n** Nglanggar hak cipta\n** Disuwun sing nulis\n** Pangalihan rusak",
-       "delete-edit-reasonlist": "Besut jalaraning pambusak",
+       "delete-edit-reasonlist": "Besut alesané pambusak",
        "delete-toobig": "Kaca iki darbé sujarah besutan sing dawa, punjul $1 {{PLURAL:$1|owahan}}.\nPambusak tumrap kaca sing kaya mangkono wis ora diidinaké nedya njagani murih ora ana karusakan ing {{SITENAME}}.",
        "delete-warning-toobig": "Kaca iki duwé sujarah besut sing dawa, punjul $1 {{PLURAL:$1|révisi}}.\nMbusak kaca iki bisa ngrusak lakuné basis dhata ing {{SITENAME}};\nkudu diayahi kanthi ngati-ati.",
        "deleteprotected": "Panjenengan ora bisa mbusak kaca iki amarga direksa.",
        "protect-cascadeon": "Kaca iki lagi direksa amerga disertakaké ing {{PLURAL:$1|kaca|kaca-kaca}} sing wis direksa mawa pilihan pangreksan runtun diaktifaké. Panjenengan bisa ngganti tingkat pangreksan kanggo kaca iki, nanging perkara iku ora awèh pengaruh pangreksan runtun.",
        "protect-default": "Idinaké kabèh panganggo",
        "protect-fallback": "Perlu idin hak aksès \"$1\"",
-       "protect-level-autoconfirmed": "Blokir panganggo anyar lan ora kadhaptar",
+       "protect-level-autoconfirmed": "Mung idinaké panganggo sing otomatis kadhaftar",
        "protect-level-sysop": "Namung opsis (operator sistem)",
        "protect-summary-cascade": "runtun",
        "protect-expiring": "kadaluwarsa $1 (UTC)",
        "uctop": "(saiki)",
        "month": "Saka wulan (lan sadurungé):",
        "year": "Wiwit taun (lan sadurungé):",
-       "sp-contributions-newbies": "Namung panganggo-panganggo anyar",
+       "sp-contributions-newbies": "Tuduhaké mung sumbangané akun-akun anyar waé",
        "sp-contributions-newbies-sub": "Kanggo panganggo anyar",
        "sp-contributions-newbies-title": "Sumbanganing para panganggo anyar",
        "sp-contributions-blocklog": "Log blokir",
        "fix-double-redirects": "Dandani kabèh pangalihan gandha sing tumuju marang irah-irahan asli",
        "move-leave-redirect": "Ungkur kaca alihan",
        "protectedpagemovewarning": "'''Pènget:''' Kaca iki wis dikunci dadi mung panganggo sing nduwé hak aksès pangurus baé sing bisa mindhahaké.\nCathetan entri pungkasan disadiakaké ing ngisor kanggo referensi:",
-       "semiprotectedpagemovewarning": "'''Cathetan:''' Kaca iki wis direksa saéngga mung panganggo kadhaptar sing bisa mindhahaké.\nEntri cathetan pungkasan disadiakake ing ngisor kanggo referensi:",
+       "semiprotectedpagemovewarning": "<strong>Cathetan:</strong> Kaca iki wis direksa saéngga mung panganggo kadhaftar sing bisa ngalihaké.\nÈntri log pungkasan cumepak ing ngisor kanggo rujukan:",
        "move-over-sharedrepo": "[[:$1]] ana ing panyimpenan barengan. Ngalih barkas mawa sesirah iki bakal ngamblegi barkas barengan iku.",
        "file-exists-sharedrepo": "Jeneng berkas kapilih wis ana kanggo nèng panyimpenan bebarengan.\nMangga pilih jeneng liya.",
        "export": "Ekspor kaca",
index aefa164..4cf917e 100644 (file)
        "searcharticle": "Rodyti",
        "history": "Puslapio istorija",
        "history_short": "Istorija",
+       "history_small": "istorija",
        "updatedmarker": "atnaujinta nuo paskutinio mano apsilankymo",
        "printableversion": "Versija spausdinimui",
        "permalink": "Nuolatinė nuoroda",
        "selfredirect": "<strong>Dėmesio:</strong> Jūs nukreipiate puslapį atgal į jį patį. Galbūt parinkote netinkamą nukreipimo kreipinį arba taisote ne tą straipsnį. \nJei vėl paspausite \"$1\", šis nukreipimas vis vien bus sukurtas.",
        "missingcommenttext": "Prašome įvesti komentarą.",
        "missingcommentheader": "<strong>Priminimas:</strong> Jūs nenurodėte šio komentaro antraštės.\nJei vėl paspausite „$1“, jūsų keitimas bus įrašytas be jo.",
-       "summary-preview": "Komentaro peržiūra:",
+       "summary-preview": "Keitimo santraukos peržiūra:",
        "subject-preview": "Temos peržiūra:",
        "previewerrortext": "Įvyko klaida bandant peržiūrėti jūsų pakeitimus.",
        "blockedtitle": "Naudotojas yra užblokuotas",
        "search-file-match": "(atitinka rinkmenos turinį)",
        "search-suggest": "Galbūt norėjote $1",
        "search-rewritten": "Rodomi $1 rezultatai. Vietoje to ieškoti $2.",
-       "search-interwiki-caption": "Dukteriniai projektai",
+       "search-interwiki-caption": "Dukterinių projektų rezultatai",
        "search-interwiki-default": "Rezultatai iš $1:",
        "search-interwiki-more": "(daugiau)",
+       "search-interwiki-more-results": "daugiau rezultatų",
        "search-relatedarticle": "Susiję",
        "searchrelated": "susiję",
        "searchall": "visi",
        "youremail": "El. paštas:",
        "username": "{{GENDER:$1|Naudotojo vardas}}:",
        "prefs-memberingroups": "{{PLURAL:$1|Grupės|Grupių}} {{GENDER:$2|narys|narė}}:",
+       "group-membership-link-with-expiry": "$1 (iki $2)",
        "prefs-registration": "Registravimosi laikas:",
        "yourrealname": "Tikrasis vardas:",
        "yourlanguage": "Sąsajos kalba:",
        "prefs-help-prefershttps": "Šis nustatymas suveiks kitą kartą prisijungiant.",
        "prefswarning-warning": "Jūs atlikote savo nustatymų pakeitimus, kurie dar nebuvo išsaugoti.\nJei paliksite puslapį nepaspaudę \"$1\", jūsų nustatymai nebus atnaujinti.",
        "prefs-tabs-navigation-hint": "Patarimas: galite naudoti kairės ir dešinės rodyklių ženkliukus, kad skirtukų sąraše judėtumėte tarp skirtukų.",
-       "userrights": "Naudotojų teisių valdymas",
-       "userrights-lookup-user": "Tvarkyti naudotojo grupes",
+       "userrights": "Naudotojų teisės",
+       "userrights-lookup-user": "Pasirinkti vartotoją",
        "userrights-user-editname": "Įveskite naudotojo vardą:",
-       "editusergroup": "Redaguoti {{GENDER:$1|naudotojo}} grupes",
+       "editusergroup": "Įkelti vartotojo grupes",
        "editinguser": "Redaguojamos {{GENDER:$1|naudotojo}} <strong>[[User:$1|$1]]</strong> $2 teisės",
-       "userrights-editusergroup": "Redaguoti naudotojų grupes",
-       "userrights-viewusergroup": "Žiūrėti naudotojo grupes",
+       "viewinguserrights": "Peržiūrimos {{GENDER:$1|naudotojo|naudotojos}} <strong>[[User:$1|$1]]</strong> $2 teisės",
+       "userrights-editusergroup": "Redaguoti {{GENDER:$1|naudotojo|naudotojos}} grupes",
+       "userrights-viewusergroup": "Žiūrėti {{GENDER:$1|naudotojo|naudotojos}} grupes",
        "saveusergroups": "Saugoti {{GENDER:$1|naudotojo}} grupes",
        "userrights-groupsmember": "Narys:",
        "userrights-groupsmember-auto": "Narys automatiškai:",
        "userrights-expiry-current": "Baigiasi $1",
        "userrights-expiry-none": "Nesibaigia",
        "userrights-expiry": "Baigiasi:",
+       "userrights-expiry-existing": "Egzistuojantis galiojimo laikas: $3, $2",
        "userrights-expiry-othertime": "Kitas laikas:",
+       "userrights-expiry-options": "1 diena:1 day,1 savaitė:1 week,1 mėnuo:1 month,3 mėnesiai:3 months,6 mėnesiai:6 months,1 metai:1 year",
+       "userrights-invalid-expiry": "„$1“ grupės galiojimo laikas negalimas.",
+       "userrights-expiry-in-past": "„$1“ grupės galiojimo laikas yra praeityje.",
        "userrights-conflict": "Naudotojo teisių konfliktas! Prašome dar kartą taikyti savo keitimus.",
        "group": "Grupė:",
        "group-user": "Naudotojai",
        "recentchanges-legend-newpage": "{{int:recentchanges-label-newpage}} (taip pat žiūrėkite [[Special:NewPages|naujausių straipsnių sąrašą]])",
        "recentchanges-submit": "Rodyti",
        "rcfilters-activefilters": "Aktyvūs filtrai",
+       "rcfilters-quickfilters": "Išsaugoti filtro nustatymai",
+       "rcfilters-quickfilters-placeholder-title": "Nėra išsaugotų nuorodų",
+       "rcfilters-savedqueries-defaultlabel": "Išsaugoti filtrai",
+       "rcfilters-savedqueries-rename": "Pervadinti",
+       "rcfilters-savedqueries-setdefault": "Nustatyti kaip numatytą",
+       "rcfilters-savedqueries-unsetdefault": "Pašalinti kaip numatytą",
+       "rcfilters-savedqueries-remove": "Pašalinti",
+       "rcfilters-savedqueries-new-name-label": "Pavadinimas",
+       "rcfilters-savedqueries-apply-label": "Išsaugoti nustatymus",
+       "rcfilters-savedqueries-cancel-label": "Atšaukti",
+       "rcfilters-savedqueries-add-new-title": "Išsaugoti dabartinius filtro nustatymus",
+       "rcfilters-restore-default-filters": "Atstatyti numatytuosius filtrus",
        "rcfilters-clear-all-filters": "Valyti visus filtrus",
+       "rcfilters-search-placeholder": "Filtruoti naujausius pakeitimus (naršykite arba pradėkite rašyti)",
        "rcfilters-invalid-filter": "Negalimas filtras",
+       "rcfilters-empty-filter": "Nėra aktyvių filtrų. Rodomi visi indeliai.",
        "rcfilters-filterlist-title": "Filtrai",
        "rcfilters-filterlist-whatsthis": "Kas tai?",
+       "rcfilters-filterlist-feedbacklink": "Pateikite atsiliepimą apie naujus (beta) filtrus",
+       "rcfilters-highlightbutton-title": "Paryškinti rezultatus",
        "rcfilters-highlightmenu-title": "Pasirinkite spalvą",
+       "rcfilters-highlightmenu-help": "Pasirinkite spalvą šio elemento paryškinimui",
        "rcfilters-filterlist-noresults": "Nerastas toks filtras",
+       "rcfilters-noresults-conflict": "Nerasta jokių rezultatų, nes paieškos kriterijai konfliktuoja",
        "rcfilters-filtergroup-registration": "Vartotojo registracija",
        "rcfilters-filter-registered-label": "Registruoti",
+       "rcfilters-filter-registered-description": "Prisijungę redaktoriai.",
        "rcfilters-filter-unregistered-label": "Neregistruoti",
        "rcfilters-filter-unregistered-description": "Redaktoriai, kurie nėra prisijungę.",
        "rcfilters-filter-editsbyself-label": "Jūsų keitimai",
        "rcfilters-filter-editsbyself-description": "Jūsų keitimai.",
        "rcfilters-filter-editsbyother-label": "Kitų keitimai",
-       "rcfilters-filter-editsbyother-description": "Kaitimai sukurti kitų vartotojų (ne jūsų).",
+       "rcfilters-filter-editsbyother-description": "Visi keitimai, išskyrus jūsų.",
        "rcfilters-filtergroup-userExpLevel": "Patirties lygis (tik registruotiems vartotojams)",
        "rcfilters-filter-user-experience-level-newcomer-label": "Naujokai",
+       "rcfilters-filter-user-experience-level-newcomer-description": "Mažiau nei 10 keitimų ir 4 dienų aktyvumo.",
        "rcfilters-filter-user-experience-level-learner-label": "Mokiniai",
        "rcfilters-filter-user-experience-level-experienced-label": "Patyrę vartotojai",
        "rcfilters-filter-user-experience-level-experienced-description": "Daugiau nei 30 dienų veiklos ir 500 keitimų.",
+       "rcfilters-filtergroup-automated": "Automatiniai indeliai",
        "rcfilters-filter-bots-label": "Robotas",
        "rcfilters-filter-bots-description": "Keitimai, atlikti automatinių įrankių.",
        "rcfilters-filter-humans-label": "Žmogaus (ne roboto)",
        "rcfilters-filter-minor-description": "Keitimai, kuriuos autorius pažymėjo kaip mažus.",
        "rcfilters-filter-major-label": "Nesmulkūs pakeitimai",
        "rcfilters-filter-major-description": "Keitimai, nepažymėti kaip smulkūs.",
+       "rcfilters-filtergroup-watchlist": "Puslapiai, įtraukti į stebimų sąrašą",
+       "rcfilters-filter-watchlist-watched-label": "Stebimų sąraše",
+       "rcfilters-filter-watchlist-watched-description": "Pakeitimai puslapiuose, jūsų Stebimųjų sąraše.",
+       "rcfilters-filter-watchlist-watchednew-label": "Nauji Stebimųjų sąrašo pakeitimai",
+       "rcfilters-filter-watchlist-notwatched-label": "Nėra Stebimųjų sąraše",
        "rcfilters-filtergroup-changetype": "Pakeitimo tipas",
        "rcfilters-filter-pageedits-label": "Puslapių keitimai",
        "rcfilters-filter-newpages-label": "Puslapių sukūrimai",
        "rcfilters-filter-newpages-description": "Keitimai, kurie sukuria naujus puslapius.",
        "rcfilters-filter-categorization-label": "Kategorijų pakeitimai",
        "rcfilters-filter-categorization-description": "Įrašai puslapių, kurie yra pridedami ar pašalinami iš kategorijų.",
+       "rcfilters-filter-logactions-label": "Įrašyti veiksmai",
+       "rcfilters-filter-lastrevision-description": "Naujausias puslapio keitimas.",
+       "rcfilters-filter-previousrevision-description": "Visi keitimai, kurie nėra naujausi puslapio keitimai.",
        "rcnotefrom": "Žemiau yra {{PLURAL:$5|pakeitimas|pakeitimai}} pradedant <strong>$3, $4</strong> (rodoma iki <strong>$1</strong> pakeitimų).",
+       "rclistfromreset": "Nustatyti duomenų pasirinkimą iš naujo",
        "rclistfrom": "Rodyti naujus pakeitimus pradedant $3 $2",
        "rcshowhideminor": "$1 smulkius keitimus",
        "rcshowhideminor-show": "Rodyti",
        "unblocked-id": "Blokavimas $1 buvo pašalintas",
        "unblocked-ip": "[[Special:Contributions/$1|$1]] buvo atblokuotas.",
        "blocklist": "Blokuoti naudotojai",
+       "autoblocklist-submit": "Ieškoti",
        "ipblocklist": "Blokuoti naudotojai",
        "ipblocklist-legend": "Rasti užblokuotą naudotoją",
        "blocklist-userblocks": "Slėpti paskyrų blokavimus",
        "api-error-emptypage": "Kurti naujus, tuščius puslapius neleidžiama.",
        "api-error-publishfailed": "Vidinė klaida: serveriui nepavyko paskelbti laikino failo.",
        "api-error-stashfailed": "Vidinė klaida: serveriui nepavyko išsaugoti laikinąjį failą.",
-       "api-error-unknown-warning": "Nežinomas įspėjimas: $1",
+       "api-error-unknown-warning": "Nežinomas įspėjimas: „$1“.",
        "api-error-unknownerror": "Nežinoma klaida: \"$1\"",
        "duration-seconds": "$1 {{PLURAL:$1|sekundė|sekundės|sekundžių}}",
        "duration-minutes": "$1 {{PLURAL:$1|minutė|minutės|minučių}}",
        "pagelang-reason": "Priežastis",
        "pagelang-submit": "Pateikti",
        "pagelang-nonexistent-page": "Puslapis $1 neegzistuoja.",
+       "pagelang-unchanged-language": "Puslapis $1 jau yra $2 kalba.",
+       "pagelang-unchanged-language-default": "$1 puslapis jau yra viki turinio numatyta kalba.",
        "pagelang-db-failed": "Duomenų bazei nepavyko pakeisti puslapio kalbos.",
        "right-pagelang": "Keisti puslapio kalbą",
        "action-pagelang": "keisti puslapio kalbą",
        "mw-widgets-titleinput-description-new-page": "puslapis dar neegzistuoja",
        "mw-widgets-titleinput-description-redirect": "nukreipti į $1",
        "mw-widgets-categoryselector-add-category-placeholder": "Pridėti kategoriją...",
+       "mw-widgets-usersmultiselect-placeholder": "Pridėti daugiau...",
+       "date-range-from": "Nuo datos:",
+       "date-range-to": "Iki datos:",
        "sessionmanager-tie": "Negalima kombinuoti kelių užklausų autentikacijos tipų: $1.",
        "sessionprovider-generic": "$1 sesijos",
        "sessionprovider-mediawiki-session-cookiesessionprovider": "sesijos su slapukais",
index 35c30f6..483e027 100644 (file)
        "authpage-cannot-link-continue": "Ситимниир кыах суох. Сиэссийэттэн тахсан хаалбыккын быһыылаах.",
        "cannotauth-not-allowed-title": "Киирэр көҥүллэммэт",
        "cannotauth-not-allowed": "Бу сирэйи туһанарыҥ сатаммат эбит",
+       "removecredentials": "Бэлиэ-ааты сот",
+       "removecredentials-submit": "Бэлиэ-ааты сот",
+       "removecredentials-invalidsubpage": "$1 бэлиэтэнии сатаммат көрүҥэ эбит.",
+       "removecredentials-success": "Бэлиэтэнии сотулунна.",
        "credentialsform-provider": "Учуоттуур дааннай көрүҥэ:",
        "credentialsform-account": "Бэлиэ-аат:",
        "cannotlink-no-provider-title": "Бэлиэ-ааттар суохтар",
        "userjsispublic": "Болҕой: JavaScript сирэйигэр кистэлэҥ сибидиэнньэ суох буолуохтаах, тоҕо диэтэххэ ону атын кыттааччылар хааччаҕа суох көрөр кыахтаахтар.",
        "usercssispublic": "Болҕой: CSS  сирэйигэр кистэлэҥ сибидиэнньэ суох буолуохтаах, тоҕо диэтэххэ ону атын кыттааччылар хааччаҕа суох көрөр кыахтаахтар.",
        "restrictionsfield-badip": "IP эбэтэр IP-лар диапазоннара сатаммат: $1",
-       "restrictionsfield-label": "Көҥүллэммит IP диапазона:"
+       "restrictionsfield-label": "Көҥүллэммит IP диапазона:",
+       "revid": "$1 торум",
+       "pageid": "$1 сирэй нүөмэрэ",
+       "gotointerwiki": "{{SITENAME}} сиртэн тахсарга",
+       "gotointerwiki-invalid": "Аат алҕастаах.",
+       "gotointerwiki-external": "[[$2]] диэн сиргэ бараары {{SITENAME}} сиртэн тахсан эрэҕин.\n\n'''[$1 Манна $1 көс]'''"
 }
index 6b8aeed..93ee0c8 100644 (file)
        "rcfilters-filter-minor-description": "«Кече үзгәртү» дип тамгаланган үзгәртүләр",
        "rcfilters-filter-pageedits-label": "Бит үзгәртүләре",
        "rcfilters-filter-newpages-label": "Бит төзүләре",
-       "rcfilters-filter-logactions-label": "Беркетмәләнә торган гамәлләр",
+       "rcfilters-filter-logactions-label": "Беркетмәләнүче гамәлләр",
        "rcfilters-filter-logactions-description": "Административ гамәлләр, хисап язмасын төзүләр, битне бетерүләр, файл йөкләүләр...",
        "rcnotefrom": "Астарак <strong>$3, $4</strong> өчен {{PLURAL:$5|үзгәртүләр күрсәтелгән}} (<strong>$1</strong> артык түгел).",
        "rclistfrom": "$3 $2 башлап яңа үзгәртүләрне күрсәт",
index 8457f35..0d601fd 100644 (file)
        "passwordreset-nocaller": "מען דארף פֿארזארגן א רופֿער",
        "passwordreset-nosuchcaller": "רופֿער איז נישט פֿאראן: $1",
        "passwordreset-invalidemail": "אומגילטיקער ע־פאסט אדרעס",
+       "passwordreset-nodata": "מ׳האט נישט פֿארזארגט נישט קיין באניצער־נאמען און נישט קיין ע־פאסט אדרעס",
        "changeemail": "ענדערן אדער אראפנעמען ע-פּאָסט אַדרעס",
        "changeemail-header": "דערגאַנצט די פֿאָרעם צו ענדערן אייער ע-פּאָסט אַדרעס .\nטאמער ווילט איר אראפנעמען די צוארדנונג פון איינעם פון אייערע ע־פאסט אדרעסן פו אייער קאנטע, לאזט ליידיג דעם נייעם ע־פאסט אדרעס ווען איר גיט איין די פֿארעם.",
        "changeemail-no-info": "איר דאַרפֿט זיין אַרײַנלאגירט צוצוקומען גלײַך צו דעם דאָזיגן בלאַט.",
        "rcfilters-savedqueries-remove": "אראפנעמען",
        "rcfilters-savedqueries-new-name-label": "נאָמען",
        "rcfilters-savedqueries-cancel-label": "אַנולירן",
+       "rcfilters-search-placeholder": "פֿילטערן לעצטיקע ענדערונגען (דורכקוקן אדער אָנהייבן אַריינקלאַפן)",
        "rcfilters-invalid-filter": "אומגילטיגער פֿילטער",
        "rcfilters-empty-filter": "קיין אַקטיווע פילטערס. אלע ביישטייערונגען געוויזן.",
        "rcfilters-filterlist-title": "פֿילטערס",
index 1f5f78e..e19345c 100644 (file)
        "undeleteextrahelp": "若要還原所有的頁面歷史,請取消勾選所有核選方塊並點選 <strong><em>{{int:undeletebtn}}</em></strong>。\n若要還原指定的頁面歷史,請勾選要還原的修訂核選方塊並點選 <strong><em>{{int:undeletebtn}}</em></strong>。",
        "undeleterevisions": "已刪除 $1 個修訂",
        "undeletehistory": "若您還原該頁面,所有的修訂歷史也會一併還原。\n若刪除之後已有使用相同名稱建立的新頁面,還原的修訂歷史會出現在此頁面之前的歷史中。",
-       "undeleterevdel": "若最新頁面或檔案修訂被部份刪除,將無法執行取消刪除的動作。\n這種情況您必須取勾選或取消隱藏已刪除的最新修訂。",
+       "undeleterevdel": "若最新頁面或檔案修訂被部份刪除,將無法執行取消刪除的動作。\n這種情況您必須取勾選或取消隱藏已刪除的最新修訂。",
        "undeletehistorynoadmin": "已刪除此頁面。\n以下摘要顯示刪除原因與刪除前所有編輯過此頁面的使用者詳細資料。\n這些已刪除的實際文字修訂僅對管理員可用。",
        "undelete-revision": "被 $3 刪除的 $1 (於 $4 $5) 修訂:",
        "undeleterevision-missing": "無效或遺失的修訂。\n您可能使用了錯誤的連結,或該修訂已從封存中還原或刪除。",
index 6717a8e..802619e 100644 (file)
@@ -80,6 +80,7 @@ TEXT
                        'Disable link table updates. Is faster but leaves the wiki in an inconsistent state'
                );
                $this->addOption( 'image-base-path', 'Import files from a specified path', false, true );
+               $this->addOption( 'skip-to', 'Start from nth page by skipping first n-1 pages', false, true );
                $this->addArg( 'file', 'Dump file to import [else use stdin]', false );
        }
 
@@ -301,6 +302,11 @@ TEXT
                                return false;
                        }
                }
+               if ( $this->hasOption( 'skip-to' ) ) {
+                       $nthPage = (int)$this->getOption( 'skip-to' );
+                       $importer->setPageOffset( $nthPage );
+                       $this->pageCount = $nthPage - 1;
+               }
                $importer->setPageCallback( [ $this, 'reportPage' ] );
                $this->importCallback = $importer->setRevisionCallback(
                        [ $this, 'handleRevision' ] );
index 92e3e1c..992ce99 100644 (file)
                #mw-interwiki-results {
                        width: 30%;
                        display: inline-block; /* used to align interwiki sidebar with the top of the main search results */
-                       margin-left: 10%;
+                       margin-left: 8%; /* since inline-block causes whitespace issues, this is 8 instead of 10% */
                }
                .mw-search-createlink,
                .mw-search-nonefound,
diff --git a/tests/phpunit/includes/GlobalFunctions/wfArrayFilterTest.php b/tests/phpunit/includes/GlobalFunctions/wfArrayFilterTest.php
new file mode 100644 (file)
index 0000000..afd80ff
--- /dev/null
@@ -0,0 +1,37 @@
+<?php
+
+class WfArrayFilterTest extends \PHPUnit_Framework_TestCase {
+       public function testWfArrayFilter() {
+               $arr = [ 'a' => 1, 'b' => 2, 'c' => 3 ];
+               $filtered = wfArrayFilter( $arr, function( $val, $key ) {
+                       return $key !== 'b';
+               } );
+               $this->assertSame( [ 'a' => 1, 'c' => 3 ], $filtered );
+
+               $arr = [ 'a' => 1, 'b' => 2, 'c' => 3 ];
+               $filtered = wfArrayFilter( $arr, function( $val, $key ) {
+                       return $val !== 2;
+               } );
+               $this->assertSame( [ 'a' => 1, 'c' => 3 ], $filtered );
+
+               $arr = [ 'a', 'b', 'c' ];
+               $filtered = wfArrayFilter( $arr, function( $val, $key ) {
+                       return $key !== 0;
+               } );
+               $this->assertSame( [ 1 => 'b',  2 => 'c' ], $filtered );
+       }
+
+       public function testWfArrayFilterByKey() {
+               $arr = [ 'a' => 1, 'b' => 2, 'c' => 3 ];
+               $filtered = wfArrayFilterByKey( $arr, function( $key ) {
+                       return $key !== 'b';
+               } );
+               $this->assertSame( [ 'a' => 1, 'c' => 3 ], $filtered );
+
+               $arr = [ 'a', 'b', 'c' ];
+               $filtered = wfArrayFilterByKey( $arr, function( $key ) {
+                       return $key !== 0;
+               } );
+               $this->assertSame( [ 1 => 'b',  2 => 'c' ], $filtered );
+       }
+}
index 862b7d0..c237c50 100644 (file)
@@ -362,4 +362,25 @@ class SanitizerTest extends MediaWikiTestCase {
                        [ '+1 +2', '+1', '+2' ],
                ];
        }
+
+       /**
+        * @dataProvider provideIsReservedDataAttribute
+        */
+       public function testIsReservedDataAttribute( $attr, $expected ) {
+               $this->assertSame( $expected, Sanitizer::isReservedDataAttribute( $attr ) );
+       }
+
+       public static function provideIsReservedDataAttribute() {
+               return [
+                       [ 'foo', false ],
+                       [ 'data', false ],
+                       [ 'data-foo', false ],
+                       [ 'data-mw', true ],
+                       [ 'data-ooui', true ],
+                       [ 'data-parsoid', true ],
+                       [ 'data-mw-foo', true ],
+                       [ 'data-ooui-foo', true ],
+                       [ 'data-mwfoo', true ], // could be false but this is how it's implemented currently
+               ];
+       }
 }
index 308e6de..029d1fe 100644 (file)
@@ -98,6 +98,9 @@ class EnhancedChangesListTest extends MediaWikiLangTestCase {
                $recentChange = $this->getEditChange( '20131103092153' );
                $enhancedChangesList->recentChangesLine( $recentChange, false );
 
+               $html = $enhancedChangesList->endRecentChangesList();
+               $this->assertContains( 'data-mw-revid="5"', $html );
+
                $recentChange2 = $this->getEditChange( '20131103092253' );
                $enhancedChangesList->recentChangesLine( $recentChange2, false );
 
@@ -105,6 +108,13 @@ class EnhancedChangesListTest extends MediaWikiLangTestCase {
 
                preg_match_all( '/td class="mw-enhanced-rc-nested"/', $html, $matches );
                $this->assertCount( 2, $matches[0] );
+
+               $recentChange3 = $this->getLogChange();
+               $enhancedChangesList->recentChangesLine( $recentChange3, false );
+
+               $html = $enhancedChangesList->endRecentChangesList();
+               $this->assertContains( 'data-mw-logaction="foo/bar"', $html );
+               $this->assertContains( 'data-mw-logid="25"', $html );
        }
 
        /**
@@ -129,6 +139,15 @@ class EnhancedChangesListTest extends MediaWikiLangTestCase {
                return $recentChange;
        }
 
+       private function getLogChange() {
+               $user = $this->getMutableTestUser()->getUser();
+               $recentChange = $this->testRecentChangesHelper->makeLogRecentChange( 'foo', 'bar', $user,
+                       'Title', '20131103092153', 0, 0
+               );
+
+               return $recentChange;
+       }
+
        /**
         * @return RecentChange
         */
index 51cfadc..f892eb7 100644 (file)
@@ -119,15 +119,17 @@ class OldChangesListTest extends MediaWikiLangTestCase {
                );
        }
 
-       public function testRecentChangesLine_Tags() {
+       public function testRecentChangesLine_Attribs() {
                $recentChange = $this->getEditChange();
                $recentChange->mAttribs['ts_tags'] = 'vandalism,newbie';
 
                $oldChangesList = $this->getOldChangesList();
                $line = $oldChangesList->recentChangesLine( $recentChange, false, 1 );
 
-               $this->assertRegExp( '/<li class="[\w\s-]*mw-tag-vandalism[\w\s-]*">/', $line );
-               $this->assertRegExp( '/<li class="[\w\s-]*mw-tag-newbie[\w\s-]*">/', $line );
+               $this->assertRegExp( '/<li data-mw-revid="\d+" class="[\w\s-]*mw-tag-vandalism[\w\s-]*">/',
+                       $line );
+               $this->assertRegExp( '/<li data-mw-revid="\d+" class="[\w\s-]*mw-tag-newbie[\w\s-]*">/',
+                       $line );
        }
 
        public function testRecentChangesLine_numberOfWatchingUsers() {
index 3363bca..53f02df 100644 (file)
@@ -10,8 +10,7 @@ class PasswordResetTest extends PHPUnit_Framework_TestCase {
         * @dataProvider provideIsAllowed
         */
        public function testIsAllowed( $passwordResetRoutes, $enableEmail,
-               $allowsAuthenticationDataChange, $canEditPrivate, $canSeePassword,
-               $userIsBlocked, $isAllowed
+               $allowsAuthenticationDataChange, $canEditPrivate, $block, $globalBlock, $isAllowed
        ) {
                $config = new HashConfig( [
                        'PasswordResetRoutes' => $passwordResetRoutes,
@@ -25,13 +24,12 @@ class PasswordResetTest extends PHPUnit_Framework_TestCase {
 
                $user = $this->getMockBuilder( User::class )->getMock();
                $user->expects( $this->any() )->method( 'getName' )->willReturn( 'Foo' );
-               $user->expects( $this->any() )->method( 'isBlocked' )->willReturn( $userIsBlocked );
+               $user->expects( $this->any() )->method( 'getBlock' )->willReturn( $block );
+               $user->expects( $this->any() )->method( 'getGlobalBlock' )->willReturn( $globalBlock );
                $user->expects( $this->any() )->method( 'isAllowed' )
-                       ->will( $this->returnCallback( function ( $perm ) use ( $canEditPrivate, $canSeePassword ) {
+                       ->will( $this->returnCallback( function ( $perm ) use ( $canEditPrivate ) {
                                if ( $perm === 'editmyprivateinfo' ) {
                                        return $canEditPrivate;
-                               } elseif ( $perm === 'passwordreset' ) {
-                                       return $canSeePassword;
                                } else {
                                        $this->fail( 'Unexpected permission check' );
                                }
@@ -44,67 +42,103 @@ class PasswordResetTest extends PHPUnit_Framework_TestCase {
 
        public function provideIsAllowed() {
                return [
-                       [
+                       'no routes' => [
                                'passwordResetRoutes' => [],
                                'enableEmail' => true,
                                'allowsAuthenticationDataChange' => true,
                                'canEditPrivate' => true,
-                               'canSeePassword' => true,
-                               'userIsBlocked' => false,
+                               'block' => null,
+                               'globalBlock' => null,
                                'isAllowed' => false,
                        ],
-                       [
+                       'email disabled' => [
                                'passwordResetRoutes' => [ 'username' => true ],
                                'enableEmail' => false,
                                'allowsAuthenticationDataChange' => true,
                                'canEditPrivate' => true,
-                               'canSeePassword' => true,
-                               'userIsBlocked' => false,
+                               'block' => null,
+                               'globalBlock' => null,
                                'isAllowed' => false,
                        ],
-                       [
+                       'auth data change disabled' => [
                                'passwordResetRoutes' => [ 'username' => true ],
                                'enableEmail' => true,
                                'allowsAuthenticationDataChange' => false,
                                'canEditPrivate' => true,
-                               'canSeePassword' => true,
-                               'userIsBlocked' => false,
+                               'block' => null,
+                               'globalBlock' => null,
                                'isAllowed' => false,
                        ],
-                       [
+                       'cannot edit private data' => [
                                'passwordResetRoutes' => [ 'username' => true ],
                                'enableEmail' => true,
                                'allowsAuthenticationDataChange' => true,
                                'canEditPrivate' => false,
-                               'canSeePassword' => true,
-                               'userIsBlocked' => false,
+                               'block' => null,
+                               'globalBlock' => null,
                                'isAllowed' => false,
                        ],
-                       [
+                       'blocked with account creation disabled' => [
                                'passwordResetRoutes' => [ 'username' => true ],
                                'enableEmail' => true,
                                'allowsAuthenticationDataChange' => true,
                                'canEditPrivate' => true,
-                               'canSeePassword' => true,
-                               'userIsBlocked' => true,
+                               'block' => new Block( [ 'createAccount' => true ] ),
+                               'globalBlock' => null,
                                'isAllowed' => false,
                        ],
-                       [
+                       'blocked w/o account creation disabled' => [
                                'passwordResetRoutes' => [ 'username' => true ],
                                'enableEmail' => true,
                                'allowsAuthenticationDataChange' => true,
                                'canEditPrivate' => true,
-                               'canSeePassword' => false,
-                               'userIsBlocked' => false,
+                               'block' => new Block( [] ),
+                               'globalBlock' => null,
                                'isAllowed' => true,
                        ],
-                       [
+                       'using blocked proxy' => [
                                'passwordResetRoutes' => [ 'username' => true ],
                                'enableEmail' => true,
                                'allowsAuthenticationDataChange' => true,
                                'canEditPrivate' => true,
-                               'canSeePassword' => true,
-                               'userIsBlocked' => false,
+                               'block' => new Block( [ 'systemBlock' => 'proxy' ] ),
+                               'globalBlock' => null,
+                               'isAllowed' => false,
+                       ],
+                       'globally blocked with account creation disabled' => [
+                               'passwordResetRoutes' => [ 'username' => true ],
+                               'enableEmail' => true,
+                               'allowsAuthenticationDataChange' => true,
+                               'canEditPrivate' => true,
+                               'block' => null,
+                               'globalBlock' => new Block( [ 'systemBlock' => 'global-block', 'createAccount' => true ] ),
+                               'isAllowed' => false,
+                       ],
+                       'globally blocked with account creation not disabled' => [
+                               'passwordResetRoutes' => [ 'username' => true ],
+                               'enableEmail' => true,
+                               'allowsAuthenticationDataChange' => true,
+                               'canEditPrivate' => true,
+                               'block' => null,
+                               'globalBlock' => new Block( [ 'systemBlock' => 'global-block', 'createAccount' => false ] ),
+                               'isAllowed' => true,
+                       ],
+                       'blocked via wgSoftBlockRanges' => [
+                               'passwordResetRoutes' => [ 'username' => true ],
+                               'enableEmail' => true,
+                               'allowsAuthenticationDataChange' => true,
+                               'canEditPrivate' => true,
+                               'block' => new Block( [ 'systemBlock' => 'wgSoftBlockRanges', 'anonOnly' => true ] ),
+                               'globalBlock' => null,
+                               'isAllowed' => true,
+                       ],
+                       'all OK' => [
+                               'passwordResetRoutes' => [ 'username' => true ],
+                               'enableEmail' => true,
+                               'allowsAuthenticationDataChange' => true,
+                               'canEditPrivate' => true,
+                               'block' => null,
+                               'globalBlock' => null,
                                'isAllowed' => true,
                        ],
                ];