Merge "AllMessagesTablePager: Use $this->msg instead of wfMessage"
authorjenkins-bot <jenkins-bot@gerrit.wikimedia.org>
Fri, 24 May 2019 22:16:07 +0000 (22:16 +0000)
committerGerrit Code Review <gerrit@wikimedia.org>
Fri, 24 May 2019 22:16:07 +0000 (22:16 +0000)
65 files changed:
README
RELEASE-NOTES-1.34
includes/AjaxResponse.php
includes/Block.php
includes/DefaultSettings.php
includes/FeedUtils.php
includes/MediaWiki.php
includes/MovePage.php
includes/OutputPage.php
includes/ServiceWiring.php
includes/Setup.php
includes/Storage/DerivedPageDataUpdater.php
includes/Title.php
includes/actions/RawAction.php
includes/api/ApiMain.php
includes/api/ApiMove.php
includes/api/ApiQueryProtectedTitles.php
includes/api/ApiQueryRevisions.php
includes/api/i18n/mk.json
includes/cache/localisation/LocalisationCache.php
includes/clientpool/SquidPurgeClient.php
includes/debug/logger/LegacyLogger.php
includes/debug/logger/monolog/LineFormatter.php
includes/deferred/CdnCacheUpdate.php
includes/htmlform/HTMLForm.php
includes/installer/i18n/nb.json
includes/jobqueue/jobs/RefreshLinksJob.php
includes/preferences/DefaultPreferencesFactory.php
includes/resourceloader/ResourceLoaderModule.php
includes/specials/SpecialBlockList.php
includes/specials/SpecialSearch.php
includes/specials/pagers/ImageListPager.php
includes/widget/SearchInputWidget.php
includes/widget/search/SearchFormWidget.php
languages/Language.php
languages/i18n/bjn.json
languages/i18n/bn.json
languages/i18n/en.json
languages/i18n/fy.json
languages/i18n/hr.json
languages/i18n/lrc.json
languages/i18n/nb.json
languages/i18n/nqo.json
languages/i18n/qqq.json
languages/i18n/sr-ec.json
languages/i18n/sr-el.json
languages/i18n/sv.json
languages/messages/MessagesEn.php
maintenance/benchmarks/benchmarkPurge.php
maintenance/purgeChangedPages.php
maintenance/purgeList.php
opensearch_desc.php
resources/Resources.php
resources/src/jquery/jquery.suggestions.js
resources/src/mediawiki.special.apisandbox/apisandbox.js
resources/src/mediawiki.special.block.js
resources/src/mediawiki.widgets/mw.widgets.CopyTextLayout.css [new file with mode: 0644]
resources/src/mediawiki.widgets/mw.widgets.CopyTextLayout.js [new file with mode: 0644]
tests/phpunit/includes/MovePageTest.php
tests/phpunit/includes/OutputPageTest.php
tests/phpunit/includes/WebRequestTest.php
tests/phpunit/includes/api/ApiMainTest.php
tests/phpunit/includes/debug/logger/LegacyLoggerTest.php
tests/phpunit/includes/debug/logger/monolog/LineFormatterTest.php
thumb.php

diff --git a/README b/README
index ad9b9d9..b9b2c8a 100644 (file)
--- a/README
+++ b/README
@@ -23,7 +23,7 @@ RELEASE-NOTES, INSTALL, and UPGRADE.
 * Seeking help from a person?
 ** https://www.mediawiki.org/wiki/Special:MyLanguage/Communication
 * Looking to file a bug report or a feature request?
-** https://bugs.mediawiki.org/
+** https://phabricator.mediawiki.org/
 * Interested in helping out?
 ** https://www.mediawiki.org/wiki/Special:MyLanguage/How_to_contribute
 
index 8183145..e59d7f7 100644 (file)
@@ -35,6 +35,13 @@ For notes on 1.33.x and older releases, see HISTORY.
   module or will be generated by Mediawiki itself (depending on the set-up).
 
 ==== Changed configuration ====
+* $wgUseCdn, $wgCdnServers, $wgCdnServersNoPurge, and $wgCdnMaxAge – These four
+  CDN-related config variables have been renamed from being specific to Squid –
+  they were previously $wgUseSquid, $wgSquidServers, $wgSquidServersNoPurge, and
+  $wgSquidMaxage respectively. This aligns them with the related existing
+  variable $wgCdnMaxageLagged. The previous configuration variable names are
+  deprecated, but will be used as the fall back if they are still set.
+  Note that wgSquidPurgeUseHostHeader has not been renamed, as it is deprecated.
 * …
 
 ==== Removed configuration ====
@@ -218,6 +225,11 @@ because of Phabricator reports.
 * Parser::$mConf is deprecated. It will be removed entirely in a later version.
   Some context can be found at T224165.
 * Constructing Parser directly is deprecated. Obtain one from ParserFactory.
+* Title::moveSubpages is deprecated. Use MovePage::moveSubpages or
+  MovePage::moveSubpagesIfAllowed.
+* The MWNamespace class is deprecated. Use MediaWikiServices::getNamespaceInfo.
+* (T62260) Hard deprecate Language::getExtraUserToggles() method.
+* …
 
 === Other changes in 1.34 ===
 * …
index 5f889ad..323c5d3 100644 (file)
@@ -179,8 +179,7 @@ class AjaxResponse {
                        # If CDN caches are configured, tell them to cache the response,
                        # and tell the client to always check with the CDN. Otherwise,
                        # tell the client to use a cached copy, without a way to purge it.
-
-                       if ( $this->mConfig->get( 'UseSquid' ) ) {
+                       if ( $this->mConfig->get( 'UseCdn' ) ) {
                                # Expect explicit purge of the proxy cache, but require end user agents
                                # to revalidate against the proxy on each visit.
                                # Surrogate-Control controls our CDN, Cache-Control downstream caches
index 9f7f77d..0f5e8dd 100644 (file)
@@ -1154,7 +1154,7 @@ class Block extends AbstractBlock {
                        if ( !IP::isValid( $ipaddr ) ) {
                                continue;
                        }
-                       # Don't check trusted IPs (includes local squids which will be in every request)
+                       # Don't check trusted IPs (includes local CDNs which will be in every request)
                        if ( $proxyLookup->isTrustedProxy( $ipaddr ) ) {
                                continue;
                        }
@@ -1208,14 +1208,14 @@ class Block extends AbstractBlock {
         *  - Other softblocks are chosen over autoblocks
         *  - If there are multiple exact or range blocks at the same level, the one chosen
         *    is random
-        * This should be used when $blocks where retrieved from the user's IP address
+        * This should be used when $blocks were retrieved from the user's IP address
         * and $ipChain is populated from the same IP address information.
         *
         * @param array $blocks Array of Block objects
         * @param array $ipChain List of IPs (strings). This is used to determine how "close"
         *     a block is to the server, and if a block matches exactly, or is in a range.
         *     The order is furthest from the server to nearest e.g., (Browser, proxy1, proxy2,
-        *     local-squid, ...)
+        *     local-cdn, ...)
         * @throws MWException
         * @return Block|null The "best" block from the list
         */
index 9efcfb4..eed732b 100644 (file)
@@ -2701,7 +2701,8 @@ $wgExtensionInfoMTime = false;
  * @name   HTTP proxy (CDN) settings
  *
  * Many of these settings apply to any HTTP proxy used in front of MediaWiki,
- * although they are referred to as Squid settings for historical reasons.
+ * although they are sometimes still referred to as Squid settings for
+ * historical reasons.
  *
  * Achieving a high hit ratio with an HTTP proxy requires special
  * configuration. See https://www.mediawiki.org/wiki/Manual:Squid_caching for
@@ -2713,8 +2714,10 @@ $wgExtensionInfoMTime = false;
 /**
  * Enable/disable CDN.
  * See https://www.mediawiki.org/wiki/Manual:Squid_caching
+ *
+ * @since 1.34 Renamed from $wgUseSquid.
  */
-$wgUseSquid = false;
+$wgUseCdn = false;
 
 /**
  * If you run Squid3 with ESI support, enable this (default:false):
@@ -2756,12 +2759,15 @@ $wgInternalServer = false;
  * out s-maxage in the CDN config.
  *
  * 18000 seconds = 5 hours, more cache hits with 2678400 = 31 days.
+ *
+ * @since 1.34 Renamed from $wgSquidMaxage
  */
-$wgSquidMaxage = 18000;
+$wgCdnMaxAge = 18000;
 
 /**
  * Cache timeout for the CDN when DB replica DB lag is high
- * @see $wgSquidMaxage
+ * @see $wgCdnMaxAge
+ *
  * @since 1.27
  */
 $wgCdnMaxageLagged = 30;
@@ -2784,7 +2790,7 @@ $wgCdnReboundPurgeDelay = 0;
 
 /**
  * Cache timeout for the CDN when a response is known to be wrong or incomplete (due to load)
- * @see $wgSquidMaxage
+ * @see $wgCdnMaxAge
  * @since 1.27
  */
 $wgCdnMaxageSubstitute = 60;
@@ -2803,20 +2809,24 @@ $wgForcedRawSMaxage = 300;
  * headers sent/modified from these proxies when obtaining the remote IP address
  *
  * For a list of trusted servers which *aren't* purged, see $wgSquidServersNoPurge.
+ *
+ * @since 1.34 Renamed from $wgSquidServers.
  */
-$wgSquidServers = [];
+$wgCdnServers = [];
 
 /**
- * As above, except these servers aren't purged on page changes; use to set a
- * list of trusted proxies, etc. Supports both individual IP addresses and
- * CIDR blocks.
+ * As with $wgCdnServers, except these servers aren't purged on page changes;
+ * use to set a list of trusted proxies, etc. Supports both individual IP
+ * addresses and CIDR blocks.
+ *
  * @since 1.23 Supports CIDR ranges
+ * @since 1.34 Renamed from $wgSquidServersNoPurge
  */
-$wgSquidServersNoPurge = [];
+$wgCdnServersNoPurge = [];
 
 /**
  * Whether to use a Host header in purge requests sent to the proxy servers
- * configured in $wgSquidServers. Set this to false to support Squid
+ * configured in $wgCdnServers. Set this to false to support a CDN
  * configured in forward-proxy mode.
  *
  * If this is set to true, a Host header will be sent, and only the path
@@ -6505,7 +6515,7 @@ $wgCachePrefix = false;
 /**
  * Display the new debugging toolbar. This also enables profiling on database
  * queries and other useful output.
- * Will be ignored if $wgUseFileCache or $wgUseSquid is enabled.
+ * Will be ignored if $wgUseFileCache or $wgUseCdn is enabled.
  *
  * @since 1.19
  */
@@ -9083,6 +9093,17 @@ $wgReportToEndpoints = [];
  */
 $wgFeaturePolicyReportOnly = [];
 
+/**
+ * Options for Special:Search completion widget form created by SearchFormWidget class.
+ * Settings that can be used:
+ * - showDescriptions: true/false - whether to show opensearch description results
+ * - performSearchOnClick:  true/false - whether to perform search on click
+ * See also TitleWidget.js UI widget.
+ * @since 1.34
+ * @var array
+ */
+$wgSpecialSearchFormOptions = [];
+
 /**
  * For really cool vim folding this needs to be at the end:
  * vim: foldmarker=@{,@} foldmethod=marker
index 0a88b23..59efc98 100644 (file)
@@ -20,7 +20,6 @@
  * @file
  * @ingroup Feed
  */
-use MediaWiki\MediaWikiServices;
 
 /**
  * Helper functions for feeds
@@ -29,25 +28,6 @@ use MediaWiki\MediaWikiServices;
  */
 class FeedUtils {
 
-       /**
-        * Check whether feed's cache should be cleared; for changes feeds
-        * If the feed should be purged; $timekey and $key will be removed from cache
-        *
-        * @param string $timekey Cache key of the timestamp of the last item
-        * @param string $key Cache key of feed's content
-        */
-       public static function checkPurge( $timekey, $key ) {
-               global $wgRequest, $wgUser;
-
-               $purge = $wgRequest->getVal( 'action' ) === 'purge';
-               // Allow users with 'purge' right to clear feed caches
-               if ( $purge && $wgUser->isAllowed( 'purge' ) ) {
-                       $cache = MediaWikiServices::getInstance()->getMainWANObjectCache();
-                       $cache->delete( $timekey, 1 );
-                       $cache->delete( $key, 1 );
-               }
-       }
-
        /**
         * Check whether feeds can be used and that $type is a valid feed type
         *
index 69bafaf..ca77121 100644 (file)
@@ -486,14 +486,14 @@ class MediaWiki {
                        }
 
                        # Let CDN cache things if we can purge them.
-                       if ( $this->config->get( 'UseSquid' ) &&
+                       if ( $this->config->get( 'UseCdn' ) &&
                                in_array(
                                        // Use PROTO_INTERNAL because that's what getCdnUrls() uses
                                        wfExpandUrl( $request->getRequestURL(), PROTO_INTERNAL ),
                                        $requestTitle->getCdnUrls()
                                )
                        ) {
-                               $output->setCdnMaxage( $this->config->get( 'SquidMaxage' ) );
+                               $output->setCdnMaxage( $this->config->get( 'CdnMaxAge' ) );
                        }
 
                        $action->show();
@@ -597,7 +597,7 @@ class MediaWiki {
                wfDebug( __METHOD__ . ': primary transaction round committed' );
 
                // Run updates that need to block the user or affect output (this is the last chance)
-               DeferredUpdates::doUpdates( 'enqueue', DeferredUpdates::PRESEND );
+               DeferredUpdates::doUpdates( 'run', DeferredUpdates::PRESEND );
                wfDebug( __METHOD__ . ': pre-send deferred updates completed' );
                // T214471: persist the session to avoid race conditions on subsequent requests
                $request->getSession()->save();
index 004ca07..d045355 100644 (file)
@@ -286,6 +286,132 @@ class MovePage {
                return $this->moveUnsafe( $user, $reason, $createRedirect, $changeTags );
        }
 
+       /**
+        * Move the source page's subpages to be subpages of the target page, without checking user
+        * permissions. The caller is responsible for moving the source page itself. We will still not
+        * do moves that are inherently not allowed, nor will we move more than $wgMaximumMovedPages.
+        *
+        * @param User $user
+        * @param string|null $reason The reason for the move
+        * @param bool|null $createRedirect Whether to create redirects from the old subpages to
+        *  the new ones
+        * @param string[] $changeTags Applied to entries in the move log and redirect page revision
+        * @return Status Good if no errors occurred. Ok if at least one page succeeded. The "value"
+        *  of the top-level status is an array containing the per-title status for each page. For any
+        *  move that succeeded, the "value" of the per-title status is the new page title.
+        */
+       public function moveSubpages(
+               User $user, $reason = null, $createRedirect = true, array $changeTags = []
+       ) {
+               return $this->moveSubpagesInternal( false, $user, $reason, $createRedirect, $changeTags );
+       }
+
+       /**
+        * Move the source page's subpages to be subpages of the target page, with user permission
+        * checks. The caller is responsible for moving the source page itself.
+        *
+        * @param User $user
+        * @param string|null $reason The reason for the move
+        * @param bool|null $createRedirect Whether to create redirects from the old subpages to
+        *  the new ones. Ignored if the user doesn't have the 'suppressredirect' right.
+        * @param string[] $changeTags Applied to entries in the move log and redirect page revision
+        * @return Status Good if no errors occurred. Ok if at least one page succeeded. The "value"
+        *  of the top-level status is an array containing the per-title status for each page. For any
+        *  move that succeeded, the "value" of the per-title status is the new page title.
+        */
+       public function moveSubpagesIfAllowed(
+               User $user, $reason = null, $createRedirect = true, array $changeTags = []
+       ) {
+               return $this->moveSubpagesInternal( true, $user, $reason, $createRedirect, $changeTags );
+       }
+
+       /**
+        * @param bool $checkPermissions
+        * @param User $user
+        * @param string $reason
+        * @param bool $createRedirect
+        * @param array $changeTags
+        * @return Status
+        */
+       private function moveSubpagesInternal(
+               $checkPermissions, User $user, $reason, $createRedirect, array $changeTags
+       ) {
+               global $wgMaximumMovedPages;
+               $services = MediaWikiServices::getInstance();
+
+               if ( $checkPermissions ) {
+                       if ( !$services->getPermissionManager()->userCan(
+                               'move-subpages', $user, $this->oldTitle )
+                       ) {
+                               return Status::newFatal( 'cant-move-subpages' );
+                       }
+               }
+
+               $nsInfo = $services->getNamespaceInfo();
+
+               // Do the source and target namespaces support subpages?
+               if ( !$nsInfo->hasSubpages( $this->oldTitle->getNamespace() ) ) {
+                       return Status::newFatal( 'namespace-nosubpages',
+                               $nsInfo->getCanonicalName( $this->oldTitle->getNamespace() ) );
+               }
+               if ( !$nsInfo->hasSubpages( $this->newTitle->getNamespace() ) ) {
+                       return Status::newFatal( 'namespace-nosubpages',
+                               $nsInfo->getCanonicalName( $this->newTitle->getNamespace() ) );
+               }
+
+               // Return a status for the overall result. Its value will be an array with per-title
+               // status for each subpage. Merge any errors from the per-title statuses into the
+               // top-level status without resetting the overall result.
+               $topStatus = Status::newGood();
+               $perTitleStatus = [];
+               $subpages = $this->oldTitle->getSubpages( $wgMaximumMovedPages + 1 );
+               $count = 0;
+               foreach ( $subpages as $oldSubpage ) {
+                       $count++;
+                       if ( $count > $wgMaximumMovedPages ) {
+                               $status = Status::newFatal( 'movepage-max-pages', $wgMaximumMovedPages );
+                               $perTitleStatus[$oldSubpage->getPrefixedText()] = $status;
+                               $topStatus->merge( $status );
+                               $topStatus->setOk( true );
+                               break;
+                       }
+
+                       // We don't know whether this function was called before or after moving the root page,
+                       // so check both titles
+                       if ( $oldSubpage->getArticleID() == $this->oldTitle->getArticleID() ||
+                               $oldSubpage->getArticleID() == $this->newTitle->getArticleID()
+                       ) {
+                               // When moving a page to a subpage of itself, don't move it twice
+                               continue;
+                       }
+                       $newPageName = preg_replace(
+                                       '#^' . preg_quote( $this->oldTitle->getDBkey(), '#' ) . '#',
+                                       StringUtils::escapeRegexReplacement( $this->newTitle->getDBkey() ), # T23234
+                                       $oldSubpage->getDBkey() );
+                       if ( $oldSubpage->isTalkPage() ) {
+                               $newNs = $this->newTitle->getTalkPage()->getNamespace();
+                       } else {
+                               $newNs = $this->newTitle->getSubjectPage()->getNamespace();
+                       }
+                       // T16385: we need makeTitleSafe because the new page names may be longer than 255
+                       // characters.
+                       $newSubpage = Title::makeTitleSafe( $newNs, $newPageName );
+
+                       $mp = new MovePage( $oldSubpage, $newSubpage );
+                       $method = $checkPermissions ? 'moveIfAllowed' : 'move';
+                       $status = $mp->$method( $user, $reason, $createRedirect, $changeTags );
+                       if ( $status->isOK() ) {
+                               $status->setResult( true, $newSubpage->getPrefixedText() );
+                       }
+                       $perTitleStatus[$oldSubpage->getPrefixedText()] = $status;
+                       $topStatus->merge( $status );
+                       $topStatus->setOk( true );
+               }
+
+               $topStatus->value = $perTitleStatus;
+               return $topStatus;
+       }
+
        /**
         * Moves *without* any sort of safety or sanity checks. Hooks can still fail the move, however.
         *
index edffc3b..54b3ee5 100644 (file)
@@ -746,10 +746,10 @@ class OutputPage extends ContextSource {
                        'user' => $this->getUser()->getTouched(),
                        'epoch' => $config->get( 'CacheEpoch' )
                ];
-               if ( $config->get( 'UseSquid' ) ) {
+               if ( $config->get( 'UseCdn' ) ) {
                        $modifiedTimes['sepoch'] = wfTimestamp( TS_MW, $this->getCdnCacheEpoch(
                                time(),
-                               $config->get( 'SquidMaxage' )
+                               $config->get( 'CdnMaxAge' )
                        ) );
                }
                Hooks::run( 'OutputPageCheckLastModified', [ &$modifiedTimes, $this ] );
@@ -818,7 +818,7 @@ class OutputPage extends ContextSource {
         * @return int Timestamp
         */
        private function getCdnCacheEpoch( $reqTime, $maxAge ) {
-               // Ensure Last-Modified is never more than (wgSquidMaxage) in the past,
+               // Ensure Last-Modified is never more than $wgCdnMaxAge in the past,
                // because even if the wiki page content hasn't changed since, static
                // resources may have changed (skin HTML, interface messages, urls, etc.)
                // and must roll-over in a timely manner (T46570)
@@ -2248,12 +2248,12 @@ class OutputPage extends ContextSource {
         *
         * @param string|int|float|bool|null $mtime Last-Modified timestamp
         * @param int $minTTL Minimum TTL in seconds [default: 1 minute]
-        * @param int $maxTTL Maximum TTL in seconds [default: $wgSquidMaxage]
+        * @param int $maxTTL Maximum TTL in seconds [default: $wgCdnMaxAge]
         * @since 1.28
         */
        public function adaptCdnTTL( $mtime, $minTTL = 0, $maxTTL = 0 ) {
                $minTTL = $minTTL ?: IExpiringStore::TTL_MINUTE;
-               $maxTTL = $maxTTL ?: $this->getConfig()->get( 'SquidMaxage' );
+               $maxTTL = $maxTTL ?: $this->getConfig()->get( 'CdnMaxAge' );
 
                if ( $mtime === null || $mtime === false ) {
                        return $minTTL; // entity does not exist
@@ -2567,7 +2567,7 @@ class OutputPage extends ContextSource {
 
                if ( $this->mEnableClientCache ) {
                        if (
-                               $config->get( 'UseSquid' ) &&
+                               $config->get( 'UseCdn' ) &&
                                !$response->hasCookies() &&
                                !SessionManager::getGlobalSession()->isPersistent() &&
                                !$this->isPrintable() &&
@@ -2584,7 +2584,7 @@ class OutputPage extends ContextSource {
                                        # start with a shorter timeout for initial testing
                                        # header( 'Surrogate-Control: max-age=2678400+2678400, content="ESI/1.0"');
                                        $response->header(
-                                               "Surrogate-Control: max-age={$config->get( 'SquidMaxage' )}" .
+                                               "Surrogate-Control: max-age={$config->get( 'CdnMaxAge' )}" .
                                                "+{$this->mCdnMaxage}, content=\"ESI/1.0\""
                                        );
                                        $response->header( 'Cache-Control: s-maxage=0, must-revalidate, max-age=0' );
index c9db5a8..c5764d2 100644 (file)
@@ -484,8 +484,8 @@ return [
        'ProxyLookup' => function ( MediaWikiServices $services ) : ProxyLookup {
                $mainConfig = $services->getMainConfig();
                return new ProxyLookup(
-                       $mainConfig->get( 'SquidServers' ),
-                       $mainConfig->get( 'SquidServersNoPurge' )
+                       $mainConfig->get( 'CdnServers' ),
+                       $mainConfig->get( 'CdnServersNoPurge' )
                );
        },
 
index a51cb83..f367fc2 100644 (file)
@@ -518,9 +518,61 @@ foreach ( LanguageCode::getNonstandardLanguageCodeMapping() as $code => $bcp47 )
 // To determine the user language, use $wgLang->getCode()
 $wgContLanguageCode = $wgLanguageCode;
 
+// Temporary backwards-compatibility reading of old Squid-named CDN settings as of MediaWiki 1.34,
+// to support sysadmins who fail to update their settings immediately:
+
+if ( isset( $wgUseSquid ) ) {
+       // If the sysadmin is still setting a value of $wgUseSquid to true but $wgUseCdn is the default of
+       // false, to be safe, assume they do want this still, so enable it.
+       if ( !$wgUseCdn && $wgUseSquid ) {
+               $wgUseCdn = $wgUseSquid;
+               wfDeprecated( '$wgUseSquid enabled but $wgUseCdn disabled; enabling CDN functions', '1.34' );
+       }
+} else {
+       // Backwards-compatibility for extensions that read this value.
+       $wgUseSquid = $wgUseCdn;
+}
+
+if ( isset( $wgSquidServers ) ) {
+       // If the sysadmin is still setting a value of $wgSquidServers but $wgCdnServers is the default of
+       // empty, to be safe, assume they do want these servers to be still used, so use them.
+       if ( !empty( $wgSquidServers ) && empty( $wgCdnServers ) ) {
+               $wgCdnServers = $wgSquidServers;
+               wfDeprecated( '$wgSquidServers set, $wgCdnServers empty; using them', '1.34' );
+       }
+} else {
+       // Backwards-compatibility for extensions that read this value.
+       $wgSquidServers = $wgCdnServers;
+}
+
+if ( isset( $wgSquidServersNoPurge ) ) {
+       // If the sysadmin is still setting values in $wgSquidServersNoPurge but $wgCdnServersNoPurge is
+       // the default of empty, to be safe, assume they do want these servers to be still used, so use
+       // them.
+       if ( !empty( $wgSquidServersNoPurge ) && empty( $wgCdnServersNoPurge ) ) {
+               $wgCdnServersNoPurge = $wgSquidServersNoPurge;
+               wfDeprecated( '$wgSquidServersNoPurge set, $wgCdnServersNoPurge empty; using them', '1.34' );
+       }
+} else {
+       // Backwards-compatibility for extensions that read this value.
+       $wgSquidServersNoPurge = $wgCdnServersNoPurge;
+}
+
+if ( isset( $wgSquidMaxage ) ) {
+       // If the sysadmin is still setting a value of $wgSquidMaxage and it's higher than $wgCdnMaxAge,
+       // to be safe, assume they want the higher (lower performance requirement) value, so use that.
+       if ( $wgCdnMaxAge < $wgSquidMaxage ) {
+               $wgCdnMaxAge = $wgSquidMaxage;
+               wfDeprecated( '$wgSquidMaxage set higher than $wgCdnMaxAge; using the higher value', '1.34' );
+       }
+} else {
+       // Backwards-compatibility for extensions that read this value.
+       $wgSquidMaxage = $wgCdnMaxAge;
+}
+
 // Easy to forget to falsify $wgDebugToolbar for static caches.
 // If file cache or CDN cache is on, just disable this (DWIMD).
-if ( $wgUseFileCache || $wgUseSquid ) {
+if ( $wgUseFileCache || $wgUseCdn ) {
        $wgDebugToolbar = false;
 }
 
index bc48a0e..ff5541d 100644 (file)
@@ -1582,10 +1582,10 @@ class DerivedPageDataUpdater implements IDBAccessObject {
                ];
                $deferValues = [ false, DeferredUpdates::PRESEND, DeferredUpdates::POSTSEND ];
                if ( !in_array( $options['defer'], $deferValues, true ) ) {
-                       throw new InvalidArgumentException( 'invalid value for defer: ' . $options['defer'] );
+                       throw new InvalidArgumentException( 'Invalid value for defer: ' . $options['defer'] );
                }
-               Assert::parameterType( 'integer|null', $options['transactionTicket'],
-                       '$options[\'transactionTicket\']' );
+               Assert::parameterType(
+                       'integer|null', $options['transactionTicket'], '$options[\'transactionTicket\']' );
 
                $updates = $this->getSecondaryDataUpdates( $options['recursive'] );
 
@@ -1596,14 +1596,13 @@ class DerivedPageDataUpdater implements IDBAccessObject {
                $causeAction = $this->options['causeAction'] ?? 'unknown';
                $causeAgent = $this->options['causeAgent'] ?? 'unknown';
                $legacyRevision = new Revision( $this->revision );
+               $ticket = $options['transactionTicket'];
 
-               if ( $options['defer'] === false && $options['transactionTicket'] !== null ) {
+               if ( $options['defer'] === false && $ticket !== null ) {
                        // For legacy hook handlers doing updates via LinksUpdateConstructed, make sure
                        // any pending writes they made get flushed before the doUpdate() calls below.
                        // This avoids snapshot-clearing errors in LinksUpdate::acquirePageLock().
-                       $this->loadbalancerFactory->commitAndWaitForReplication(
-                               __METHOD__, $options['transactionTicket']
-                       );
+                       $this->loadbalancerFactory->commitAndWaitForReplication( __METHOD__, $ticket );
                }
 
                foreach ( $updates as $update ) {
@@ -1616,8 +1615,8 @@ class DerivedPageDataUpdater implements IDBAccessObject {
                        }
 
                        if ( $options['defer'] === false ) {
-                               if ( $update instanceof DataUpdate && $options['transactionTicket'] !== null ) {
-                                       $update->setTransactionTicket( $options['transactionTicket'] );
+                               if ( $update instanceof DataUpdate && $ticket !== null ) {
+                                       $update->setTransactionTicket( $ticket );
                                }
                                $update->doUpdate();
                        } else {
index 866f041..c4fe858 100644 (file)
@@ -3480,6 +3480,7 @@ class Title implements LinkTarget, IDBAccessObject {
        /**
         * Move this page's subpages to be subpages of $nt
         *
+        * @deprecated since 1.34, use MovePage instead
         * @param Title $nt Move target
         * @param bool $auth Whether $wgUser's permissions should be checked
         * @param string $reason The reason for the move
@@ -3494,7 +3495,6 @@ class Title implements LinkTarget, IDBAccessObject {
        public function moveSubpages( $nt, $auth = true, $reason = '', $createRedirect = true,
                array $changeTags = []
        ) {
-               global $wgMaximumMovedPages;
                // Check permissions
                if ( !$this->userCan( 'move-subpages' ) ) {
                        return [
@@ -3514,46 +3514,21 @@ class Title implements LinkTarget, IDBAccessObject {
                        ];
                }
 
-               $subpages = $this->getSubpages( $wgMaximumMovedPages + 1 );
-               $retval = [];
-               $count = 0;
-               foreach ( $subpages as $oldSubpage ) {
-                       $count++;
-                       if ( $count > $wgMaximumMovedPages ) {
-                               $retval[$oldSubpage->getPrefixedText()] = [
-                                       [ 'movepage-max-pages', $wgMaximumMovedPages ],
-                               ];
-                               break;
-                       }
+               global $wgUser;
+               $mp = new MovePage( $this, $nt );
+               $method = $auth ? 'moveSubpagesIfAllowed' : 'moveSubpages';
+               $result = $mp->$method( $wgUser, $reason, $createRedirect, $changeTags );
 
-                       // We don't know whether this function was called before
-                       // or after moving the root page, so check both
-                       // $this and $nt
-                       if ( $oldSubpage->getArticleID() == $this->getArticleID()
-                               || $oldSubpage->getArticleID() == $nt->getArticleID()
-                       ) {
-                               // When moving a page to a subpage of itself,
-                               // don't move it twice
-                               continue;
-                       }
-                       $newPageName = preg_replace(
-                                       '#^' . preg_quote( $this->mDbkeyform, '#' ) . '#',
-                                       StringUtils::escapeRegexReplacement( $nt->getDBkey() ), # T23234
-                                       $oldSubpage->getDBkey() );
-                       if ( $oldSubpage->isTalkPage() ) {
-                               $newNs = $nt->getTalkPage()->getNamespace();
-                       } else {
-                               $newNs = $nt->getSubjectPage()->getNamespace();
-                       }
-                       # T16385: we need makeTitleSafe because the new page names may
-                       # be longer than 255 characters.
-                       $newSubpage = self::makeTitleSafe( $newNs, $newPageName );
+               if ( !$result->isOk() ) {
+                       return $result->getErrorsArray();
+               }
 
-                       $success = $oldSubpage->moveTo( $newSubpage, $auth, $reason, $createRedirect, $changeTags );
-                       if ( $success === true ) {
-                               $retval[$oldSubpage->getPrefixedText()] = $newSubpage->getPrefixedText();
+               $retval = [];
+               foreach ( $result->getValue() as $key => $status ) {
+                       if ( $status->isOK() ) {
+                               $retval[$key] = $status->getValue();
                        } else {
-                               $retval[$oldSubpage->getPrefixedText()] = $success;
+                               $retval[$key] = $status->getErrorsArray();
                        }
                }
                return $retval;
index 14f7603..505c9d5 100644 (file)
@@ -67,7 +67,7 @@ class RawAction extends FormlessAction {
 
                $contentType = $this->getContentType();
 
-               $maxage = $request->getInt( 'maxage', $config->get( 'SquidMaxage' ) );
+               $maxage = $request->getInt( 'maxage', $config->get( 'CdnMaxAge' ) );
                $smaxage = $request->getIntOrNull( 'smaxage' );
                if ( $smaxage === null ) {
                        if (
index 1a7175a..b845c57 100644 (file)
@@ -148,7 +148,7 @@ class ApiMain extends ApiBase {
        private $mContinuationManager;
        private $mAction;
        private $mEnableWrite;
-       private $mInternalMode, $mSquidMaxage;
+       private $mInternalMode, $mCdnMaxAge;
        /** @var ApiBase */
        private $mModule;
 
@@ -288,7 +288,7 @@ class ApiMain extends ApiBase {
                $this->mContinuationManager = null;
                $this->mEnableWrite = $enableWrite;
 
-               $this->mSquidMaxage = -1; // flag for executeActionWithErrorHandling()
+               $this->mCdnMaxAge = -1; // flag for executeActionWithErrorHandling()
                $this->mCommit = false;
        }
 
@@ -1368,18 +1368,20 @@ class ApiMain extends ApiBase {
                                                $ts->format( 'D M j H:i:s Y' ) === $value ||
                                                $ts->format( 'D M  j H:i:s Y' ) === $value
                                        ) {
+                                               $config = $this->getConfig();
                                                $lastMod = $module->getConditionalRequestData( 'last-modified' );
                                                if ( $lastMod !== null ) {
                                                        // Mix in some MediaWiki modification times
                                                        $modifiedTimes = [
                                                                'page' => $lastMod,
                                                                'user' => $this->getUser()->getTouched(),
-                                                               'epoch' => $this->getConfig()->get( 'CacheEpoch' ),
+                                                               'epoch' => $config->get( 'CacheEpoch' ),
                                                        ];
-                                                       if ( $this->getConfig()->get( 'UseSquid' ) ) {
+
+                                                       if ( $config->get( 'UseCdn' ) ) {
                                                                // T46570: the core page itself may not change, but resources might
                                                                $modifiedTimes['sepoch'] = wfTimestamp(
-                                                                       TS_MW, time() - $this->getConfig()->get( 'SquidMaxage' )
+                                                                       TS_MW, time() - $config->get( 'CdnMaxAge' )
                                                                );
                                                        }
                                                        Hooks::run( 'OutputPageCheckLastModified', [ &$modifiedTimes, $this->getOutput() ] );
index cc4490e..89ecc43 100644 (file)
@@ -201,22 +201,22 @@ class ApiMove extends ApiBase {
        public function moveSubpages( $fromTitle, $toTitle, $reason, $noredirect, $changeTags = [] ) {
                $retval = [];
 
-               $success = $fromTitle->moveSubpages( $toTitle, true, $reason, !$noredirect, $changeTags );
-               if ( isset( $success[0] ) ) {
-                       $status = $this->errorArrayToStatus( $success );
-                       return [ 'errors' => $this->getErrorFormatter()->arrayFromStatus( $status ) ];
+               $mp = new MovePage( $fromTitle, $toTitle );
+               $result =
+                       $mp->moveSubpagesIfAllowed( $this->getUser(), $reason, !$noredirect, $changeTags );
+               if ( !$result->isOk() ) {
+                       // This means the whole thing failed
+                       return [ 'errors' => $this->getErrorFormatter()->arrayFromStatus( $result ) ];
                }
 
                // At least some pages could be moved
                // Report each of them separately
-               foreach ( $success as $oldTitle => $newTitle ) {
+               foreach ( $result->getValue() as $oldTitle => $status ) {
                        $r = [ 'from' => $oldTitle ];
-                       if ( is_array( $newTitle ) ) {
-                               $status = $this->errorArrayToStatus( $newTitle );
-                               $r['errors'] = $this->getErrorFormatter()->arrayFromStatus( $status );
+                       if ( $status->isOK() ) {
+                               $r['to'] = $status->getValue();
                        } else {
-                               // Success
-                               $r['to'] = $newTitle;
+                               $r['errors'] = $this->getErrorFormatter()->arrayFromStatus( $status );
                        }
                        $retval[] = $r;
                }
index f526685..8edf00c 100644 (file)
@@ -135,7 +135,7 @@ class ApiQueryProtectedTitles extends ApiQueryGeneratorBase {
 
                                if ( isset( $prop['parsedcomment'] ) ) {
                                        $vals['parsedcomment'] = Linker::formatComment(
-                                               $commentStore->getComment( 'pt_reason', $row )->text, $titles
+                                               $commentStore->getComment( 'pt_reason', $row )->text
                                        );
                                }
 
index fc50289..ee6a264 100644 (file)
@@ -114,7 +114,7 @@ class ApiQueryRevisions extends ApiQueryRevisionsBase {
 
                if ( $revCount > 0 && $enumRevMode ) {
                        $this->dieWithError(
-                               [ 'apierror-revisions-nolist', $this->getModulePrefix() ], 'invalidparammix'
+                               [ 'apierror-revisions-norevids', $this->getModulePrefix() ], 'invalidparammix'
                        );
                }
 
@@ -389,6 +389,10 @@ class ApiQueryRevisions extends ApiQueryRevisionsBase {
 
                $this->addOption( 'LIMIT', $this->limit + 1 );
 
+               // T224017: `rev_timestamp` is never the correct index to use for this module, but
+               // MariaDB (10.1.37-39) sometimes insists on trying to use it anyway. Tell it not to.
+               $this->addOption( 'IGNORE INDEX', [ 'revision' => 'rev_timestamp' ] );
+
                $count = 0;
                $generated = [];
                $hookData = [];
index 912f026..fa4110e 100644 (file)
@@ -68,7 +68,7 @@
        "apihelp-edit-param-text": "Содржина на страницата.",
        "apihelp-edit-param-summary": "Опис на уредувањето. Ова е и назив на поднасловот кога не се зададени $1section=new и $1sectiontitle.",
        "apihelp-edit-param-tags": "Ознаки за измена што се однесуваат на преработката.",
-       "apihelp-edit-param-minor": "СиÑ\82но Ñ\83Ñ\80едÑ\83ваÑ\9aе.",
+       "apihelp-edit-param-minor": "Ð\9eзнаÑ\87и Ð³Ð¾ Ñ\83Ñ\80едÑ\83ваÑ\9aево ÐºÐ°ÐºÐ¾ Ñ\81иÑ\82но.",
        "apihelp-edit-param-notminor": "Неситно уредување.",
        "apihelp-edit-param-bot": "Означи го уредувањето како ботовско.",
        "apihelp-edit-param-basetimestamp": "Датум и време на преработката на базата, кои се користат за утврдување на спротиставености во уредувањето. Може да се добие преку [[Special:ApiHelp/query+revisions|action=query&prop=revisions&rvprop=timestamp]].",
index 788eec3..bb84f97 100644 (file)
@@ -108,14 +108,15 @@ class LocalisationCache {
         */
        public static $allKeys = [
                'fallback', 'namespaceNames', 'bookstoreList',
-               'magicWords', 'messages', 'rtl', 'capitalizeAllNouns', 'digitTransformTable',
-               'separatorTransformTable', 'minimumGroupingDigits',
-               'fallback8bitEncoding', 'linkPrefixExtension',
-               'linkTrail', 'linkPrefixCharset', 'namespaceAliases',
-               'dateFormats', 'datePreferences', 'datePreferenceMigrationMap',
-               'defaultDateFormat', 'extraUserToggles', 'specialPageAliases',
-               'imageFiles', 'preloadedMessages', 'namespaceGenderAliases',
-               'digitGroupingPattern', 'pluralRules', 'pluralRuleTypes', 'compiledPluralRules',
+               'magicWords', 'messages', 'rtl', 'capitalizeAllNouns',
+               'digitTransformTable', 'separatorTransformTable',
+               'minimumGroupingDigits', 'fallback8bitEncoding',
+               'linkPrefixExtension', 'linkTrail', 'linkPrefixCharset',
+               'namespaceAliases', 'dateFormats', 'datePreferences',
+               'datePreferenceMigrationMap', 'defaultDateFormat',
+               'specialPageAliases', 'imageFiles', 'preloadedMessages',
+               'namespaceGenderAliases', 'digitGroupingPattern', 'pluralRules',
+               'pluralRuleTypes', 'compiledPluralRules',
        ];
 
        /**
@@ -129,7 +130,7 @@ class LocalisationCache {
        /**
         * Keys for items which are a numbered array.
         */
-       public static $mergeableListKeys = [ 'extraUserToggles' ];
+       public static $mergeableListKeys = [];
 
        /**
         * Keys for items which contain an array of arrays of equivalent aliases
index 75f51ef..6b5482c 100644 (file)
@@ -150,7 +150,7 @@ class SquidPurgeClient {
                        if ( IP::isIPv4( $this->host ) ) {
                                $this->ip = $this->host;
                        } elseif ( IP::isIPv6( $this->host ) ) {
-                               throw new MWException( '$wgSquidServers does not support IPv6' );
+                               throw new MWException( '$wgCdnServers does not support IPv6' );
                        } else {
                                Wikimedia\suppressWarnings();
                                $this->ip = gethostbyname( $this->host );
index bbcd33a..72c7643 100644 (file)
 namespace MediaWiki\Logger;
 
 use DateTimeZone;
+use Error;
 use Exception;
 use WikiMap;
 use MWDebug;
 use MWExceptionHandler;
 use Psr\Log\AbstractLogger;
 use Psr\Log\LogLevel;
+use Throwable;
 use UDPTransport;
 
 /**
@@ -269,7 +271,7 @@ class LegacyLogger extends AbstractLogger {
                        $e = $context['exception'];
                        $backtrace = false;
 
-                       if ( $e instanceof Exception ) {
+                       if ( $e instanceof Throwable || $e instanceof Exception ) {
                                $backtrace = MWExceptionHandler::getRedactedTrace( $e );
 
                        } elseif ( is_array( $e ) && isset( $e['trace'] ) ) {
@@ -405,8 +407,9 @@ class LegacyLogger extends AbstractLogger {
                        return $item->format( 'c' );
                }
 
-               if ( $item instanceof Exception ) {
-                       return '[Exception ' . get_class( $item ) . '( ' .
+               if ( $item instanceof Throwable || $item instanceof Exception ) {
+                       $which = $item instanceof Error ? 'Error' : 'Exception';
+                       return '[' . $which . ' ' . get_class( $item ) . '( ' .
                                $item->getFile() . ':' . $item->getLine() . ') ' .
                                $item->getMessage() . ']';
                }
index 8537d71..d0748bc 100644 (file)
 
 namespace MediaWiki\Logger\Monolog;
 
+use Error;
 use Exception;
 use Monolog\Formatter\LineFormatter as MonologLineFormatter;
 use MWExceptionHandler;
+use Throwable;
 
 /**
  * Formats incoming records into a one-line string.
@@ -32,7 +34,7 @@ use MWExceptionHandler;
  * excluded from '%context%' output if the '%exception%' placeholder is
  * present.
  *
- * Exceptions that are logged with this formatter will optional have their
+ * Throwables that are logged with this formatter will optional have their
  * stack traces appended. If that is done, MWExceptionHandler::redactedTrace()
  * will be used to redact the trace information.
  *
@@ -75,7 +77,7 @@ class LineFormatter extends MonologLineFormatter {
                        $e = $record['context']['exception'];
                        unset( $record['context']['exception'] );
 
-                       if ( $e instanceof Exception ) {
+                       if ( $e instanceof Throwable || $e instanceof Exception ) {
                                $prettyException = $this->normalizeException( $e );
                        } elseif ( is_array( $e ) ) {
                                $prettyException = $this->normalizeExceptionArray( $e );
@@ -93,9 +95,9 @@ class LineFormatter extends MonologLineFormatter {
        }
 
        /**
-        * Convert an Exception to a string.
+        * Convert a Throwable to a string.
         *
-        * @param Exception $e
+        * @param Exception|Throwable $e
         * @return string
         */
        protected function normalizeException( $e ) {
@@ -103,12 +105,12 @@ class LineFormatter extends MonologLineFormatter {
        }
 
        /**
-        * Convert an exception to an array of structured data.
+        * Convert a throwable to an array of structured data.
         *
-        * @param Exception $e
+        * @param Exception|Throwable $e
         * @return array
         */
-       protected function exceptionAsArray( Exception $e ) {
+       protected function exceptionAsArray( $e ) {
                $out = [
                        'class' => get_class( $e ),
                        'message' => $e->getMessage(),
@@ -127,7 +129,7 @@ class LineFormatter extends MonologLineFormatter {
        }
 
        /**
-        * Convert an array of Exception data to a string.
+        * Convert an array of Throwable data to a string.
         *
         * @param array $e
         * @return string
@@ -142,7 +144,8 @@ class LineFormatter extends MonologLineFormatter {
                ];
                $e = array_merge( $defaults, $e );
 
-               $str = "\n[Exception {$e['class']}] (" .
+               $which = is_a( $e['class'], Error::class, true ) ? 'Error' : 'Exception';
+               $str = "\n[$which {$e['class']}] (" .
                        "{$e['file']}:{$e['line']}) {$e['message']}";
 
                if ( $this->includeStacktraces && $e['trace'] ) {
@@ -154,7 +157,8 @@ class LineFormatter extends MonologLineFormatter {
                        $prev = $e['previous'];
                        while ( $prev ) {
                                $prev = array_merge( $defaults, $prev );
-                               $str .= "\nCaused by: [Exception {$prev['class']}] (" .
+                               $which = is_a( $prev['class'], Error::class, true ) ? 'Error' : 'Exception';
+                               $str .= "\nCaused by: [$which {$prev['class']}] (" .
                                        "{$prev['file']}:{$prev['line']}) {$prev['message']}";
 
                                if ( $this->includeStacktraces && $prev['trace'] ) {
index 2d07f75..66ce9a3 100644 (file)
@@ -79,14 +79,14 @@ class CdnCacheUpdate implements DeferrableUpdate, MergeableUpdate {
        }
 
        /**
-        * Purges a list of CDN nodes defined in $wgSquidServers.
+        * Purges a list of CDN nodes defined in $wgCdnServers.
         * $urlArr should contain the full URLs to purge as values
         * (example: $urlArr[] = 'http://my.host/something')
         *
         * @param string[] $urlArr List of full URLs to purge
         */
        public static function purge( array $urlArr ) {
-               global $wgSquidServers, $wgHTCPRouting;
+               global $wgCdnServers, $wgHTCPRouting;
 
                if ( !$urlArr ) {
                        return;
@@ -120,20 +120,20 @@ class CdnCacheUpdate implements DeferrableUpdate, MergeableUpdate {
                }
 
                // Do direct server purges if enabled (this does not scale very well)
-               if ( $wgSquidServers ) {
-                       // Maximum number of parallel connections per squid
-                       $maxSocketsPerSquid = 8;
+               if ( $wgCdnServers ) {
+                       // Maximum number of parallel connections per CDN
+                       $maxSocketsPerCdn = 8;
                        // Number of requests to send per socket
                        // 400 seems to be a good tradeoff, opening a socket takes a while
                        $urlsPerSocket = 400;
-                       $socketsPerSquid = ceil( count( $urlArr ) / $urlsPerSocket );
-                       if ( $socketsPerSquid > $maxSocketsPerSquid ) {
-                               $socketsPerSquid = $maxSocketsPerSquid;
+                       $socketsPerCdn = ceil( count( $urlArr ) / $urlsPerSocket );
+                       if ( $socketsPerCdn > $maxSocketsPerCdn ) {
+                               $socketsPerCdn = $maxSocketsPerCdn;
                        }
 
                        $pool = new SquidPurgeClientPool;
-                       $chunks = array_chunk( $urlArr, ceil( count( $urlArr ) / $socketsPerSquid ) );
-                       foreach ( $wgSquidServers as $server ) {
+                       $chunks = array_chunk( $urlArr, ceil( count( $urlArr ) / $socketsPerCdn ) );
+                       foreach ( $wgCdnServers as $server ) {
                                foreach ( $chunks as $chunk ) {
                                        $client = new SquidPurgeClient( $server );
                                        foreach ( $chunk as $url ) {
index f5be83f..5042028 100644 (file)
@@ -1062,10 +1062,10 @@ class HTMLForm extends ContextSource {
        }
 
        /**
-        * Set whether the HTML form can be collapsed.
+        * Enable collapsible mode, and set whether the form is collapsed by default.
         *
         * @since 1.34
-        * @param bool $collapsedByDefault (optional) whether the form is collapsed by default
+        * @param bool $collapsedByDefault Whether the form is collapsed by default (optional).
         * @return HTMLForm $this for chaining calls
         */
        public function setCollapsibleOptions( $collapsedByDefault = false ) {
index 8dec566..fc299fb 100644 (file)
@@ -70,9 +70,9 @@
        "config-wincache": "[https://www.iis.net/downloads/microsoft/wincache-extension WinCache] er installert",
        "config-no-cache-apcu": "<strong>Advarsel:</strong> Kunne ikke finne [https://www.php.net/apcu APCu] eller [https://www.iis.net/downloads/microsoft/wincache-extension WinCache].\nObjekthurtiglagring er ikke aktivert.",
        "config-mod-security": "'''Advarsel''': Din web-tjener har [https://modsecurity.org/ mod_security] påslått. Hvis denne er feilinnstilt, kan det gi problemer for MediaWiki eller annen programvare som tillater brukere å poste vilkårlig innhold.\nSjekk [https://modsecurity.org/documentation/ mod_security-dokumentasjonen] eller ta kontakt med din nettleverandør hvis du opplever tilfeldige feil.",
-       "config-diff3-bad": "GNU diff3 ikke funnet.",
+       "config-diff3-bad": "GNU diff3 ikke funnet. Du kan ignorere dette for øyeblikket, men du kan støte på redigeringskonflikter oftere.",
        "config-git": "Har funnet Git version control software: <code>$1</code>.",
-       "config-git-bad": "Git version control software ble ikke funnet.",
+       "config-git-bad": "Git version control software ble ikke funnet. Du kan ignorere dette for øyeblikket. Merk at Special:Version ikke vil vise hashverdien for commits.",
        "config-imagemagick": "Fant ImageMagick: <code>$1</code>.\nBildeminiatyrisering vil aktiveres om du aktiverer opplastinger.",
        "config-gd": "Fant innebygd GD-grafikkbibliotek.\nBildeminiatyrisering vil aktiveres om du aktiverer opplastinger.",
        "config-no-scaling": "Kunne ikke finne GD-bibliotek eller ImageMagick.\nBildeminiatyrisering vil være deaktivert.",
        "config-using-32bit": "<strong>Adversel:</strong> Systemet ditt ser ut til å være 32-bit-basert, mens dette er [https://www.mediawiki.org/wiki/Special:MyLanguage/Manual:32-bit not advised].",
        "config-db-type": "Databasetype:",
        "config-db-host": "Databasevert:",
-       "config-db-host-help": "Hvis databasen kjører på en annen tjenermaskin, skriv inn vertsnavnet eller IP-adressen her.\n\nHvis du bruker et webhotell, vil du kunne be om aktuelt vertsnavn fra din leverandør.\n\nHvis du installerer på en Windowstjener og bruker MySQL, kan det hende at «localhost» ikke brukes som tjenernavn. Hvis så er tilfelle, prøv «127.0.0.1» som lokal IP-adresse.\n\nHvis du bruker PostgreSQL, la dette feltet være blankt slik at koplingen gjøres via en \"Unix socket\".",
+       "config-db-host-help": "Hvis databasen kjører på en annen tjenermaskin, skriv inn vertsnavnet eller IP-adressen her.\n\nHvis du bruker et webhotell, vil du kunne be om aktuelt vertsnavn fra din leverandør.\n\nHvis du bruker MySQL, kan det hende at «localhost» ikke brukes som tjenernavn. Hvis så er tilfelle, prøv «127.0.0.1» som lokal IP-adresse.\n\nHvis du bruker PostgreSQL, la dette feltet være blankt slik at koplingen gjøres via en \"Unix socket\".",
        "config-db-host-oracle": "Database TNS:",
        "config-db-host-oracle-help": "Skriv inn et gyldig [http://download.oracle.com/docs/cd/B28359_01/network.111/b28317/tnsnames.htm Local Connect Name]; en tnsnames.ora-fil må være synlig for installasjonsprosessen.<br />Hvis du bruker klientbibliotek 10g eller nyere kan du også bruke navngivingsmetoden [http://download.oracle.com/docs/cd/E11882_01/network.112/e10836/naming.htm Easy Connect].",
        "config-db-wiki-settings": "Identifiser denne wikien",
-       "config-db-name": "Databasenavn:",
+       "config-db-name": "Databasenavn (ingen bindestreker):",
        "config-db-name-help": "Velg et navn som identifiserer wikien din.\nDet bør ikke inneholde mellomrom.\n\nHvis du bruker en delt nettvert vil verten din enten gi deg et spesifikt databasenavn å bruke, eller la deg opprette databaser via kontrollpanelet.",
        "config-db-name-oracle": "Databaseskjema:",
        "config-db-account-oracle-warn": "Det finnes tre mulig fremgangsmåter for å installere Oracle som database:\n\nHvis du ønsker å opprette en databasekonto som del av installasjonsprosessen, oppgi da en konto med SYSDBA-rolle som databasekonto for installasjonen og angi påkrevd autentiseringsinformasjon for web-aksesskontoen. Ellers kan du enten opprette web-aksesskontoen manuelt eller kun oppgi den kontoen (hvis den har påkrevede tillatelser for å opprette skjemeobjektene) , alternativt oppgi to ulike kontoer, en med opprettelsesprivilegier (create) og en begrenset konto for web-aksess.\n\nSkript for å opprette en konto med påkrevde privilegier finnes i \"maintenance/oracle/\"-folderen av denne installasjonen. Husk at det å bruke en begrenset konto vil blokkere all vedlikeholdsfunksjonalitet med standard konto.",
        "config-db-account-lock": "Bruk det samme brukernavnet og passordet under normal drift",
        "config-db-wiki-account": "Brukerkonto for normal drift",
        "config-db-wiki-help": "Skriv inn brukernavnet og passordet som vil bli brukt til å koble til databasen under normal wikidrift.\nHvis kontoen ikke finnes, og installasjonskontoen har tilstrekkelige privilegier, vil denne brukerkontoen bli opprettet med et minimum av privilegier, tilstrekkelig for å operere wikien.",
-       "config-db-prefix": "Databasetabellprefiks:",
+       "config-db-prefix": "Databasetabellprefiks (ingen bindestreker):",
        "config-db-prefix-help": "Hvis du trenger å dele en database mellom flere wikier, eller mellom MediaWiki og andre nettapplikasjoner, kan du velge å legge til et prefiks til alle tabellnavnene for å unngå konflikter.\nIkke bruk mellomrom.\n\nDette feltet er vanligvis tomt.",
        "config-mysql-old": "MySQL $1 eller senere kreves, du har $2.",
        "config-db-port": "Databaseport:",
-       "config-db-schema": "Skjema for MediaWiki",
+       "config-db-schema": "Skjema for MediaWiki (ingen bindestreker):",
        "config-db-schema-help": "Dette skjemaet er som regel riktig.\nBare endre det hvis du vet at du trenger det.",
        "config-pg-test-error": "Får ikke kontakt med database '''$1''': $2",
        "config-sqlite-dir": "SQLite datamappe:",
        "config-invalid-db-server-oracle": "Ugyldig database-TNS «$1».\nBruk enten \"TNS Name\" eller en \"Easy Connect\"-streng ([http://docs.oracle.com/cd/E11882_01/network.112/e10836/naming.htm Oracle Naming Methods])",
        "config-invalid-db-name": "Ugyldig databasenavn «$1».\nBruk bare ASCII-bokstaver (a-z, A-Z), tall (0-9), undestreker (_) og bindestreker (-).",
        "config-invalid-db-prefix": "Ugyldig databaseprefiks «$1».\nBruk bare ASCII-bokstaver (a-z, A-Z), tall (0-9), undestreker (_) og bindestreker (-).",
-       "config-connection-error": "$1.\n\nSjekk verten, brukernavnet og passordet nedenfor og prøv igjen.",
+       "config-connection-error": "$1.\n\nSjekk verten, brukernavnet og passordet nedenfor og prøv igjen. Hvis du brukte «localhost» som databasevert, prøv å bruke «127.0.0.1» i stedet (eller motsatt).",
        "config-invalid-schema": "Ugyldig skjema for MediaWiki «$1».\nBruk bare ASCII-bokstaver (a-z, A-Z), tall (0-9) og undestreker (_).",
        "config-db-sys-create-oracle": "Installasjonsprogrammet støtter kun bruk av en SYSDBA-konto for opprettelse av en ny konto.",
        "config-db-sys-user-exists-oracle": "Brukerkontoen «$1» finnes allerede. SYSDBA kan kun brukes for oppretting av nye kontoer!",
        "config-sqlite-cant-create-db": "Kunne ikke opprette databasefilen <code>$1</code>.",
        "config-sqlite-fts3-downgrade": "PHP mangler FTS3-støtte, nedgraderer tabeller",
        "config-can-upgrade": "Det er MediaWiki-tabeller i denne databasen.\nFor å oppgradere dem til MediaWiki $1, klikk '''Fortsett'''.",
+       "config-upgrade-error": "En feil oppsto under oppgradering av MediaWiki-tabeller i databasen din.\n\nFor mer informasjon, se på loggen ovenfor; klikk <strong>Fortsett</strong> for å prøve igjen.",
        "config-upgrade-done": "Oppgradering fullført.\n\nDu kan nå [$1 begynne å bruke wikien din].\n\nHvis du ønsker å regenerere <code>LocalSettings.php</code>-filen din, klikk på knappen nedenfor.\nDette er '''ikke anbefalt''' med mindre du har problemer med wikien din.",
        "config-upgrade-done-no-regenerate": "Oppgradering fullført.\n\nDu kan nå [$1 begynne å bruke wikien din].",
        "config-regenerate": "Regenerer LocalSettings.php →",
        "config-install-done": "<strong>Gratulrerer!</strong>\nDu har lykkes i å installere MediaWiki.\n\nInstallasjonsprogrammet har generert en <code>LocalSettings.php</code>-fil.\nDen inneholder alle dine konfigureringer.\n\nDu må laste den ned og legge den på hovedfolderen for din wiki-installasjon (der index.php ligger). Nedlastingen skulle ha startet automatisk.\n\nHvis ingen nedlasting ble tilbudt, eller du avbrøt den, kan du få den i gang ved å klikke på lenken under:\n\n$3\n\n<strong>OBS:</strong> Hvis du ikke gjør dette nå, vil den genererte konfigurasjonsfilen ikke være tilgjengelig for deg senere.\n\nNår dette er gjort, kan du <strong>[$2 gå inn i wikien]</strong>.",
        "config-install-done-path": "<strong>Gratulerer!</strong>\nDu har installert MediaWiki.\n\nInstallereren har generert en <code>LocalSettings.php</code>-fil.\nDen inneholder all konfigurasjonen for wikien.\n\nDu må laste den ned og legge den i <code>$4</code>. Nedlastingen skal ha startet automatisk.\n\nOm nedlastingen ikke ble startet, eller om du avbrøt den, kan du starte på nytt ved å klikke lenken nedenfor:\n\n$3\n\n<strong>Merk:</strong> Om du ikke gjør dette nå vil den genererte konfigurasjonen ikke være tilgjengelig senere.\n\nNår dette er gjort kan du <strong>[$2 gå til wikien din]</strong>.",
        "config-install-success": "MediaWiki har blitt installert. Du kan nå\nbesøke <$1$2> for å se wikien din.\nOm du har spørsmål, sjekk de ofte stilte spørsmålene:\n<https://www.mediawiki.org/wiki/Special:MyLanguage/Manual:FAQ> eller bruk et av\nsupportforumene som lenkes til fra den siden.",
+       "config-install-db-success": "Databasen ble satt opp",
        "config-download-localsettings": "Last ned <code>LocalSettings.php</code>",
        "config-help": "hjelp",
        "config-help-tooltip": "klikk for å utvide",
index b1c805b..a0b6e07 100644 (file)
@@ -280,8 +280,7 @@ class RefreshLinksJob extends Job {
                        // Carry over cause so the update can do extra logging
                        'causeAction' => $this->params['causeAction'],
                        'causeAgent' => $this->params['causeAgent'],
-                       'defer' => false,
-                       'transactionTicket' => $ticket,
+                       'transactionTicket' => $ticket
                ];
                if ( !empty( $this->params['triggeringUser'] ) ) {
                        $userInfo = $this->params['triggeringUser'];
index b18088f..1ba6d99 100644 (file)
@@ -496,18 +496,6 @@ class DefaultPreferencesFactory implements PreferencesFactory {
                        }
                }
 
-               // Stuff from Language::getExtraUserToggles()
-               // FIXME is this dead code? $extraUserToggles doesn't seem to be defined for any language
-               $toggles = $this->contLang->getExtraUserToggles();
-
-               foreach ( $toggles as $toggle ) {
-                       $defaultPreferences[$toggle] = [
-                               'type' => 'toggle',
-                               'section' => 'personal/i18n',
-                               'label-message' => "tog-$toggle",
-                       ];
-               }
-
                // show a preview of the old signature first
                $oldsigWikiText = MediaWikiServices::getInstance()->getParser()->preSaveTransform(
                        '~~~',
index 53ed133..66a4edf 100644 (file)
@@ -504,10 +504,11 @@ abstract class ResourceLoaderModule implements LoggerAwareInterface {
                                        'md_skin' => $vary,
                                        'md_deps' => $deps,
                                ],
-                               [ 'md_module', 'md_skin' ],
+                               [ [ 'md_module', 'md_skin' ] ],
                                [
                                        'md_deps' => $deps,
-                               ]
+                               ],
+                               __METHOD__
                        );
 
                        if ( $dbw->trxLevel() ) {
index 4e541c9..8c6ad2d 100644 (file)
@@ -45,7 +45,7 @@ class SpecialBlockList extends SpecialPage {
                $this->outputHeader();
                $out = $this->getOutput();
                $out->setPageTitle( $this->msg( 'ipblocklist' ) );
-               $out->addModuleStyles( [ 'mediawiki.special', 'mediawiki.special.blocklist' ] );
+               $out->addModuleStyles( [ 'mediawiki.special' ] );
 
                $request = $this->getRequest();
                $par = $request->getVal( 'ip', $par );
index 4adc247..ed83aaf 100644 (file)
@@ -290,6 +290,7 @@ class SpecialSearch extends SpecialPage {
                }
 
                $out = $this->getOutput();
+               $widgetOptions = $this->getConfig()->get( 'SpecialSearchFormOptions' );
                $formWidget = new MediaWiki\Widget\Search\SearchFormWidget(
                        $this,
                        $this->searchConfig,
@@ -308,7 +309,7 @@ class SpecialSearch extends SpecialPage {
                        // only do the form render here for the empty $term case. Rendering
                        // the form when a search is provided is repeated below.
                        $out->addHTML( $formWidget->render(
-                               $this->profile, $term, 0, 0, $this->offset, $this->isPowerSearch()
+                               $this->profile, $term, 0, 0, $this->offset, $this->isPowerSearch(), $widgetOptions
                        ) );
                        return;
                }
@@ -365,7 +366,7 @@ class SpecialSearch extends SpecialPage {
                // start rendering the page
                $out->enableOOUI();
                $out->addHTML( $formWidget->render(
-                       $this->profile, $term, $num, $totalRes, $this->offset, $this->isPowerSearch()
+                       $this->profile, $term, $num, $totalRes, $this->offset, $this->isPowerSearch(), $widgetOptions
                ) );
 
                // did you mean... suggestions
index ea55568..8f31f3e 100644 (file)
@@ -513,7 +513,7 @@ class ImageListPager extends TablePager {
                                return $this->getLanguage()->formatNum( intval( $value ) + 1 );
                        case 'top':
                                // Messages: listfiles-latestversion-yes, listfiles-latestversion-no
-                               return $this->msg( 'listfiles-latestversion-' . $value );
+                               return $this->msg( 'listfiles-latestversion-' . $value )->escaped();
                        default:
                                throw new MWException( "Unknown field '$field'" );
                }
index d4ffed2..2f0c23d 100644 (file)
@@ -14,6 +14,7 @@ class SearchInputWidget extends TitleInputWidget {
        protected $validateTitle = false;
        protected $highlightFirst = false;
        protected $dataLocation = 'header';
+       protected $showDescriptions = false;
 
        /**
         * @param array $config Configuration options
@@ -41,6 +42,10 @@ class SearchInputWidget extends TitleInputWidget {
                        $this->dataLocation = $config['dataLocation'];
                }
 
+               if ( !empty( $config['showDescriptions'] ) ) {
+                       $this->showDescriptions = true;
+               }
+
                // Initialization
                $this->addClasses( [ 'mw-widget-searchInputWidget' ] );
        }
@@ -58,6 +63,9 @@ class SearchInputWidget extends TitleInputWidget {
                if ( $this->dataLocation ) {
                        $config['dataLocation'] = $this->dataLocation;
                }
+               if ( $this->showDescriptions ) {
+                       $config['showDescriptions'] = true;
+               }
                $config['$overlay'] = true;
                return parent::getConfig( $config );
        }
index 7c28b5e..62ee9cb 100644 (file)
@@ -40,6 +40,7 @@ class SearchFormWidget {
         * @param int $totalResults The total estimated results found
         * @param int $offset Current offset in search results
         * @param bool $isPowerSearch Is the 'advanced' section open?
+        * @param array $options Widget options
         * @return string HTML
         */
        public function render(
@@ -48,7 +49,8 @@ class SearchFormWidget {
                $numResults,
                $totalResults,
                $offset,
-               $isPowerSearch
+               $isPowerSearch,
+               array $options = []
        ) {
                $user = $this->specialSearch->getUser();
 
@@ -63,7 +65,7 @@ class SearchFormWidget {
                                ]
                        ) .
                                '<div id="mw-search-top-table">' .
-                                       $this->shortDialogHtml( $profile, $term, $numResults, $totalResults, $offset ) .
+                                       $this->shortDialogHtml( $profile, $term, $numResults, $totalResults, $offset, $options ) .
                                '</div>' .
                                "<div class='mw-search-visualclear'></div>" .
                                "<div class='mw-search-profile-tabs'>" .
@@ -81,12 +83,20 @@ class SearchFormWidget {
         * @param int $numResults The number of results shown
         * @param int $totalResults The total estimated results found
         * @param int $offset Current offset in search results
+        * @param array $options Widget options
         * @return string HTML
         */
-       protected function shortDialogHtml( $profile, $term, $numResults, $totalResults, $offset ) {
+       protected function shortDialogHtml(
+               $profile,
+               $term,
+               $numResults,
+               $totalResults,
+               $offset,
+               array $options = []
+       ) {
                $html = '';
 
-               $searchWidget = new SearchInputWidget( [
+               $searchWidget = new SearchInputWidget( $options + [
                        'id' => 'searchText',
                        'name' => 'search',
                        'autofocus' => trim( $term ) === '',
index 2262fa7..6c8b19e 100644 (file)
@@ -814,7 +814,8 @@ class Language {
         * @return array
         */
        public function getExtraUserToggles() {
-               return (array)self::$dataCache->getItem( $this->mCode, 'extraUserToggles' );
+               wfDeprecated( __METHOD__, '1.34' );
+               return [];
        }
 
        /**
index 4af0bd4..52d5c06 100644 (file)
        "tog-hideminor": "Sungkupakan babakan sapalih dalam paubahan pahanyarnya",
        "tog-hidepatrolled": "Sungkupakan babakan taawasi dalam paubahan pahanyarnya",
        "tog-newpageshidepatrolled": "Sungkupakan tungkaran nang diitihi matan daptar tungkaran hanyar",
-       "tog-hidecategorization": "Patak tumbungnya tungkaran",
+       "tog-hidecategorization": "Tukupakan pamilahan halaman",
        "tog-extendwatchlist": "Singkaiakan daptar itihan hagan manampaiakan samunyaan paubahan, kada nang hanyar haja.",
-       "tog-usenewrc": "Garumbungakan babakan di tampilan paubahan pahanyarnya wan daptar itihan badasar tungkaran",
+       "tog-usenewrc": "Galambangakan babakan di tampilan paubahan pahanyarnya wan daptar itihan badasar halaman",
        "tog-numberheadings": "Bari numur judul utumatis",
-       "tog-editondblclick": "Babak tungkaran wan dua kali klik",
+       "tog-editondblclick": "Babak halaman wan dua kali kalik",
        "tog-editsectiononrightclick": "Kawa'akan mambabak sub-hagian lawan mang-klik kanan pada judul hagian",
-       "tog-watchcreations": "Tambahi tungkaran nang ulun ulah ka daptar itihan",
-       "tog-watchdefault": "Tambahi tungkaran nang ulun babak ka daptar itihan ulun",
-       "tog-watchmoves": "Tambahi tungkaran nang ulun pindah ka daptar itihan ulun",
-       "tog-watchdeletion": "Tambahi tungkaran nang ulun hapus ka daptar itihan ulun",
+       "tog-watchcreations": "Tambahi halaman nang ulun ulah ka daptar itihan",
+       "tog-watchdefault": "Tambahi halaman nang ulun babak ka daptar itihan ulun",
+       "tog-watchmoves": "Tambahi halaman nang ulun pindah ka daptar itihan ulun",
+       "tog-watchdeletion": "Tambahi halaman nang ulun hapus ka daptar itihan ulun",
        "tog-watchuploads": "Tambahi barakas hanyar nang ulun unggah ka daptar itihan ulun",
-       "tog-watchrollback": "Tambahi tungkaran nang suah ulun bulikakan ka dalam daptar itihan ulun",
+       "tog-watchrollback": "Tambahi halaman nang suah ulun bulikakan ka dalam daptar itihan ulun",
        "tog-minordefault": "Tandai samunyaan babakan sawagai babakan sapalih sacara baku",
        "tog-previewontop": "Tampaiakan titilikan sabalum kutak babak",
        "tog-previewonfirst": "Tampaiakan titilikan pada babakan panambaian",
-       "tog-enotifwatchlistpages": "Kirimi ulun sur-él amun sabuting tungkaran dalam daptar itihan ulun baubah",
+       "tog-enotifwatchlistpages": "Kirimi ulun sur-él amun sabuting halaman dalam daptar itihan ulun baubah",
        "tog-enotifusertalkpages": "Surili ulun amun tungkaran pamandiran ulun baubah",
        "tog-enotifminoredits": "Kirimi ulun sur-él jua amun ada babakan sapalih",
        "tog-enotifrevealaddr": "Tampaiakan alamat sur-él ulun pada sur-él pamadahan",
        "tog-shownumberswatching": "Tampaiakan barapa pamakai nang maitihi",
        "tog-oldsig": "Tandateken nang sudah ada:",
        "tog-fancysig": "Tapsirakan tandatangan sawagai naskah wiki (kada batautan utumatis)",
-       "tog-uselivepreview": "Tampaiakan pratayang tanpa mamuat baasa tungkaran",
+       "tog-uselivepreview": "Tampaiakan titilikan tanpa mamuat baasa halaman",
        "tog-forceeditsummary": "Ingatakan ulun wayah babuat sabuting kasimpulan babakan puang",
        "tog-watchlisthideown": "Sungkupakan babakan ulun di daptar itihan",
        "tog-watchlisthidebots": "Sungkupakan babakan bot di daptar itihan",
        "category-file-count-limited": "Tumbung ngini baisi {{PLURAL:$1|barakas|$1 barakas}} barikut.",
        "listingcontinuesabbrev": "samb.",
        "index-category": "Tungkaran tasusun bapadalakan kata",
-       "noindex-category": "Tungkaran nang diindéks",
+       "noindex-category": "Halaman nang diindéks",
        "broken-file-category": "Tutungkaran lawan tatautan barakas pagat",
        "about": "Pasal",
        "article": "Tungkaran isi",
        "cancel": "Walangi",
        "moredotdotdot": "Lainnya...",
        "morenotlisted": "Daptar ngini mungkin kada langkap",
-       "mypage": "Tungkaran",
+       "mypage": "Halaman",
        "mytalk": "Pamandiran",
        "anontalk": "Pamandiran",
        "navigation": "Napigasi",
        "viewsource-title": "Tiringi asalmula matan $1",
        "actionthrottled": "Kalakuan dikiripi",
        "actionthrottledtext": "Pian dibatasi gasan manggawi tindakan ngini talalu banyak dalam waktu handap, wan Pian sudah limpua batas nang dibarii. Silahkan cuba baasa imbah babarapa manit.",
-       "protectedpagetext": "Tungkaran ngini sudah disunduk gasan mancagah babakan.",
+       "protectedpagetext": "Halaman ngini sudah disunduk gasan mancagah babakan.",
        "viewsourcetext": "Pian kawa manjanaki wan manyalin asal-mula halaman ngini.",
-       "viewyourtext": "Pian kawa maniringi wan manyalin asalmula matan '''babakan pian''' ka tungkaran ngini:",
-       "protectedinterface": "Tungkaran ngini manyadiakan naskah antarmuha gasan parangkat lunak, wan dilindungi tahadap panyalahpakaian. Gasan manambah atawa mambabak tarjamahan pada sabarataan wiki, muhun pakai [https://translatewiki.net translatewiki.net], pruyik palukalan MediaWiki.",
+       "viewyourtext": "Pian kawa manjanaki wan manyalin asalmula matan '''babakan pian''' ka halaman ngini:",
+       "protectedinterface": "Halaman ngini manyadiakan naskah antarmuha gasan parangkat lunak, wan dilindungi tahadap panyalahgunaan. Gasan manambah atawa mambabak tarjamahan pada sabarataan wiki, muhun pakai [https://translatewiki.net translatewiki.net], rangka-gawi palokalan MediaWiki.",
        "editinginterface": "'''Paringatan:''' Pian mambabak sabuting tungkaran nang dipuruk hagan manyadiakan naskah antarmuha gasan parangkat lunak.\nPaubahan ka tungkaran ngini akan bapangaruh matan tampaian antarmuha gasan pamakai lain.\nGasan tarjamahan, muhun pakai [https://translatewiki.net/wiki/Main_Page?setlang=bjn translatewiki.net], rangka gawian palokalan MediaWiki.",
-       "cascadeprotected": "Tungkaran ini sudah dilindungi matan pambabakan, maraga nangini tamasuk dalam {{PLURAL:$1|tungkaran|tutungkaran}} dudi nang dilindungi \"barénténg\": $2",
+       "cascadeprotected": "Halaman ini sudah dilindungi matan pambabakan, maraga nangini tamasuk dalam {{PLURAL:$1|halaman}} dudi nang dilindungi \"barénténg\": $2",
        "namespaceprotected": "Pian kada baisi ijin hagan mambabak tutungkaran dalam ngaran kamar '''$1'''.",
        "customcssprotected": "Pian kada baisi ijin mambabak tungkaran CSS ngini, karana ngini baisi setelan paribadi pamakai lain.",
        "customjsprotected": "Pian kada baisi ijin mambabak tungkaran JavaScript ngini, karana ngini baisi setelan paribadi pamakai lain.",
        "invalidtitle-knownnamespace": "Judul nang kada sah lawan ruang-ngaran \"$2\" wan teks \"$3\"",
        "invalidtitle-unknownnamespace": "Judul nang kada sah lawan numur ruang ngaran kada dikatahui $1 wan teks \"$2\"",
        "exception-nologin": "Balum babuat log",
-       "exception-nologin-text": "Silahkan babuat log gasan kawa maaksis tungkaran atau gawian ngini",
+       "exception-nologin-text": "Silahkan babuat log gasan kawa masuk ka halaman atau gawian ngini",
        "virus-badscanner": "Konpigurasi buruk: pamindai virus kada dipinandui: ''$1''",
        "virus-scanfailed": "Pamindaian gagal (kudi $1)",
        "virus-unknownscanner": "Antivirus kada dipinandui:",
-       "logouttext": "<strong>Pian wayahini kaluar log.</strong>\n\n\nIngatakan bahwa babarapa tungkaran mungkin masih manampaiakan pian kaya masih babuat log, sampai pian mambarasihi singgahan panjalajah pian.",
+       "logouttext": "<strong>Pian wayahini kaluar log.</strong>\n\nIngatakan bahwa babarapa halaman mungkin masih manampaiakan pian kaya masih babuat log, sampai Pian mambarasihi singgahan panjalajah pian.",
        "welcomeuser": "Salamat datang,  $1 !",
        "welcomecreation-msg": "Akun pian sudah diulah.\nPian kawa maubah [[Special:Preferences|preperensi]] {{SITENAME}} amun pian handak.",
        "yourname": "Ngaran pamakai:",
        "loginreqlink": "Babuat log",
        "loginreqpagetext": "Pian musti $1 hagan maniringi rungkaran-tungkaran lain.",
        "accmailtitle": "Katasunduk takirim.",
-       "accmailtext": "Sabuting katasunduk babarang gasan [[User talk:$1|$1]] sudah dikirim ka $2.\n\nKatasunduk gasan pamakai hanyar nangini kawa diubah di tungkaran ''[[Special:ChangePassword|ubah katasunduk]]'' imbah babuat log.",
+       "accmailtext": "Sabuting katasunduk babarang gasan [[User talk:$1|$1]] sudah dikirim ka $2.\n\nKatasunduk gasan pamakai hanyar nangini kawa diubah di halaman ''[[Special:ChangePassword|ubah katasunduk]]'' limbah babuat log.",
        "newarticle": "(Hanyar)",
        "newarticletext": "Pian maumpati tautan ka halaman nang balum tasadia. Amun handak maulah halaman itu, katiklah isi halaman di kutak di bawah ngini (janaki [$1 halaman patulung] gasan maklumat labih lanjut). Amun pian kada bakurinah sampai ka halaman ngini, kalik picikan <strong>back</strong> di panjalajah wéb Pian.",
-       "anontalkpagetext": "----''Ngini adalah tungkaran pamandiran gasan pamakai kada bangaran nang baluman ma-ulah akun pulang, atawa  kada mamakainya. Kami tapaksa mamakai numurik alamat IP hagan maminanduinya.\nAlamat IP nangkaini kawaai dipuruk ulih babarapa pamakai.\nAmun Pian adalah pamakai kada bangaran wan marasa kumin nang kada pas ta ka Pian, muhun [[Special:CreateAccount|ulah sabuah akun]] atawa [[Special:UserLogin|babuat log]] gasan mahindari kabingungan awan pamakai kada bangaran lain kaina.",
+       "anontalkpagetext": "----''Ngini adalah halaman pamandiran gasan pamakai kada bangaran nang baluman ma-ulah akun pulang, atawa  kada mamakainya. Kami tapaksa mamakai numurik alamat IP hagan maminanduinya.\nAlamat IP nangkaini kawaai dipuruk ulih babarapa pamakai.\nAmun Pian adalah pamakai kada bangaran wan marasa kumin nang kada pas ta ka Pian, muhun [[Special:CreateAccount|ulah sabuah akun]] atawa [[Special:UserLogin|babuat log]] gasan mahindari kabingungan awan pamakai kada bangaran lain kaina.",
        "noarticletext": "Damini kadada naskah di halaman ngini.\nPian kawa [[Special:Search/{{PAGENAME}}|mangikihi gasan judul halaman ngini]] di halaman lain, <span class=\"plainlinks\">[{{fullurl:{{#Special:Log}}|page={{FULLPAGENAMEE}}}} mancari log tarait], atawa [{{fullurl:{{FULLPAGENAME}}|action=edit}} maulah halaman ngini]</span>.",
        "noarticletext-nopermission": "Wayahini kadada naskah di halaman ngini.\nPian kawa [[Special:Search/{{PAGENAME}}|manggagai gasan judul halaman ngini]] di halaman lain, atawa <span class=\"plainlinks\">[{{fullurl:{{#Special:Log}}|page={{FULLPAGENAMEE}}}} manggagai log tarait]</span>, tagal Pian kada baisi ijin gasan maulah halaman ngini.",
        "userpage-userdoesnotexist": "Akun pamakai \"<nowiki>$1</nowiki>\" kada tadaptar.\nMuhun pariksa/ditukui amun Pian handak maulah/mambabak tungkaran ngini.",
        "userjspreview": "'''Ingatakan bahwasa Pian tis/manilik pamakai JavaScript Pian.'''\n'''Nangini baluman tasimpan pulang!'''",
        "sitecsspreview": "'''Ingatakan bahwasa Pian manilik CSS ini haja.'''\n'''Nangini lagi baluman tasimpan!'''",
        "sitejspreview": "'''Ingatakan bahwasa Pian manilik JavaScript code ini haja.'''\n'''Nangini lagi baluman tasimpan!'''",
-       "userinvalidconfigtitle": "'''Paringatan:''' Kadada kulimbit \"$1\".\nTungkaran-tungkaran .css, .json wan .js ulahan mamuruk aksara halus, cuntuh {{ns:user}}:Foo/vector.css sawagai tandingan {{ns:user}}:Foo/Vector.css.",
+       "userinvalidconfigtitle": "'''Paringatan:''' Kadada kulimbit \"$1\".\nhalaman .css, .json wan .js ulahan mamakai aksara halus, cuntuh {{ns:user}}:Foo/vector.css sabagai tandingan {{ns:user}}:Foo/Vector.css.",
        "updated": "(Dihanyarakan)",
        "note": "'''Catatan:'''",
        "previewnote": "'''Ingatakanlah bahwasa ngini titilikan haja''' Paubahan Pian baluman disimpan!",
        "readonlywarning": "'''Paringatan: Basis data disunduk gasan diharagu, jadinya Pian kada kawa manyimpan babakan Pian wayahini.'''\nPian mungkin bagusnya manyalin wan malikap naskah ka sabuah barakas naskah wan simpan ngini gasan kainah.\n\nPambakal nang manyunduk manjalasakan kaini: $1",
        "protectedpagewarning": "'''Paringatan: Tungkaran ngini sudah dilindungi nang akibatnya pamakai awan hak istimiwa pambakal nang kawa mambabak ini.'''\nLog masuk pauncitnya disadiakan di bawah gasan rujukan:",
        "semiprotectedpagewarning": "'''Catatan:''' Tungkaran ngini sudah dilindungi nang akibatnya pamakai tadaptar haja nang kawa mambabak.\nLog masuk pauncitnya disadiakan di bawah gasan rujukan:",
-       "cascadeprotectedwarning": "<strong>Paringatan:</strong> Tungkaran ngini dilindungi jadinya pamakai lawan [[Special:ListGroupRights|hak aksis batantu] wara nang kawa mambabaknya maraga ditransklusiakan dalam {{PLURAL:$1|tungkaran|tungkaran-tungkaran}} nang dilindungi barinting.",
+       "cascadeprotectedwarning": "<strong>Paringatan:</strong> Halaman ngini dilindungi jadinya pamakai lawan [[Special:ListGroupRights|hak aksis batantu]] wara nang kawa mambabaknya maraga ditransklusiakan dalam {{PLURAL:$1|halaman}} nang dilindungi barinting.",
        "titleprotectedwarning": "'''Paringatan: Tungkaran ngini sudah dilindungi nang akibatnya [[Special:ListGroupRights|hak khas]] diparluakan hagan maulah ngini.'''\nLog masuk pauncitnya disadiakan di bawah gasan rujukan:",
        "templatesused": "{{PLURAL:$1|Citakan|Citakan}} nang dipakai di halaman ngini:",
        "templatesusedpreview": "{{PLURAL:$1|Citakan|Cicitakan}} nang dipakai di titilikan ngini:",
        "defaultmessagetext": "Naskah baku pasan",
        "content-failed-to-parse": "Gagal manjabarakan isi $2 gasan model $1: $3",
        "invalid-content-data": "Data isi kada sah",
-       "content-not-allowed-here": "Isi \"$1\" kada diijinakan di tungkaran [[:$2]] di bagian \"$3\"",
+       "content-not-allowed-here": "Isi \"$1\" kada diijinakan di halaman [[:$2]] di palih \"$3\"",
        "content-model-wikitext": "teks wiki",
        "content-model-text": "teks polos",
        "content-model-javascript": "JavaScript",
        "parser-template-recursion-depth-warning": "Citakan batas kadalaman recursi limpuar ($1)",
        "language-converter-depth-warning": "Batas kadalaman pangonversi basa limpuar ($1)",
        "node-count-exceeded-category": "Tungkaran di mana node-count tarlalui",
-       "node-count-exceeded-warning": "Tungkaran malabihi jumlah node",
+       "node-count-exceeded-warning": "Halaman malabihi jumlah node",
        "expansion-depth-exceeded-category": "Tungkaran dimana kadalaman ikspansi talalui",
        "expansion-depth-exceeded-warning": "Tungkaran malabihi kadalaman ikspansi",
        "parser-unstrip-loop-warning": "Lingkaran unstrip taditiksi",
        "historysize": "($1 {{PLURAL:$1|bita|bibita}})",
        "historyempty": "kusung",
        "history-feed-title": "Riwayat ralatan",
-       "history-feed-description": "Riwayat ralatan gasan tungkaran ngini pada wiki",
+       "history-feed-description": "Riwayat ralatan gasan halaman ngini pada wiki",
        "history-feed-item-nocomment": "$1 wayah $2",
        "history-feed-empty": "Tungkaran nang diminta kadada.\nIni pinanya sudah dihapus matan wiki ini, atawa dingarani lain.\nCubai [[Special:Search|gagai di wiki ini]] gasan tungkaran hanyar bakarabat.",
        "rev-deleted-comment": "(kasimpulan babakan dibuang)",
        "stub-threshold-disabled": "Kada kawa-akan",
        "recentchangesdays": "Jumlah hari nang manampaiakan paubahan pahanyarnya:",
        "recentchangesdays-max": "Paling lawas $1 {{PLURAL:$1|hari|hahari}}",
-       "recentchangescount": "Rikinan babakan default gasan ditampaiakan di paubahan pahanyarnya, riwayat tungkaran, wan di tungkaran log:",
+       "recentchangescount": "Rikinan babakan standar gasan ditampaiakan di paubahan pahanyarnya, riwayat halaman, wan di halaman log:",
        "prefs-help-recentchangescount": "Rikinan paningginya: 1000",
        "savedprefs": "Kakatujuan Pian sudah ham disimpan.",
        "timezonelegend": "Waktu banua:",
        "badsiglength": "Tapak tangan Sampian talalu panjang. Jangan malabihi pada $1 {{PLURAL:$1|karakter|karakter}}.",
        "yourgender": "Kaya apa pian handak dijalasakan?",
        "gender-unknown": "Wayah manyambat pian, parangkat lunak pacangan mamakai kata netral wayah parlu",
-       "gender-male": "Inya (lakian) mambabak tungkaran wiki",
-       "gender-female": "Inya (binian) mambabak tungkaran wiki",
+       "gender-male": "Inya (lakian) mambabak halaman wiki",
+       "gender-female": "Inya (binian) mambabak halaman wiki",
        "prefs-help-gender": "Paraturan katujuan ngini opsional.\nParangkat lambik mamakai nilainya gasan maarahakan pian wan manyambat pian ka sabarataan pamakaian mamakai hiauan janis kalamin.\nInformasi nginji pacangan publik.",
        "email": "Suril",
        "prefs-help-realname": "Ngaran bujur adalah pilihan haja.\nAmun Pian mamilih manyadiakan ini, ini akan dipuruk gasan paminanduan kulihan gawian Pian.",
        "right-minoredit": "Tandai bababakan sawagai sapalih",
        "right-move": "Mamindahakan tungkaran",
        "right-move-subpages": "Ugahakan tutungkaran awan subtumgkaran-nya",
-       "right-move-rootuserpages": "Mamindahakan tungkaran utama pamakai",
+       "right-move-rootuserpages": "Mamindahakan halaman utama pamakai",
        "right-movefile": "Mamindahakan barakas",
        "right-suppressredirect": "Kada maulah paugahan matan tutungkaran asal mula parhatan tutungkan pindahan",
        "right-upload": "Unggahakan barakas",
        "right-editusercss": "Babak pamruk lain babarakas CSS",
        "right-edituserjson": "Mambabak barakas JSON pamakai lain",
        "right-edituserjs": "Mambabak barakas JS pamakai lain",
-       "right-rollback": "Mambulikakan hancap babakan pamakai pauncitnya nang mambabak tungkaran tartantu",
+       "right-rollback": "Mambulikakan hancap babakan pamakai pauncitnya nang mambabak halaman tartantu",
        "right-markbotedits": "Tandai bababakan dibulikakan sawagai bababakan bot",
        "right-noratelimit": "Kada pangaruh awan watas rating",
        "right-import": "Impur tutungkaran matan wiwiki lain",
        "action-suppressionlog": "tiringi log paribadi ini",
        "action-block": "Blukir pamakai ngini matan mambabak",
        "action-protect": "Ubah tingkat parlindungan tungkaran ngini",
-       "action-rollback": "Mambulikakan hancap babakan matan pamakai pauncitnya nang mambabak tungkaran tartantu.",
+       "action-rollback": "Mambulikakan hancap babakan matan pamakai pauncitnya nang mambabak halaman tartantu.",
        "action-import": "Impur tungkaran ngini matan wiki lain",
        "action-importupload": "Impur tungkaran ngini matan sabuah barakas hunggahan",
        "action-patrol": "tandai babakan nang lain sawagai ta'awasi",
        "zip-bad": "Barakas ngini korup atawa pinanya barakas ZIP nang kada kawa dibaca.\nBarakas ngini kada kawa dipariksa  gasan kaamanan.",
        "zip-unsupported": "Barakas ngini adalah sabuah barakas ZIP nang dipuruk pitur ZIP nang kada disukung ulih MediaWiki.\nNgini kada kawa dipariksa gasan kaamanan.",
        "uploadstash": "Simpanan hunggahan",
-       "uploadstash-summary": "Tungkaran ngini manyadiaakan ungkaian ka barakas nang taunggah (atawa dalam prosés unggahan) tapi baluman ditarbitakan ka wiki.\nBarakas ngini kada kawa dijanaki ka siapa pun kacuali pamakai nang maunggahnya.",
+       "uploadstash-summary": "Halaman ngini manyadiaakan ungkaian ka barakas nang taunggah (atawa dalam prosés unggahan) tapi baluman dicungulakan ka wiki.\nBarakas ngini kada kawa dijanaki ka siapa pun kacuali pamakai nang maunggahnya.",
        "uploadstash-clear": "Kalarakan babarakas simpanan.",
        "uploadstash-nofiles": "Pian kada baisi babarakas simpanan.",
        "uploadstash-badtoken": "Aksi kada ruhui dilaksanaakan, pinanya karana babakan Pian sudah kadaluarsa. Cubai pulang.",
        "filehist-comment": "Ulasan",
        "imagelinks": "Tautan barakas",
        "linkstoimage": "{{PLURAL:$1|Halaman|$1 halaman}} nangini mamakai barakas ngini:",
-       "linkstoimage-more": "Labih daripada $1 {{PLURAL:$1|pamakaian tungkaran|pamakaian tutungkaran}} ka barakas ngini.\nDaptar barikut manampaiakan {{PLURAL:$1|tungkaran panambaian|$1 tungkaran panambaiam}} nang mamakai barakas ngini haja.\nSabuah [[Special:WhatLinksHere/$2|daptar hibak]] tasadia.",
+       "linkstoimage-more": "Labih daripada $1 {{PLURAL:$1|pamakaian halaman|pamakaian halaman}} ka barakas ngini.\nDaptar barikut manampaiakan {{PLURAL:$1|halaman panambaian|$1 halaman panambaian}} nang mamakai barakas ngini haja.\nSabuting [[Special:WhatLinksHere/$2|daptar hibak]] tasadia.",
        "nolinkstoimage": "Kadada tutungkaran nang mamakai barakas ngini.",
        "morelinkstoimage": "Tiringi [[Special:WhatLinksHere/$1|tautan lagi]] ka barakas ngini.",
        "linkstoimage-redirect": "$1 (barakas paugahan) $2",
        "unusedimagestext": "Babarakas barikut ada tagal kada diumpatakan di tungkaran mamana.\nMuhun catat bahwasa situs web lain pina-ai bataut ka sabuah barakas awan sabuah URL langsung, wan karana ngini masih-ha didaptar di sia biar gin aktip dipuruk.",
        "unusedcategoriestext": "Tumbung tutungkaran barikut ada, walaupun kadada tungkaran lain atawa tumbung mamuruknya.",
        "notargettitle": "Kadada tujuan",
-       "notargettext": "Pian kada manantuakan tungkaran atawa pamakai tujuan tugas ngini.",
+       "notargettext": "Pian kada manantuakan halaman atawa pamakai tujuan tugas ngini.",
        "nopagetitle": "Kadada tungkaran sasaran",
        "nopagetext": "Tungkaran sasaran nang Pian ajuakan kadada.",
        "pager-newer-n": "{{PLURAL:$1|labih hanyar 1|labih hanyar $1}}",
        "speciallogtitlelabel": "Tujuan (judul atawa {{ns:user}}:ngaran pamakai gasan pamakai)",
        "log": "Log",
        "all-logs-page": "Samunyaan log umum",
-       "alllogstext": "Tampaian baimbai matan sabataan log nang ada matan {{SITENAME}}.\nPian kada mawatasi tiringan lawan mamilih sabuah macam log, ngaran-pamakai (sansitip kapital), atawa tungkaran tapangaruh (sansitip kapital jua).",
+       "alllogstext": "Tampaian baimbai matan sabataan log nang ada matan {{SITENAME}}.\nPian kada mawatasi tiringan lawan mamilih sabuting macam log, ngaran-pamakai (sansitip kapital), atawa halaman tapangaruh (sansitip kapital jua).",
        "logempty": "Kadada barang nang parsis pintang log.",
        "log-title-wildcard": "Gagai judul ba-awalan awan naskah ngini",
        "showhideselectedlogentries": "Tampaiakan/sungkupakan masukan log tapilih",
        "activeusers-from": "Manampaiakan papamuruk mulai matan:",
        "activeusers-noresult": "Kadada papamuruk tatamu.",
        "listgrouprights": "Daptar hak galambang",
-       "listgrouprights-summary": "Nangini daptar galambang pamakai nang tahaga di wiki ini, lawan daptar hak maungkai bubuhannya. Maklumat salanjutnya sual hak masing-masing kawa ditamuakan di [[{{MediaWiki:Listgrouprights-helppage}}|tungkaran patulung hak pamakai]].",
+       "listgrouprights-summary": "Nangini daptar galambang pamakai nang tahaga di wiki ini, lawan daptar hak maungkai bubuhannya. Maklumat salanjutnya sual hak masing-masing kawa ditamuakan di [[{{MediaWiki:Listgrouprights-helppage}}|halaman patulung hak pamakai]].",
        "listgrouprights-key": "* <span class=\"listgrouprights-granted\">Hak nang balaku</span>\n* <span class=\"listgrouprights-revoked\">Hak nang dicukut</span>",
        "listgrouprights-group": "Galambang",
        "listgrouprights-rights": "Hak",
        "unwatchthispage": "Mandak maitihi",
        "notanarticle": "Lainan sabuting tungkaran isi",
        "notvisiblerev": "Ralatan sudah dihapus",
-       "watchlist-details": "Tahaga {{PLURAL:$1|$1 tungkaran|$1 tungkaran}} di daptar itihan Pian, (tamasuk tungkaran pamandiran).",
+       "watchlist-details": "Tahaga {{PLURAL:$1|halaman}} di daptar itihan Pian, (tamasuk halaman pamandiran).",
        "wlheader-enotif": "Suril pamadahan dipajahi.",
        "wlheader-showupdated": "Tutungkaran nang ba-ubah tumatan ilangan tauncit Pian ditampaiakan dalam <strong>hurup kandal</strong>.",
        "wlnote": "Dibawah ngini adalah {{PLURAL:$1|paubahan pahabisan|<strong>$1</strong> paubahan pahabisan}} dalam {{PLURAL:$2|sajam|<strong>$2</strong> jam}} par $3, $4.",
        "rollbacklinkcount": "bulikakan $1 {{PLURAL:$1|babakan}}",
        "rollbackfailed": "Guling-bulik luput",
        "cantrollback": "Kada kawa mambalikakan babakan;\npanyumbang tauncit adalah asa-asanya panulis tungkaran ngini.",
-       "alreadyrolled": "Kada kawa malakukan pambulikan ka ralatan pauncitnya [[:$1]] ulih [[User:$2|$2]] ([[User talk:$2|pandir]]{{int:pipe-separator}}[[Special:Contributions/$2|{{int:contribslink}}]]);\npamakai lain sudah mambabak atawa malakukan pambulikan lawan tungkaran ngini.\n\nBabakan pauncitnya dilakukan ulih [[User:$3|$3]] ([[User talk:$3|pandir]]{{int:pipe-separator}}[[Special:Contributions/$3|{{int:contribslink}}]]).",
+       "alreadyrolled": "Kada kawa malakukan pambulikan ka ralatan pauncitnya [[:$1]] ulih [[User:$2|$2]] ([[User talk:$2|pandir]]{{int:pipe-separator}}[[Special:Contributions/$2|{{int:contribslink}}]]);\npamakai lain sudah mambabak atawa malakukan pambulikan lawan halaman ngini.\n\nBabakan pauncitnya dilakukan ulih [[User:$3|$3]] ([[User talk:$3|pandir]]{{int:pipe-separator}}[[Special:Contributions/$3|{{int:contribslink}}]]).",
        "editcomment": "Kumintar pambabakan adalah: <em>$1</em>.",
        "revertpage": "←Babakan [[Special:Contributions/$2|$2]] ([[User talk:$2|pandir]]) dibulikakan ka ralatan tauncit ulih [[User:$1|$1]]",
        "revertpage-nouser": "Pambulikan babakan ulih (pamuruk dihapus) ka babakan tauncit ulih [[User:$1|$1]]",
        "sp-contributions-search": "Kikihi sumbangan",
        "sp-contributions-username": "Alamat IP atawa ngaran-pamakai:",
        "sp-contributions-toponly": "Tampaiakan wastu ralatan nang paling atas (pauncitnya)",
-       "sp-contributions-newonly": "Hanya tampaiakan babakan nang barupa paulahan tungkaran",
+       "sp-contributions-newonly": "Hanya tampaiakan babakan nang barupa paulahan halaman",
        "sp-contributions-submit": "Kikih",
        "whatlinkshere": "Tautan balik",
        "whatlinkshere-title": "Halaman nang batautan ka ''$1''",
        "blockiptext": "Puruk purmulir di bawah hagan mamblukir hak ungkai manulis matan sabuah alamat IP atawa ngaran-pamuruk.\nNgini dipuruk hagan mancagah vandalisma haja, wan sasuai awan [[{{MediaWiki:Policy-url}}|kabijakan]].\nIsi sabuah alasan khas di bawah (gasan cuntuh, manulisakan tutungkaran nang suah divandal)",
        "ipaddressorusername": "Alamat IP atawa ngaran pamakai:",
        "ipbreason": "Alasan:",
-       "ipbreason-dropdown": "*Alasan umum\n** Vandalisma\n** Mambariakan katarangan kada bujur alias palsu\n** Mahilangakan isi tungkaran\n** Spam tautan ka situs luar\n** Mangaradau ka tungkaran\n** Parilaku intimidasi/mancapa\n** Manyalahgunaakan babarapa akun\n** Ngaran pamakai kada layak",
+       "ipbreason-dropdown": "*Alasan umum\n** Vandalisma\n** Mambariakan katarangan kada bujur alias palsu\n** Mahilangakan isi halaman\n** Spam tautan ka situs luar\n** Mangaradau ka halaman\n** Parilaku intimidasi/mancapa\n** Manyalahgunaakan babarapa akun\n** Ngaran pamakai kada layak",
        "ipb-hardblock": "Tangati pamakai tadaptar gasan mambabak matan alamat IP ngini",
        "ipbcreateaccount": "Tangkal paulahan akun",
        "ipbemailban": "Tangkal pamuruk mangirimi suril",
        "ipbother": "Wayah lain:",
        "ipboptions": "2 jam:2 hours,1 hari:1 day,3 hari:3 days,1 minggu:1 week,2 minggu:2 weeks,1 bulan:1 month,3 bulan:3 months,6 bulan:6 months,1 tahun:1 year,salawasan:infinite",
        "ipbhidename": "Sungkupakan ngaranpamuruk matan babakan wan dadaptar",
-       "ipbwatchuser": "Itihi tungkaran pamakai wan pamandiran pamakai ngini",
+       "ipbwatchuser": "Itihi halaman pamakai wan pamandiran pamakai ngini",
        "ipb-disableusertalk": "Tangkal pamuruk ngini mambabak tungkaran pamandirannya wayah diblukir",
        "ipb-change-block": "Blukir pulang pamakai lawan setélan ngini",
        "ipb-confirm": "Yakinakan blukir",
        "ipbnounblockself": "Pian kada dibulihakan malapas blukir Pian surang",
        "lockdb": "Sunduk basisdata",
        "unlockdb": "Lapas sunduk basisdata",
-       "lockdbtext": "Manyunduk basis data akan maampihakan kamampuan samunyaan pamakai mambabak tungkaran, maubah kakatujuan sidin, mambabak paitihin sidin, wan nang lainnya nang parlu diubah dalam basis data.\nMuhun yakinakan nangini bujur nang handak Pian gawi, wan Pian akan malapas-sunduk basis data amun paharaguan tuntung.",
-       "unlockdbtext": "Malapas sunduk basis data akan manyimpan-pulang kamampuan samunyaan pamakai gasan mambabak tungkaran, maubah kakatujuan sidin, mambabak paitihan sidin, wan nang lainnya nang parlu diubah dalam basis data.\nMuhun yakinakan nang ngini nang Pian handak gawi.",
+       "lockdbtext": "Manyunduk basis data akan maampihakan kamampuan samunyaan pamakai mambabak halaman, maubah kakatujuan sidin, mambabak paitihin sidin, wan nang lainnya nang parlu diubah dalam basis data.\nMuhun yakinakan nangini bujur nang handak Pian gawi, wan Pian akan malapas-sunduk basis data amun paharaguan tuntung.",
+       "unlockdbtext": "Malapas sunduk basis data akan manyimpan-pulang kamampuan samunyaan pamakai gasan mambabak halaman, maubah kakatujuan sidin, mambabak paitihan sidin, wan nang lainnya nang parlu diubah dalam basis data.\nMuhun yakinakan nang ngini nang Pian handak gawi.",
        "lockconfirm": "I'ih, ulun bujuran handak manyunduk basisdata.",
        "unlockconfirm": "I'ih, ulun bujuran handak malapas sunduk basisdata.",
        "lockbtn": "Sunduk basisdata",
        "movepagetext": "Mamakai purmulir di bawah akan mangganti ngaran sabuting tungkaran, mamindahakan samunyaan halam ka ngaran nang hanyar. Judul lawas akan jadi sabuting tungkaran paugahan ka judul hanyar. Pian kawa mahanyari bahwasanya paugahan-paugahan manuju ka judul nang samustinya langsung. Amun kada, pastiakan pariksa gasan [[Special:DoubleRedirects|ganda]] atawa [[Special:BrokenRedirects|paugahan pagat]]. Pian batanggung jawab gasan mamastiakan tautan-tautan tatarusan manuju ka mana nang samustinya.\n\nCatatan bahwasanya tungkaran '''kada''' akan tapindah amun sudah ada tungkaran nang bangaran hanyar ngitu, kacuali amun tungkaran itu puang atawa sabuting paugahan wan kadada halam babakan.\n\n'''Paringatan!'''\nIni kawa maakibatakan paubahan kada taduga wan drastis gasan sabuting tungkaran rami; muhun mamastiakan Pian paham akibatnya sabalum manarusakan.",
        "movepagetext-noredirectfixer": "Mamakai purmulir di bawah akan mangganti ngaran sabuting tungkaran, mamindahakan samunyaan halam ka ngaran nang hanyar.\nJudul lawas akan jadi sabuting tungkaran paugahan ka judul hanyar.\nPastiakan pariksa gasan [[Special:DoubleRedirects|ganda]] atawa [[Special:BrokenRedirects|paugahan pagat]].\nPian batanggung jawab gasan mamastiakan tautan-tautan tatarusan manuju ka mana nang samustinya.\n\nCatatan bahwasanya tungkaran '''kada''' akan tapindah amun sudah ada tungkaran nang bangaran hanyar ngitu, kacuali amun tungkaran itu puang atawa sabuah paugahan wan kadada halam babakan.\n\n'''Paringatan!'''\nIni kawa maakibatakan paubahan kada taduga wan drastis gasan sabuah tungkaran rami; \nmuhun mamastiakan Pian paham akibatnya sabalum manarusakan.",
        "movepagetalktext": "Tungkaran pamandiran tarait akan langsung dipindahakan baimbai wan ini '''kacuali amun:'''\n*Sabuah tungkaran pamandiran nang kada puang sudah baisi awan judul hanyar, atawa\n*Pian kada manyuntring kutak di bawah.",
-       "moveuserpage-warning": "'''Paringatan:''' Pian parhatan mamindahakan tungkaran pamakai. Parlu Pian tahu lamun cuma tungkaran nang akan dipindahakan tapi pamakai ''kada'' baganti ngaran.",
-       "movenologintext": "Pian musti manjadi pamakai tadaptar wan [[Special:UserLogin|babuat log]] gasan mamindahakan suatu tungkaran.",
+       "moveuserpage-warning": "'''Paringatan:''' Pian parhatan mamindahakan halaman pamakai. Parlu Pian tahu lamun cuma halaman nang akan dipindahakan tapi pamakai ''kada'' baganti ngaran.",
+       "movenologintext": "Pian musti manjadi pamakai tadaptar wan [[Special:UserLogin|babuat log]] gasan mamindahakan suatu halaman.",
        "movenotallowed": "Pian kada baisi ijin hagan mamindahakan tutungkaran.",
        "movenotallowedfile": "Pian kada baisi ijin hagan mamindahakan babarakas.",
-       "cant-move-user-page": "Pian kada baisi ijin gasan mamindahakan tungkaran pamakai (tapisah matan sub-tutungkaran).",
-       "cant-move-to-user-page": "Pian kada baisi ijin gasan mamindahakan tungkaran ka suatu tungkaran pamakai (kacuali ka sub-tutungkaran pamakai).",
+       "cant-move-user-page": "Pian kada baisi ijin gasan mamindahakan halaman pamakai (tapisah matan sub-halaman).",
+       "cant-move-to-user-page": "Pian kada baisi ijin gasan mamindahakan halaman ka suatu halaman pamakai (kacuali ka sub-halaman pamakai).",
        "newtitle": "Ka judul hanyar:",
        "move-watch": "Itihi tungkaran asal mula wan tungkaran tujuan",
        "movepagebtn": "Pindahakan tungkaran",
        "imageinvalidfilename": "Ngaran barakas tujuan kada sah",
        "fix-double-redirects": "Mutakhirakan babarapa paugahan nang manitik ka judul asli",
        "move-leave-redirect": "Ulah paugahan ka judul hanyar",
-       "protectedpagemovewarning": "'''Paringatan''': Tungkaran ngini sudah dikunci wan cuma pamakai nang baisi hak pambakal haja nang kawa mamindahakannya.\nMasukan catatan pauncitnya disadiaakan di bawah gasan rujukan:",
+       "protectedpagemovewarning": "'''Paringatan''': Halaman ngini sudah disunduk wan cuma pamakai nang baisi hak pambakal haja nang kawa mamindahakannya.\nMasukan catatan pauncitnya disadiaakan di bawah gasan rujukan:",
        "semiprotectedpagemovewarning": "'''Catatan:''' Tungkaran ngini sudah dilindungi laluai pamuruk tadaptar haja nang kawa mamindahakan ngini.\nLog masuk pauncitan disadiakan di bawah gasan rujukan:",
        "move-over-sharedrepo": "==Barakas ada==\n[[:$1]] ada pintangan panyimpanan babagi. Mamindahakan sabuah barakas ka judul ngini akan manulis-tindih barakas babagi.",
        "file-exists-sharedrepo": "Ngaran barakas nang dipilih sudah dipuruk pintangan panyimpanan babagi.\nMuhun pilih ngaran lain.",
        "import-logentry-interwiki-detail": "$1 {{PLURAL:$1|ralatan|raralatan}} matan $2",
        "javascripttest": "Mantis JavaScript",
        "tooltip-pt-userpage": "Halaman {{GENDER:|pamakai Pian}}",
-       "tooltip-pt-anonuserpage": "Tungkaran pamakai IP Pian",
+       "tooltip-pt-anonuserpage": "Halaman pamakai IP Pian",
        "tooltip-pt-mytalk": "Halaman {{GENDER:|pamandiran Pian}}",
        "tooltip-pt-anontalk": "Pamandiran pasal bababakan matan alamat IP ngini",
        "tooltip-pt-preferences": "Kakatujuan {{GENDER:|Pian}}",
        "pageinfo-default-sort": "Kunci urut baku",
        "pageinfo-length": "Panjang tungkaran (dalam bita)",
        "pageinfo-article-id": "ID Tungkaran",
-       "pageinfo-language": "Basa isi tungkaran",
-       "pageinfo-content-model": "Mudil isi tungkaran",
+       "pageinfo-language": "Basa isi halaman",
+       "pageinfo-content-model": "Mudil isi halaman",
        "pageinfo-robot-policy": "Pangindéksan ulih robot",
        "pageinfo-robot-index": "Dibulihakan",
        "pageinfo-robot-noindex": "Kada dibulihakan",
        "pageinfo-watchers": "Jumlah pa-itih tungkaran",
        "pageinfo-few-watchers": "Kurang matan $1 {{PLURAL:$1|pa-ilang}}",
-       "pageinfo-redirects-name": "Jumlah paugahan ka tungkaran ngini",
+       "pageinfo-redirects-name": "Jumlah paugahan ka halaman ngini",
        "pageinfo-subpages-name": "Subtungkaran tungkaran ngini",
        "pageinfo-subpages-value": "$1 ($2 {{PLURAL:$2|paugahan|paugahan}}; $3 {{PLURAL:$3|non-paugahan|non-paugahan}})",
        "pageinfo-firstuser": "Pa-ulah tungkaran",
        "confirm-unwatch-button": "OK",
        "confirm-unwatch-top": "Buang tungkaran ini matan paitihan Pian?",
        "imgmultipageprev": "← tungkaran sabalumnya",
-       "imgmultipagenext": "tungkaran salanjutnya →",
+       "imgmultipagenext": "halaman salanjutnya →",
        "imgmultigo": "Tulak!",
        "imgmultigoto": "Tulak ka tungkaran $1",
        "ascending_abbrev": "naik",
        "version-software-product": "Produk",
        "version-software-version": "Virsi",
        "version-entrypoints-header-url": "URL",
-       "redirect": "Paugahan badasarakan ID barakas, pamakai, tungkaran, ralatan, atawa log",
-       "redirect-summary": "Tungkaran istimiwa ngini baugah ka barakas (sasuai ngarannya), halaman (sasuai ID ralatan atawa ID tungkaran), tungkaran pamakai (sasuai ID pamakai), atawa buatan log (ID lognya). Pamakaian: [[{{#Special:Redirect}}/file/Cuntuh.jpg]], [[{{#Special:Redirect}}/page/64308]], [[{{#Special:Redirect}}/revision/328429]], [[{{#Special:Redirect}}/user/101]], or [[{{#Special:Redirect}}/logid/186]].",
+       "redirect": "Paugahan badasarakan ID barakas, pamakai, halaman, ralatan, atawa log",
+       "redirect-summary": "Halaman istimiwa ngini baugah ka barakas (sasuai ngarannya), halaman (sasuai ID ralatan atawa ID halaman), halaman pamakai (sasuai ID pamakai), atawa buatan log (ID lognya). Pamakaian: [[{{#Special:Redirect}}/file/Cuntuh.jpg]], [[{{#Special:Redirect}}/page/64308]], [[{{#Special:Redirect}}/revision/328429]], [[{{#Special:Redirect}}/user/101]], atawa [[{{#Special:Redirect}}/logid/186]].",
        "redirect-submit": "Lanjut",
        "redirect-lookup": "Panggagaian:",
        "redirect-value": "Nilai:",
        "htmlform-reset": "Bulikakan paubahan",
        "htmlform-selectorother-other": "Lain-lain",
        "logentry-delete-delete": "$1 {{GENDER:$2|mahapus}} halaman $3",
-       "logentry-delete-restore": "$1 {{GENDER:$2|mambulikakan}} tungkaran $3 ($4)",
+       "logentry-delete-restore": "$1 {{GENDER:$2|mambulikakan}} halaman $3 ($4)",
        "logentry-delete-event": "$1 mangganti kakawaan dijanaki {{PLURAL:$5|sabuah log kajadian|$5 log kajadian}} pintangan $3: $4",
-       "logentry-delete-revision": "$1 {{GENDER:$2|maubah}} tampaian {{PLURAL:$5|$5 ralatan}} di tungkaran $3: $4",
+       "logentry-delete-revision": "$1 {{GENDER:$2|maubah}} tampaian {{PLURAL:$5|$5 ralatan}} di halaman $3: $4",
        "logentry-delete-event-legacy": "$1 mangganti kakawaan dijanaki log kajadian pintangan $3",
        "logentry-delete-revision-legacy": "$1 mangganti kakawaan dijanaki ralatan pintangan tungkaran $3",
        "logentry-suppress-delete": "$1 ditikin tungkaran $3",
        "revdelete-restricted": "Talamar pambatasan hagan pambakal-pambakal",
        "revdelete-unrestricted": "Buang pambatasan gasan pambakal-pambakal",
        "logentry-move-move": "$1 {{GENDER:$2|mamindahakan}} halaman $3 ka $4",
-       "logentry-move-move-noredirect": "$1 {{GENDER:$2|mamindahakan}} tungkaran $3 ka $4 kada pakai maulah paugahan",
-       "logentry-move-move_redir": "$1 {{GENDER:$2|mamindahakan}} tungkaran $3 ka $4 manimpa paugahan lawas",
+       "logentry-move-move-noredirect": "$1 {{GENDER:$2|mamindahakan}} halaman $3 ka $4 kada pakai maulah paugahan",
+       "logentry-move-move_redir": "$1 {{GENDER:$2|mamindahakan}} halaman $3 ka $4 manimpa paugahan lawas",
        "logentry-move-move_redir-noredirect": "$1 diugah tungkaran $3 ka $4 lung sabuah paugahan awan-kada maninggalakan sabuah paugahan",
        "logentry-patrol-patrol": "$1 diciri'i ralatan $4 matan tungkaran $3 taawasi",
-       "logentry-patrol-patrol-auto": "$1 utumatis {{GENDER:$2|manandai}} ralatan $4 matan tungkaran $3 taitihi",
+       "logentry-patrol-patrol-auto": "$1 utumatis {{GENDER:$2|manandai}} ralatan $4 matan halaman $3 taitihi",
        "logentry-newusers-newusers": "$1 ma-ulah sabuting akun pamakai",
        "logentry-newusers-create": "$1 {{GENDER:$2|maulah}} akun pamakai",
        "logentry-newusers-create2": "$1 ma-ulah sabuting akun pamakai $3",
        "feedback-adding": "Manambahi kitihanbalik ka tungkaran...",
        "feedback-bugcheck": "Harat! hanyar dipariksa bahwasa ngini lainan salah asa [$1 bug nang dipinandui].",
        "feedback-bugnew": "Ulun mamariksa. Malapurakan sabuah bug hanyar",
-       "feedback-bugornote": "Lamun Pian sudah siap gasan mamaparakan masalah téknis sacara rinci silakan [$1 malapurakan bug].\nLamun kada, Pian kawa mamakai purmulir mudah di bawah ngini. Kumintar Pian akan ditambahakan ka tungkaran \"[$3 $2]\", baimbai lawan ngaran pamakai Pian wan apa paramban nang Pian pakai.",
+       "feedback-bugornote": "Lamun Pian sudah siap gasan mamaparakan masalah téknis sacara rinci silakan [$1 malapurakan bug].\nLamun kada, Pian kawa mamakai purmulir mudah di bawah ngini. Kumintar Pian akan ditambahakan ka halaman \"[$3 $2]\", baimbai lawan ngaran pamakai Pian wan apa paramban nang Pian pakai.",
        "feedback-cancel": "Pasah",
        "feedback-close": "Sudah",
        "feedback-error1": "Kasalahan: kulihan matan API kada-dipinandui",
        "special-characters-group-thai": "Thai",
        "special-characters-group-lao": "Lao",
        "special-characters-group-khmer": "Khmer",
-       "randomrootpage": "Tungkaran dasar sambarang"
+       "randomrootpage": "Halaman dasar sambarang"
 }
index f3a4d8d..2fc856d 100644 (file)
        "ipb-confirm": "বাধা নিশ্চিতকরণ",
        "ipb-sitewide": "সাইটব্যাপী",
        "ipb-partial": "আংশিক",
-       "ipb-sitewide-help": "à¦\89à¦\87à¦\95িতà§\87 à¦¸à¦¬ à¦ªà¦¾à¦¤à¦¾ ও অন্যান্য সব অবদানে বাধা।",
+       "ipb-sitewide-help": "à¦\89à¦\87à¦\95ির à¦¸à¦¬ à¦ªà¦¾à¦¤à¦¾à¦¯à¦¼ ও অন্যান্য সব অবদানে বাধা।",
        "ipb-partial-help": "নির্দিষ্ট পাতা ও নামস্থানসমূহ।",
        "ipb-pages-label": "পাতা",
        "ipb-namespaces-label": "নামস্থানসমূহ",
index 71f5633..0dd9fe0 100644 (file)
        "mw-widgets-abandonedit-discard": "Discard edits",
        "mw-widgets-abandonedit-keep": "Continue editing",
        "mw-widgets-abandonedit-title": "Are you sure?",
+       "mw-widgets-copytextlayout-copy": "Copy",
+       "mw-widgets-copytextlayout-copy-fail": "Failed to copy to clipboard.",
+       "mw-widgets-copytextlayout-copy-success": "Copied to clipboard.",
        "mw-widgets-dateinput-no-date": "No date selected",
        "mw-widgets-dateinput-placeholder-day": "YYYY-MM-DD",
        "mw-widgets-dateinput-placeholder-month": "YYYY-MM",
index b67abb2..9b14ac1 100644 (file)
        "timezonelegend": "Tiidsône:",
        "localtime": "Pleatslike tiid:",
        "timezoneuseserverdefault": "Wikistandert brûke ($1)",
-       "timezoneuseoffset": "Oars (tiidferskil oanjaan)",
+       "timezoneuseoffset": "Oars (ferskil hjirûnder oanjaan)",
+       "timezone-useoffset-placeholder": "Foarbyldwearden: \"-07:00\" as \"01:00\"",
        "servertime": "Servertiid:",
-       "guesstimezone": "Freegje de blêder",
+       "guesstimezone": "Webblêder ynfolje litte",
        "timezoneregion-africa": "Afrika",
        "timezoneregion-america": "Amearika",
        "timezoneregion-antarctica": "Antarktika",
-       "timezoneregion-arctic": "Arktysk",
+       "timezoneregion-arctic": "Noardpoalgebiet",
        "timezoneregion-asia": "Aazje",
        "timezoneregion-atlantic": "Atlantyske Oseaan",
        "timezoneregion-australia": "Austraalje",
        "prefs-namespaces": "Nammeromten",
        "default": "standert",
        "prefs-files": "Bestannen",
-       "prefs-custom-js": "Persoanlik JS",
+       "prefs-custom-css": "Oanpast CSS",
+       "prefs-custom-js": "Oanpast JavaScript",
+       "prefs-common-config": "Dield CSS/JSON/JavaScript foar alle foarmjouwings:",
        "prefs-reset-intro": "Jo kinne dizze side brûke, en set jo ynstellings werom nei de websteestandert.\nDat kin net ûngedien makke wurde.",
        "prefs-emailconfirm-label": "E-mailbefêstiging:",
        "youremail": "E-mail:",
index 4e8d0e8..5c71b05 100644 (file)
        "virus-scanfailed": "skeniranje neuspješno (kod $1)",
        "virus-unknownscanner": "nepoznati antivirus:",
        "logouttext": "'''Odjavili ste se.'''\n\nNeke se stranice mogu prikazivati kao da ste još uvijek prijavljeni, sve dok ne očistite međuspremnik svog preglednika.",
+       "logging-out-notify": "Odjavljujemo Vas, molimo pričekajte.",
        "cannotlogoutnow-title": "Odjava trenutno nije moguća",
        "cannotlogoutnow-text": "Odjava nije moguća tijekom uporabe $1.",
        "welcomeuser": "Dobrodošli, $1!",
index e5f17c0..41f87a8 100644 (file)
@@ -80,7 +80,7 @@
        "february": "فڤریٱ",
        "march": "مارس",
        "april": "آڤریلٛ",
-       "may_long": "ماٛ",
+       "may_long": "ماٛی",
        "june": "ژوئٱن",
        "july": "جۊلای",
        "august": "آگوست",
        "feb": "فڤریٱ",
        "mar": "مارس",
        "apr": "آڤریلٛ",
-       "may": "ماٛ",
+       "may": "ماٛی",
        "jun": "ژوئٱن",
        "jul": "جۊلای",
        "aug": "آگوست",
        "february-date": "فڤریٱ $1",
        "march-date": "مارس  $1",
        "april-date": "آڤریلٛ $",
-       "may-date": "ماٛ $1",
+       "may-date": "ماٛی $1",
        "june-date": "ژوئٱن $1",
        "july-date": "جۊلای $1",
        "august-date": "آگوست $1",
        "createacct-another-username-ph": "نوم کاریاری تو ناْ بٱزنؽت",
        "yourpassword": "پٱسڤورد:",
        "userlogin-yourpassword": "پٱسڤورد",
-       "userlogin-yourpassword-ph": "رازینٱ گوئارسناْ بٱزاْ",
-       "createacct-yourpassword-ph": "رازÛ\8cÙ\86Ù± Ú¯Ù\88ئاردن ناْ بٱزاْ",
-       "yourpasswordagain": "Û\8cاÙ\9b Ù\87Ù\86Û\8c Ø±Ø§Ø²Û\8cÙ\86Ù± Ú¯Ù\88ئاردن ناْ بٱزاْ",
+       "userlogin-yourpassword-ph": "رازینٱ گوئارسن ناْ بٱزاْ",
+       "createacct-yourpassword-ph": "رازÛ\8cÙ\86Ù± Ú¯Ù\88ئارسن ناْ بٱزاْ",
+       "yourpasswordagain": "Û\8cاÙ\9b Ù\87Ù\86Û\8c Ø±Ø§Ø²Û\8cÙ\86Ù± Ú¯Ù\88ئارسن ناْ بٱزاْ",
        "createacct-yourpasswordagain": "پٱسڤورد تازٱ ناْ تٱیید كو",
-       "createacct-yourpasswordagain-ph": "Û\8cاÙ\9b Ú¯Ù\84Ù\9b Ù\87Ù\86Û\8c Ø±Ø§Ø²Û\8cÙ\86Ù± Ú¯Ù\88ئاردن بٱزٱ",
+       "createacct-yourpasswordagain-ph": "Û\8cاÙ\9b Ú¯Ù\84Ù\9b Ù\87Ù\86Û\8c Ø±Ø§Ø²Û\8cÙ\86Ù± Ú¯Ù\88ئارسن بٱزٱ",
        "userlogin-remembermypassword": "مناْ د سامونٱ ڤادار",
        "userlogin-signwithsecure": "ڤٱسل بیئن ٱمن ناْ ڤ کار باٛیر",
        "yourdomainname": "پوشگر شما:",
-       "password-change-forbidden": "Ø´Ù\88Ù\85ا Ù\86ئÙ\85Û\8c ØªÙ\88Ù\99Ù\86Û\8cت Ø±Ø§Ø²Û\8cÙ\86Û\95 Ú¯Ù\88ڤاردئÙ\86 Ø®Ù\88تÙ\88Ù\99Ù\86Û\95 Ø¯ Ø¦Û\8c Ú¤Û\8cÚ©Û\8c Ø¢Ù\84ئشت Ø¨Ø£Ú©Û\8cت.",
+       "password-change-forbidden": "Ø´Ù\85ا Ù\86Ù\85ؽ ØªÙ\88Ù\86ؽت Ø±Ø§Ø²Û\8cÙ\86Ù± Ú¯Ù\88ئارسÙ\86 Ø®Ù\88تÙ\88Ù\86اÙ\92 Ø¯ Ø¦Ø§Ø½ Ú¤Û\8cÚ©Û\8c Ø¢Ù\84شت Ø¨Ù±Ú©Ø½ت.",
        "externaldberror": "اْشتبایؽ د اْرتبات ڤا رسینٱگا پیش اومایٱ یا شما سلا یٱ ناْ کاْ یاٛ هساو خارجی خوتو ناْ ڤ هنگوم سازی بٱکؽت نارؽت.",
        "login": "ڤامؽن اوماین",
        "nav-login-createaccount": " ڤامؽن اوماین/دۏرس کردن هساو",
        "retypenew": "رازینٱ گوئارسن تازٱ ناْ د نۊ ٱنجومیارنیسی بٱکؽت:",
        "resetpass_submit": "رازینٱ گوئارسن ناْ بٱزنؽت ۉ بؽایؽت ڤامؽن",
        "changepassword-success": "رازینە گوڤاردئن شوما ڤا خوٙیی آلئشت کاری بی!",
-       "changepassword-throttled": "Ø´Ù\88Ù\85ا ØªØ§ Ø§Û\8cساÙ\92 Ø³Û\8c Ú¤Ø§Ù\85ؽÙ\86 Ø§Ù\88Ù\85اÛ\8cÙ\86 Ù\81رٱ ØªÙ±Ù\81رٱ Ú©Ø±Ø¯Ø½ØªÙ±.\n$1 Ù\84Ù\88تÙ\81 Ø¨Ù±Ú©Ø½Øª Ø³Û\8c ØªÙ±Ù\81راÙ\9b Ù\87Ù\86Û\8c Ú¯Ø±Ø½ Ø¨Ø§Ù\9bسؽت.",
-       "resetpass_forbidden": "نأبوٙە رازینە گوڤاردنیانە آلئشتکاری بأکیت",
-       "resetpass-no-info": "Ø´Ù\88Ù\85ا Ø³Û\8c Û\8cÛ\95 Ú©Ø¦ Ø¯ Ø¦Û\8c Ø¨Ø£Ù\84Ú¯Û\95 Ø¯Ø£Ø³Ø±Ø¦Ø³Û\8c Ø¯Ø§Ø´ØªÙ\88Ù\99Û\8cÛ\8cت Ø¨Ø§Ø³ Ø¨Û\8cاÛ\8cÛ\8cت Ú¤Ø§Ù\85Û\8cن.",
-       "resetpass-submit-loggedin": "رارینە گوڤاردئن نە آلئشت بأکیت",
-       "resetpass-submit-cancel": "أنجوم شیڤئستئن",
+       "changepassword-throttled": "شما تا ایساْ سی ڤامؽن اوماین فرٱ تٱفرٱ کردؽتٱ.\n$1 لوتف بٱکؽت سی تٱفراٛ هنی گرؽ باٛسؽت.",
+       "resetpass_forbidden": "نمۊئٱ رازینٱ گوئارسنؽا ناْ آشتکاری بٱکؽت",
+       "resetpass-no-info": "Ø´Ù\85ا Ø³Û\8c Û\8cÙ± Ú©Ø§Ù\92 Ø¯ Ø§Ø½ Ø¨Ù±Ù\84Ú¯Ù± Ø¯Ù±Ø³Ø±Ø³Û\8c Ø¯Ø§Ø´ØªÛ\8aÛ\8cؽت Ø¨Ø§Û\8cٱد Ø¨Ø½Ø§Û\8cؽت Ú¤Ø§Ù\85ؽن.",
+       "resetpass-submit-loggedin": "رارینٱ گوئارسن ناْ آلشت بٱکؽت",
+       "resetpass-submit-cancel": "ٱنجوم شؽڤسن",
        "resetpass-wrong-oldpass": "رازینە گوڤاردئن تازە یا موڤأقأتی نادیارە.\nگاسی شوما ئیسئنی یا یا رازینە گوڤاردئن خوتوٙنە د خوٙیی آلئشت دأئیتە یا یئ گئل رازینە گوڤاردئن موڤأقأت هأنی حاستیتە.",
        "resetpass-recycled": "لوطف بأکیت رازینە گوڤاردئن خوتوٙنە سی چیا هأنی د رازینە گوڤاردئن ئیسئنی د نۊ زئنە بأکیت.",
-       "resetpass-temp-emailed": "Ø´Ù\88Ù\85ا Ú¤Ø§ Û\8cئ Ú¯Ø¦Ù\84 Ø±Ø§Ø²Û\8cÙ\86Û\95 Ú¯Ù\88ڤاردئÙ\86 Ù\85Ù\88ڤأÙ\82أتÛ\8c Ø¦Ù\88Ù\99Ù\85اÛ\8cتÛ\95 Ú¤Ø§Ù\85Û\8cÙ\86.\nسÛ\8c Ø¦Ù\88Ù\99Ù\85ائÙ\86 Ú¤Ø¦ Ø¯Ø£Ø±Ø\8c Û\8cئ Ú¯Ø¦Ù\84 Ø±Ø§Ø²Û\8cÙ\86Û\95 Ú¯Ù\88ڤاردئÙ\86 Ù\87Ø£Ù\86Û\8c Ù\86Û\95 Ø¦Û\8cÚ\86ئ Ø¬Ø§Ú¯Ø¦Ø±(Ù\85Û\8cزÙ\88Ù\99Ù\86کارÛ\8c) Ø¨Ø£Ú©Û\8cت.",
-       "resetpass-temp-password": "رازینە گوڤاردئن موڤأقأت:",
-       "resetpass-abort-generic": "Ø¢Ù\84ئشت Ø¯Ø£Ø¦Ù\86 Ø±Ø§Ø²Û\8cÙ\86Û\95 Ú¯Ù\88ڤاردئÙ\86 Ú¤Ø§ Û\8cئ Ú¯Ø¦Ù\84 Ø¯Ø¦Ù\85ادÛ\8cس Ø®Ø¦Ø±Ø§Ú¤ Ø¨Û\8cÛ\8cÛ\95.",
-       "resetpass-expired": "گات دیاری رازینە گوڤاردئن شوما تأموم بییە. لوطف بأکیت یئ گئل رازینە گوڤاردئن هأنی نە سی ڤامین ئوٙمائن میزوٙنکاری بأکیت.",
+       "resetpass-temp-emailed": "Ø´Ù\85ا Ú¤Ø§ Û\8cاÙ\9b Ø±Ø§Ø²Û\8cÙ\86Ù± Ú¯Ù\88ئارسÙ\86 Ù\85Ù\88Ú¤Ù±Ù\82ٱتÛ\8c Ø§Ù\88Ù\85اÛ\8cؽتٱ Ú¤Ø§Ù\85ؽÙ\86.\nسÛ\8c Ø§Ù\88Ù\85اÛ\8cÙ\86 Ú¤ Ø¯Ù±Ø±Ø\8c Û\8cاÙ\9b Ø±Ø§Ø²Û\8cÙ\86Ù± Ú¯Ù\88ئارسÙ\86 Ù\87Ù\86Û\8c Ù\86اÙ\92 Ø§Û\8cÚ\86اÙ\92 Ø¬Ø§Ú¯Û\8cر(Ù\85Û\8cزÙ\88Ù\86کارÛ\8c) Ø¨Ù±Ú©Ø½ت.",
+       "resetpass-temp-password": "رازینٱ گوئارسن موڤٱقٱتت:",
+       "resetpass-abort-generic": "Ø¢Ù\84شت Ø¯Ø§Ù\9bئÙ\86 Ø±Ø§Ø²Û\8cÙ\86Ù± Ú¯Ù\88ئارسÙ\86 Ú¤Ø§ Û\8cاÙ\9b Ø¯Ù\85ادÛ\8cس Ø®Ø±Ø§Ù\88 Ø¨Û\8cÙ±.",
+       "resetpass-expired": "گات دؽاری رازینٱ گوئاردسن شما تموم بیٱ. لوتف بٱکؽت یاٛ رازینٱ گوئاردسن هنی ناْ سی ڤامؽن اوماین میزونکاری بٱکؽت.",
        "resetpass-expired-soft": "گات دیاری رازینە گوڤاردئن شوما تأموم بییە و باس د نۊ زئنە با. لوطف بأکیت یئ گئل رازینە گوڤاردئن هأنی نە ئنتئخاڤ بأکیت، یا سی د نۊ زئنە کئردئن د نئهاتئر د ئیچئ \"{{int:authprovider-resetpass-skip-label}}\" بأپوٙرنیت.",
        "resetpass-validity-soft": "رازینە گوڤاردئن توٙ نادیاره:$1\n\n لوطف بأکیت یئ گئل رازینە گوڤاردئن هأنی نە ئنتئخاڤ بأکیت، یا سی د نۊ زئنە کئردئن د نئهاتئر د ئیچئ \"{{int:authprovider-resetpass-skip-label}}\" بأپوٙرنیت.",
-       "passwordreset": "د Ù\86Û\8a Ø¯Ø§Ù\9bئÙ\86 Ø±Ø§Ø²Û\8cÙ± Ú¯Ù\88ئاردن",
-       "passwordreset-text-one": "ئÛ\8c Ù\86Ù\88Ù\85 Ø¨Ø£Ù\84Ú¯Û\95 Ù\86Û\95 Ø³Û\8c Ú¯Ø¦Ø±Ø¦ØªØ¦Ù\86 Û\8cئ Ú¯Ø¦Ù\84 Ø±Ø§Ø²Û\8cÙ\86Û\95 Ú¯Ù\88ڤاردئÙ\86 Ù\85Ù\88ڤأÙ\82أت Ú¤Ø§ Ø£Ù\86جÙ\88Ù\85اÙ\86اÙ\85Û\95 ØªÙ\88Ù\99 Ù¾Ù\88ر Ø¨Ø£Ú©Û\8cت.",
-       "passwordreset-text-many": "{{PLURAL:$1|Û\8cئ Ú¯Ø¦Ù\84 Ø¯ Ø¬Ø§Ú¯Û\95 Û\8cا Ù\86Û\95 Ø³Û\8c Ú¯Ø¦Ø±Ø¦ØªØ¦Ù\86 Ø±Ø§Ø²Û\8cÙ\86Û\95 Ú¯Ù\88ڤاردئÙ\86 Ù\85Ù\88ڤأÙ\82أتÛ\8c Ù\86Û\95 Ú¤Ø§ Ø£Ù\86جÙ\88Ù\85اÙ\86اÙ\85Û\95 Ú¯Ø¦Ø±Ø¦ØªÛ\95 Ø¨Ù\88Ù\99Ø£ Ù¾Ù\88ر Ø¨Ø£Ú©Û\8cت.}}",
-       "passwordreset-disabled": "Ù\86Û\8a Ú©Ø¦Ø±Ø¯Ø¦Ù\86 Ø±Ø§Ø²Û\8cÙ\86Û\95 Ú¯Ù\88ڤاردئÙ\86 Ø¯ Ø¦Û\8c Ú¤Û\8cÚ©Û\8c Ù\86اکÙ\88Ù\86ئشگأر Ø¨Û\8cÛ\8cÛ\95.",
-       "passwordreset-emaildisabled": "چیا هأنی کئ هان د أنجومانامە د ئی ڤیکی ناکونئشتگأر بینە.",
+       "passwordreset": "د Ù\86Û\8a Ø¯Ø§Ù\9bئÙ\86 Ø±Ø§Ø²Û\8cÙ± Ú¯Ù\88ئارسن",
+       "passwordreset-text-one": "اؽ Ù\86Ù\88Ù\85 Ø¨Ù±Ù\84Ú¯Ù± Ù\86اÙ\92 Ø³Û\8c Ú¯Ø±ØªÙ\86 Û\8cاÙ\9b Ø±Ø§Ø²Û\8cÙ\86Ù± Ú¯Ù\88ئارسÙ\86 Ù\85Ù\88Ú¤Ù±Ù\82ٱت Ú¤Ø§ Ù±Ù\86جÙ\88Ù\85اÙ\86اÙ\85Ù± ØªÙ\88 Ù¾Ù\88ر Ø¨Ù±Ú©Ø½ت.",
+       "passwordreset-text-many": "{{PLURAL:$1|Û\8cاÙ\9b Ø¯ Ø¬Ø§Ú¯Ù±Û\8cا Ù\86اÙ\92 Ø³Û\8c Ú¯Ø±ØªÙ\86 Ø±Ø§Ø²Û\8cÙ\86Ù± Ú¯Ù\88ئارسÙ\86 Ù\85Ù\88Ú¤Ù±Ù\82ٱتÛ\8c Ù\86اÙ\92 Ú¤Ø§ Ù±Ù\86جÙ\88Ù\85اÙ\86اÙ\85Ù± Ú¯Ø±ØªÙ± Ø¨Û\8aئٱ Ù¾Ù\88ر Ø¨Ù±Ú©Ø½ت.}}",
+       "passwordreset-disabled": "Ù\86Û\8a Ú©Ø±Ø¯Ù\86 Ø±Ø§Ø²Û\8cÙ\86Ù± Ú¯Ù\88ئارسÙ\86 Ø¯ Ø§Ø½ Ú¤Û\8cÚ©Û\8c Ù\86اکÙ\88Ù\86شگٱر Ø¨Û\8cÙ±.",
+       "passwordreset-emaildisabled": "چیا هنی کاْ هان د ٱنجومانامٱ د اؽ ڤیکی ناکونشگٱر بیٱ.",
        "passwordreset-username": "نوم کاریاری:",
-       "passwordreset-domain": "پوشگئر",
-       "passwordreset-email": "تÛ\8cرÙ\86ئشÙ\88Ù\99Ù\86 Ø£Ù\86جÙ\88Ù\85اÙ\86اÙ\85Û\95",
-       "passwordreset-emailtitle": "جوزئیات حئساڤ ها د {{نوم مالگە}}",
+       "passwordreset-domain": "پۊشگر",
+       "passwordreset-email": "تÛ\8cرÙ\86Ø´Ù\88Ý© Ù±Ù\86جÙ\88Ù\85اÙ\86اÙ\85Ù±",
+       "passwordreset-emailtitle": "جۏزیات هساو ها د {{نوم مالگٱ}}",
        "passwordreset-emailtext-ip": "یە کئسی(گاسی خوتوٙ، ڤا تیرنئشوٙن آی پی $1) د نۊ زئنە کئردئن رازینە گوڤاردئنئتوٙ د {{SITENAME}} حاستیتە($4).\nسی کاریار «$2» یئ گئل رازینە گوڤاردئن موڤأقتی رأڤأندیاری بییە و هومبأراڤأر «$3» ە.\nأر دالئتوٙ یە بییە ئیسئ ڤاس بیائیت ڤامین ساموٙنە و یئ گئل رازینە گوڤاردئن هأنی بئهایت.\n رازینە گوڤاردئن {{PLURAL:$3|ئی رازینە یا گوڤاردئن موڤأقأتی|ئی رازینە یا گوڤاردئن موڤأقأتی}} شوما د گات {{PLURAL:$5|یئ روٙ|$5 روٙ}} باطئل بوٙە.\n\nأر کأسی هأنی چئن حاستی داشتە یا یە کئ رازینە گوڤاردئن دئمایی شوما د ڤیرئتوٙ ئوٙما و دە نئمیهایت ڤئنە آلئشت کاری بأکیت، می توٙنیت د ئی پئیغوم تیە پوٙشی بأکیت و هأموٙ رازینە گوڤاردئن دئمایی نە بونیت د کار.",
        "passwordreset-emailtext-user": "کاریار $1 د {{SITENAME}} د نۊ زئنە کئردئن رازینە گوڤاردئن شومانە د{{SITENAME}} ($4) حاستە. {{PLURAL:$3|حئساڤ|حئساڤیا}} کاریاری کئ هان د هار و ڤا ئی تیرنئشوٙن أنجومانامە هان د ئرتئڤاط:\n\n$2\n\n رازینە گوڤاردئن {{PLURAL:$3|ئی رازینە یا گوڤاردئن موڤأقأتی|ئی رازینە یا گوڤاردئن موڤأقأتی}} شوما د گات {{PLURAL:$5|یئ روٙ|$5 روٙ}} باطئل بوٙە.\nأر کأسی هأنی چئن حاستی داشتە یا یە کئ رازینە گوڤاردئن دئمایی شوما د ڤیرئتوٙ ئوٙما و دە نئمیهایت ڤئنە آلئشت کاری بأکیت، می توٙنیت د ئی پئیغوم تیە پوٙشی بأکیت و هأموٙ رازینە گوڤاردئن دئمایی نە بونیت د کار.",
-       "passwordreset-emailelement": "نوم کاریاری: \n$1\n\nرازینە گوڤاردئن موڤأقتی: \n$2",
+       "passwordreset-emailelement": "نوم کاریاری: \n$1\n\nرازینٱ گوئارسن موڤٱقتی: \n$2",
        "passwordreset-emailsentemail": "یئ گئل رازینە گوڤاردئن هأنی سی أنجومانامە کئل بییە.",
        "changeemail": "أنجومانامە توٙنە آلئشت کاری بأکیت",
-       "changeemail-header": "ئÛ\8c Ù\81Ù\88رÙ\85ئ Ù\86Û\95 Ø³Û\8c Ø¢Ù\84ئشتکارÛ\8c Ø£Ù\86جÙ\88Ù\85اÙ\86اÙ\85Û\95 ØªÙ\88Ù\99 Ù¾Ù\88ر Ø¨Ø£Ú©Û\8cت. Ø£Ø± Ù\85Û\8cھاÛ\8cت Ú¾Ø£Ø± Ø¬Ù\88Ù\99ر Ø£Ù\86جÙ\88Ù\85اÙ\86اÙ\85Û\95 Û\8cÛ\8c Ù\86Û\95 Ø¯ Ù\85Û\8cÙ\86جا Ø­Ø¦Ø³Ø§Ú¤Ø¦ØªÙ\88Ù\99 Ù¾Ø§Ú©Ø³Ø§ Ø¨Ø£Ú©Û\8cتØ\8c Ø¬Ø§Ú¯Û\95 Ø¯Ø£Ø¦Ù\86 Ø£Ù\86جÙ\88Ù\85اÙ\86اÙ\85Û\95 Ù\86ئ Ø¯ Ú\86ئÙ\86Û\8c Ù\81Ù\88رÙ\85Û\8c Ø­Ø§Ù\84Û\8c Ø¨Ø£Ù\86Û\8cت.",
-       "changeemail-no-info": "Ø´Ù\88Ù\85ا Ø³Û\8c Û\8cÛ\95 Ú©Ø¦ Ø¯ Ø¦Û\8c Ø¨Ø£Ù\84Ú¯Û\95 Ø¯Ø£Ø³Ø±Ø¦Ø³Û\8c Ø¯Ø§Ø´ØªÙ\88Ù\99Û\8cÛ\8cت Ø¨Ø§Ø³ Ø¨Û\8cاÛ\8cÛ\8cت Ú¤Ø§Ù\85Û\8cن.",
+       "changeemail-header": "اؽ Ù\81Ù\88رÙ\85 Ù\86اÙ\92 Ø³Û\8c Ø¢Ù\84شتکارÛ\8c Ù±Ù\86جÙ\88Ù\85اÙ\86اÙ\85Ù± ØªÙ\88 Ù¾Ù\88ر Ø¨Ù±Ú©Ø½Øª. Ù±Ø± Ù\85ؽÙ\87اÛ\8cت Ú¾Ù±Ø± Ø¬Û\8aر Ù±Ù\86جÙ\88Ù\85اÙ\86اÙ\85Ù± Ù\86اÙ\92 Ø¯ Ù\85ؽÙ\86جا Ù\87ساÙ\88 ØªÙ\88 Ù¾Ø§Ú©Ø³Ø§ Ø¨Ù±Ú©Ø½ØªØ\8c Ø¬Ø§Ú¯Ù± Ø¯Ø§Ù\9bئÙ\86 Ù±Ù\86جÙ\88Ù\85اÙ\86اÙ\85Ù± Ù\86اÙ\92 Ø¯ Ú\86Ù\86Û\8c Ù\81Ù\88رÙ\85ؽ Ù\87اÙ\84Ù\9bÛ\8c Ø¨Ù±Ù\86ؽت.",
+       "changeemail-no-info": "Ø´Ù\85ا Ø³Û\8c Û\8cÙ± Ú©Ø§Ù\92 Ú¤ Ø§Ø½ Ø¨Ù±Ù\84Ú¯Ù± Ø¯Ù±Ø³Ø±Ø³Û\8c Ø¯Ø§Ø´ØªÛ\8aÛ\8cؽت Ø¨Ø§Û\8cٱد Ø¨Ø½Ø§Û\8cؽت Ú¤Ø§Ù\85ؽن.",
        "changeemail-oldemail": "تیرنئشوٙن أنجومانامە ئیسئنی:",
        "changeemail-newemail": "تیرنئشوٙن أنجومانامە تازە:",
        "changeemail-newemail-help": "أر شوما میھایت تیرنئشوٙن أنجفونامە توٙنە ڤئرداریت چئنی جاگە یی نە بایأد حالی بأنیت. شوما. ئوٙسئ أر رازینە گورادئنئتوٙ د ڤیرتوٙ رأتە با نئمی توٙنیت د نۊ زئنەش بأکیت و ھأنی ھیچ جوٙر أنجومانامە یی د ئی ڤیکی ڤئ دأس شوما نئمی رئسە.-",
index 026a5b8..c97fb36 100644 (file)
        "virus-scanfailed": "skanning mislyktes (kode $1)",
        "virus-unknownscanner": "ukjent antivirusprogram:",
        "logouttext": "'''Du er nå logget ut.'''\n\nVær oppmerksom på at noen sider kan fortsette å dukke opp som om du fortsatt var innlogget, helt til du nullstiller nettleserens mellomlager (cache).",
+       "logging-out-notify": "Du blir logget ut, vennligst vent.",
+       "logout-failed": "Kan ikke logge ut nå: $1",
        "cannotlogoutnow-title": "Kan ikke logge ut nå",
        "cannotlogoutnow-text": "Å logge ut er ikke mulig ved bruk av $1.",
        "welcomeuser": "Velkommen $1!",
index 3148cf1..4ba091c 100644 (file)
                        "Babamamadidiane"
                ]
        },
+       "tog-underline": "ߛߘߌ߬ߜߋ߲߬ ߞߘߐߞߍ߬ߙߍ߲߬ߘߍ߬ߣߍ߲",
+       "tog-hideminor": "ߡߊ߬ߦߟߍ߬ߡߊ߲߬ߠߌ߲߬ ߘߋ߬ߣߍ߲ ߠߎ߬ ߢߡߊߘߏ߲߰ ߡߊ߬ߦߟߍ߬ߡߊ߲߬ߠߌ߲߬ ߞߐ߯ߟߕߊ ߟߎ߬ ߘߐ߫",
+       "tog-hidepatrolled": "ߡߊ߬ߦߟߍ߬ߡߊ߲߬ߠߌ߲ ߓߍ߬ߙߍ߲߬ߓߍ߬ߙߍ߲߬ߣߍ߲ ߠߎ߬ ߢߡߊߘߏ߲߰ ߡߊ߬ߦߟߍ߬ߡߊ߲߬ߠߌ߲߬ ߞߐ߯ߟߕߊ ߟߎ߬ ߘߐ߫.",
+       "tog-newpageshidepatrolled": "ߞߐߜߍ߫ ߓߍ߬ߙߍ߲߬ߓߍ߬ߙߍ߲߬ߣߍ߲ ߠߎ߬ ߢߡߊߘߏ߲߰ ߞߐߜߍ߫ ߞߎߘߊ ߟߎ߬ ߘߐ߫.",
        "tog-hidecategorization": "ߞߐߜߍ ߟߎ߬ ߦߌߟߡߊߦߊߟߌ ߢߡߊߘߏ߲߰",
        "tog-numberheadings": "ߕߍ߰ߟߌ ߡߐ߬ߟߐ߲ ߠߎ߬ ߝߙߍߕߍ߫ ߞߍ߲ߖߘߍߡߊߓߟߏߡߊ߬",
        "tog-editondblclick": "ߞߏߜߍ ߟߎ߬ ߡߊߦߟߍ߬ߡߊ߲߫ ߛߐ߲߬ߞߌ߲߬ߠߌ߲߬ߞߏ ߝߌ߬ߟߊ߬ ߟߊ߫",
        "anontalk": "ߢߊߝߐߞߣߍ",
        "navigation": "ߛߏ߲߯ߓߊߟߌ",
        "and": "&#32;ߊ߬ ߣߌ߫",
+       "faq": "ߢ.ߡ",
        "actions": "ߞߍߟߌ ߟߎ߬",
        "namespaces": "ߕߐ߯ ߛߓߍ ߞߣߍ",
        "variants": "ߦߟߍ߬ߡߊ߲߬ߦߟߍ߬ߡߊ߲߬ߠߊ ߟߎ߬",
        "nosuchspecialpage": "ߘߐߜߍ߫ ߓߟߏߡߊߞߊ߬ߣߍ߲߬ ߛߎ߮ ߏ߬ ߝߋ߲߫ ߕߍ߫ ߦߊ߲߬",
        "nospecialpagetext": "<strong>ߊߟߎ߫ ߓߘߊ߫ ߞߐߜߍ߫ ߓߟߏߡߊߞߊ߬ߣߍ߲ ߘߏ߫ ߢߌߣߌ߲߫ ߡߍ߲ ߕߺߴߦߋ߲߬.</strong>\nߞߐߜߍ߫ ߓߟߏߡߊߞߊ߬ߣߍ߲߫ ߓߘߍ߬ߡߊ ߟߎ߬ ߛߙߍߘߍ ߦߋ߫ ߢߌ߲߬ ߠߋ߫ ߞߊ߲߬ [[Special:SpecialPages|{{int:specialpages}}]].",
        "error": "ߝߎ߬ߕߎ߲߬ߕߌ",
+       "databaseerror-error": "ߝߎ߬ߕߎ߲߬ߕߌ: $1",
+       "internalerror": "ߞߣߐߟߊߘߐ߫ ߝߎߕߎ߲ߕߌ",
+       "internalerror_info": "ߞߣߐߟߊߘߐ߫ ߝߎ߬ߕߎ߲߬ߕߌ: $1",
+       "filecopyerror": "ߊ߬ ߕߍ߫ ߣߊ߬ ߛߐ߲߬ ߠߊ߫ ߞߐߕߐ߮ $1 ߓߊߦߟߍ߬ߡߊ߲߬ ߠ ߦߊ߲߬ߊ߫ $2",
+       "filerenameerror": "ߞߐߕߐ߮ \"$1\" ߕߍ߫ ߛߐ߲߬ ߓߊߦߟߍ߬ߡߊ߲߬ ߠߊ߫ ߦߊ߲߬  \"$2\".",
        "badtitle": "ߞߎ߲߬ߕߐ߰ ߖߎ߮",
        "badtitletext": "ߞߐߜߍ߫ ߡߊߢߌ߬ߣߌ߲߬ߞߊ߬ߣߍ߲ ߞߎ߲߬ߕߐ߮ ߓߍ߲߬ߣߍ߲߬ ߕߍ߫߸ ߊ߬ ߘߐߞߏߟߏ߲ ߦߋ߫߸ ߥߟߊ߫ ߞߊ߲ ߠߎ߬ ߣߌ߫ ߢߐ߲߯ߕߍ߫ ߛߘߌ߬ߜߋ߲ ߓߍ߲߬ߓߊߟߌ ߤߊߡߊ߲߫ ߥߞߌ ߟߎ߬ ߕߍ߫ ߛߘߌ߬ߜߋ߲.\nߛߓߍߘߋ߲߫ ߞߋߟߋ߲߫ ߥߟߊ߫ ߛߌߦߊߡߊ߲ ߠߎ߬ ߟߋ߬ ߦߋ߫ ߞߍ߫ ߟߴߊ߬ ߘߐ߫߸ ߡߍ߲ ߠߎ߬ ߕߴߛߋ߫ ߞߍ߫ ߟߊ߫ ߞߎ߲߬ߕߐ߯ ߘߌ߫.",
        "viewsource": "ߊ߬ ߛߎ߲ ߘߐߜߍ߫",
        "viewsource-title": "ߣߌ߲߬ $1 ߛߎ߲ ߘߐߜߍ߫",
        "viewsourcetext": "ߌ ߘߌ߫ ߛߋ߫ ߞߐߜߍ ߣߌ߲߬ ߛߎ߲ ߦߋ߫ ߟߊ߫߸ ߞߵߊ߬ ߓߊߓߌ߬ߟߊ߬",
+       "invalidtitle": "ߞߎ߲߬ߕߐ߮ ߓߍ߲߬ߓߊߟߌ",
+       "exception-nologin": "ߌ ߜߊ߲߬ߞߎ߲߬ߣߍ߲߬ ߕߍ߫",
        "yourname": "ߟߊߓߊ߯ߙߊߟߊߕߐ߮:",
        "userlogin-yourname": "ߟߊ߬ߓߊ߰ߙߊ߬ߟߌ߬ ߕߐ߮",
        "userlogin-yourname-ph": "ߌ ߟߊ߫ ߟߊ߬ߓߊ߰ߙߊ߬ߟߌ߬ ߕߐ߮ ߟߊߘߏ߲߬",
        "createacct-yourpasswordagain-ph": "ߌ ߟߊ߫ ߕߊ߬ߡߌ߲߬ߞߊ߲ ߠߊߘߏ߲߬ ߕߎ߲߯",
        "userlogin-remembermypassword": "ߒ ߜߊ߲߬ߞߎ߲߬ߣߍ߲ ߕߏ߫ ߞߘߊߎ߫",
        "login": "ߌ ߜߊ߲߬ߞߎ߲߬",
+       "nav-login-createaccount": "ߌ ߜߊ߲߬ߞߎ߲߬/ߖߊ߬ߕߋ߬ߘߊ ߘߏ߫ ߟߊߞߊ߬",
+       "logout": "ߌ ߜߊ߲߬ߞߎ߲߬ ߓߐ߫",
+       "userlogout": "ߌ ߜߊ߲߬ߞߎ߲߬ߣߍ߲ ߓߐ߫",
        "userlogin-noaccount": "ߖߊ߬ߕߋ߬ߘߊ߬ ߕߴߌ ߓߟߏ߫ ߓߊ߬؟",
        "userlogin-joinproject": "ߘߏ߫ ߟߊߞߊ߬ {{SITENAME}}",
        "createaccount": "ߖߊ߬ߕߋ߬ߘߊ ߘߏ߫ ߟߊߞߊ߬",
        "userlogin-resetpassword-link": "ߌ ߟߊ߫ ߕߊ߬ߡߌ߲߬ߞߊ߲ ߓߘߊ߫ ߓߐ߫ ߌ ߞߣߐ߫؟",
        "userlogin-helplink2": "ߜߊ߲߬ߞߎ߲߬ߠߌ߲ ߘߍ߬ߡߍ߲߬ߠߌ߲",
+       "userlogin-createanother": "ߖߊ߬ߕߋ߬ߘߊ߬ ߞߎߘߊ߫ ߛߌ߲ߘߌ߫",
        "createacct-emailoptional": "ߢߎߡߍߙߋ߲߫ ߞߏ߲ߘߏ",
        "createacct-email-ph": "ߌ ߟߊ߫ ߢߎߡߍߙߋ߲߫ ߞߏ߲ߘߏ ߟߊߘߏ߲߬",
+       "createacct-reason-ph": "ߡߎ߲߬ߠߊ߫ ߌ ߦߋ߫ ߖߊ߬ߕߋ߬ߘߊ߰ ߜߘߍ߫ ߛߌ߲ߘߌ߫ ߟߊ߫",
        "createacct-submit": "ߖߊ߬ߕߋ߬ߘߊ ߘߏ߫ ߘߊߦߟߍ߬",
+       "createacct-another-submit": "ߖߊ߬ߕߋߘߊ ߛߌ߲ߘߌ߫",
        "createacct-benefit-heading": "{{SITENAME}} ߛߌ߲ߘߌߣߍ߲߫ ߦߴߌ ߢߐ߲߭ ߡߐ߱ ߟߎ߬ ߟߋ߬ ߓߟߏ߫",
        "createacct-benefit-body1": "{{PLURAL:$1|ߊ߬ ߡߊߦߟߍ߬ߡߊ߲߬|ߊ߬ߟߎ߬ ߡߊߦߟߍ߬ߡߊ߲߬}}",
        "createacct-benefit-body2": "$1 {{PLURAL:$1|ߘߐߜߍ|ߞߐߜߍ ߟߎ߬}}",
        "pt-login-button": "ߌ ߜߊ߲߬ߞߎ߲߬",
        "pt-createaccount": "ߖߊ߬ߕߋ߬ߘߊ ߘߏ߫ ߛߌ߲ߘߌ߫",
        "pt-userlogout": "ߌ ߜߊ߲߬ߞߎ߲߬ߣߍ߲ ߓߐ߫",
+       "changepassword": "ߕߊ߬ߡߌ߲߬ߞߊ߲ ߡߊߝߊ߬ߟߋ߲߬",
+       "resetpass_announce": "ߣߴߌ ߦߴߊ߬ ߝߍ߬ ߞߵߌ ߟߊ߫ ߜߊ߲߬ߞߎ߲߬ߠߌ߲ ߠߊߓߊ߲߫߸ ߌ ߦߋ߫ ߖߊ߬ߕߋ߬ߘߊ߰ ߞߎߘߊ߫ ߟߊߘߊ߲߫.",
+       "resetpass_header": "ߖߊ߬ߕߋ߬ߘߊ ߕߊ߬ߡߌ߲߬ߞߊ߲ ߡߊߝߊ߬ߟߋ߲߬",
+       "oldpassword": "ߕߊ߬ߡߌ߲߬ߞߊ߲߬ ߞߘߐ",
+       "newpassword": "ߕߊ߬ߡߌ߲߬ߞߊ߲߬ ߞߎߘߊ",
+       "retypenew": "ߕߊ߬ߡߌ߲߬ߞߊ߲߬ ߞߎߘߊ ߡߊߛߊ߬ߦߌ߬",
+       "resetpass_submit": "ߕߊ߬ߡߌ߲߬ߞߊ߲ ߠߊߘߏ߲߬ ߞߵߌ ߜߊ߲߬ߞߎ߲߬",
        "passwordreset": "ߕߊ߬ߡߌ߲߬ߞߊ߲ ߡߊߦߟߍ߬ߡߊ߲߬",
        "bold_sample": "ߛߓߍߘߋ߲߫ ߞߎ߲ߓߊ",
        "bold_tip": "ߛߓߍߘߋ߲߫ ߞߎ߲ߓߊ",
        "minoredit": "ߣߌ߲߬ ߦߋ߫ ߡߊ߬ߦߟߍ߬ߡߊ߲߬ߠߌ߲߬ ߘߋ߬ߣߍ߲ ߘߏ߫ ߟߋ߬ ߘߌ߫",
        "watchthis": "ߘߐߜߍ ߣߌ߲߬ ߘߐߜߍ߫",
        "savearticle": "ߊ߬ ߟߊߞߎ߲߬ߘߎ߬",
+       "savearticle-start": "ߞߐߜߍ ߟߊߞߎ߲߬ߘߎ߬",
+       "savechanges-start": "ߡߊ߬ߦߟߍ߬ߡߊ߲߬ߠߌ߲ ߠߊߞߎ߲߬ߘߎ߬",
        "preview": "ߊ߬ ߘߐߜߍ߫ ߡߎߣߎ߲߬",
        "showpreview": "ߢߍߦߋߟߌ ߘߐߜߍ߫",
        "showdiff": "ߡߊ߬ߦߟߍ߬ߡߊ߲߬ߠߌ ߠߎ߫ ߦߌ߬ߘߊ߬",
        "anoneditwarning": "<strong>Warning:</strong> ߌ ߜߊ߲߬ߞߎ߲߬ߣߍ߲߬ ߕߍ߫.ߌ ߓߊ߯ ߡߊ߬ߦߟߍ߬ߡߊ߲߬ߠߌ߲ ߛߎ߯-ߎ߯-ߛߎ߫ ߞߍ߫߸ ߌ ߟߊ߫ IP ߛߊ߲߬ߓߊ߬ߕߐ߮ ߘߌ߫ ߞߍ߫ ߦߋߕߊ ߘߌ߫.ߣߴߌ ߞߊ߬ ߜߊ߲߬ߞߎ߲߬ߠߌ߲߬ ߖߐ߲ߖߐ߲ ߞߍ߫ ߕߎ߬ߡߊ ߡߍ߲ <strong>[$1 log in]</strong> or <strong>[$2 create an account]</strong> ߌ ߟߊ߫ ߡߊ߬ߦߟߍ߬ߡߊ߲߬ߣߍ߲ ߠߎ߬ ߘߌ߫ ߓߌ߬ߟߊ߬ ߌ ߜߊ߲߬ߞߎ߲߬ ߕߐ߮ ߟߊ߫߸ ߊ߬ ߣߌ߫ ߣߝߊ߬ ߜߘߍ߫ ߟߎ߫.",
+       "anonpreviewwarning": "<em>ߌ ߜߊ߲߬ߞߎ߲߬ߣߍ߲߬ ߕߍ߫. ߟߊ߬ߞߎ߲߬ߘߎ߬ߟߌ ߘߴߌ ߟߊ߫ IP ߛߊ߲߬ߓߊ߬ߕߐ߮ ߟߊߡߙߊ߬ ߞߐߜߍ ߣߌ߲߬ ߡߊ߬ߦߟߍ߬ߡߊ߲߬ߠߌ߲ ߘߐ߬ߝߐ ߘߐ߫</em>",
        "blockedtext": "<strong>ߌ ߟߊ߫ ߟߊ߬ߓߊ߰ߙߊ߬ ߕߐ߮ ߥߟߊ߫ IP ߛߊ߲߬ߓߊ߬ߕߐ߮ ߓߘߊ߫ ߓߊ߬ߟߊ߲߬߸</strong>\n\nߌ ߓߊ߬ߟߊ߲߬ߣߍ߲߬ ߦߋ߫ $1 ߟߋ߬ ߓߟߏ߫.\nߞߎ߲߭ ߡߍ߲ ߦߴߊ߬ ߟ߫ߊ߫ <em>$2</em>.\n\n•ߓߊ߬ߟߊ߲߬ߠߌ߲ ߘߊߡߌ߬ߣߊ: $8\n•ߓߊ߬ߟߊ߲߬ߠߌ߲ ߛߕߊ ߝߊ: $6\n•ߓߊ߬ߟߊ߲߬ߠߌ߲ ߘߊ߬ߟߎ: $7 \n\nߌ ߘߌ߫ ߛߋ߫ ߗߋߛߓߍ ߗߋ߫ ߟߊ߫ $1 ߡߊ߬ ߥߟߊ߫ ߡߐ߰ ߜߘߍ߫ \n[[{{MediaWiki:Grouppage-sysop}}|administrator]] ߞߊ߬ ߘߊߘߐߖߊߥߏ ߞߍ߫ ߓߊ߬ߟߊ߲߬ߠߌ߲ ߞߊ߲߬.\nߌ ߕߍ߫ ߣߊ߬ ߛߋ߫ ߟߊ߫  \"{{int:emailuser}}\" ߟߊߓߊ߯ߙߊ߫ ߟߊ߫߸ ߟߊ߬ߓߊ߰ߙߊ߬ߢߊ߬ ߖߐ߲ߖߐ߲ ߡߍ߲ ߦߋ߫ ߦߋ߲߬߸ ߢߎߡߍߙߋ߲߫ ߞߏ߲ߘߏ߫ ߖߐ߲ߖߐ߲߫ ߓߟߏߡߊߞߊ߬ߣߍ߲ ߘߏ߫ ߦߴߌ ߟߊ߫ [[Special:Preferences|account preferences]] ߘߐ߫߸ ߊ߬ ߣߴߌ ߡߊ߫ ߓߊ߬ߟߊ߲߬ ߊ߬ ߟߊߓߊ߯ߙߊ ߞߏߛߐ߲߬ ߘߋ߫. ߌ ߟߊ߫ IP ߛߊ߲߬ߓߊ߬ߕߐ߮ ߦߋ߫ $3 ߟߋ߬ ߘߌ߫ ߕߊ߲߬߸ ߊ߬ ߣߴߌ ߟߊ߫ ߛߊ߲߬ߓߊ߬ߕߐ߮ ߓߊ߬ߟߊ߲߬ߣߍ߲ ߦߋ߫ #$5 ߟߋ߬ ߘߌ߫.\nߖߊ߰ߣߌ߲߬ ߌ ߦߋ߫ ߛߊ߲ߝߍ߫ ߝߊߙߊ߲ߝߊ߯ߛߌ ߣߌ߲߬ ߓߍ߯ ߟߊߘߏ߲߬ ߌ ߟߊ߫ ߢߌ߬ߣߌ߲߬ߞߊ߬ߟߌ ߘߐ߫.",
        "loginreqlink": "ߌ ߜߊ߲߬ߞߎ߲߬",
        "newarticletext": "ߌ ߓߘߊ߫ ߛߘߌ߬ߜߋ߲ ߘߏ߫ ߟߊߓߊ߬ߕߏ߬ ߞߐߜߍ ߘߏ߫ ߘߐ߫߸ ߡߍ߲ ߕߴߦߋ߲߬ ߡߎߣߎ߲߬.\nߣߵߌ ߦߴߊ߬ ߝߍ߫ ߞߊ߬ ߞߐߜߍ ߘߏ߫ ߟߊߘߊ߲߫߸ ߛߓߍߟߌ ߘߊߡߌ߬ߣߊ߬ ߘߎ߰ߟߊ߬ߘߐ߫ ߞߏ߲ߘߏ ߘߐ߫ (ߞߊ߬ [$1 ߘߍ߬ߡߍ߲߬ߠߌ߲ ߞߐߜߍ] ߦߋ߫߸ ߖߐ߲߬ߛߊ߬ ߌ ߘߌ߫ ߞߌ߬ߓߊ߬ߙߏ߬ ߖߐ߲ߖߐ߲ ߛߐ߬ߘߐ߲߬). ߣߵߌ ߘߏ߲߬ ߞߍ߫ ߘߊ߫ ߦߊ߲߬ ߝߎ߬ߕߎ߲߬ߕߌ߬ ߓߟߏߡߊ߬߸ ߌ ߟߊ߫ ߛߏ߲߯ߓߊߟߊ߲ <strong>back</strong> ߛߐ߲߬ߞߌ߲߫.",
        "nextrevision": "ߡߊ߬ߛߋ߬ߦߌ߲߬ߣߍ߲߬ ߞߎߘߊ ←",
        "currentrevisionlink": "ߡߊ߬ߛߊ߬ߦߌ߲߬ߠߌ߲ ߕߊ߬ߡߌ߲߬ߣߍ߲",
        "cur": "ߞߍߞߎߘߊ",
+       "next": "ߢߍߕߊ",
        "last": "ߢߍߕߊ",
        "histlegend": "ߝߘߏ߬ߢߐ߲߰ߡߊ ߡߊߡߌ߬ߘߊ: ߓߊߓߌߟߊߟߌ߫ ߞߏ߲ߘߏ ߡߊߡߌ߬ߘߊ߬ ߟߊߢߐ߲߯ߡߊ߫ ߞߊߡߊ߬߸ ߊ߬ ߣߌ߫ ߞߊ߬ ߟߊߢߐ߲߯ߡߊ߫ ߞߘߎ ߛߐ߲߬ߞߌ߲߫ ߊ߬ ߣߌ߫ ߓߊ߫ ߡߊߡߌ߬ߣߊ߬ߣߍ߲ ߕߍ߫ ߥߟߊ߫ ߞߎ߬ߘߎ ߡߍ߲ ߦߋ߫ ߘߎ߰ߟߊ߫. < br/> Legend: ({{int: cur}}) = ߓߐߢߐ߲߯ߡߊ ߡߍ߲ ߦߋ߫ ߕߋ߲߬ߕߋ߲߬ ߓߊ ߟߊ߫߸ ({{int: ߟߊߓߊ߲}}) = ߓߐߢߐ߲߯ߡߊ ߡߍ߲ ߦߋ߫ ߓߊ߫ ߕߊ߬ߡߌ߲߬ߣߍ߲ ߝߍ߬߸ {{int: ߢߟߊߞߎߘߦߊ߫ ߞߏߘߋߞߏߘߋ}} = ߛߊߞߍߟߌ߫ ߝߕߌߣߍ߲߫.",
        "history-fieldset-title": "ߣߐ߬ߡߊ߬ߛߊߦߌ߲ ߠߎ߬ ߛߍ߲ߛߍ߲߫",
        "history-feed-title": "ߡߊ߬ߛߊ߬ߦߌ߲߬ߠߌ߲ ߘߐ߬ߝߐ",
        "history-feed-description": "ߞߐߜߍ ߣߌ߲߬ ߡߊ߬ߦߟߍ߬ߡߊ߲߬ߠߌ߲ ߘߐ߬ߝߐ߸ ߥߞߌ ߘߐ߫",
        "rev-delundel": "ߊ߬ ߦߋߢߊ ߡߊߦߟߍ߬ߡߊ߲߫",
+       "revdelete-show-file-submit": "ߐ߲߬ߐ߲߬ߐ߲߫",
        "mergelog": "ߥߴߌ ߜߊ߲߬ߞߎ߲߬",
        "history-title": "$1 ߡߛߊ߬ߦߌ߲߬ߠߌ߲ ߘߐ߬ߝߐ",
        "difference-title": "ߘߊ߲߬ߝߘߊ߬ߓߐ ߡߍ߲ ߦߋ߫ ߡߛߊ߬ߦߌ߲߬ߠߌ߲ $1 ߕߍ߫",
        "search-showingresults": "{{PLURAL:$4|Result <strong>$1</strong> of <strong>$3</strong>|Results <strong>$1 – $2</strong> of <strong>$3</strong>}}",
        "search-nonefound": "ߖߋ߬ߓߟߌ߬ ߛߌ߫ ߕߍ߫ ߢߌ߬ߣߌ߲߬ߞߊ߬ߟߌ ߣߌ߲߫ ߞߊ߲߬.",
        "mypreferences": "ߟߊ߬ߝߌ߬ߛߦߊ߬ߟߌ",
+       "timezoneregion-africa": "ߊߝߙߌߞߌ߬",
        "group-bot": "ߓߏߕ",
        "group-sysop": "ߞߎ߲߬ߠߊ߬ߛߌ߰ߟߊ",
        "grouppage-bot": "{{ns:project}}:ߓߏߕ",
index 10fdb84..683e975 100644 (file)
        "mw-widgets-abandonedit-discard": "Text shown on the button which closes an editor and discards changes when the user confirms that they want to leave the editor.\n\nPreceded by the prompt {{msg-mw|mw-widgets-abandonedit}}.\n\nFollowed by the button {{msg-mw|mw-widgets-abandonedit-keep}}.",
        "mw-widgets-abandonedit-keep": "Text shown on the button which does not do anything when the user decides that they do not want to leave the editor.\n\nPreceded by the button {{msg-mw|mw-widgets-abandonedit-discard}}.",
        "mw-widgets-abandonedit-title": "Title of the dialog shown when the user tries to leave the editor without saving their changes.\n\nFollowed by the following buttons:\n* {{msg-mw|mw-widgets-abandonedit-discard}}\n* {{msg-mw|mw-widgets-abandonedit-keep}}\n{{Identical|Are you sure?}}",
+       "mw-widgets-copytextlayout-copy": "Label of button to copy text to clipboard.",
+       "mw-widgets-copytextlayout-copy-fail": "Message shown when copying to clipboard failed.",
+       "mw-widgets-copytextlayout-copy-success": "Message shown when copying to clipboard failed.",
        "mw-widgets-dateinput-no-date": "Label of a date input field when no date has been selected.",
        "mw-widgets-dateinput-placeholder-day": "[[File:DateInputWidget active, empty.png|frame|Screenshot]]\nPlaceholder displayed in a date input field when it's empty, representing a date format with 4 digits for year, 2 digits for month, and 2 digits for day, separated with hyphens. This should be uppercase, if possible, and must not include any additional explanations. If there is no good way to translate it, make this message blank.",
        "mw-widgets-dateinput-placeholder-month": "Placeholder displayed in a date input field when it's empty, representing a date format with 4 digits for year and 2 digits for month, separated with hyphens (without a day). This should be uppercase, if possible, and must not include any additional explanations. If there is no good way to translate it, make this message blank.",
index 0dfdb07..3da455d 100644 (file)
        "nohistory": "Не постоји историја измена ове странице.",
        "currentrev": "Најновија измена",
        "currentrev-asof": "Најновија измена на датум $2 у $3",
-       "revisionasof": "Измена на датум $2 у $3",
+       "revisionasof": "Измена на датум $1",
        "revision-info": "Измена од $1 од стране {{GENDER:$6|корисника $2|кориснице $2}}$7",
        "previousrevision": "← Старија измена",
        "nextrevision": "Новија измена →",
index 836f8ad..0a2da29 100644 (file)
        "nohistory": "Ne postoji istorija izmena ove stranice.",
        "currentrev": "Najnovija izmena",
        "currentrev-asof": "Najnovija izmena na datum $2 u $3",
-       "revisionasof": "Izmena na datum $2 u $3",
+       "revisionasof": "Izmena na datum $1",
        "revision-info": "Izmena od $1 od strane {{GENDER:$6|korisnika $2|korisnice $2}}$7",
        "previousrevision": "← Starija izmena",
        "nextrevision": "Novija izmena →",
index 5cd8455..52f2e9f 100644 (file)
        "virus-scanfailed": "skanning misslyckades (kod $1)",
        "virus-unknownscanner": "okänt antivirusprogram:",
        "logouttext": "<strong>Du är nu utloggad.</strong>\n\nObservera att det, tills du tömmer din webbläsares cache, på vissa sidor kan det se ut som att du fortfarande är inloggad.",
+       "logging-out-notify": "Du loggas ut, var god vänta.",
+       "logout-failed": "Kan inte logga ut nu: $1",
        "cannotlogoutnow-title": "Kan inte logga ut nu",
        "cannotlogoutnow-text": "Det går inte att logga ut med $1.",
        "welcomeuser": "Välkommen, $1!",
index d0115ea..666b28f 100644 (file)
@@ -37,13 +37,6 @@ $digitTransformTable = null;
  */
 $separatorTransformTable = null;
 
-/**
- * Extra user preferences, which will be shown in Special:Preferences as
- * checkboxes. Extra settings in derived languages will automatically be
- * appended to the array of the fallback languages.
- */
-$extraUserToggles = [];
-
 /**
  * URLs do not specify their encoding. UTF-8 is used by default, but if the
  * URL is not a valid UTF-8 sequence, we have to try to guess what the real
index e681a04..bb41a91 100644 (file)
@@ -1,6 +1,6 @@
 <?php
 /**
- * Benchmark for Squid purge.
+ * Benchmark for CDN purge.
  *
  * This program is free software; you can redistribute it and/or modify
  * it under the terms of the GNU General Public License as published by
 require_once __DIR__ . '/Benchmarker.php';
 
 /**
- * Maintenance script that benchmarks Squid purge.
+ * Maintenance script that benchmarks CDN purge.
  *
  * @ingroup Benchmark
  */
 class BenchmarkPurge extends Benchmarker {
        public function __construct() {
                parent::__construct();
-               $this->addDescription( 'Benchmark the Squid purge functions.' );
+               $this->addDescription( 'Benchmark the CDN purge functions.' );
        }
 
        public function execute() {
-               global $wgUseSquid, $wgSquidServers;
-               if ( !$wgUseSquid ) {
-                       $this->fatalError( "Squid purge benchmark doesn't do much without squid support on." );
+               global $wgUseCdn, $wgCdnServers;
+
+               if ( !$wgUseCdn ) {
+                       $this->error( "CDN purge benchmark doesn't do much without CDN support on." );
                } else {
-                       $this->output( "There are " . count( $wgSquidServers ) . " defined squid servers:\n" );
+                       $this->output( "There are " . count( $wgCdnServers ) . " defined CDN servers:\n" );
                        if ( $this->hasOption( 'count' ) ) {
                                $lengths = [ intval( $this->getOption( 'count' ) ) ];
                        } else {
@@ -47,7 +48,7 @@ class BenchmarkPurge extends Benchmarker {
                        }
                        foreach ( $lengths as $length ) {
                                $urls = $this->randomUrlList( $length );
-                               $trial = $this->benchSquid( $urls );
+                               $trial = $this->benchCdn( $urls );
                                $this->output( $trial . "\n" );
                        }
                }
@@ -55,12 +56,12 @@ class BenchmarkPurge extends Benchmarker {
 
        /**
         * Run a bunch of URLs through CdnCacheUpdate::purge()
-        * to benchmark Squid response times.
+        * to benchmark CDN response times.
         * @param array $urls A bunch of URLs to purge
         * @param int $trials How many times to run the test?
         * @return string
         */
-       private function benchSquid( $urls, $trials = 1 ) {
+       private function benchCdn( $urls, $trials = 1 ) {
                $start = microtime( true );
                for ( $i = 0; $i < $trials; $i++ ) {
                        CdnCacheUpdate::purge( $urls );
index 81fb5e3..8f47b16 100644 (file)
@@ -136,9 +136,9 @@ class PurgeChangedPages extends Maintenance {
                                }
                        }
 
-                       // Send batch of purge requests out to squids
-                       $squid = new CdnCacheUpdate( $urls, count( $urls ) );
-                       $squid->doUpdate();
+                       // Send batch of purge requests out to CDN servers
+                       $cdn = new CdnCacheUpdate( $urls, count( $urls ) );
+                       $cdn->doUpdate();
 
                        if ( $this->hasOption( 'sleep-per-batch' ) ) {
                                // sleep-per-batch is milliseconds, usleep wants micro seconds.
index 16a62f4..d558c47 100644 (file)
@@ -1,6 +1,6 @@
 <?php
 /**
- * Send purge requests for listed pages to squid
+ * Send purge requests for listed pages to CDN
  *
  * This program is free software; you can redistribute it and/or modify
  * it under the terms of the GNU General Public License as published by
 require_once __DIR__ . '/Maintenance.php';
 
 /**
- * Maintenance script that sends purge requests for listed pages to squid.
+ * Maintenance script that sends purge requests for listed pages to CDN.
  *
  * @ingroup Maintenance
  */
 class PurgeList extends Maintenance {
        public function __construct() {
                parent::__construct();
-               $this->addDescription( 'Send purge requests for listed pages to squid' );
+               $this->addDescription( 'Send purge requests for listed pages to CDN' );
                $this->addOption( 'purge', 'Whether to update page_touched.', false, false );
                $this->addOption( 'namespace', 'Namespace number', false, true );
                $this->addOption( 'all', 'Purge all pages', false, false );
@@ -120,7 +120,7 @@ class PurgeList extends Maintenance {
 
        /**
         * Helper to purge an array of $urls
-        * @param array $urls List of URLS to purge from squids
+        * @param array $urls List of URLS to purge from CDNs
         */
        private function sendPurgeRequest( $urls ) {
                if ( $this->hasOption( 'delay' ) ) {
index bd3281a..15ec62d 100644 (file)
@@ -36,7 +36,7 @@ if ( $wgRequest->getVal( 'ctype' ) == 'application/xml' ) {
 $response = $wgRequest->response();
 $response->header( "Content-type: $ctype" );
 
-// Set an Expires header so that squid can cache it for a short time
+// Set an Expires header so that CDN can cache it for a short time
 // Short enough so that the sysadmin barely notices when $wgSitename is changed
 $expiryTime = 600; # 10 minutes
 $response->header( 'Expires: ' . gmdate( 'D, d M Y H:i:s', time() + $expiryTime ) . ' GMT' );
index 4c359ee..483e374 100644 (file)
@@ -2027,6 +2027,7 @@ return [
                        'resources/src/mediawiki.special/userrights.css',
                        'resources/src/mediawiki.special/watchlist.css',
                        'resources/src/mediawiki.special/block.less',
+                       'resources/src/mediawiki.special/blocklist.less',
                ],
                'targets' => [ 'desktop', 'mobile' ],
        ],
@@ -2043,6 +2044,7 @@ return [
                        'oojs-ui.styles.icons-editing-advanced',
                        'oojs-ui.styles.icons-interactions',
                        'oojs-ui.styles.icons-moderation',
+                       'mediawiki.widgets',
                        'mediawiki.widgets.datetime',
                        'jquery.makeCollapsible',
                ],
@@ -2128,10 +2130,6 @@ return [
                ],
                'targets' => [ 'desktop', 'mobile' ],
        ],
-       'mediawiki.special.blocklist' => [
-               'styles' => 'resources/src/mediawiki.special/blocklist.less',
-               'targets' => [ 'desktop', 'mobile' ],
-       ],
        'mediawiki.special.changecredentials.js' => [
                'scripts' => 'resources/src/mediawiki.special.changecredentials.js',
                'dependencies' => [
@@ -2503,12 +2501,16 @@ return [
                'scripts' => [
                        'resources/src/mediawiki.widgets/mw.widgets.NamespaceInputWidget.js',
                        'resources/src/mediawiki.widgets/mw.widgets.ComplexNamespaceInputWidget.js',
+                       'resources/src/mediawiki.widgets/mw.widgets.CopyTextLayout.js',
                        'resources/src/mediawiki.widgets/mw.widgets.TitleWidget.js',
                        'resources/src/mediawiki.widgets/mw.widgets.TitleInputWidget.js',
                        'resources/src/mediawiki.widgets/mw.widgets.TitleSearchWidget.js',
                        'resources/src/mediawiki.widgets/mw.widgets.ComplexTitleInputWidget.js',
                        'resources/src/mediawiki.widgets/mw.widgets.TitleOptionWidget.js',
                ],
+               'styles' => [
+                       'resources/src/mediawiki.widgets/mw.widgets.CopyTextLayout.css',
+               ],
                'skinStyles' => [
                        'default' => [
                                'resources/src/mediawiki.widgets/mw.widgets.TitleWidget.less',
@@ -2522,11 +2524,17 @@ return [
                        'mediawiki.Title',
                        'mediawiki.api',
                        'mediawiki.String',
+                       // CopyTextLayout
+                       'mediawiki.notify',
                ],
                'messages' => [
                        // NamespaceInputWidget
                        'blanknamespace',
                        'namespacesall',
+                       // CopyTextLayout
+                       'mw-widgets-copytextlayout-copy',
+                       'mw-widgets-copytextlayout-copy-fail',
+                       'mw-widgets-copytextlayout-copy-success',
                        // TitleInputWidget
                        'mw-widgets-titleinput-description-new-page',
                        'mw-widgets-titleinput-description-redirect',
index a585cf3..9e6ecc8 100644 (file)
                                                }
                                                $.suggestions.hide( context );
                                                $.suggestions.cancel( context );
-                                       } );
+                                       } )
+                                       // Simulate a keypress on load. This loads the search suggestions when there are already
+                                       // typed characters before the JavaScript is loaded.
+                                       .trigger( 'keypress' );
                        }
 
                        // Store the context for next time
index e063a39..631a5c6 100644 (file)
                 * @return {OO.ui.MenuOptionWidget[]} Each item's data should be an OO.ui.FieldLayout
                 */
                formatRequest: function ( displayParams, rawParams ) {
-                       var jsonInput,
+                       var jsonLayout,
                                items = [
                                        new OO.ui.MenuOptionWidget( {
                                                label: Util.parseMsg( 'apisandbox-request-format-url-label' ),
-                                               data: new OO.ui.FieldLayout(
-                                                       new OO.ui.TextInputWidget( {
-                                                               readOnly: true,
-                                                               value: mw.util.wikiScript( 'api' ) + '?' + $.param( displayParams )
-                                                       } ), {
-                                                               label: Util.parseMsg( 'apisandbox-request-url-label' )
-                                                       }
-                                               )
+                                               data: new mw.widgets.CopyTextLayout( {
+                                                       label: Util.parseMsg( 'apisandbox-request-url-label' ),
+                                                       copyText: mw.util.wikiScript( 'api' ) + '?' + $.param( displayParams )
+                                               } )
                                        } ),
                                        new OO.ui.MenuOptionWidget( {
                                                label: Util.parseMsg( 'apisandbox-request-format-json-label' ),
-                                               data: new OO.ui.FieldLayout(
-                                                       jsonInput = new OO.ui.MultilineTextInputWidget( {
+                                               data: jsonLayout = new mw.widgets.CopyTextLayout( {
+                                                       label: Util.parseMsg( 'apisandbox-request-json-label' ),
+                                                       copyText: JSON.stringify( displayParams, null, '\t' ),
+                                                       multiline: true,
+                                                       textInput: {
                                                                classes: [ 'mw-apisandbox-textInputCode' ],
-                                                               readOnly: true,
                                                                autosize: true,
-                                                               maxRows: 6,
-                                                               value: JSON.stringify( displayParams, null, '\t' )
-                                                       } ), {
-                                                               label: Util.parseMsg( 'apisandbox-request-json-label' )
+                                                               maxRows: 6
                                                        }
-                                               ).on( 'toggle', function ( visible ) {
+                                               ).on( 'toggle', function ( visible ) {
                                                        if ( visible ) {
                                                                // Call updatePosition instead of adjustSize
                                                                // because the latter has weird caching
                                                                // behavior and the former bypasses it.
-                                                               jsonInput.updatePosition();
+                                                               jsonLayout.textInput.updatePosition();
                                                        }
                                                } )
                                        } )
                                progressLoading = false;
                                $progressText = $( '<span>' ).text( mw.message( 'apisandbox-sending-request' ).text() );
                                progress = new OO.ui.ProgressBarWidget( {
-                                       progress: false,
-                                       $content: $progressText
+                                       progress: false
                                } );
 
                                $result = $( '<div>' )
-                                       .append( progress.$element );
+                                       .append( $progressText, progress.$element );
 
                                resultPage = page = new OO.ui.PageLayout( '|results|', { expanded: false } );
                                page.setupOutlineItem = function () {
                        };
 
                this.$element.empty()
-                       .append( new OO.ui.ProgressBarWidget( {
-                               progress: false,
-                               text: mw.message( 'apisandbox-loading', this.displayText ).text()
-                       } ).$element );
+                       .append(
+                               document.createTextNode(
+                                       mw.message( 'apisandbox-loading', this.displayText ).text()
+                               ),
+                               new OO.ui.ProgressBarWidget( { progress: false } ).$element
+                       );
 
                Util.fetchModuleInfo( this.apiModule )
                        .done( function ( pi ) {
index 58657db..6d003aa 100644 (file)
                                pageRestrictionsWidget.setDisabled( !editingIsSelected || isSitewide );
                                namespaceRestrictionsWidget.setDisabled( !editingIsSelected || isSitewide );
                                if ( blockAllowsUTEdit ) {
-                                       // This option is disabled for partial blocks unless a namespace restriction
-                                       // for the User_talk namespace is in place.
+                                       // Disable for partial blocks, unless the block is against the User_talk namespace
                                        preventTalkPageEditWidget.setDisabled(
-                                               editingIsSelected &&
-                                               editingRestrictionValue === 'partial' &&
-                                               namespaceRestrictionsWidget.getValue().indexOf(
-                                                       String( mw.config.get( 'wgNamespaceIds' ).user_talk )
-                                               ) === -1
+                                               // Partial block that doesn't block editing
+                                               !editingIsSelected ||
+                                               // Partial block that blocks editing and doesn't block the User_talk namespace
+                                               (
+                                                       editingRestrictionValue === 'partial' &&
+                                                       namespaceRestrictionsWidget.getValue().indexOf(
+                                                               String( mw.config.get( 'wgNamespaceIds' ).user_talk )
+                                                       ) === -1
+                                               )
                                        );
                                }
                        }
diff --git a/resources/src/mediawiki.widgets/mw.widgets.CopyTextLayout.css b/resources/src/mediawiki.widgets/mw.widgets.CopyTextLayout.css
new file mode 100644 (file)
index 0000000..f09128a
--- /dev/null
@@ -0,0 +1,19 @@
+/*!
+ * MediaWiki Widgets – CopyTextLayout styles.
+ *
+ * @copyright 2011-2015 MediaWiki Widgets Team and others; see AUTHORS.txt
+ * @license The MIT License (MIT); see LICENSE.txt
+ */
+
+.mw-widget-copyTextLayout > .oo-ui-fieldLayout-body > .oo-ui-fieldLayout-field {
+       /* TODO: This should be upstreamed to OOUI */
+       max-width: 50em;
+}
+
+.mw-widget-copyTextLayout-multiline-button {
+       display: block;
+       max-width: 50em;
+       margin-top: 0.5em;
+       /* Float to right of inline help */
+       float: right;
+}
diff --git a/resources/src/mediawiki.widgets/mw.widgets.CopyTextLayout.js b/resources/src/mediawiki.widgets/mw.widgets.CopyTextLayout.js
new file mode 100644 (file)
index 0000000..65e7eb7
--- /dev/null
@@ -0,0 +1,114 @@
+/*!
+ * MediaWiki Widgets - CopyTextLayout class.
+ *
+ * @copyright 2011-2015 MediaWiki Widgets Team and others; see AUTHORS.txt
+ * @license The MIT License (MIT); see LICENSE.txt
+ */
+( function () {
+
+       /**
+        * An action field layout containing some readonly text and a button to copy
+        * it to the clipboard.
+        *
+        * @class
+        * @extends OO.ui.ActionFieldLayout
+        *
+        * @constructor
+        * @param {Object} [config] Configuration options
+        * @cfg {string} copyText Text to copy, can also be provided as textInput.value
+        * @cfg {Object} textInput Config for text input
+        * @cfg {Object} button Config for button
+        * @cfg {string} successMessage Success message,
+        *  defaults to 'mw-widgets-copytextlayout-copy-success'.
+        * @cfg {string} failMessage Failure message,
+        *  defaults to 'mw-widgets-copytextlayout-copy-fail'.
+        */
+       mw.widgets.CopyTextLayout = function MwWidgetsCopyTextLayout( config ) {
+               var TextClass;
+               config = config || {};
+
+               // Properties
+               TextClass = config.multiline ? OO.ui.MultilineTextInputWidget : OO.ui.TextInputWidget;
+               this.textInput = new TextClass( $.extend( {
+                       value: config.copyText,
+                       readOnly: true
+               }, config.textInput ) );
+               this.button = new OO.ui.ButtonWidget( $.extend( {
+                       label: mw.msg( 'mw-widgets-copytextlayout-copy' ),
+                       icon: 'articles'
+               }, config.button ) );
+               this.successMessage = config.successMessage || mw.msg( 'mw-widgets-copytextlayout-copy-success' );
+               this.failMessage = config.failMessage || mw.msg( 'mw-widgets-copytextlayout-copy-fail' );
+
+               // Parent constructor
+               mw.widgets.CopyTextLayout.super.call( this, this.textInput, this.button, config );
+
+               // HACK: Remove classes which connect widgets when using
+               // a multiline text input. TODO: This should be handled in OOUI.
+               if ( config.multiline ) {
+                       this.$input.removeClass( 'oo-ui-actionFieldLayout-input' );
+                       this.$button
+                               .removeClass( 'oo-ui-actionFieldLayout-button' )
+                               .addClass( 'mw-widget-copyTextLayout-multiline-button' );
+               }
+
+               // Events
+               this.button.connect( this, { click: 'onButtonClick' } );
+               this.textInput.$input.on( 'click', this.onInputClick.bind( this ) );
+
+               this.$element.addClass( 'mw-widget-copyTextLayout' );
+       };
+
+       /* Inheritence */
+
+       OO.inheritClass( mw.widgets.CopyTextLayout, OO.ui.ActionFieldLayout );
+
+       /* Methods */
+
+       /**
+        * Handle button click events
+        *
+        * @fires copy
+        */
+       mw.widgets.CopyTextLayout.prototype.onButtonClick = function () {
+               var copied;
+
+               this.selectText();
+
+               try {
+                       copied = document.execCommand( 'copy' );
+               } catch ( e ) {
+                       copied = false;
+               }
+               if ( copied ) {
+                       mw.notify( this.successMessage );
+               } else {
+                       mw.notify( this.failMessage, { type: 'error' } );
+               }
+
+               this.emit( 'copy', copied );
+       };
+
+       /**
+        * Handle button click events
+        */
+       mw.widgets.CopyTextLayout.prototype.onInputClick = function () {
+               this.selectText();
+       };
+
+       /**
+        * Select the text to copy
+        */
+       mw.widgets.CopyTextLayout.prototype.selectText = function () {
+               var input = this.textInput.$input[ 0 ],
+                       scrollTop = input.scrollTop,
+                       scrollLeft = input.scrollLeft;
+
+               this.textInput.select();
+
+               // Restore scroll position
+               input.scrollTop = scrollTop;
+               input.scrollLeft = scrollLeft;
+       };
+
+}() );
index 1b2b159..db9d2ab 100644 (file)
@@ -5,6 +5,13 @@
  */
 class MovePageTest extends MediaWikiTestCase {
 
+       public function setUp() {
+               parent::setUp();
+               $this->tablesUsed[] = 'page';
+               $this->tablesUsed[] = 'revision';
+               $this->tablesUsed[] = 'comment';
+       }
+
        /**
         * @dataProvider provideIsValidMove
         * @covers MovePage::isValidMove
@@ -83,4 +90,108 @@ class MovePageTest extends MediaWikiTestCase {
                $status = $mp->move( $user, 'Reason', true );
                $this->assertTrue( $status->hasMessage( $error ) );
        }
+
+       /**
+        * Test moving subpages from one page to another
+        * @covers MovePage::moveSubpages
+        */
+       public function testMoveSubpages() {
+               $name = ucfirst( __FUNCTION__ );
+
+               $subPages = [ "Talk:$name/1", "Talk:$name/2" ];
+               $ids = [];
+               $pages = [
+                       $name,
+                       "Talk:$name",
+                       "$name 2",
+                       "Talk:$name 2",
+               ];
+               foreach ( array_merge( $pages, $subPages ) as $page ) {
+                       $ids[$page] = $this->createPage( $page );
+               }
+
+               $oldTitle = Title::newFromText( "Talk:$name" );
+               $newTitle = Title::newFromText( "Talk:$name 2" );
+               $mp = new MovePage( $oldTitle, $newTitle );
+               $status = $mp->moveSubpages( $this->getTestUser()->getUser(), 'Reason', true );
+
+               $this->assertTrue( $status->isGood(),
+                       "Moving subpages from Talk:{$name} to Talk:{$name} 2 was not completely successful." );
+               foreach ( $subPages as $page ) {
+                       $this->assertMoved( $page, str_replace( $name, "$name 2", $page ), $ids[$page] );
+               }
+       }
+
+       /**
+        * Test moving subpages from one page to another
+        * @covers MovePage::moveSubpagesIfAllowed
+        */
+       public function testMoveSubpagesIfAllowed() {
+               $name = ucfirst( __FUNCTION__ );
+
+               $subPages = [ "Talk:$name/1", "Talk:$name/2" ];
+               $ids = [];
+               $pages = [
+                       $name,
+                       "Talk:$name",
+                       "$name 2",
+                       "Talk:$name 2",
+               ];
+               foreach ( array_merge( $pages, $subPages ) as $page ) {
+                       $ids[$page] = $this->createPage( $page );
+               }
+
+               $oldTitle = Title::newFromText( "Talk:$name" );
+               $newTitle = Title::newFromText( "Talk:$name 2" );
+               $mp = new MovePage( $oldTitle, $newTitle );
+               $status = $mp->moveSubpagesIfAllowed( $this->getTestUser()->getUser(), 'Reason', true );
+
+               $this->assertTrue( $status->isGood(),
+                       "Moving subpages from Talk:{$name} to Talk:{$name} 2 was not completely successful." );
+               foreach ( $subPages as $page ) {
+                       $this->assertMoved( $page, str_replace( $name, "$name 2", $page ), $ids[$page] );
+               }
+       }
+
+       /**
+        * Shortcut function to create a page and return its id.
+        *
+        * @param string $name Page to create
+        * @return int ID of created page
+        */
+       protected function createPage( $name ) {
+               return $this->editPage( $name, 'Content' )->value['revision']->getPage();
+       }
+
+       /**
+        * @param string $from Prefixed name of source
+        * @param string $to Prefixed name of destination
+        * @param string $id Page id of the page to move
+        * @param array|string|null $opts Options: 'noredirect' to expect no redirect
+        */
+       protected function assertMoved( $from, $to, $id, $opts = null ) {
+               $opts = (array)$opts;
+
+               Title::clearCaches();
+               $fromTitle = Title::newFromText( $from );
+               $toTitle = Title::newFromText( $to );
+
+               $this->assertTrue( $toTitle->exists(),
+                       "Destination {$toTitle->getPrefixedText()} does not exist" );
+
+               if ( in_array( 'noredirect', $opts ) ) {
+                       $this->assertFalse( $fromTitle->exists(),
+                               "Source {$fromTitle->getPrefixedText()} exists" );
+               } else {
+                       $this->assertTrue( $fromTitle->exists(),
+                               "Source {$fromTitle->getPrefixedText()} does not exist" );
+                       $this->assertTrue( $fromTitle->isRedirect(),
+                               "Source {$fromTitle->getPrefixedText()} is not a redirect" );
+
+                       $target = Revision::newFromTitle( $fromTitle )->getContent()->getRedirectTarget();
+                       $this->assertSame( $toTitle->getPrefixedText(), $target->getPrefixedText() );
+               }
+
+               $this->assertSame( $id, $toTitle->getArticleID() );
+       }
 }
index afc6bb5..ebd9f1d 100644 (file)
@@ -526,9 +526,9 @@ class OutputPageTest extends MediaWikiTestCase {
                                function ( $op ) {
                                        $op->getContext()->setUser( $this->getTestUser()->getUser() );
                                } ],
-                       'After Squid expiry' =>
+                       'After CDN expiry' =>
                                [ $lastModified, $lastModified, false,
-                                       [ 'UseSquid' => true, 'SquidMaxage' => 3599 ] ],
+                                       [ 'UseCdn' => true, 'CdnMaxAge' => 3599 ] ],
                        'Hook allows cache use' =>
                                [ $lastModified + 1, $lastModified, true, [],
                                function ( $op, $that ) {
@@ -2225,7 +2225,7 @@ class OutputPageTest extends MediaWikiTestCase {
        }
 
        public function provideAdaptCdnTTL() {
-               global $wgSquidMaxage;
+               global $wgCdnMaxAge;
                $now = time();
                self::$fakeTime = $now;
                return [
@@ -2234,7 +2234,7 @@ class OutputPageTest extends MediaWikiTestCase {
                        'Five minutes from now' => [ [ $now + 300 ], IExpiringStore::TTL_MINUTE ],
                        'Five minutes ago, initial maxage four minutes' =>
                                [ [ $now - 300 ], 270, [ 'initialMaxage' => 240 ] ],
-                       'A very long time ago' => [ [ $now - 1000000000 ], $wgSquidMaxage ],
+                       'A very long time ago' => [ [ $now - 1000000000 ], $wgCdnMaxAge ],
                        'Initial maxage zero' => [ [ $now - 300 ], 270, [ 'initialMaxage' => 0 ] ],
 
                        'false' => [ [ false ], IExpiringStore::TTL_MINUTE ],
index cda5660..0d5c59b 100644 (file)
@@ -391,7 +391,7 @@ class WebRequestTest extends MediaWikiTestCase {
         * @dataProvider provideGetIP
         * @covers WebRequest::getIP
         */
-       public function testGetIP( $expected, $input, $squid, $xffList, $private, $description ) {
+       public function testGetIP( $expected, $input, $cdn, $xffList, $private, $description ) {
                $this->setServerVars( $input );
                $this->setMwGlobals( [
                        'wgUsePrivateIPs' => $private,
@@ -405,7 +405,7 @@ class WebRequestTest extends MediaWikiTestCase {
                        ]
                ] );
 
-               $this->setService( 'ProxyLookup', new ProxyLookup( [], $squid ) );
+               $this->setService( 'ProxyLookup', new ProxyLookup( [], $cdn ) );
 
                $request = new WebRequest();
                $result = $request->getIP();
@@ -587,8 +587,8 @@ class WebRequestTest extends MediaWikiTestCase {
        public function testGetIpLackOfRemoteAddrThrowAnException() {
                // ensure that local install state doesn't interfere with test
                $this->setMwGlobals( [
-                       'wgSquidServersNoPurge' => [],
-                       'wgSquidServers' => [],
+                       'wgCdnServers' => [],
+                       'wgCdnServersNoPurge' => [],
                        'wgUsePrivateIPs' => false,
                        'wgHooks' => [],
                ] );
index 9cb84e2..a5518a1 100644 (file)
@@ -490,7 +490,7 @@ class ApiMainTest extends ApiTestCase {
         * @param int $status Expected response status
         * @param array $options Array of options:
         *   post => true Request is a POST
-        *   cdn => true CDN is enabled ($wgUseSquid)
+        *   cdn => true CDN is enabled ($wgUseCdn)
         */
        public function testCheckConditionalRequestHeaders(
                $headers, $conditions, $status, $options = []
@@ -508,7 +508,7 @@ class ApiMainTest extends ApiTestCase {
                $priv->mInternalMode = false;
 
                if ( !empty( $options['cdn'] ) ) {
-                       $this->setMwGlobals( 'wgUseSquid', true );
+                       $this->setMwGlobals( 'wgUseCdn', true );
                }
 
                // Can't do this in TestSetup.php because Setup.php will override it
@@ -531,7 +531,7 @@ class ApiMainTest extends ApiTestCase {
        }
 
        public static function provideCheckConditionalRequestHeaders() {
-               global $wgSquidMaxage;
+               global $wgCdnMaxAge;
                $now = time();
 
                return [
@@ -614,15 +614,15 @@ class ApiMainTest extends ApiTestCase {
                                [ [ 'If-Modified-Since' => 'a potato' ],
                                        [ 'last-modified' => wfTimestamp( TS_MW, $now - 1 ) ], 200 ],
 
-                       // Anything before $wgSquidMaxage seconds ago should be considered
+                       // Anything before $wgCdnMaxAge seconds ago should be considered
                        // expired.
                        'If-Modified-Since with CDN post-expiry' =>
-                               [ [ 'If-Modified-Since' => wfTimestamp( TS_RFC2822, $now - $wgSquidMaxage * 2 ) ],
-                                       [ 'last-modified' => wfTimestamp( TS_MW, $now - $wgSquidMaxage * 3 ) ],
+                               [ [ 'If-Modified-Since' => wfTimestamp( TS_RFC2822, $now - $wgCdnMaxAge * 2 ) ],
+                                       [ 'last-modified' => wfTimestamp( TS_MW, $now - $wgCdnMaxAge * 3 ) ],
                                        200, [ 'cdn' => true ] ],
                        'If-Modified-Since with CDN pre-expiry' =>
-                               [ [ 'If-Modified-Since' => wfTimestamp( TS_RFC2822, $now - $wgSquidMaxage / 2 ) ],
-                                       [ 'last-modified' => wfTimestamp( TS_MW, $now - $wgSquidMaxage * 3 ) ],
+                               [ [ 'If-Modified-Since' => wfTimestamp( TS_RFC2822, $now - $wgCdnMaxAge / 2 ) ],
+                                       [ 'last-modified' => wfTimestamp( TS_MW, $now - $wgCdnMaxAge * 3 ) ],
                                        304, [ 'cdn' => true ] ],
                ];
        }
index 37a28c3..6c2fdda 100644 (file)
@@ -124,6 +124,26 @@ class LegacyLoggerTest extends MediaWikiTestCase {
                ];
        }
 
+       /**
+        * @covers MediaWiki\Logger\LegacyLogger::interpolate
+        */
+       public function testInterpolate_Error() {
+               // @todo Merge this into provideInterpolate once we drop HHVM support
+               if ( !class_exists( \Error::class ) ) {
+                       $this->markTestSkipped( 'Error class does not exist' );
+               }
+
+               $err = new \Error( 'Test error' );
+               $message = '{exception}';
+               $context = [ 'exception' => $err ];
+               $expect = '[Error ' . get_class( $err ) . '( ' .
+                       $err->getFile() . ':' . $err->getLine() . ') ' .
+                       $err->getMessage() . ']';
+
+               $this->assertEquals(
+                       $expect, LegacyLogger::interpolate( $message, $context ) );
+       }
+
        /**
         * @covers MediaWiki\Logger\LegacyLogger::shouldEmit
         * @dataProvider provideShouldEmit
index 2768d32..bdd5c81 100644 (file)
@@ -20,6 +20,7 @@
 
 namespace MediaWiki\Logger\Monolog;
 
+use AssertionError;
 use InvalidArgumentException;
 use LengthException;
 use LogicException;
@@ -72,4 +73,50 @@ class LineFormatterTest extends MediaWikiTestCase {
                $this->assertContains( "\nCaused by: [Exception LogicException]", $out );
                $this->assertContains( "\n  #0", $out );
        }
+
+       /**
+        * @covers MediaWiki\Logger\Monolog\LineFormatter::normalizeException
+        */
+       public function testNormalizeExceptionErrorNoTrace() {
+               if ( !class_exists( AssertionError::class ) ) {
+                       $this->markTestSkipped( 'AssertionError class does not exist' );
+               }
+
+               $fixture = new LineFormatter();
+               $fixture->includeStacktraces( false );
+               $fixture = TestingAccessWrapper::newFromObject( $fixture );
+               $boom = new InvalidArgumentException( 'boom', 0,
+                       new LengthException( 'too long', 0,
+                               new AssertionError( 'Spock wuz here' )
+                       )
+               );
+               $out = $fixture->normalizeException( $boom );
+               $this->assertContains( "\n[Exception InvalidArgumentException]", $out );
+               $this->assertContains( "\nCaused by: [Exception LengthException]", $out );
+               $this->assertContains( "\nCaused by: [Error AssertionError]", $out );
+               $this->assertNotContains( "\n  #0", $out );
+       }
+
+       /**
+        * @covers MediaWiki\Logger\Monolog\LineFormatter::normalizeException
+        */
+       public function testNormalizeExceptionErrorTrace() {
+               if ( !class_exists( AssertionError::class ) ) {
+                       $this->markTestSkipped( 'AssertionError class does not exist' );
+               }
+
+               $fixture = new LineFormatter();
+               $fixture->includeStacktraces( true );
+               $fixture = TestingAccessWrapper::newFromObject( $fixture );
+               $boom = new InvalidArgumentException( 'boom', 0,
+                       new LengthException( 'too long', 0,
+                               new AssertionError( 'Spock wuz here' )
+                       )
+               );
+               $out = $fixture->normalizeException( $boom );
+               $this->assertContains( "\n[Exception InvalidArgumentException]", $out );
+               $this->assertContains( "\nCaused by: [Exception LengthException]", $out );
+               $this->assertContains( "\nCaused by: [Error AssertionError]", $out );
+               $this->assertContains( "\n  #0", $out );
+       }
 }
index 7032909..43dd5d4 100644 (file)
--- a/thumb.php
+++ b/thumb.php
@@ -272,7 +272,7 @@ function wfStreamThumb( array $params ) {
 
        // For 404 handled thumbnails, we only use the base name of the URI
        // for the thumb params and the parent directory for the source file name.
-       // Check that the zone relative path matches up so squid caches won't pick
+       // Check that the zone relative path matches up so CDN caches won't pick
        // up thumbs that would not be purged on source file deletion (T36231).
        if ( $rel404 !== null ) { // thumbnail was handled via 404
                if ( rawurldecode( $rel404 ) === $img->getThumbRel( $thumbName ) ) {